feat: fledgling jsr — claim packages on JSR + link repo for OIDC publishing#7
Open
theoephraim wants to merge 5 commits into
Open
feat: fledgling jsr — claim packages on JSR + link repo for OIDC publishing#7theoephraim wants to merge 5 commits into
fledgling jsr — claim packages on JSR + link repo for OIDC publishing#7theoephraim wants to merge 5 commits into
Conversation
|
The changes in this PR will be included in the next version bump.
|
|
I forgot I had Claude draft a proposal for a PR 😅 Something unique about JSR compared to NPM is that it scores your package based on the presence of certain metadata, too, which is why there is a jsr-meta script as well. Maybe worth considering here for setup completeness? Or perhaps that is better suited for package publishing in Bumpy instead. |
…t-API clients to)
…to jsr.io JSR scores packages partly on having a description and marked runtime compatibility, and both live only on jsr.io — the jsr.json manifest has no description field, so they can't be set at publish time. Reconcile them in `fledgling jsr` (which already holds the full-access token): description from package.json, runtimeCompat from config (no inference). Drift-aware and idempotent — only changed fields are PATCHed, each as its own request since JSR's updatePackage body is a oneOf. Opt out with --skip-metadata.
cli.ts previously held the npm-shaped arg schema, the default/add command logic (runPlain/createRun), and every gunshi command object inline — the odd one out, since sync/init/jsr already kept their behavior in their own files. Extract the shared flag schema + gunshi plumbing (Ctx, selectorsOf) into args.ts, move the default/add command (which share createRun) into add.ts, and have sync.ts/init.ts/jsr-cmd.ts each export their own full command object (name, description, args, run) next to the logic it calls. cli.ts is now just imports + gunshi wiring.
Consistent naming across commands: add.command.ts, sync.command.ts, init.command.ts, jsr.command.ts, all under src/commands/. Only import paths changed (adjusted for the extra directory level) — no behavior change.
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 a new
fledgling jsr [packages…]subcommand — the same first-publish story fledgling tells for npm, on JSR. JSR has no create-on-first-publish, so every package must exist on jsr.io before CI (or anyone) can publish a version. For each target package this:jsr.json(name, version, sourceexportsentry) frompackage.jsonwhere missing — an existingjsr.json/deno.jsonis authoritative and never rewrittenPOST /scopes/{scope}/packages)PATCH githubRepository) — JSR's entire trusted-publishing setup: any workflow in the linked repo can then publish token-lessly via OIDC (npx jsr publishwithpermissions: id-token: write, noJSR_TOKENsecret in CI)package.json) and runtime compatibility (from config) to jsr.io. JSR scores packages partly on these, and they live only on jsr.io (thejsr.jsonmanifest has nodescriptionfield), so they can't ride along at publish time — the local tool that holds the token is the right place to reconcile them. Drift-aware: only changed fields are pushed.Idempotent like the npm flow: claimed packages are skipped, the repo link is re-asserted, and metadata drift is reconciled on every run.
Design notes
processTarget's npm-shaped settings would make everything conditional, sosrc/jsr.ts(API client + helpers, the JSR analogue ofnpm.ts) andsrc/jsr-cmd.ts(clack flow mirroringsync.ts) stand alone.--scope/fledgling.jsr.scopeconfig → the npm name's own scope.package.json(collapsed to one line, clamped to JSR's 250-char limit).runtimeCompatis not guessed from source — it's set explicitly viafledgling.jsr.runtimeCompat(root default) or a package's ownpackage.json(per-package override). Each metadata field is a separatePATCHbecause JSR'supdatePackagebody is aoneOf. Opt out entirely with--skip-metadata.Retry-After-aware exponential backoff, plus a 1s per-package cooldownweeklyPackageLimitExceededthe run stops cleanly, lists what's left, and says to re-run after the reset (re-running picks up where it left off)GET /user/member/{scope}preflight separates "token can't manage this scope" from per-package failuresmissingPermission) — surfaced with a specific "needs a FULL-access token" message--yesto apply, interactive confirm in a TTY,--dry-runfor CI. No token / invalid token degrades to a dry run with guidance.Verified against JSR's docs + OpenAPI
Confirmed against
api.jsr.io/.well-known/openapi, thejsr.jsonschema, and the scoring/quotas docs:jsr.jsonmanifest fields are name, version, license, exports, publish — no description (so metadata must go through the API)PackageScoreincludeshasDescription,atLeastOneRuntimeCompatible,multipleRuntimesCompatible,hasProvenance, README/docs factorsUpdatePackageRequestis aoneOf— one field per PATCHpackage/publish(publish only) vsall(management)Testing
--help, completions, and config types wired--scopemapping, plan output, no-token/invalid-token degradation, already-claimed path, metadata drift detection (reads live description + runtimeCompat, diffs, plans only the changes), 250-char truncation warning, and--skip-metadataopt-outJSR_TOKEN). The claim/link/metadata/quota logic is ported faithfully from the reference script that ran against 30 live packages, and the endpoints/fields are re-verified against the OpenAPI spec. Note the management API is undocumented-as-stable — worth flagging in release notes.Credit
Huge thanks to @Saeris for the groundwork this is built on: the proposal and reference implementation (
proposals/fledgling-jsr-support.md+scripts/jsr-claim.mjs+scripts/jsr-meta.mjs), including the live findings on rate limits, the weekly quota, token permission requirements, and the score-metadata approach.