Skip to content

Commit e486a10

Browse files
committed
Merge origin/main into fix/update-flow-hardening
Resolves apps/site/scripts/build-cdn.mjs by keeping both sides: main's RELEASE_VERSION guard and strict publishedAt from the #37 review, plus this branch's resolvePlatformArtifacts, MIN_REQUIRED_VERSION and the manifest fields that name each platform's artifact. Verified by running the merged script: it writes 0.9.2 with npm's own publish time and six platform entries with real checksums.
2 parents 62ffdfd + 12069a8 commit e486a10

1 file changed

Lines changed: 24 additions & 6 deletions

File tree

apps/site/scripts/build-cdn.mjs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ function parseArgs() {
3030
return { out, skipRg };
3131
}
3232

33+
const RELEASE_VERSION = /^\d+\.\d+\.\d+$/;
34+
3335
/**
3436
* Resolve the version this CDN advertises from a *published* release, never from
3537
* the working tree.
@@ -50,7 +52,18 @@ function parseArgs() {
5052
*/
5153
async function resolvePublishedRelease(packageName) {
5254
const pinned = process.env.PYTHINKER_CDN_VERSION?.trim();
53-
if (pinned) return { version: pinned, publishedAt: new Date().toISOString() };
55+
if (pinned) {
56+
// The override answers to the same shape rule as the registry path below.
57+
// A client rejects a manifest whose `version` is not semver, so an
58+
// unusable override has to stop the build instead of publishing a
59+
// latest.json that every installed client fails to parse.
60+
if (!RELEASE_VERSION.test(pinned)) {
61+
throw new Error(`PYTHINKER_CDN_VERSION is not a release version: ${pinned}`);
62+
}
63+
// Build time is the only timestamp available for a manual pin; the
64+
// registry path below requires npm's own and never stamps one.
65+
return { version: pinned, publishedAt: new Date().toISOString() };
66+
}
5467
const view = JSON.parse(
5568
execFileSync(
5669
'npm',
@@ -59,16 +72,21 @@ async function resolvePublishedRelease(packageName) {
5972
),
6073
);
6174
const version = view['dist-tags']?.latest;
62-
if (typeof version !== 'string' || !/^\d+\.\d+\.\d+$/.test(version)) {
75+
if (typeof version !== 'string' || !RELEASE_VERSION.test(version)) {
6376
throw new Error(
6477
`npm dist-tag latest for ${packageName} is not a release version: ${String(version)}`,
6578
);
6679
}
6780
const publishedAt = view.time?.[version];
68-
return {
69-
version,
70-
publishedAt: typeof publishedAt === 'string' ? publishedAt : new Date().toISOString(),
71-
};
81+
// Stamping build time here is the bug this function documents: it would move
82+
// the rollout anchor on every unrelated site deploy. Unreadable registry
83+
// metadata is a failed read, and a failed read must fail the build.
84+
if (typeof publishedAt !== 'string' || !Number.isFinite(Date.parse(publishedAt))) {
85+
throw new Error(
86+
`npm has no usable publish time for ${packageName}@${version}: ${String(publishedAt)}`,
87+
);
88+
}
89+
return { version, publishedAt };
7290
}
7391

7492
const RELEASE_DOWNLOAD_BASE = 'https://github.com/Pythoughts-labs/pythinker-code/releases/download';

0 commit comments

Comments
 (0)