Pinning entry timestamps to the commit date made two builds of the same
VERSION differ whenever the workflow failed late and was re-run from a
fix-up commit — the no-overwrite guard then rejected the rerun. Pin to a
fixed epoch (SOURCE_DATE_EPOCH overridable) and walk files in sorted
order so every runner emits identical bytes for a given version. Bump
to 0.2.2 because the 0.2.1 immutable slot holds a commit-time-stamped
build.
adm-zip stamps entries with file mtimes, i.e. the git checkout time on
CI, so two builds of the same commit differed byte-wise and tripped the
immutable no-overwrite guard on workflow re-runs. Pin every entry to the
commit date (SOURCE_DATE_EPOCH convention) instead.
0.2.0 was never published (no manifest entry, no GitHub release), but a
stale chrome-store zip from the first failed run occupies its immutable
slot; move the release to 0.2.1 rather than deleting the object.
head() resolves to { meta, res, status } — raw headers live at
res.headers and x-oss-meta-* values are pre-parsed into meta. The
previous direct res.headers access crashed the post-upload verification
after the first successful put.
Replace the broken yarn/Node 18 release workflow (wrong package manager,
missing build/ dir, archived actions) with a manifest-based distribution
flow modeled on yaklang/browser-binaries-mirror:
- scripts/package-release.mjs: package the four variants, emit
release-entry.json and per-artifact sha256 checksums
- scripts/build-manifest.mjs: merge into a bounded public manifest
(10 versions) with invariant validation
- scripts/publish-oss.mjs: immutable artifacts (forbid-overwrite,
one-year cache) and mutable manifest (5-minute cache, checksum
published second), idempotent via head + sha256 comparison
- scripts/verify-public.mjs: post-publish verification from the public
endpoint (bytes, headers, zip layout)
- release.yml: pnpm + Node 22, full verify:production, OSS publish,
GitHub Release, separate public verify job, publish concurrency group
- ci.yml: run verify:production on push/PR
- single-source the extension version in package.json (wxt.config reads)
- document the distribution protocol in README