Decentralize Subcommand#181
Open
shawntabrizi wants to merge 5 commits into
Open
Conversation
Before, `dot decentralize --site=example.com` picked a random `decent-ffe0ab72.dot`. The label was unrecognisable in the resulting `.dot.li` URL and gave the user no clue which site they were mirroring. After, the auto-name starts with a dumb transliteration of the URL's hostname (lowercase, dots → hyphens, sanitised to `[a-z0-9-]`, capped at 30 chars), followed by a 4-letter random tail + 2 digits. No TLD or `www.` stripping — that requires the Public Suffix List, which we don't want as a dep; users who want a clean name pass `--dot` explicitly. Falls back to the legacy `decent-` shape for unparseable inputs. example.com → example-com-uslj17.dot shawntabrizi.com → shawntabrizi-com-byhq57.dot shawntabrizi.github.io → shawntabrizi-github-io-<rand>NN.dot Also fixes a latent classifier bug. The previous hex-based suffix produced labels with >2 trailing digits ~62% of the time (whenever the random hex happened to end in a digit), classified as RESERVED and silently masked by the 20-attempt retry loop. The new generator uses lowercase letters only in the variable middle so the trailing- digit invariant holds for every call. New test file covers the invariants across 200 iterations: exactly 2 trailing digits, base length ≥9 (NoStatus), normalizeDomain regex compatibility, plus the hostname-incorporation cases.
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
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
dot decentralize— point at a live static site, get back a.dotURL. Wraps the existingrunStorageDeploy(Bulletin chunked upload + DotNS register) behind awget --mirrorof the source site.Default signs with the user's
dot initsession account so the registered.dotname is owned by them.--surioverrides it;--suri //Bobis the explicit zero-setup path used by the dot-decentralize demo service.Mechanics:
wget --mirror --convert-links --adjust-extension --page-requisites --no-parent --no-host-directoriesinto a fresh tmp dir. URL passed as a separate execve argument, never spliced into a shell string. Validateshttp(s)scheme only.runStorageDeploy(the same pathdot deployuses), so any improvements to chunked-storage / retries / DotNS commit-reveal flow into this command for free..dot.liURL is recognisable.shawntabrizi.com→shawntabrizi-com-byhq57.dot,example.com→example-com-uslj17.dot,shawntabrizi.github.io→shawntabrizi-github-io-<rand>NN. The transformation is intentionally dumb: lowercase, dots → hyphens, sanitise to[a-z0-9-], cap host segment at 30 chars, pad with random letters so the base length lands in DotNS's NoStatus classifier branch (baseLength >= 9+ exactly 2 trailing digits → no PoP required). No TLD orwww.stripping — that requires the Public Suffix List, which we don't want as a dep, and users who want a clean name pass--dot=<name>explicitly. Falls back todecent-<rand>NNfor unparseable inputs.randomBytes.toString("hex")happened to end in a digit), silently masked by the retry loop as RESERVED. The new generator uses lowercase-only letters for the variable middle so the trailing-digit invariant always holds.wget. Added todot init(src/utils/toolchain.ts) so a freshdot initprovisions it alongside git/ipfs/foundry. Manual hint:brew install wget.Surface added:
src/commands/decentralize/index.ts— CLI handler (telemetry spans for signer / availability / random-name / mirror / storage)src/utils/decentralize/mirror.ts— wget wrapper +WgetMissingError,InvalidSiteUrlErrorsrc/utils/decentralize/randomName.ts—generateLabel(siteUrl?)+findAvailableRandomName({ siteUrl, ... })with 20-attempt capsrc/utils/decentralize/randomName.test.ts— 15 invariant tests (hostname incorporation incl.www.and multi-segment public suffixes preserved verbatim, path-ignore, fallback, exactly 2 trailing digits across 200 iterations, NoStatus base length, length cap, normalizeDomain compatibility)src/index.ts— wires the commandsrc/telemetry-config.ts— adds"decentralize"to the command tag unionsrc/utils/toolchain.ts— addswgettoTOOL_STEPSTest plan
End-to-end verified manually on
paseo-next-v2:dot decentralize --site=example.com --suri //Bob→example-com-uslj17.dot→ CIDbafybeicpx…→ live at https://example-com-uslj17.dot.li, generalised "Owned by a development account" footerdot decentralize --site=shawntabrizi.com --suri //Bob→shawntabrizi-com-byhq57.dot(hostname incorporated verbatim incl.-com, NoStatus shape, 4 random letters + 2 digits suffix)dot decentralize --site=shawntabrizi.com --dot=shawntabrizi42 --suri //Bob→shawntabrizi42.dot.li(custom NoStatus-compatible name, 12-char base + 2 trailing digits — bypasses URL-derived naming)dot decentralize --site=shawntabrizi.com --dot=shawntabrizi --suri //Bob→ refuses with the chain's "requires ProofOfPersonhoodFull" error (expected —availability.tsreturnsavailable + notefor PoP-gated names; deploy fails at chain register)dot decentralize --site=example.com(no--suri, no session) → no //Bob fallback; goes throughgetSessionSignerpnpm format:check,pnpm lint:license,pnpm test src/commands/decentralize src/utils/decentralize src/utils/signerclean — 15 new tests for the label generator passTODOs / follow-ups
Required before merge:
mirror.ts— URL validation (http/https only, shorthand expansion, scheme rejection),WgetMissingErrormapping fromENOENT,countFileswalks subdirs, empty-mirror failure path..changeset/<slug>.mdor the release workflow no-ops. Patch-level bump is fine.availability.tsreturnsavailablewith an advisorynotefor PoP-gated names;dot decentralizeproceeds to mirror the site, then the chain rejects atregister(). Should short-circuit on the advisory note when the signer can't meet the requirement (e.g. NoStatus signer + Full-PoP name) so the user doesn't waste wget cycles. Only relevant when--dotis provided; URL-derived names always fit NoStatus by construction.Nice-to-have:
runStorageDeploy's phase events through to a real progress UI instead of dumping rawevent.kind. Today the user seesphase-start,chunk-progresslines — readable, but coarser thandot deploy's Ink TUI.--sitesmarts: auto-detect when the URL is a known SPA hosting host (Vercel/Netlify/Pages) and warn that client-side routing won't work without a 404 →index.htmlrewrite.dot --help, but a one-liner in the README's command table would help.~/.polkadot/state can surfacepublicKey: Uint8Array expected of length 32, not of length=0fromgetSessionSignerinstead ofSignerNotAvailableError. Pre-existing — not caused by this PR — but more visible now that this command exposes the no-flag default. Worth a follow-up inauth.ts.Out of scope but flagging:
main.@polkadot-api/json-rpc-provider-proxy@0.4.0(pulled in transitively via@novasamatech/product-sdk@0.7.9-4per thepnpm.overridespin) runtime-imports@polkadot-api/json-rpc-providerbut declares it only as adevDependency. pnpm skips the install;bun build --compileand evenbun run src/index.tsthen fail withCannot find module '@polkadot-api/json-rpc-provider'. One-line fix: add@polkadot-api/json-rpc-provideras a direct dep inpackage.jsonso it lands in the top-levelnode_modules/@polkadot-api/. First entered the lockfile in582a15f(2026-04-15) — not introduced by this PR, but the PR's verification flow tripped over it.Related
The prototype web service that wraps this CLI for a conference demo lives at shawntabrizi/dot-decentralize. It passes
--suri=//Bobto every invocation so all served domains end up owned by the shared test account.