Initial release: business-name finder with live domain availability
Free, no-account tool for naming a business and finding a domain you can actually register. Availability uses no paid API and no key. IANA's RDAP bootstrap maps ~1,200 TLDs to their authoritative registry servers (404 = free, 200 = taken); the handful with no RDAP at all (.io, .co, .me, .sh, .gg, .us) fall back to a DNS NS lookup and are reported as "probably free" rather than confirmed, because a registered-but-undelegated domain is indistinguishable that way. Name generation is pure, deterministic, and client-side — eight strategies over a curated word bank, ranked by a scorer that does the real quality work. Three of its guards (prefix-only hint matching, -er-only syncopation, truncation rejection) exist because of specific bad output and should not be relaxed. Optional AI suggestions use the visitor's OWN Anthropic/Gemini key from localStorage, called browser-direct, so this stays free to run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JChWdFJPCRxMBxErb8kUVK
This commit is contained in:
92
README.md
Normal file
92
README.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# names.poweredbyotm.com
|
||||
|
||||
Free business-name finder: type a few keywords, get brandable name ideas, and see
|
||||
which domains are actually free — checked against the registries themselves.
|
||||
|
||||
- **Stack:** Next.js 15 (App Router, `output: "standalone"`), React 18, no DB, no
|
||||
auth, public. Name generation runs **client-side**; availability is a server
|
||||
route because browsers can't do DNS and RDAP servers send no CORS headers.
|
||||
- **Repo:** `tonym/names` on `git.poweredbyotm.com`.
|
||||
- **Deploy:** OTM platform — first-party app (`/apps`), built + deployed via the
|
||||
platform MCP, not docker-compose-from-this-repo.
|
||||
|
||||
## How availability works — and what it costs (nothing)
|
||||
|
||||
There is no paid domain API here and no key to manage.
|
||||
|
||||
1. **RDAP** (RFC 7482), the registries' own replacement for WHOIS. IANA
|
||||
publishes a bootstrap file at `data.iana.org/rdap/dns.json` mapping every TLD
|
||||
to its authoritative RDAP server. We cache it for 24h, resolve the TLD
|
||||
ourselves, and query that server directly — `404` means unregistered, `200`
|
||||
means registered. Covers ~1,200 TLDs including `.com/.net/.org/.ai/.dev/.app`.
|
||||
2. **DNS `NS` lookup**, for the TLDs that publish no RDAP server at all — `.io`,
|
||||
`.co`, `.me`, `.sh`, `.gg`, `.us`, `.de`. NXDOMAIN strongly suggests
|
||||
unregistered, but a registered domain with no delegated nameservers looks
|
||||
identical. These report `unverified-available` and the UI shows them in amber
|
||||
as *probably free*, never as a confirmed green.
|
||||
|
||||
**Do not "simplify" this by pointing everything at `rdap.org`.** Its redirector
|
||||
returns a bare `404` both for "this domain is free" and for "I have no RDAP
|
||||
server for this TLD" — the two cases are indistinguishable from the status code,
|
||||
which is exactly the bug that would report every `.io` as available.
|
||||
|
||||
Manners, since we're an anonymous client against other people's public
|
||||
endpoints: 60 domains max per request, 8-wide concurrency, a per-IP token
|
||||
bucket, and a 10-minute result cache.
|
||||
|
||||
## Name generation
|
||||
|
||||
`src/lib/generate.ts` is pure and deterministic — the same
|
||||
`(keywords, style, seed)` always yields the same list, so re-renders don't
|
||||
reshuffle results and a shared URL reproduces what the sender saw.
|
||||
|
||||
Eight strategies (compound, suffix-word, action, blend, coined, clipped, root,
|
||||
domain hack) over the vocabulary in `src/lib/wordbank.ts`. The strategies are
|
||||
cheap and dumb on purpose — **quality comes from `scoreName`**, so tune the
|
||||
scorer before adding more words.
|
||||
|
||||
Three guards exist because of specific bad output, and removing them brings it
|
||||
straight back:
|
||||
|
||||
- `expandKeywords` matches category hints by **prefix, never substring** — plain
|
||||
containment let `repair` match the `ai` category (rep-**ai**-r) and drag
|
||||
neural-network vocabulary into an auto-shop brief.
|
||||
- `syncopate` only drops the schwa from a final `-er` (`flicker` → `flickr`).
|
||||
The original "drop the last vowel" produced `crema` → `crem`, `kettle` →
|
||||
`kettl`, `security` → `securit`.
|
||||
- `isTruncation` rejects any candidate that is a strict prefix of a word the
|
||||
generator knows. This is what keeps stumps out of the results.
|
||||
|
||||
`diversify()` caps each strategy at ~28% of the returned list. Without it the
|
||||
top 20 came back as eighteen coinages — scoring alone clumps badly.
|
||||
|
||||
## Bring-your-own AI key
|
||||
|
||||
Optional. `/settings` stores an Anthropic or Gemini key in `localStorage`
|
||||
(`names.aiKey`) and the browser calls that provider **directly** — the key never
|
||||
touches our server. Same pattern as `rpo`'s Google Vision key, for the same
|
||||
reason: the platform has no per-app env tool, and this is a free public tool that
|
||||
shouldn't hold a metered credential.
|
||||
|
||||
The `anthropic-dangerous-direct-browser-access` header is correct here and would
|
||||
be wrong in a product that owns the key. The distinction is whose key it is.
|
||||
|
||||
## Registrar links
|
||||
|
||||
`src/lib/registrars.ts`. Links are plain today — every `affiliateCode` is `""`.
|
||||
Fill one in and `HAS_AFFILIATE_LINKS` flips, which turns on the footer
|
||||
disclosure automatically. Keeping both in one file is deliberate: a disclosure
|
||||
that can drift out of sync with whether links actually pay is worse than none.
|
||||
|
||||
## Local development
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # http://localhost:3000
|
||||
npm run typecheck
|
||||
npm run build
|
||||
```
|
||||
|
||||
No env vars are needed to run it. The suggestions lightbulb degrades to a quiet
|
||||
"not configured" state unless `GITEA_URL` / `GITEA_TOKEN` / `GITEA_REPO` are set
|
||||
(the platform injects those at deploy time).
|
||||
Reference in New Issue
Block a user