Skip to content

pit: read names as well as endings from the paste field - #172

Merged
ralyodio merged 2 commits into
mainfrom
feat/paste-parse-names
Aug 1, 2026
Merged

pit: read names as well as endings from the paste field#172
ralyodio merged 2 commits into
mainfrom
feat/paste-parse-names

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

What

The master paste field only understood endings. Anything with a dot in it — blue.eggs, torlink.agent — came back as:

not a valid TLD — letters, digits and dashes only, no dots

That describes the field, not the mistake. A name under an ending is a thing this registry sells; the paste box just had no way to express one. Every one of those lines was a name the operator was entitled to register.

All four spellings now parse:

pasted read as
foo ending .foo
.whatever ending .whatever
bar.foo name bar under .foo
.foo.whatever name foo under .whatever

How

  • parseTldList classifies each token instead of stripping it to an ending. Entries carry label (null for an ending), and the result gains a names array alongside tlds. Dedup keys on the whole thing, so .eggs and blue.eggs in one paste are two entries.
  • registerTlds splits endings from names, claims the endings the pasted names need first, then registers the names. An ending claimed on a name's behalf lands in claimed and is reported like any other — acquiring something the operator did not read themselves asking for should be visible.
  • registerName re-checks ownership, so a name under an ending you do not hold now reports you do not own .eggs rather than the dot complaint.
  • Both claim routes counted success by claimed.length. A paste of blue.eggs under an ending you already hold claims nothing and would have flashed red over a registration that worked; they now count names too.
  • a.b.c is neither an ending nor a name. It survives parsing as its own bad text so it can be rejected by name instead of vanishing from the report.

The shared rules

These rules live in two places: apps/pwa/src/lib/moshpit-name.mjs and the published @moshcoder/moshpit-name, with a drift test keeping them honest.

Both carry this change. @moshcoder/moshpit-name@0.2.0 is published (moshcoder/moshpit-name#1), this app depends on ^0.2.0, and the drift test is a straight deepEqual over the whole result — names included — rather than the shim the first commit needed while the package was a version behind.

Tests

340 pass, 0 fail, 0 skipped in apps/pwa, against the real published package. New coverage for the four shapes, the ending-claimed-once case, the not-yours case, and re-pasting a name you already hold.

🤖 Generated with Claude Code

The paste field took `eggs` and `.eggs` and refused everything else, so
`blue.eggs` came back as "not a valid TLD — letters, digits and dashes
only, no dots". That reads as a complaint about the paste, but the paste
was fine: a name under an ending is a thing this registry sells, and the
field simply had no way to say one.

All four spellings now parse — `foo`, `bar.foo`, `.whatever` and
`.foo.whatever` — and each entry records which it was rather than being
flattened to an ending. A pasted name claims the ending it needs first,
in the same batch, because the alternative is refusing the line and
asking the operator to paste the halves in the right order to reach the
same place.

An ending claimed on a name's behalf is reported like any other claim.
Quietly acquiring something nobody read themselves asking for is the one
outcome here worth being loud about.

Names that cannot land now say why. A name under someone else's ending
reports "you do not own .agent" — the fact that sends you somewhere
useful — instead of the dot complaint, which sent you off to fix a paste
that never had anything wrong with it.

The vendored parser is ahead of @moshcoder/moshpit-name for the moment.
The drift test holds both copies to the rules they share and records the
gap explicitly; it goes back to a straight comparison once the package
ships name parsing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

The vendored parser was ahead of the published package for one commit, and
the drift test held the two to their shared rules while that was true. 0.2.0
ships the same name parsing, so the comparison goes back to what it is for:
a straight deepEqual over the whole result, names included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ralyodio
ralyodio marked this pull request as ready for review August 1, 2026 04:24
@ralyodio
ralyodio merged commit e73aaf5 into main Aug 1, 2026
3 checks passed
@ralyodio
ralyodio deleted the feat/paste-parse-names branch August 1, 2026 04:33
@ralyodio ralyodio mentioned this pull request Aug 1, 2026
ralyodio added a commit that referenced this pull request Aug 1, 2026
install.sh resolves releases/latest, so the ten commits merged since
v0.14.0 have been sitting on main unreachable — including the reason
`curl <name>` did not work.

The headline is parking. A parked name always resolved somewhere, but the
address it pointed at was a host that routes by Host header and answers
"Application not found" for a name it has never heard of, so
`curl scrambled.eggs` resolved and then died one layer up (#180). It could
not be fixed there: the platform rejects a Moshpit ending as a custom
domain and no public CA will certify a TLD outside the DNS root. The
bridge is already running locally for the name to resolve at all, so it
now serves the answer too — parked names point at loopback and a catch-all
responder 302s them to the Pit.

Underneath that was a quieter one. fetchTlds read the first page of the
ending list and stopped; the registry answers 200 rows and reports the
real total, but 200 rows look exactly like a complete list of 200. `.eggs`
sat past that line, so `dns install` wrote a config that did not route it
and the name failed to resolve — a DNS-shaped symptom three layers from
the cause. It was hiding 94% of the namespace: 3707 endings, 200 visible
(#181).

Also here:
  dns resolve now reports a parked name's page in the Pit instead of an IP
  that answers for nobody, with --open to go there (#179)
  the pit's /n/ pages are crawlable — robots.txt, a generated sitemap, and
  canonical tags that name the pit host rather than the app host it shares
  a service with (#175, #176)
  the claim box takes a whole name, claiming the ending first when it is
  free and minting the name under it (#173)
  the endings list pages instead of stopping at 200 (#174), the paste field
  reads names as well as endings (#172), related endings keep the name you
  are reading (#177), and integrations ship JSON support matrices (#178)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant