A no-op re-publish produced new manifest bytes and checksum for
identical content, which raced the CDN cache and failed verification.
Compare against the existing manifest verbatim and keep its updated_at
when the merged result is unchanged.
The CDN in front of aliyun-oss.yaklang.com rewrites JSON responses to
max-age=60 (the browser-binaries manifest gets the same), which is
stricter than the 300s we set at upload. Assert the effective window is
short rather than matching the upload value.
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