From 941894ca904d44ea42cf785a6a8667ccb018a0c0 Mon Sep 17 00:00:00 2001 From: Nathan Arthur Date: Wed, 15 Jul 2026 07:27:12 -0500 Subject: [PATCH 1/3] feat: publish a prebuilt tarball on release Add `files: ["dist"]` so `pnpm pack` ships the compiled output (dist/ is gitignored, so without this the tarball would be empty), and a Release workflow that builds, packs, and attaches expost-.tgz to each published GitHub release. Consumers can then install expost from the release asset URL instead of as a git dependency, so they never run the install-time `tsc` build. That fixes cold builds (e.g. Render PR previews) and needs no token, since release assets on a public repo download anonymously. See beeminder/blog#656. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yaml | 30 ++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 31 insertions(+) create mode 100644 .github/workflows/release.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..d3b4b4e --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,30 @@ +name: Release +# Build a prebuilt npm tarball and attach it to the GitHub release, so +# consumers can install expost from the release asset URL (no token, no +# install-time tsc build). See beeminder/blog#656. +on: + release: + types: [published] +permissions: + contents: write +env: + PNPM_VERSION: 9 +jobs: + pack: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + - run: pnpm install --frozen-lockfile + - run: pnpm run build + - run: pnpm pack # respects files:[dist] -> expost-.tgz + - name: Attach tarball to release + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.event.release.tag_name }} + run: gh release upload "$TAG" expost-*.tgz --clobber diff --git a/package.json b/package.json index 46de563..dbec856 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "type": "module", + "files": ["dist"], "scripts": { "test": "vitest", "lint": "eslint .", From 5dc4c5f11395756706aa094214a8840b2897cdad Mon Sep 17 00:00:00 2001 From: Nathan Arthur Date: Wed, 15 Jul 2026 07:45:02 -0500 Subject: [PATCH 2/3] feat: auto-release on merge to master MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trigger the Release workflow on every push to master. The version is auto-computed from git tags via semver-action (patch bump when there's no conventional-commit signal), so nothing needs hand-editing — merge to master and a release with the prebuilt tarball is cut. Mirrors the approach in PinePeakDigital/buzz. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yaml | 41 +++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d3b4b4e..9b3602f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,19 +1,35 @@ name: Release -# Build a prebuilt npm tarball and attach it to the GitHub release, so -# consumers can install expost from the release asset URL (no token, no -# install-time tsc build). See beeminder/blog#656. +# On every merge to master, auto-compute the next version from git tags and +# cut a GitHub release with a prebuilt npm tarball attached. Consumers install +# expost from that release asset URL (no token, no install-time tsc build). +# No version field to hand-edit — the tag is derived, not stored. See +# beeminder/blog#656. on: - release: - types: [published] + push: + branches: [master] permissions: contents: write +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false env: PNPM_VERSION: 9 jobs: - pack: + release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - run: git fetch --prune --tags + - id: semver + uses: ietf-tools/semver-action@v1 + with: + token: ${{ github.token }} + branch: master + fallbackTag: v1.0.0 + noVersionBumpBehavior: patch # release on every merge, not just conventional commits + skipInvalidTags: true - uses: actions/setup-node@v4 with: node-version: 20 @@ -22,9 +38,14 @@ jobs: version: ${{ env.PNPM_VERSION }} - run: pnpm install --frozen-lockfile - run: pnpm run build - - run: pnpm pack # respects files:[dist] -> expost-.tgz - - name: Attach tarball to release + - name: Pack tarball named for the release tag + env: + VERSION: ${{ steps.semver.outputs.next }} + run: | + pnpm pack # respects files:[dist]; produces expost-.tgz + mv expost-*.tgz "expost-${VERSION#v}.tgz" + - name: Create release with tarball env: GH_TOKEN: ${{ github.token }} - TAG: ${{ github.event.release.tag_name }} - run: gh release upload "$TAG" expost-*.tgz --clobber + VERSION: ${{ steps.semver.outputs.next }} + run: gh release create "$VERSION" "expost-${VERSION#v}.tgz" --title "$VERSION" --generate-notes From 432fa634a01cd5ea89a338197770ff02aa0d44bd Mon Sep 17 00:00:00 2001 From: Nathan Arthur Date: Wed, 15 Jul 2026 07:51:59 -0500 Subject: [PATCH 3/3] chore: eslint-ignore vendored etherpad/ reference code etherpad/expost.js is a vendored WordPress/browser jQuery snippet, not part of the shipped package (files:[dist] excludes it). It tripped no-undef on browser globals (jQuery, document, ajaxurl), which was failing lint on master too. Ignore the directory so lint reflects the package's own source. Co-Authored-By: Claude Opus 4.8 (1M context) --- eslint.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.js b/eslint.config.js index 7f221a8..0260d5f 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -4,7 +4,7 @@ import parser from "@typescript-eslint/parser"; export default tseslint.config( { - ignores: ["node_modules", "dist"], + ignores: ["node_modules", "dist", "etherpad"], }, eslint.configs.recommended, ...tseslint.configs.recommended,