Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ jobs:
publish:
runs-on: ubuntu-latest
environment: npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
node-version: 24
registry-url: https://registry.npmjs.org
package-manager-cache: false
- run: npm install --global npm@latest
- run: npm ci
- run: npm run verify
- run: node scripts/publish-workspace-if-needed.mjs beatapi-client
Expand Down
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project uses [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.1.1] - 2026-07-20

### Changed

- Publish both npm packages from GitHub Actions through npm Trusted Publishing
and short-lived OIDC credentials instead of a long-lived automation token.
- Add an approval-gated `npm` deployment environment and automatic npm
provenance for future releases.
- Normalize the CLI binary path in the published package metadata.

## [0.1.0] - 2026-07-17

### Added
Expand All @@ -20,5 +30,6 @@ and this project uses [Semantic Versioning](https://semver.org/).
- Structured errors, request IDs, bounded retries, CI, package checks, and npm
release automation.

[Unreleased]: https://github.com/BeatAPI/beatapi-cli/compare/v0.1.0...HEAD
[Unreleased]: https://github.com/BeatAPI/beatapi-cli/compare/v0.1.1...HEAD
[0.1.1]: https://github.com/BeatAPI/beatapi-cli/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/BeatAPI/beatapi-cli/releases/tag/v0.1.0
21 changes: 19 additions & 2 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,20 @@
2. Log in to npm with the BeatAPI publishing account.
3. Publish or reserve both package names: `beatapi-client` and `beatapi`.
4. In GitHub, create an environment named `npm`.
5. Add an environment secret named `NPM_TOKEN` with publish access to both
packages. Keep required reviewer protection enabled for production releases.
5. Add the publishing owner as a required reviewer for the `npm` environment
and allow release tags matching `v*`.
6. On npmjs.com, configure a GitHub Actions Trusted Publisher separately for
`beatapi-client` and `beatapi` with these exact values:
- organization: `BeatAPI`;
- repository: `beatapi-cli`;
- workflow filename: `release.yml`;
- environment: `npm`;
- allowed action: `npm publish`.

The release workflow uses npm Trusted Publishing over OIDC. It intentionally
does not store or reference a long-lived `NPM_TOKEN`. GitHub grants the workflow
a short-lived identity for each approved release, and npm automatically records
provenance for public packages published from the public repository.

The package names were unregistered when this repository was prepared. npm
names are first-come, first-served, so reserve them before announcing the
Expand All @@ -30,6 +42,11 @@ release.
10. Run `beatapi --version`, `beatapi --help`, and an authenticated
`beatapi auth status` smoke test.

The workflow installs the current npm CLI on Node.js 24 because Trusted
Publishing requires npm 11.5.1 or newer and Node.js 22.14.0 or newer. Do not add
an `NPM_TOKEN` fallback: a missing OIDC trust relationship should fail closed
instead of silently using a persistent credential.

## Rollback

npm package versions are immutable. If a release is defective:
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "beatapi-cli-workspace",
"version": "0.1.0",
"version": "0.1.1",
"private": true,
"description": "Official TypeScript client and CLI for BeatAPI AI video workflows.",
"type": "module",
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "beatapi",
"version": "0.1.0",
"version": "0.1.1",
"description": "Command-line interface for BeatAPI AI music video and ecommerce video workflows.",
"type": "module",
"bin": {
"beatapi": "./dist/bin.js"
"beatapi": "dist/bin.js"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand All @@ -19,7 +19,7 @@
"test": "tsx --test test/*.test.ts"
},
"dependencies": {
"beatapi-client": "0.1.0",
"beatapi-client": "0.1.1",
"cross-keychain": "1.1.0"
},
"engines": {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { promptSecret as defaultPromptSecret } from "./prompt.js";
import { persistWebhookSecret } from "./webhook-secrets.js";

export const VERSION = "0.1.0";
export const VERSION = "0.1.1";

const HELP = `BeatAPI CLI ${VERSION}

Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "beatapi-client",
"version": "0.1.0",
"version": "0.1.1",
"description": "Type-safe JavaScript and TypeScript client for the BeatAPI async video API.",
"type": "module",
"main": "./dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion scripts/package-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ try {
"utf8",
),
);
if (installedPackage.version !== "0.1.0") {
if (installedPackage.version !== "0.1.1") {
throw new Error("Installed CLI package version did not match the release.");
}

Expand Down
20 changes: 20 additions & 0 deletions test/release-workflow.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";

const workflow = await readFile(
new URL("../.github/workflows/release.yml", import.meta.url),
"utf8",
);

test("publishes both packages through approval-gated OIDC", () => {
assert.match(workflow, /id-token:\s*write/);
assert.match(workflow, /environment:\s*npm/);
assert.match(workflow, /node-version:\s*24/);
assert.match(workflow, /npm install --global npm@latest/);
assert.match(
workflow,
/publish-workspace-if-needed\.mjs beatapi-client[\s\S]*publish-workspace-if-needed\.mjs beatapi/,
);
assert.doesNotMatch(workflow, /NPM_TOKEN|NODE_AUTH_TOKEN/);
});
Loading