Instructions for AI assistants working on backblaze-labs/b2-action (the Backblaze B2 GitHub Action).
A GitHub Action that wraps @backblaze-labs/b2-sdk to upload, download, sync, copy, and manage Backblaze B2 Cloud Storage from a CI workflow. Node 24 JavaScript action, single dist/index.js produced by @vercel/ncc.
The SDK at @backblaze-labs/b2-sdk is the source of truth for B2 wire-protocol concerns. Whenever you'd reach for raw HTTP, fetch, boto3, the b2 CLI, or a shelled-out subprocess: stop and use the SDK instead.
This repo mirrors the SDK's style as closely as practical:
- Biome formatter / linter, 2-space indent, single quotes, no semicolons, 100-char line width.
exactOptionalPropertyTypesON. Use conditional spread...(v !== undefined ? { k: v } : {})instead of passingundefined.verbatimModuleSyntaxON. Useimport typefor type-only imports.- Internal relative imports use
.tsextensions, not.js. - All source under
src/. Tests under__tests__/next to the repo root (so we don't ship them indist/).
pnpm install
pnpm lint # biome check --error-on-warnings
pnpm lint:fix
pnpm typecheck # tsc --noEmit
pnpm test # vitest run, against B2Simulator
pnpm build # ncc build src/main.ts -o dist
pnpm all # lint + typecheck + test + build
pnpm verify-dist # build, then `git diff --exit-code dist/`: must be clean before commitsrc/main.ts is the entrypoint. It:
- Calls
parseInputs()(src/inputs.ts) which readsINPUT_*env vars via@actions/core, validates them, applies the credential-fallback chain (application-key-idinput →B2_APPLICATION_KEY_IDenv var; same for the secret), and masks the secret value. - Calls
buildClient(...)(src/client.ts) which constructs aB2ClientwithuserAgent: 'b2-github-action/<version>', authorizes, and masks the resulting auth token. - Dispatches on
inputs.actionto a command module undersrc/commands/. Each command returns a structured result. - Maps the result onto
core.setOutput(...)calls. - Any thrown error becomes
core.setFailed(msg).
Each src/commands/<verb>.ts exports one async function that takes (bucket: Bucket, inputs: ParsedInputs) and returns a typed result. The function does its own progress reporting (via src/progress.ts) and core.startGroup / core.endGroup framing. It does NOT call core.setOutput: that's the dispatcher's job.
The SDK enforces a stable b2-sdk-typescript/<v> + @backblaze-labs/b2-sdk prefix in the User-Agent. We append b2-github-action/<v> so Backblaze server-side logs can identify CI traffic. Do not rename either token. The version constant lives in src/version.ts and must be bumped in lockstep with package.json version.
dist/index.js (and its sourcemap) is committed to git: GitHub Actions reads it directly. CI fails if pnpm build produces a diff that wasn't committed. Always run pnpm build before opening a PR that changes anything under src/.
Tests run against the SDK's in-memory B2Simulator (@backblaze-labs/b2-sdk/simulator). No real network. Pattern (see __tests__/commands/upload-download.test.ts):
const sim = new B2Simulator()
const client = new B2Client({
applicationKeyId: 'test-key-id',
applicationKey: 'test-key',
transport: sim.transport(),
})
await client.authorize()
const bucket = await client.createBucket({ bucketName: 'gh-action-test', bucketType: 'allPrivate' })The __tests__/inputs.test.ts file exercises the env-var fallback chain by setting INPUT_* env vars directly. Always clear them in beforeEach to avoid cross-test bleed.
Do not run git add, git commit, git push, git rebase, gh pr create, or any command that mutates git history unless the user explicitly asks for that specific action in the current turn. Edit files freely; suggest commands the user could run.