From 36931fdff58f8a1e3ce6b12eba7f88916c2b5362 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Sat, 26 Sep 2026 03:56:58 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=F0=9F=94=A7=EF=BC=9Aget=20the=20fi?= =?UTF-8?q?rst=20release=20ready=20to=20publish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every place a user meets the packages now leads to the API reference on the portal. Each package's homepage, the first link on its npm page, points at open.inf.is/docs/sdk/, which lists the reference for every release. Each package README, which npm shows on the same page, ends with a Documentation section linking there, and the root README links it in its opening and in its own Documentation section. The homepage is set in tools/sync-package-metadata.js with the rest of the shared metadata. RELEASING.md published the never-released packages straight from main. That would ship them at the version main carries, 0.0.0, with their workspace dependencies pinned to the versions main carries for those, which for the already-published packages are releases that predate this code. The steps now publish the new packages by hand only after the "Version packages" PR has merged, so they go out at the release version, and let the release workflow publish the rest through trusted publishing. They also name the exact trusted-publisher settings, including an empty environment, and drop a stale pnpm version. Signed-off-by: Derek Lewis Assisted-by: Claude-Code:claude-opus-5 --- README.md | 8 +++- RELEASING.md | 61 ++++++++++++++++++-------- packages/assert/README.md | 5 +++ packages/assert/package.json | 1 + packages/gh-file-importer/README.md | 6 +++ packages/gh-file-importer/package.json | 1 + packages/util-array/README.md | 5 +++ packages/util-array/package.json | 1 + packages/util-core/README.md | 5 +++ packages/util-core/package.json | 1 + packages/util-date/README.md | 5 +++ packages/util-date/package.json | 1 + packages/util-errors/README.md | 5 +++ packages/util-errors/package.json | 1 + packages/util-md-table/README.md | 5 +++ packages/util-md-table/package.json | 1 + packages/util-number/README.md | 5 +++ packages/util-number/package.json | 1 + packages/util-object/README.md | 5 +++ packages/util-object/package.json | 1 + packages/util-string/README.md | 5 +++ packages/util-string/package.json | 1 + packages/util-text/README.md | 5 +++ packages/util-text/package.json | 1 + packages/util-types/README.md | 5 +++ packages/util-types/package.json | 1 + packages/util/README.md | 5 +++ packages/util/package.json | 1 + tools/sync-package-metadata.js | 8 +++- 29 files changed, 135 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 7a42ca0..b8596b0 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ development: type guards, argument validation, structured errors, and terminal text. They are published separately, versioned together, and depend on almost nothing. +The API reference for all of them is on the +[OpenINF portal](https://open.inf.is/docs/sdk/). ## Why another utility suite @@ -155,7 +157,11 @@ TypeScript consumers want `moduleResolution` set to `node16`, `nodenext`, or ## Documentation -API documentation is generated with [TypeDoc](https://typedoc.org): +The API reference for every package is published on the +[OpenINF portal](https://open.inf.is/docs/sdk/), with one reference per release, +so the pages match the version you installed. + +It is generated here with [TypeDoc](https://typedoc.org): ```console pnpm install diff --git a/RELEASING.md b/RELEASING.md index d42bb10..fd010bd 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -190,36 +190,58 @@ Two constraints make the first release different from every later one: - **A package must already exist on npm before you can configure it.** There's no way to pre-authorize a name that has never been published. -`@openinf/util-core`, `@openinf/util`, `@openinf/assert`, `@openinf/util-array`, -`@openinf/util-number`, `@openinf/util-date`, and `@openinf/util-string` have -never been published. So, once: +So a package that has never been published goes through one release by hand, and +it has to be the release itself rather than whatever version `main` currently +carries. Published from `main` before the "Version packages" PR has merged, a +new package would go out at the version `main` carries for it, with its +`workspace:*` dependencies pinned to the versions `main` carries for them, which +for an already-published dependency is an old release that predates this code. -1. Publish those seven manually, authenticated locally with an npm account that - can create packages under the `@openinf` scope: +Once, for the release that first includes a new package: + +1. For each package that **is** already on npm, add a trusted publisher now (see + step 4 for the settings). These can be set up before anything else. + +2. Run **Release** and merge the "Version packages" PR it opens, as usual. + +3. From an up-to-date `main`, publish only the new packages, authenticated + locally with an npm account that can create packages under the `@openinf` + scope. Name each one with `--filter`; pnpm publishes them in dependency + order: ```bash + git pull + pnpm install --frozen-lockfile pnpm run build - pnpm --filter @openinf/util-core --filter @openinf/util \ - --filter @openinf/assert --filter @openinf/util-array \ - --filter @openinf/util-number --filter @openinf/util-date \ - --filter @openinf/util-string publish + pnpm --filter @openinf/ --filter @openinf/ \ + publish --no-git-checks ``` + Leave out `--provenance`: it needs the CI's OIDC token and fails on a laptop, + so these first versions are the only ones without an attestation. `publishConfig.access` is set to `public` in each `package.json`, so no - `--access` flag is needed — without it npm would reject a scoped package as + `--access` flag is needed; without it npm would reject a scoped package as private. -2. For **each** of the thirteen packages, on npmjs.com → package → Settings → - add a trusted publisher: - - Organization/user: the GitHub owner of this repo - - Repository: this repo - - Workflow filename: `release.yml` — just the filename, **not** the full +4. For each package you just published, on npmjs.com → package → Settings → add + a trusted publisher: + - Publisher: GitHub Actions + - Organization or user: `OpenINF` + - Repository: `sdk` + - Workflow filename: `release.yml`, just the filename and **not** the full `.github/workflows/release.yml` path, which is a common cause of an E404 that looks like a missing package rather than an auth failure + - Environment name: leave it empty; the release job does not run in a GitHub + environment, and a name the job does not declare makes the token exchange + fail -3. Confirm no `NPM_TOKEN` secret remains configured for the repo. If one exists, +5. Confirm no `NPM_TOKEN` secret remains configured for the repo. If one exists, it may take precedence over OIDC and defeat the point. +6. Run **Release** again. With no changesets pending, it publishes the packages + whose new version is not on the registry yet, which is every package except + the ones from step 3. + After that, both steps run from the Actions tab and no npm credentials live in CI. @@ -262,6 +284,7 @@ to `src/` at runtime — `main`, `types`, and `exports` all point into `dist/`. - **Prerelease mode** (`changeset pre enter next`) exists for shipping a `3.1.0-next.0` line, but it's easy to get wrong — do it on a dedicated branch, never on `main`, or it blocks every other merge until you exit. -- **pnpm's version is pinned** to 11.7.0 in both workflows. If you bump it, bump - it in both, and note that pnpm had an OIDC publishing regression in the 11.0.x - line — verify a publish still works after upgrading. +- **pnpm's version is pinned** in both workflows and in the root + `package.json`'s `devEngines`. If you bump it, bump all three, and note that + pnpm had an OIDC publishing regression in the 11.0.x line — verify a publish + still works after upgrading. diff --git a/packages/assert/README.md b/packages/assert/README.md index 15b75d1..1e10bb2 100644 --- a/packages/assert/README.md +++ b/packages/assert/README.md @@ -23,3 +23,8 @@ assert(port > 0, 'PORT must be positive'); // Both narrow, so `port` is a number from here on. port.toFixed(); ``` + +## Documentation + +The API reference for `@openinf/assert` and the other OpenINF packages is on the +[OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/assert/package.json b/packages/assert/package.json index 3ef699a..9175a3a 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/gh-file-importer/README.md b/packages/gh-file-importer/README.md index 7fc2d53..c838cfc 100644 --- a/packages/gh-file-importer/README.md +++ b/packages/gh-file-importer/README.md @@ -63,3 +63,9 @@ const log: Logger = { const ghFileImporter = new GhFileImporter({ destDir: './tmp', log }); ``` + +## Documentation + +The API reference for `@openinf/gh-file-importer` and the other OpenINF packages +is on the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per +release. diff --git a/packages/gh-file-importer/package.json b/packages/gh-file-importer/package.json index 6b0832f..3df0a14 100644 --- a/packages/gh-file-importer/package.json +++ b/packages/gh-file-importer/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-array/README.md b/packages/util-array/README.md index 1c32013..ce0f317 100644 --- a/packages/util-array/README.md +++ b/packages/util-array/README.md @@ -19,3 +19,8 @@ import { arraysEqual, toArray } from '@openinf/util-array'; toArray(1); // ↪ [1] arraysEqual([1, 2], [1, 2]); // ↪ true ``` + +## Documentation + +The API reference for `@openinf/util-array` and the other OpenINF packages is on +the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-array/package.json b/packages/util-array/package.json index 7148463..6229abd 100644 --- a/packages/util-array/package.json +++ b/packages/util-array/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-core/README.md b/packages/util-core/README.md index 84e06be..a532895 100644 --- a/packages/util-core/README.md +++ b/packages/util-core/README.md @@ -49,3 +49,8 @@ free of dependencies: nothing here needs anything more specific than itself. Most consumers should reach for [`@openinf/util`](https://www.npmjs.com/package/@openinf/util), which re-exports everything here alongside its full set of type guards. + +## Documentation + +The API reference for `@openinf/util-core` and the other OpenINF packages is on +the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-core/package.json b/packages/util-core/package.json index 43fc88f..a449edf 100644 --- a/packages/util-core/package.json +++ b/packages/util-core/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-date/README.md b/packages/util-date/README.md index 66f8565..43e6add 100644 --- a/packages/util-date/README.md +++ b/packages/util-date/README.md @@ -39,3 +39,8 @@ isValidDate(new Date('nope')); // ↪ false isDate({ [Symbol.toStringTag]: 'Date' }); // ↪ false isTemporalInstant(new Date()); // ↪ false ``` + +## Documentation + +The API reference for `@openinf/util-date` and the other OpenINF packages is on +the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-date/package.json b/packages/util-date/package.json index 096c2d4..68f984a 100644 --- a/packages/util-date/package.json +++ b/packages/util-date/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-errors/README.md b/packages/util-errors/README.md index b5d13c6..026bdb0 100644 --- a/packages/util-errors/README.md +++ b/packages/util-errors/README.md @@ -29,3 +29,8 @@ try { (error as MissingOptionError).code; // ↪ 'ERR_MISSING_OPTION' } ``` + +## Documentation + +The API reference for `@openinf/util-errors` and the other OpenINF packages is +on the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-errors/package.json b/packages/util-errors/package.json index 1cdd78f..20369a2 100644 --- a/packages/util-errors/package.json +++ b/packages/util-errors/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-md-table/README.md b/packages/util-md-table/README.md index 5ab7130..3a22481 100644 --- a/packages/util-md-table/README.md +++ b/packages/util-md-table/README.md @@ -30,3 +30,8 @@ console.log(mdTbl2json(table, (value) => value.toLowerCase())); { col1: 'fee', col2: 'fie', col3: 'foe', col4: 'fum' } ] ``` + +## Documentation + +The API reference for `@openinf/util-md-table` and the other OpenINF packages is +on the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-md-table/package.json b/packages/util-md-table/package.json index 35115ac..857c601 100644 --- a/packages/util-md-table/package.json +++ b/packages/util-md-table/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-number/README.md b/packages/util-number/README.md index 33aa51b..5f06cbb 100644 --- a/packages/util-number/README.md +++ b/packages/util-number/README.md @@ -31,3 +31,8 @@ isInteger(4); // ↪ true isInteger(4.5); // ↪ false isUint32(-1); // ↪ false ``` + +## Documentation + +The API reference for `@openinf/util-number` and the other OpenINF packages is +on the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-number/package.json b/packages/util-number/package.json index 03482f4..b478800 100644 --- a/packages/util-number/package.json +++ b/packages/util-number/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-object/README.md b/packages/util-object/README.md index 5a909df..70d186d 100644 --- a/packages/util-object/README.md +++ b/packages/util-object/README.md @@ -29,3 +29,8 @@ if (hasOwn(value, 'id')) { value.id; // ↪ narrowed to `unknown`, no cast needed } ``` + +## Documentation + +The API reference for `@openinf/util-object` and the other OpenINF packages is +on the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-object/package.json b/packages/util-object/package.json index fbfb3cc..15eef2d 100644 --- a/packages/util-object/package.json +++ b/packages/util-object/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-string/README.md b/packages/util-string/README.md index 2363fa6..2b348c1 100644 --- a/packages/util-string/README.md +++ b/packages/util-string/README.md @@ -29,3 +29,8 @@ isRegExp({ [Symbol.toStringTag]: 'RegExp' }); // ↪ false const mentionsNode = isStringContaining('Node'); mentionsNode('Node.js'); // ↪ true ``` + +## Documentation + +The API reference for `@openinf/util-string` and the other OpenINF packages is +on the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-string/package.json b/packages/util-string/package.json index ceb144b..20a7cd3 100644 --- a/packages/util-string/package.json +++ b/packages/util-string/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-text/README.md b/packages/util-text/README.md index 3f94d7f..452d261 100644 --- a/packages/util-text/README.md +++ b/packages/util-text/README.md @@ -20,3 +20,8 @@ import { blueify, ellipsify } from '@openinf/util-text'; console.log(blueify(ellipsify('Deserializing database tables'))); ``` + +## Documentation + +The API reference for `@openinf/util-text` and the other OpenINF packages is on +the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-text/package.json b/packages/util-text/package.json index ae1924b..5d3cad3 100644 --- a/packages/util-text/package.json +++ b/packages/util-text/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util-types/README.md b/packages/util-types/README.md index b9a72df..094d491 100644 --- a/packages/util-types/README.md +++ b/packages/util-types/README.md @@ -110,3 +110,8 @@ WebAssembly does not supply the missing reflection privilege: Passing a JavaScript object through `externref` does not expose its engine slots. A WebAssembly wrapper would still need a host-provided brand-check function. + +## Documentation + +The API reference for `@openinf/util-types` and the other OpenINF packages is on +the [OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util-types/package.json b/packages/util-types/package.json index 9e447cd..fa1d3aa 100644 --- a/packages/util-types/package.json +++ b/packages/util-types/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/packages/util/README.md b/packages/util/README.md index 42bff96..42def1d 100644 --- a/packages/util/README.md +++ b/packages/util/README.md @@ -61,3 +61,8 @@ you the same function: Depend on one of those directly if it is all you need; depend on this package for the full set of guards, validators, and helpers. + +## Documentation + +The API reference for `@openinf/util` and the other OpenINF packages is on the +[OpenINF portal](https://open.inf.is/docs/sdk/), one version per release. diff --git a/packages/util/package.json b/packages/util/package.json index f784038..9efdea1 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -34,6 +34,7 @@ "test:coverage": "node --experimental-test-module-mocks --experimental-test-coverage --test-coverage-include='test-dist/src/**' --test 'test-dist/test/**/*.js'", "prepublishOnly": "npm run clean && npm run build" }, + "homepage": "https://open.inf.is/docs/sdk/", "repository": { "type": "git", "url": "https://github.com/OpenINF/sdk.git", diff --git a/tools/sync-package-metadata.js b/tools/sync-package-metadata.js index aeb4db5..51335a1 100644 --- a/tools/sync-package-metadata.js +++ b/tools/sync-package-metadata.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -// Normalizes the package-invariant metadata (repository, bugs, files, +// Normalizes the package-invariant metadata (homepage, repository, bugs, files, // engines, author, license, types, exports) that every publishable // workspace package under packages/* should share, rewriting each // package.json from a single canonical definition instead of by @@ -16,6 +16,7 @@ const path = require('path'); const PACKAGES_DIR = path.join(__dirname, '..', 'packages'); const REPO_URL = 'https://github.com/OpenINF/sdk.git'; const ISSUES_URL = 'https://github.com/OpenINF/sdk/issues'; +const DOCS_URL = 'https://open.inf.is/docs/sdk/'; const AUTHOR = 'The OpenINF Authors'; const LICENSE = 'MIT'; // The oldest Node.js release line still inside an LTS window. OpenINF supports @@ -40,6 +41,7 @@ const FIELD_ORDER = [ 'exports', 'sideEffects', 'scripts', + 'homepage', 'repository', 'bugs', 'keywords', @@ -101,6 +103,10 @@ function syncOne(dirName) { // here instead of letting this flatten it to false. pkg.sideEffects = false; + // npm shows the homepage as the package page's first link, which is where a + // reader looks for documentation, and the README is already on the page + // itself. Without one, npm falls back to the repository root. + pkg.homepage = DOCS_URL; pkg.repository = { type: 'git', url: REPO_URL,