Skip to content

feat(pit): filter the namespace as you type - #168

Merged
ralyodio merged 1 commit into
mainfrom
feat/pit-filter
Aug 1, 2026
Merged

feat(pit): filter the namespace as you type#168
ralyodio merged 1 commit into
mainfrom
feat/pit-filter

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Finding an ending meant paging through them. This adds a filter box over both tabs.

Syntax

typed means
eggs substring — .eggs, .eggsalad
.eggs same; the leading dot is ignored
def* glob anchored at both ends — .default, .defer, but not .undef
de**f a run of stars is one wildcard

Exact hits sort first, then shortest, so eggs puts .eggs above .eggsalad rather than burying it alphabetically.

How it works

  • Live: debounced 200ms on keyup (plus input, since paste and IME never fire keyup) against GET /api/moshpit/tlds?q=&scope=. The in-flight request is aborted when the next keystroke lands — without that, a slow answer for de can arrive after the fast one for def* and overwrite it.
  • Server-side too: ?q= filters the page itself, so the filter is bookmarkable, shareable, and works with the script blocked. The form is a plain GET; the script only removes the page load.
  • Each hit carries its name count (or price, for someone else's), computed in the same query rather than N+1 on a keyup handler.
  • The query survives tab switches and paging.

The script is the only one /pit carries, and that was the bar: this page locked browsers up one PR ago with no JavaScript on it at all, so anything added here has to make the DOM smaller. A dozen matching rows instead of a page load does.

Safety

% and _ mean something to LIKE and nothing in a TLD, so they're stripped when the query is parsed rather than escaped on the way to SQL — no input can reach the database still carrying a wildcard we didn't put there. Covered by a test.

Testing

  • New apps/pwa/test/moshpit-search.test.mjs — 16 tests: parser semantics, LIKE-wildcard smuggling, glob anchoring (undef is not a def*), scope isolation (?scope=mine needs a session and never returns someone else's), the unfiltered response being byte-for-byte unchanged, and ?q= filtering the page with no script.
  • apps/pwa: 323 pass, 0 fail. Repo root: 762 pass, 0 fail, 2 skipped.

🤖 Generated with Claude Code

Finding an ending meant paging through them. Now there is a filter box:
`eggs` matches anywhere in the name, `def*` is a glob anchored at both ends,
and the leading dot people naturally type is ignored. Debounced at 200ms on
keyup, and the in-flight request is aborted when the next keystroke lands --
otherwise a slow answer for `de` arrives after the fast one for `def*` and the
list flickers back to a query nobody is typing any more.

`?q=` is also read server-side, so the filter is bookmarkable, shareable, and
still works when the script does not run. The form is a plain GET; the script
only upgrades it to answer without a page load.

The script is the only one this page carries, and that is the bar it had to
clear: /pit locked browsers up a fix ago with no JavaScript on it at all, so
anything added here has to make the DOM smaller. A dozen matching rows instead
of a page load does.

Wildcards that mean something to LIKE and nothing in a TLD (% and _) are
stripped when the query is parsed rather than escaped on the way to SQL, so no
input can reach the database still carrying a wildcard we did not put there.

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.

@ralyodio
ralyodio marked this pull request as ready for review August 1, 2026 02:47
@ralyodio
ralyodio merged commit 73f945c into main Aug 1, 2026
3 checks passed
@ralyodio
ralyodio deleted the feat/pit-filter branch August 1, 2026 02:48
@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 sixteen commits merged since
v0.13.3 have been sitting on main unreachable — including a fix for a page
that locks browsers up.

The headline is the pit. /pit rendered every ending an account held and a form
per name under each, with no bound on either: at 50 endings x 100 names that
was 3.1 MiB of HTML and 36,082 DOM elements, and it managed to jam a browser
with no script on the page at all (#167). It now draws a window and says what
it is not drawing — 173 KiB, 1,926 elements — with a filter box over the top
that takes `eggs` as a substring and `def*` as a glob, debounced against the
API (#168).

The namespace also stopped being the one part of the product a script could
not touch: /api/moshpit/* now accepts the same API key /api/me and
/api/sessions already did (#169), and /pit/dns finally documents the
TronBrowser route for machines whose DNS is not theirs to change (#165).

  moshcode: foreign keys are enforced, and the licence package.json
  claims actually ships (#154)
  cli: help aliases exit 0 (#157), invalid integration commands fail (#160),
  `--` is honoured (#159), a BOM before a shebang no longer breaks (#158)
  skills: engines with no skills primitive are reported, not dropped (#166);
  `--name` requires a value (#156)
  mcp: an unsupported flag is rejected rather than registered as the server
  name (#164)
  pit: the namespace rules are vendored again with a drift test holding them
  to the published package (#161, #162, #163)

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