From 549be16b9f6232d33721ae26cc95f04294f300cd Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Mon, 6 Apr 2026 23:52:34 +0200 Subject: [PATCH 01/14] ci: fix broken actions --- .github/workflows/publish.yml | 1 + .github/workflows/version.yml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7525b9561..4bfe2a0a6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -64,6 +64,7 @@ jobs: cache: npm - run: npm ci + - run: npm run build - run: git config --local user.email 'action@github.com' - run: git config --local user.name 'GitHub Action' diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index 9507efca5..57a4e3e2a 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -11,6 +11,10 @@ on: workflow_dispatch: +permissions: + contents: write + pull-requests: write + env: COMMIT_USER: Hiro DevOps COMMIT_EMAIL: 45208873+blockstack-devops@users.noreply.github.com From 246d8ca193b7b69192657241f0ea3f5d8b3c219e Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 12:09:20 +0200 Subject: [PATCH 02/14] ci: switch to changesets --- .changeset/README.md | 8 +++ .changeset/config.json | 11 ++++ .github/workflows/publish.yml | 83 ------------------------------ .github/workflows/pull-request.yml | 51 ------------------ .github/workflows/release.yml | 66 ++++++++++++++++++++++++ .github/workflows/version.yml | 61 ---------------------- lerna.json | 6 --- package.json | 4 +- 8 files changed, 87 insertions(+), 203 deletions(-) create mode 100644 .changeset/README.md create mode 100644 .changeset/config.json delete mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/version.yml diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 000000000..e5b6d8d6a --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 000000000..dfe3bb47a --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [["@stacks/*"]], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 5cff1860c..000000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: publish - -on: - push: - branches: - - main - tags-ignore: - - "**" - paths-ignore: - - "**.md" - - workflow_dispatch: - -permissions: - id-token: write # Required for OIDC - contents: read - -jobs: - pre-run: - uses: ./.github/workflows/pre-run.yml - secrets: inherit - - publish: - runs-on: ubuntu-latest - needs: pre-run - if: "needs.pre-run.outputs.is-not-fork == 'true' && (github.event_name == 'workflow_dispatch' || contains(github.event.head_commit.message, 'chore: version packages'))" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 0 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: 24 - cache: npm - - - run: npm ci - - run: npm run build - - - run: git config --local user.email 'action@github.com' - - run: git config --local user.name 'GitHub Action' - - - name: Publish - run: | - npx lerna publish from-package --no-verify-access --yes - RELEASE=$(cat lerna.json | jq -r '.version') - git tag -a v$RELEASE -m v$RELEASE - git push origin v$RELEASE - - publish-beta: - runs-on: ubuntu-latest - needs: pre-run - if: "needs.pre-run.outputs.is-not-fork == 'true' && !contains(github.event.head_commit.message, 'chore: version packages')" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 0 - - # pulls all tags (needed for lerna to correctly version) - - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: 24 - cache: npm - - - run: npm ci - - run: npm run build - - - run: git config --local user.email 'action@github.com' - - run: git config --local user.name 'GitHub Action' - - - name: Version & Publish - run: | - LATEST=$(git describe --tags --abbrev=0) - npx lerna version $LATEST --force-publish --no-changelog --no-push --no-git-tag-version --yes - git commit -a -m 'DONT PUSH: fast-forward to latest npm release' --allow-empty --no-verify - npx lerna version --force-publish --no-changelog --conventional-commits --conventional-prerelease --preid beta --no-push --no-git-tag-version --yes - git commit -a -m 'DONT PUSH: version beta release' --allow-empty --no-verify - RELEASE=$(cat lerna.json | jq -r '.version') - npx lerna publish from-package --no-verify-access --pre-dist-tag beta --yes - git reset HEAD~2 --hard - git tag v$RELEASE - git push origin v$RELEASE diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 9dcfdbd7d..f6daa2789 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -26,54 +26,3 @@ jobs: needs: pre-run uses: ./.github/workflows/tests.yml secrets: inherit - - # FOR NOW DISABLE PUBLISHING TO NPM ON EACH PULL-REQUEST PUSH - # publish-pr: - # runs-on: ubuntu-latest - # needs: [pre-run, tests] - # if: needs.pre-run.outputs.is-not-fork == 'true' - # steps: - # - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - # if: github.event_name == 'pull_request' - # with: - # ref: ${{ github.event.pull_request.head.ref }} - # fetch-depth: 0 - # - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - # if: github.event_name == 'workflow_dispatch' - # with: - # fetch-depth: 0 - # - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - # with: - # node-version: 24 - # cache: npm - # - run: npm install -g npm@latest && npm ci - # - name: Set up npm auth token - # run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc - # env: - # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - # - name: Publish to npm (feature branch) - # id: publish-pr - # run: | - # PUBLISH_OUTPUT_FILE=$(mktemp) - # npx lerna publish --canary --force-publish --preid pr --dist-tag pr --no-verify-access --no-push --no-git-tag-version --yes | tee $PUBLISH_OUTPUT_FILE - # VERSION=$(grep -oP '@stacks/common\s*=>\s*\K[^\s]+' $PUBLISH_OUTPUT_FILE | head -n 1) - # echo "Canary version: $VERSION" - # echo "::set-output name=version::$VERSION" - # if: ${{ (github.head_ref || github.ref_name) != 'nakamoto' && (github.head_ref || github.ref_name) != 'next' }} - # env: - # SKIP_TESTS: true - # - name: Publish to npm (next/nakamoto) - # run: | - # git reset --hard - # npx lerna publish --canary major --force-publish --preid $BRANCH --dist-tag $BRANCH --no-verify-access --no-push --no-git-tag-version --yes - # if: ${{ (github.head_ref || github.ref_name) == 'nakamoto' || (github.head_ref || github.ref_name) == 'next' }} - # env: - # BRANCH: ${{ github.head_ref || github.ref_name }} - # SKIP_TESTS: true - # - name: Edit pull-request description with published version - # uses: janniks/pull-request-fixed-header@v1.0.1 - # with: - # header: "> This PR was published to npm with the version `${{ steps.publish-pr.outputs.version || env.BRANCH }}`\n> e.g. `npm install @stacks/common@${{ steps.publish-pr.outputs.version || env.BRANCH }} --save-exact`" - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # env: - # BRANCH: ${{ github.head_ref || github.ref_name }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..c4b8e5694 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,66 @@ +name: release + +# Release automation via Changesets. +# +# Flow: +# - Contributors add a changeset file in their PR (`npx changeset`). +# - On push to main, this workflow either: +# * Opens/updates a "chore: version packages" PR that consumes pending +# changesets, bumps versions in lockstep (see fixed-group in +# .changeset/config.json), and updates CHANGELOGs. +# * When that release PR is merged, publishes all bumped packages to npm +# and tags the release. +# +# `commitMode: github-api` makes the action create commits/tags via the GitHub +# REST API authenticated as github-actions[bot], so they get a "Verified" badge +# without us shipping signing keys to CI. + +on: + push: + branches: + - main + tags-ignore: + - '**' + paths-ignore: + - '**.md' + + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + id-token: write # npm OIDC trusted publishing + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + pre-run: + uses: ./.github/workflows/pre-run.yml + secrets: inherit + + release: + runs-on: ubuntu-latest + needs: pre-run + if: needs.pre-run.outputs.is-not-fork == 'true' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + cache: npm + + - run: npm ci + + - name: Create release PR or publish + uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b # v1.8.0 + with: + version: npm run version + publish: npm run release + title: 'chore: version packages' + commit: 'chore: version packages' + commitMode: github-api + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml deleted file mode 100644 index b43375657..000000000 --- a/.github/workflows/version.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: version - -on: - push: - branches: - - main - tags-ignore: - - '**' - paths-ignore: - - '**.md' - - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -env: - COMMIT_USER: Hiro DevOps - COMMIT_EMAIL: 45208873+blockstack-devops@users.noreply.github.com - -jobs: - pre-run: - uses: ./.github/workflows/pre-run.yml - secrets: inherit - - version: - runs-on: ubuntu-latest - needs: pre-run - if: "needs.pre-run.outputs.is-not-fork == 'true' && !contains(github.event.head_commit.message, 'chore: version packages')" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 0 - ref: main - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: 24 - cache: npm - - - run: npm install -g npm@latest - - run: npm ci - - # workaround for changesets/action to allow not using changesets - # todo: add `force` option on fork to allow removing this workaround - - run: | - npx changeset init - npx changeset --empty - echo '.changeset/' >> .git/info/exclude - - - run: git tag -d $(git tag | grep 'beta') - - - name: Create Release Pull Request - uses: janniks/changesets-action@main - with: - title: 'chore: version packages' - commit: 'chore: version packages' - version: 'npm run ci:version' - env: - GITHUB_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/lerna.json b/lerna.json index 667fc6130..4382161c2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,10 +1,4 @@ { - "version": "7.4.0", - "registry": "https://registry.npmjs.org/", - "publishConfig": { - "access": "public" - }, - "changelogPreset": "conventionalcommits", "packages": [ "packages/*" ], diff --git a/package.json b/package.json index 90fd48167..9a5351b95 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "scripts": { "build": "lerna run build", "build:docs": "rimraf docs && typedoc", - "ci:version": "npx lerna version --conventional-commits --no-push --no-git-tag-version --yes", "clean": "lerna clean", "lerna": "lerna", "lint": "npm run lint:eslint && npm run lint:prettier", @@ -20,8 +19,10 @@ "lint:prettier:fix": "prettier --write \"packages/**/src/**/*.{ts,tsx|!(d.ts)}\" *.js --ignore-path .gitignore", "madge": "madge --circular --extensions ts --exclude 'd.ts' packages/", "pack": "lerna run pack", + "release": "npm run build && changeset publish", "test": "lerna run test", "typecheck": "lerna run typecheck --parallel --no-bail --stream", + "version": "changeset version", "prepare": "husky install .github/.husky" }, "devDependencies": { @@ -35,7 +36,6 @@ "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "assert": "^2.0.0", - "conventional-changelog-conventionalcommits": "^6.1.0", "esbuild": "^0.19.0", "esbuild-loader": "^4.0.0", "eslint": "^8.57.0", From 3ea8c3f45c575989116c6092a0aec1c456df413b Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 12:11:09 +0200 Subject: [PATCH 03/14] chore: update lock file --- package-lock.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index b30ac6c2a..c56ada0e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "assert": "^2.0.0", - "conventional-changelog-conventionalcommits": "^6.1.0", "esbuild": "^0.19.0", "esbuild-loader": "^4.0.0", "eslint": "^8.57.0", From 747709100e5b7aaff8d230883a20ec37ad32f333 Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 18:45:21 +0200 Subject: [PATCH 04/14] ci: update workflows --- .github/workflows/pull-request.yml | 44 ++++++++++++++++++++++++++++++ .github/workflows/release.yml | 37 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f6daa2789..2535d38d0 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -6,6 +6,10 @@ on: workflow_dispatch: +permissions: + contents: read + id-token: write # npm OIDC trusted publishing + jobs: pre-run: uses: ./.github/workflows/pre-run.yml @@ -26,3 +30,43 @@ jobs: needs: pre-run uses: ./.github/workflows/tests.yml secrets: inherit + + publish-pr: + # Snapshot-publishes every PR push to npm under the `pr` dist-tag, with + # versions of the form `-pr..`. The dist-tag is + # shared across all PRs; the version string is unique per build so you + # can pin a specific PR build via `npm i @stacks/foo@7.4.1-pr.1234.0`. + # Skipped on forks (no secrets / OIDC trust there anyway). + runs-on: ubuntu-latest + needs: [pre-run, tests] + if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'pull_request' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + cache: npm + + - run: npm ci + + - name: Seed dummy changeset if none present + run: | + if ! ls .changeset/*.md 2>/dev/null | grep -vi readme | head -1 > /dev/null; then + cat > .changeset/__snapshot.md <<'EOF' + --- + "@stacks/common": patch + --- + + snapshot + EOF + fi + + - run: npx changeset version + - run: node scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} + - run: npm run build + - run: npx changeset publish --tag pr --no-git-tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4b8e5694..b0ed6ae54 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,3 +64,40 @@ jobs: commitMode: github-api env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + beta: + # Snapshot-publishes every push to main to npm under the `beta` dist-tag, + # with versions of the form `-beta.`. Skipped on forks. + runs-on: ubuntu-latest + needs: pre-run + if: needs.pre-run.outputs.is-not-fork == 'true' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + cache: npm + + - run: npm ci + + - name: Seed dummy changeset if none present + run: | + if ! ls .changeset/*.md 2>/dev/null | grep -vi readme | head -1 > /dev/null; then + cat > .changeset/__snapshot.md <<'EOF' + --- + "@stacks/common": patch + --- + + snapshot + EOF + fi + + - run: npx changeset version + - run: node scripts/snapshot-version.mjs beta + - run: npm run build + - run: npx changeset publish --tag beta --no-git-tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 91583b607a4c26959e7283cb11d35d500d12baac Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 20:23:03 +0200 Subject: [PATCH 05/14] ci: update release scripts --- .github/DEVELOPMENT.md | 12 ++--- .github/scripts/snapshot-version.mjs | 71 ++++++++++++++++++++++++++++ .github/workflows/pull-request.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/tests.yml | 2 +- configs/webpack.config.js | 2 +- lerna.json | 6 --- package.json | 12 ++--- 8 files changed, 85 insertions(+), 24 deletions(-) create mode 100755 .github/scripts/snapshot-version.mjs delete mode 100644 lerna.json diff --git a/.github/DEVELOPMENT.md b/.github/DEVELOPMENT.md index 6caa8e4b5..af28e90b1 100644 --- a/.github/DEVELOPMENT.md +++ b/.github/DEVELOPMENT.md @@ -1,18 +1,16 @@ ## Adding dependencies -This repo uses Lerna [hoisting](https://github.com/lerna/lerna/blob/main/doc/hoist.md) for package dependencies. +This repo uses [npm workspaces](https://docs.npmjs.com/cli/v10/using-npm/workspaces) for package management. -In order to install a new dependency to a package, the [`lerna add`](https://github.com/lerna/lerna/tree/main/commands/add) command must be used, rather than `npm install `. - -For example, the following command installs `lodash` as a dependency to the `@stacks/storage` package: +To install a new dependency to a specific package, use the `-w` (workspace) flag: ```shell # Run within the root directory -npx lerna add lodash --scope @stacks/storage +npm install lodash -w @stacks/storage ``` -Add `--dev` to install as a development dependency: +Add `--save-dev` to install as a development dependency: ```shell -npx lerna add lodash --scope @stacks/storage --dev +npm install lodash -w @stacks/storage --save-dev ``` diff --git a/.github/scripts/snapshot-version.mjs b/.github/scripts/snapshot-version.mjs new file mode 100755 index 000000000..e5a153f23 --- /dev/null +++ b/.github/scripts/snapshot-version.mjs @@ -0,0 +1,71 @@ +#!/usr/bin/env node +// Rewrite packages/*/package.json to a snapshot version like +// `-.` (or `-pr..`). Run between +// `changeset version` and `changeset publish --tag `. +// +// Usage: node .github/scripts/snapshot-version.mjs [--pr ] + +import { readFile, writeFile, readdir } from 'node:fs/promises'; +import { execFileSync } from 'node:child_process'; + +const [tag, , prNumber] = process.argv.slice(2); +if (!['beta', 'pr'].includes(tag) || (tag === 'pr' && !prNumber)) { + console.error('Usage: snapshot-version.mjs [--pr ]'); + process.exit(1); +} + +const DEP_TYPES = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']; + +const entries = await readdir('packages', { withFileTypes: true }); +const pkgs = (await Promise.all( + entries + .filter((e) => e.isDirectory()) + .map((e) => `packages/${e.name}/package.json`) + .map(async (file) => { + try { return { file, json: JSON.parse(await readFile(file, 'utf8')) }; } + catch { return null; } + }), +)).filter(Boolean); + +const rep = pkgs.find(({ json }) => json.name && !json.private && /^\d+\.\d+\.\d+$/.test(json.version)); +if (!rep) { + console.error('No non-private workspace package with plain semver — did you run `changeset version` first?'); + process.exit(1); +} + +const prefix = tag === 'beta' ? `${rep.json.version}-beta.` : `${rep.json.version}-pr.${prNumber}.`; +const version = `${prefix}${nextCounter(rep.json.name, prefix)}`; +console.log(`Snapshot version: ${version} (base from ${rep.json.name})`); + +const internals = new Set(pkgs.map(({ json }) => json.name).filter(Boolean)); +const named = pkgs.filter(({ json }) => json.name); + +await Promise.all(named.map(({ file, json }) => + writeFile(file, JSON.stringify(rewrite(json, version, internals), null, 2) + '\n'), +)); +named.forEach(({ json }) => console.log(` ${json.name} → ${version}`)); + +function rewrite(json, version, internals) { + const rewriteDeps = (deps) => + Object.fromEntries(Object.entries(deps).map(([n, v]) => [n, internals.has(n) ? version : v])); + return DEP_TYPES.reduce( + (acc, dt) => (acc[dt] ? { ...acc, [dt]: rewriteDeps(acc[dt]) } : acc), + { ...json, version }, + ); +} + +function nextCounter(name, prefix) { + let raw; + try { + raw = execFileSync('npm', ['view', name, 'versions', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }); + } catch (e) { + if ((e.stderr || '').includes('E404')) return 0; + throw e; + } + const all = JSON.parse(raw); + const counters = (Array.isArray(all) ? all : [all]) + .filter((v) => v.startsWith(prefix)) + .map((v) => Number(v.slice(prefix.length))) + .filter(Number.isInteger); + return counters.length ? Math.max(...counters) + 1 : 0; +} diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 2535d38d0..7b3dccd5a 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -65,7 +65,7 @@ jobs: fi - run: npx changeset version - - run: node scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} + - run: node .github/scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} - run: npm run build - run: npx changeset publish --tag pr --no-git-tag env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0ed6ae54..2019bfa4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,7 +96,7 @@ jobs: fi - run: npx changeset version - - run: node scripts/snapshot-version.mjs beta + - run: node .github/scripts/snapshot-version.mjs beta - run: npm run build - run: npx changeset publish --tag beta --no-git-tag env: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6d798b721..7a9cb5ca3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -40,7 +40,7 @@ jobs: run: npm run madge - name: Run tests - run: npm run lerna run test --stream --parallel -- -- --coverage + run: npm run test --workspaces --if-present -- --coverage - name: Upload test coverage uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 diff --git a/configs/webpack.config.js b/configs/webpack.config.js index ae267b063..52591afb8 100644 --- a/configs/webpack.config.js +++ b/configs/webpack.config.js @@ -2,7 +2,7 @@ const webpack = require('webpack'); const path = require('path'); // Run with ANALYZE ENV to show bundle size (only works with cjs) -// e.g.: ANALYZE=true lerna run --scope @stacks/wallet-sdk build +// e.g.: ANALYZE=true npm run build -w @stacks/wallet-sdk const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const { DuplicatesPlugin } = require('inspectpack/plugin'); diff --git a/lerna.json b/lerna.json deleted file mode 100644 index 4382161c2..000000000 --- a/lerna.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "packages": [ - "packages/*" - ], - "$schema": "node_modules/lerna/schemas/lerna-schema.json" -} \ No newline at end of file diff --git a/package.json b/package.json index 9a5351b95..18d8678cf 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,9 @@ "license": "MIT", "prettier": "@stacks/prettier-config", "scripts": { - "build": "lerna run build", + "build": "npm run build --workspaces --if-present", "build:docs": "rimraf docs && typedoc", - "clean": "lerna clean", - "lerna": "lerna", + "clean": "npm run clean --workspaces --if-present", "lint": "npm run lint:eslint && npm run lint:prettier", "lint:eslint": "eslint \"packages/**/src/**/*.{ts,tsx|!(d.ts)}\" -f unix", "lint:eslint:fix": "eslint \"packages/**/src/**/*.{ts,tsx}\" -f unix --fix", @@ -18,10 +17,10 @@ "lint:prettier": "prettier --check \"packages/**/src/**/*.{ts,tsx|!(d.ts)}\" *.js --ignore-path .gitignore", "lint:prettier:fix": "prettier --write \"packages/**/src/**/*.{ts,tsx|!(d.ts)}\" *.js --ignore-path .gitignore", "madge": "madge --circular --extensions ts --exclude 'd.ts' packages/", - "pack": "lerna run pack", + "pack": "npm run pack --workspaces --if-present", "release": "npm run build && changeset publish", - "test": "lerna run test", - "typecheck": "lerna run typecheck --parallel --no-bail --stream", + "test": "npm run test --workspaces --if-present", + "typecheck": "npm run typecheck --workspaces --if-present", "version": "changeset version", "prepare": "husky install .github/.husky" }, @@ -47,7 +46,6 @@ "jest": "^29.6.2", "jest-fetch-mock": "^3.0.3", "jest-module-name-mapper": "^0.1.5", - "lerna": "^9.0.0", "madge": "^6.1.0", "path-browserify": "^1.0.1", "prettier": "^3.2.5", From f023828f1b7a86abe44e1a64332493c42da5e307 Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 20:37:33 +0200 Subject: [PATCH 06/14] ci: re-add sticky header on PR canary --- .github/scripts/snapshot-version.mjs | 4 +++- .github/workflows/pull-request.yml | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/scripts/snapshot-version.mjs b/.github/scripts/snapshot-version.mjs index e5a153f23..b258ced94 100755 --- a/.github/scripts/snapshot-version.mjs +++ b/.github/scripts/snapshot-version.mjs @@ -5,7 +5,7 @@ // // Usage: node .github/scripts/snapshot-version.mjs [--pr ] -import { readFile, writeFile, readdir } from 'node:fs/promises'; +import { readFile, writeFile, readdir, appendFile } from 'node:fs/promises'; import { execFileSync } from 'node:child_process'; const [tag, , prNumber] = process.argv.slice(2); @@ -45,6 +45,8 @@ await Promise.all(named.map(({ file, json }) => )); named.forEach(({ json }) => console.log(` ${json.name} → ${version}`)); +if (process.env.GITHUB_OUTPUT) await appendFile(process.env.GITHUB_OUTPUT, `version=${version}\n`); + function rewrite(json, version, internals) { const rewriteDeps = (deps) => Object.fromEntries(Object.entries(deps).map(([n, v]) => [n, internals.has(n) ? version : v])); diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 7b3dccd5a..dc38c42af 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -8,6 +8,7 @@ on: permissions: contents: read + pull-requests: write # sticky-header on the PR body id-token: write # npm OIDC trusted publishing jobs: @@ -65,8 +66,26 @@ jobs: fi - run: npx changeset version - - run: node .github/scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} + - id: snapshot + run: node .github/scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} - run: npm run build - run: npx changeset publish --tag pr --no-git-tag env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update PR sticky header + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + VERSION: ${{ steps.snapshot.outputs.version }} + run: | + MARKER='' + HEADER=$(printf '> This PR was published to npm with the version `%s` (dist-tag `pr`).\n> e.g. `npm install @stacks/common@%s --save-exact`\n' "$VERSION" "$VERSION") + BODY=$(gh pr view "$PR_NUMBER" --json body --jq .body) + NEW=$(MARKER="$MARKER" HEADER="$HEADER" BODY="$BODY" node -e ' + const { MARKER, HEADER, BODY } = process.env; + const i = BODY.indexOf(MARKER); + const tail = i >= 0 ? BODY.slice(i + MARKER.length).replace(/^\n+/, "") : BODY; + process.stdout.write(`${HEADER}${MARKER}\n\n${tail}`); + ') + printf '%s' "$NEW" | gh pr edit "$PR_NUMBER" --body-file - From 6bdf3fd5fff62c2ae20a77f3926add47c32b6587 Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 21:13:55 +0200 Subject: [PATCH 07/14] ci: simplify header --- .github/workflows/pull-request.yml | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index dc38c42af..fb9714d71 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -74,18 +74,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Update PR sticky header - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - VERSION: ${{ steps.snapshot.outputs.version }} - run: | - MARKER='' - HEADER=$(printf '> This PR was published to npm with the version `%s` (dist-tag `pr`).\n> e.g. `npm install @stacks/common@%s --save-exact`\n' "$VERSION" "$VERSION") - BODY=$(gh pr view "$PR_NUMBER" --json body --jq .body) - NEW=$(MARKER="$MARKER" HEADER="$HEADER" BODY="$BODY" node -e ' - const { MARKER, HEADER, BODY } = process.env; - const i = BODY.indexOf(MARKER); - const tail = i >= 0 ? BODY.slice(i + MARKER.length).replace(/^\n+/, "") : BODY; - process.stdout.write(`${HEADER}${MARKER}\n\n${tail}`); - ') - printf '%s' "$NEW" | gh pr edit "$PR_NUMBER" --body-file - + uses: janniks/pull-request-fixed-header@5d331404c3ece209cb49d932fcf0f85c995ce5b5 # v1.1.0 + with: + header: | + > This PR was published to npm with the version `${{ steps.snapshot.outputs.version }}` (dist-tag `pr`). + > e.g. `npm install @stacks/common@${{ steps.snapshot.outputs.version }} --save-exact` + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e7ff7d1f33302368849baa43e2b6533ee8c1ac07 Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 21:30:02 +0200 Subject: [PATCH 08/14] ci: fix seed --- .github/workflows/pull-request.yml | 20 ++++++++++++++++++-- .github/workflows/release.yml | 13 +++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index fb9714d71..03abe64b9 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -55,7 +55,7 @@ jobs: - name: Seed dummy changeset if none present run: | - if ! ls .changeset/*.md 2>/dev/null | grep -vi readme | head -1 > /dev/null; then + if ! ls .changeset/*.md 2>/dev/null | grep -vqi readme; then cat > .changeset/__snapshot.md <<'EOF' --- "@stacks/common": patch @@ -68,10 +68,26 @@ jobs: - run: npx changeset version - id: snapshot run: node .github/scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} - - run: npm run build + + # Build CJS+ESM only; UMD has a known module-resolution bug after + # snapshot-version rewrites internal `@stacks/*` deps to the snapshot + # version. Tracked separately. Best-effort: a per-package build failure + # doesn't abort the whole job. + - name: Build CJS+ESM per workspace (skip UMD) + run: | + for pkg in packages/*/; do + [ -f "$pkg/package.json" ] || continue + ( cd "$pkg" && npm run build:cjs --if-present && npm run build:esm --if-present ) || echo "build failed for $pkg (continuing)" + done + + # NPM_CONFIG_IGNORE_SCRIPTS skips each package's prepublishOnly hook + # (which would re-run the UMD build and fail). Safe for snapshot + # publishes — proper releases go through the `release` workflow which + # runs the full build chain. - run: npx changeset publish --tag pr --no-git-tag env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_CONFIG_IGNORE_SCRIPTS: 'true' - name: Update PR sticky header uses: janniks/pull-request-fixed-header@5d331404c3ece209cb49d932fcf0f85c995ce5b5 # v1.1.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2019bfa4f..bb1f32304 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,7 +85,7 @@ jobs: - name: Seed dummy changeset if none present run: | - if ! ls .changeset/*.md 2>/dev/null | grep -vi readme | head -1 > /dev/null; then + if ! ls .changeset/*.md 2>/dev/null | grep -vqi readme; then cat > .changeset/__snapshot.md <<'EOF' --- "@stacks/common": patch @@ -97,7 +97,16 @@ jobs: - run: npx changeset version - run: node .github/scripts/snapshot-version.mjs beta - - run: npm run build + + # See pull-request.yml for the same UMD-skipping rationale. + - name: Build CJS+ESM per workspace (skip UMD) + run: | + for pkg in packages/*/; do + [ -f "$pkg/package.json" ] || continue + ( cd "$pkg" && npm run build:cjs --if-present && npm run build:esm --if-present ) || echo "build failed for $pkg (continuing)" + done + - run: npx changeset publish --tag beta --no-git-tag env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_CONFIG_IGNORE_SCRIPTS: 'true' From d1ca1282027ae3c2b38f9834890dca824d7b0097 Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 21:47:27 +0200 Subject: [PATCH 09/14] ci: change publish location --- .github/workflows/pull-request.yml | 70 --------------------- .github/workflows/release.yml | 99 +++++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 87 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 03abe64b9..f6daa2789 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -6,11 +6,6 @@ on: workflow_dispatch: -permissions: - contents: read - pull-requests: write # sticky-header on the PR body - id-token: write # npm OIDC trusted publishing - jobs: pre-run: uses: ./.github/workflows/pre-run.yml @@ -31,68 +26,3 @@ jobs: needs: pre-run uses: ./.github/workflows/tests.yml secrets: inherit - - publish-pr: - # Snapshot-publishes every PR push to npm under the `pr` dist-tag, with - # versions of the form `-pr..`. The dist-tag is - # shared across all PRs; the version string is unique per build so you - # can pin a specific PR build via `npm i @stacks/foo@7.4.1-pr.1234.0`. - # Skipped on forks (no secrets / OIDC trust there anyway). - runs-on: ubuntu-latest - needs: [pre-run, tests] - if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'pull_request' - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 0 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: 24 - cache: npm - - - run: npm ci - - - name: Seed dummy changeset if none present - run: | - if ! ls .changeset/*.md 2>/dev/null | grep -vqi readme; then - cat > .changeset/__snapshot.md <<'EOF' - --- - "@stacks/common": patch - --- - - snapshot - EOF - fi - - - run: npx changeset version - - id: snapshot - run: node .github/scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} - - # Build CJS+ESM only; UMD has a known module-resolution bug after - # snapshot-version rewrites internal `@stacks/*` deps to the snapshot - # version. Tracked separately. Best-effort: a per-package build failure - # doesn't abort the whole job. - - name: Build CJS+ESM per workspace (skip UMD) - run: | - for pkg in packages/*/; do - [ -f "$pkg/package.json" ] || continue - ( cd "$pkg" && npm run build:cjs --if-present && npm run build:esm --if-present ) || echo "build failed for $pkg (continuing)" - done - - # NPM_CONFIG_IGNORE_SCRIPTS skips each package's prepublishOnly hook - # (which would re-run the UMD build and fail). Safe for snapshot - # publishes — proper releases go through the `release` workflow which - # runs the full build chain. - - run: npx changeset publish --tag pr --no-git-tag - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_CONFIG_IGNORE_SCRIPTS: 'true' - - - name: Update PR sticky header - uses: janniks/pull-request-fixed-header@5d331404c3ece209cb49d932fcf0f85c995ce5b5 # v1.1.0 - with: - header: | - > This PR was published to npm with the version `${{ steps.snapshot.outputs.version }}` (dist-tag `pr`). - > e.g. `npm install @stacks/common@${{ steps.snapshot.outputs.version }} --save-exact` - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bb1f32304..810cbd0bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,19 +1,26 @@ name: release -# Release automation via Changesets. +# All npm-publishing flows live in this single file so npm's trusted-publisher +# config only needs one workflow filename per package. # -# Flow: -# - Contributors add a changeset file in their PR (`npx changeset`). -# - On push to main, this workflow either: -# * Opens/updates a "chore: version packages" PR that consumes pending -# changesets, bumps versions in lockstep (see fixed-group in -# .changeset/config.json), and updates CHANGELOGs. -# * When that release PR is merged, publishes all bumped packages to npm -# and tags the release. +# release — push to main / workflow_dispatch. +# changesets/action opens/updates the "chore: version +# packages" PR. When that PR is merged, the same action +# publishes the bumped packages to npm under `latest`. +# `commitMode: github-api` gives commits a Verified badge +# without us shipping signing keys to CI. # -# `commitMode: github-api` makes the action create commits/tags via the GitHub -# REST API authenticated as github-actions[bot], so they get a "Verified" badge -# without us shipping signing keys to CI. +# beta — push to main. +# Snapshot-publishes every push to `@beta`, with versions +# of the form `-beta.` (counter scoped to +# the base version, queried from npm). +# +# publish-pr — pull_request. +# Same as `beta` but `@pr` dist-tag and versions of the form +# `-pr..`. Sticky-header'd into the PR +# description so reviewers can install the canary build. +# +# Forks never reach the publish step (`is-not-fork` gate from pre-run). on: push: @@ -24,6 +31,10 @@ on: paths-ignore: - '**.md' + pull_request: + paths-ignore: + - '**.md' + workflow_dispatch: permissions: @@ -41,7 +52,7 @@ jobs: release: runs-on: ubuntu-latest needs: pre-run - if: needs.pre-run.outputs.is-not-fork == 'true' + if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name != 'pull_request' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -66,11 +77,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} beta: - # Snapshot-publishes every push to main to npm under the `beta` dist-tag, - # with versions of the form `-beta.`. Skipped on forks. runs-on: ubuntu-latest needs: pre-run - if: needs.pre-run.outputs.is-not-fork == 'true' + if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'push' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -98,7 +107,9 @@ jobs: - run: npx changeset version - run: node .github/scripts/snapshot-version.mjs beta - # See pull-request.yml for the same UMD-skipping rationale. + # CJS+ESM only — UMD has a known module-resolution bug after the + # snapshot rewrite. Per-package failures are non-fatal here; whatever + # builds gets published. - name: Build CJS+ESM per workspace (skip UMD) run: | for pkg in packages/*/; do @@ -106,7 +117,61 @@ jobs: ( cd "$pkg" && npm run build:cjs --if-present && npm run build:esm --if-present ) || echo "build failed for $pkg (continuing)" done + # NPM_CONFIG_IGNORE_SCRIPTS skips each package's prepublishOnly hook + # (which would re-run the UMD build and fail). - run: npx changeset publish --tag beta --no-git-tag env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_CONFIG_IGNORE_SCRIPTS: 'true' + + publish-pr: + runs-on: ubuntu-latest + needs: pre-run + if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'pull_request' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 24 + cache: npm + + - run: npm ci + + - name: Seed dummy changeset if none present + run: | + if ! ls .changeset/*.md 2>/dev/null | grep -vqi readme; then + cat > .changeset/__snapshot.md <<'EOF' + --- + "@stacks/common": patch + --- + + snapshot + EOF + fi + + - run: npx changeset version + - id: snapshot + run: node .github/scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} + + - name: Build CJS+ESM per workspace (skip UMD) + run: | + for pkg in packages/*/; do + [ -f "$pkg/package.json" ] || continue + ( cd "$pkg" && npm run build:cjs --if-present && npm run build:esm --if-present ) || echo "build failed for $pkg (continuing)" + done + + - run: npx changeset publish --tag pr --no-git-tag + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_CONFIG_IGNORE_SCRIPTS: 'true' + + - name: Update PR sticky header + uses: janniks/pull-request-fixed-header@5d331404c3ece209cb49d932fcf0f85c995ce5b5 # v1.1.0 + with: + header: | + > This PR was published to npm with the version `${{ steps.snapshot.outputs.version }}` (dist-tag `pr`). + > e.g. `npm install @stacks/common@${{ steps.snapshot.outputs.version }} --save-exact` + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 717697a04190d0ab2709ad2b4c7433a364d414d0 Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 21:55:15 +0200 Subject: [PATCH 10/14] ci: rename flows --- .../workflows/{release.yml => publish.yml} | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) rename .github/workflows/{release.yml => publish.yml} (81%) diff --git a/.github/workflows/release.yml b/.github/workflows/publish.yml similarity index 81% rename from .github/workflows/release.yml rename to .github/workflows/publish.yml index 810cbd0bf..b7f45f0fe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/publish.yml @@ -1,24 +1,24 @@ -name: release +name: publish -# All npm-publishing flows live in this single file so npm's trusted-publisher -# config only needs one workflow filename per package. +# All npm-publishing flows live in this single file. npm's trusted-publisher +# config for every `@stacks/*` package points at `publish.yml` — renaming this +# file requires updating that config on npmjs.com per package. # -# release — push to main / workflow_dispatch. -# changesets/action opens/updates the "chore: version -# packages" PR. When that PR is merged, the same action -# publishes the bumped packages to npm under `latest`. -# `commitMode: github-api` gives commits a Verified badge -# without us shipping signing keys to CI. +# release — push to main / workflow_dispatch. +# changesets/action opens/updates the "chore: version packages" +# PR. When that PR is merged, the same action publishes the +# bumped packages to npm under `latest`. `commitMode: github-api` +# gives commits a Verified badge without signing keys in CI. # -# beta — push to main. -# Snapshot-publishes every push to `@beta`, with versions -# of the form `-beta.` (counter scoped to -# the base version, queried from npm). +# beta — push to main. +# Snapshot-publishes every push to `@beta`, with versions of the +# form `-beta.` (counter scoped to the base +# version, queried from npm). # -# publish-pr — pull_request. -# Same as `beta` but `@pr` dist-tag and versions of the form -# `-pr..`. Sticky-header'd into the PR -# description so reviewers can install the canary build. +# pr — pull_request. +# Same as `beta` but `@pr` dist-tag and versions of the form +# `-pr..`. Sticky-header'd into the PR +# description so reviewers can install the canary build. # # Forks never reach the publish step (`is-not-fork` gate from pre-run). @@ -124,7 +124,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_CONFIG_IGNORE_SCRIPTS: 'true' - publish-pr: + pr: runs-on: ubuntu-latest needs: pre-run if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'pull_request' From 488a9d80afe9f3077de30076999d5e5bb804170e Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 22:08:06 +0200 Subject: [PATCH 11/14] chore: fix repository link --- packages/bns/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bns/package.json b/packages/bns/package.json index 5577e806c..fd8381bd5 100755 --- a/packages/bns/package.json +++ b/packages/bns/package.json @@ -48,7 +48,7 @@ ], "repository": { "type": "git", - "url": "git+https://github.com/blockstack/stacks.js.git" + "url": "git+https://github.com/stx-labs/stacks.js.git" }, "bugs": { "url": "https://github.com/blockstack/stacks.js/issues" From 56d470baa98c796c9f2195ac8654f3922e81e794 Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Tue, 19 May 2026 22:08:17 +0200 Subject: [PATCH 12/14] docs: fix shield --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33e360d7c..c0a9b33ce 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Stacks.js [![Test Action Badge](https://github.com/hirosystems/stacks.js/actions/workflows/tests.yml/badge.svg)](https://github.com/hirosystems/stacks.js/actions/workflows/tests.yml) [![Monorepo Version Label](https://img.shields.io/github/lerna-json/v/hirosystems/stacks.js?label=monorepo)](https://github.com/hirosystems/stacks.js/tree/main/packages) +# Stacks.js [![Test Action Badge](https://github.com/stx-labs/stacks.js/actions/workflows/tests.yml/badge.svg)](https://github.com/stx-labs/stacks.js/actions/workflows/tests.yml) [![Monorepo Version Label](https://img.shields.io/github/package-json/v/stx-labs/stacks.js?filename=packages%2Fcommon%2Fpackage.json&label=monorepo)](https://github.com/stx-labs/stacks.js/tree/main/packages) > [!IMPORTANT] > Looking for Nakamoto updates? From 8ee92088133540bf7b02eda7eb67c49c6f13be8c Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Wed, 20 May 2026 15:52:24 +0200 Subject: [PATCH 13/14] ci: update workflow dispatch --- .github/workflows/publish.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b7f45f0fe..a6999e806 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -31,11 +31,13 @@ on: paths-ignore: - '**.md' - pull_request: - paths-ignore: - - '**.md' - workflow_dispatch: + inputs: + pr-number: + description: 'PR number to publish a canary build for (leave blank for a normal release dispatch)' + type: string + required: false + default: '' permissions: contents: write @@ -52,7 +54,7 @@ jobs: release: runs-on: ubuntu-latest needs: pre-run - if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name != 'pull_request' + if: needs.pre-run.outputs.is-not-fork == 'true' && (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.pr-number == '')) steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -127,7 +129,7 @@ jobs: pr: runs-on: ubuntu-latest needs: pre-run - if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'pull_request' + if: needs.pre-run.outputs.is-not-fork == 'true' && github.event_name == 'workflow_dispatch' && inputs.pr-number != '' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -154,7 +156,7 @@ jobs: - run: npx changeset version - id: snapshot - run: node .github/scripts/snapshot-version.mjs pr --pr ${{ github.event.pull_request.number }} + run: node .github/scripts/snapshot-version.mjs pr --pr ${{ inputs.pr-number }} - name: Build CJS+ESM per workspace (skip UMD) run: | @@ -169,9 +171,10 @@ jobs: NPM_CONFIG_IGNORE_SCRIPTS: 'true' - name: Update PR sticky header - uses: janniks/pull-request-fixed-header@5d331404c3ece209cb49d932fcf0f85c995ce5b5 # v1.1.0 + uses: janniks/pull-request-fixed-header@57bc082ecbd040df344747d5b8644af5fad02c95 # v1.2.0 with: header: | > This PR was published to npm with the version `${{ steps.snapshot.outputs.version }}` (dist-tag `pr`). > e.g. `npm install @stacks/common@${{ steps.snapshot.outputs.version }} --save-exact` + pr-number: ${{ inputs.pr-number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 9b847d333c680b0d5636f843fefbd3b0b1306d6d Mon Sep 17 00:00:00 2001 From: jannik-stacks <237011140+jannik-stacks@users.noreply.github.com> Date: Wed, 20 May 2026 17:08:15 +0200 Subject: [PATCH 14/14] ci: simplify build --- .github/workflows/publish.yml | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a6999e806..d007aec03 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -109,18 +109,15 @@ jobs: - run: npx changeset version - run: node .github/scripts/snapshot-version.mjs beta - # CJS+ESM only — UMD has a known module-resolution bug after the - # snapshot rewrite. Per-package failures are non-fatal here; whatever - # builds gets published. - - name: Build CJS+ESM per workspace (skip UMD) + - name: Build packages run: | - for pkg in packages/*/; do - [ -f "$pkg/package.json" ] || continue - ( cd "$pkg" && npm run build:cjs --if-present && npm run build:esm --if-present ) || echo "build failed for $pkg (continuing)" - done + npm run clean --workspaces --if-present + npm run build:cjs --workspaces --if-present + npm run build:esm --workspaces --if-present + npm run build:umd --workspaces --if-present - # NPM_CONFIG_IGNORE_SCRIPTS skips each package's prepublishOnly hook - # (which would re-run the UMD build and fail). + # NPM_CONFIG_IGNORE_SCRIPTS skips each package's prepublishOnly hook, + # avoiding duplicate test/build work during publish. - run: npx changeset publish --tag beta --no-git-tag env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -158,12 +155,12 @@ jobs: - id: snapshot run: node .github/scripts/snapshot-version.mjs pr --pr ${{ inputs.pr-number }} - - name: Build CJS+ESM per workspace (skip UMD) + - name: Build packages run: | - for pkg in packages/*/; do - [ -f "$pkg/package.json" ] || continue - ( cd "$pkg" && npm run build:cjs --if-present && npm run build:esm --if-present ) || echo "build failed for $pkg (continuing)" - done + npm run clean --workspaces --if-present + npm run build:cjs --workspaces --if-present + npm run build:esm --workspaces --if-present + npm run build:umd --workspaces --if-present - run: npx changeset publish --tag pr --no-git-tag env: