FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Moshpit is lifetime pricing: $5 an ending, $2 a name, paid once by ralyodio · Pull Request #436 · moshcoder/moshcode · GitHub

Moshpit is lifetime pricing: $5 an ending, $2 a name, paid once - #436

Merged
ralyodio merged 1 commit into
mainfrom
worktree-moshpit-lifetime
Aug 28, 2026
Merged

Moshpit is lifetime pricing: $5 an ending, $2 a name, paid once#436
ralyodio merged 1 commit into
mainfrom
worktree-moshpit-lifetime

Conversation

Copy link
Copy Markdown
Contributor

Migration 010 gave endings a one-year term with renewals, per PRD 0005 §5. That is withdrawn. The prices are unchanged — what changed is that they are not charged again.

The reason is what the namespace is for. A name that lapses is a name somebody else can catch, and the whole pitch is that you can finally hold the clean name instead of the hyphenated one you settled for. An annual invoice with a drop date attached is the thing people are trying to get away from; selling it back to them undoes the pitch.

Two things worth knowing before reviewing

Names were already sold this way. moshpit_names has never had an expiry column and nothing has ever renewed a name. The PRD called it a yearly fee, the schema sold it outright, and the doc comment described the PRD. It now describes the code.

The ending term never shipped. Nothing in the app could open an ending checkout, so quoteTld and quoteRenewal were unreachable and only the webhook settler was wired up. No ending was ever charged a renewal, and no row in the wild has an expiry this drop takes away. That is why migration 016 is a plain drop rather than a grandfathering policy — §21.8 asks for one before putting endings into a lifecycle, and taking them back out of one nobody was in needs no such thing.

What changed

  • expires_at and term_started_at dropped from moshpit_tlds, columns and index. Gone rather than left NULL: a nullable expiry is an annual term waiting to be switched back on.
  • moshpit_tld_purchases keeps kind and years. That is a financial record of what was sold at the time, and a ledger is not something to rewrite once the product changes.
  • A renew row can no longer be created, but one may still settle late. It is honoured rather than refused — the buyer keeps the ending, which now keeps itself. Refusing it would take money for nothing. (A renewal for an ending that has since changed hands is still a refund.)
  • isExpired() stays and always answers no, so callers asking a fair question get a permanent answer instead of an import that fails.
  • quoteRenewal, TERM_MS and MAX_TERM_YEARS are gone rather than left as no-ops somebody could wire a checkout to. There is a test asserting they are undefined.

The pit page

Leads with it, since it is the one claim here worth making above the fold and the whole reason to prefer this over a registrar:

Bought once. Yours for good.
$5 an ending, $2 a name — paid one time, not every year. Nothing here renews, nothing lapses, and no name you hold can drop because an invoice went to an address you stopped reading.

For whoever writes the next migration

Nothing may follow the last statement in a .sql file but whitespace. migrate.mjs splits on semicolons and hands each piece to libSQL, and a trailing comment-only piece comes back as SQLITE_OK: not an error, which is as unhelpful as it sounds. Cost me a debug cycle; noted in the migration header.

Tests

591 pass in apps/pwa. moshpit-terms.test.mjs rewritten for lifetime semantics; migration verified from scratch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GWhPX5Uzd29whRg5WPAYM7

Migration 010 gave endings a one-year term with renewals, per PRD 0005
§5. That is withdrawn. The prices are unchanged; what changed is that
they are not charged again.

The reason is what the namespace is for. A name that lapses is a name
somebody else can catch, and the whole pitch is that you can finally
hold the clean name instead of the hyphenated one you settled for. An
annual invoice with a drop date attached is the thing people are
trying to get away from, and selling it back to them undoes the pitch.

Names were already sold this way and only the comments said otherwise:
`moshpit_names` has never had an expiry column and nothing has ever
renewed a name. The PRD called it a yearly fee, the schema sold it
outright, and the doc comment described the PRD. It now describes the
code.

Endings really did have the machinery, but it never shipped -- nothing
in the app could open an ending checkout, so `quoteTld` and
`quoteRenewal` were unreachable and only the webhook settler was wired
up. No ending was ever charged a renewal and no row in the wild has an
expiry this takes away, which is why migration 016 is a plain drop
rather than a grandfathering policy: §21.8 asks for one before putting
endings INTO a lifecycle, and taking them back out of one nobody was
in needs no such thing.

- `expires_at` and `term_started_at` are dropped from `moshpit_tlds`,
  columns and index. Gone rather than left NULL, because a nullable
  expiry is an annual term waiting to be switched back on.
- `moshpit_tld_purchases` KEEPS `kind` and `years`. That is a financial
  record of what was sold at the time, and a ledger is not something to
  rewrite once the product changes.
- A 'renew' row can no longer be created, but one may still settle
  late. It is honoured rather than refused -- the buyer keeps the
  ending, which now keeps itself. Refusing it would take money for
  nothing.
- `isExpired()` stays and always answers no, so callers asking a fair
  question get a permanent answer instead of an import that fails.

The pit page leads with it, since it is the one claim here worth making
above the fold and the whole reason to prefer this over a registrar.

Note for whoever writes the next migration: nothing may follow the last
statement in a .sql file but whitespace. migrate.mjs splits on
semicolons and hands each piece to libSQL, and a trailing comment-only
piece comes back as `SQLITE_OK: not an error`, which is as unhelpful as
it sounds.

591 pass in apps/pwa.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWhPX5Uzd29whRg5WPAYM7

Copy link
Copy Markdown

ThreatCrush Security Scan

23 finding(s) in the 5 file(s) this pull request changes.

MEDIUM: 23

Severity Rule Location
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:74
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:88
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:114
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:301
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:305
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:350
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:574
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:755
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:757
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:816
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:862
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:932
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1035
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1058
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1080
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1279
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1429
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1578
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1584
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1631
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1680
MEDIUM js-unescaped-html-sink apps/pwa/src/routes/moshpit.mjs:2047
MEDIUM sql-template-interpolation apps/pwa/test/moshpit-terms.test.mjs:207
36 pre-existing finding(s) elsewhere in the repository — **HIGH/CRITICAL**: 5 | **MEDIUM**: 25 | **LOW**: 6

Not introduced by this pull request. The full set is in the Security tab.

Severity Rule Location
HIGH js-ssrf-outbound-request apps/pwa/public/sw.js:45
HIGH tls-verification-disabled apps/pwa/src/lib/moshpit-gateway.mjs:299
HIGH sh-remote-script-execution install.sh:79
HIGH sh-remote-script-execution install.sh:83
HIGH tls-verification-disabled src/dns.mjs:766
MEDIUM js-timing-unsafe-mac-compare apps/pwa/src/routes/settings-sync.mjs:192
MEDIUM js-dynamic-code-execution apps/pwa/test/apikey-mask.test.mjs:129
MEDIUM sql-template-interpolation apps/pwa/test/credits-webhook-event-match.test.mjs:111
MEDIUM sql-template-interpolation apps/pwa/test/credits-webhook-event-match.test.mjs:131
MEDIUM sql-string-concatenation src/cli-schema.mjs:161
MEDIUM sql-string-concatenation src/cli-schema.mjs:503
MEDIUM sql-string-concatenation src/cli-schema.mjs:629
MEDIUM js-uninitialized-buffer src/pty.mjs:120
MEDIUM js-timing-unsafe-mac-compare src/settings-sync.mjs:325
MEDIUM insecure-temp-file test/dns-disable-restore.test.mjs:93
MEDIUM insecure-temp-file test/dns-disable-restore.test.mjs:314
MEDIUM insecure-temp-file test/news.test.mjs:693
MEDIUM insecure-temp-file test/plugins.test.mjs:152
MEDIUM insecure-temp-file test/pty.test.mjs:28
MEDIUM insecure-temp-file test/pty.test.mjs:31

…and 16 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

ralyodio merged commit 136d13e into main Aug 28, 2026
6 checks passed
ralyodio mentioned this pull request Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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


Back | FazBrowse Home | New Git URL