diff --git a/.bumpy/placeholder-readme.md b/.bumpy/placeholder-readme.md new file mode 100644 index 0000000..fe40acd --- /dev/null +++ b/.bumpy/placeholder-readme.md @@ -0,0 +1,5 @@ +--- +'fledgling': patch +--- + +The placeholder published to claim a name now ships a `README.md`, so the package's npm page says what it is: the name was claimed with [fledgling](https://github.com/dmno-dev/fledgling) (linked to the package's own repo/homepage when the manifest has one), there's nothing to install yet, and here's the one-liner to claim a name of your own. The README also now leads with a **Just claim a name** section, since `npx fledgling add --new --yes` works from any directory with no repo or config. diff --git a/README.md b/README.md index 7870085..96d5d1b 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,36 @@ > Brought to you by [Varlock](https://varlock.dev) 🧙‍♂️🔐 — [check it out to keep your secrets out of plaintext](https://varlock.dev). -`fledgling` claims your package names on npm, sets up token-less ([OIDC trusted](https://docs.npmjs.com/trusted-publishers/)) publishing, and keeps that setup **in sync as it changes** — your trusted-publishing config lives in `package.json`, and fledgling reconciles npm to match it. No `NPM_TOKEN`, no clicking through the npm website. It works for a single package or a whole monorepo, and it's idempotent, so you can re-run it any time you add a package *or* change your publishing setup. +`fledgling` does two things, and you can use either one on its own: + +1. **Claims package names on npm** — one command, from any directory, no repo or `package.json` needed. Got a name for that idea? Grab it before someone else does. +2. **Sets up token-less ([OIDC trusted](https://docs.npmjs.com/trusted-publishers/)) publishing and keeps it in sync** — your trusted-publishing config lives in `package.json`, and fledgling reconciles npm to match it. No `NPM_TOKEN`, no clicking through the npm website. + +It works for a single package or a whole monorepo, and it's idempotent, so you can re-run it any time you add a package *or* change your publishing setup.

fledgling claiming a new package in a monorepo and setting up trusted publishing

+## Just claim a name + +Have a name you want to lock down? You don't need a repo, a `package.json`, or any config — run this from your home folder or an empty directory: + +```sh +npm login # once (2FA required) +npx fledgling add my-great-new-idea --new --yes # done — the name is yours +``` + +That publishes a tiny `0.0.0` placeholder under your account (no code — just a `package.json` and a README saying the name is reserved), which is all npm needs to reserve the name. Scoped names (`@scope/thing`) work too, and you can pass several at once. When the package later lives in a repo, `npx fledgling sync` wires up trusted publishing — or never bother, and just `npm publish` over it like any other package. + +Already in a repo and only want the names, not the trust setup? Add `--skip-trust`: + +```sh +npx fledgling add "*" --skip-trust --yes # claim every package in the workspace +``` + +## Everything it does + Designed to be run with `npx` (or `bunx` / `pnpm dlx`): ```sh @@ -137,7 +161,8 @@ Precedence is **CLI flag → `fledgling` config → built-in default**. ### Just want to claim names? -To skip trusted publishing entirely and only reserve package names, you can: +See [Just claim a name](#just-claim-a-name) above. To skip trusted publishing entirely and only reserve package names, you can: +- pass **`--new`** with a name that isn't in a repo (trust is skipped automatically), - pass **`--skip-trust`** for a single run, - decline the wizard's "Set up trusted publishing?" prompt, or - set **`"trust": false`** in your `fledgling` config to make it the default. @@ -243,7 +268,7 @@ Better set once in `package.json` (see [Configuration](#configuration)); as flag For each target package: -1. **Claim** — if the name isn't on npm yet, publish a `package.json`-only placeholder (`0.0.0`, no code) to reserve it. +1. **Claim** — if the name isn't on npm yet, publish a placeholder (`0.0.0`, no code — just a `package.json` and a README noting the name was claimed with fledgling) to reserve it. 2. **Trust** — if there's no trusted publisher configured, set one up for your CI provider via `npm trust` (or replace an existing one with `--force`). Supports **GitHub, GitLab, and CircleCI**, with every option `npm trust` accepts. Both steps are skipped when already done. Placeholders are packed from a throwaway temp dir, so your real `package.json` files are never touched. diff --git a/src/npm.ts b/src/npm.ts index 87e5b13..a48b733 100644 --- a/src/npm.ts +++ b/src/npm.ts @@ -329,11 +329,30 @@ export function listTrust(name: string, registry?: string, creds?: OtpCreds): Tr } } -/** Publish a package.json-only placeholder from a throwaway dir (claims the name). */ +/** README shipped with the placeholder, so the npm page says what it is and where it came from. */ +export function placeholderReadme(manifest: Record): string { + const repo = typeof manifest.repository === 'string' ? manifest.repository : manifest.repository?.url; + const home = manifest.homepage ?? repo?.replace(/^git\+/, '').replace(/\.git$/, ''); + return [ + `# ${manifest.name}`, + '', + `🐣 This package name has been claimed with [fledgling](https://github.com/dmno-dev/fledgling)${home ? ` for [${home}](${home})` : ''}, and a real release will land here soon.`, + '', + 'This is a placeholder — there is nothing to install yet.', + '', + '---', + '', + 'Want to claim a name of your own? Run `npx fledgling add --new --yes` — it reserves the name on npm and can set up token-less (OIDC trusted) publishing for when you are ready.', + '', + ].join('\n'); +} + +/** Publish a package.json + README placeholder from a throwaway dir (claims the name). */ export function publishPlaceholder(manifest: Record, opts: PublishOptions): void { const dir = mkdtempSync(join(tmpdir(), 'fledgling-')); try { writeFileSync(join(dir, 'package.json'), JSON.stringify(manifest, null, 2) + '\n'); + writeFileSync(join(dir, 'README.md'), placeholderReadme(manifest)); const args = ['publish', '--access', 'public']; if (opts.dryRun) args.push('--dry-run'); if (opts.tag) args.push(`--tag=${opts.tag}`);