@tokenoftrust/storefront-runner 2.2.20 → 2.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/storefront/integrations/lifecycle-host-asset.mjs +1 -32
- package/package.json +1 -1
- package/packages/public-runtime/src/content-named-asset-prefixes.d.mts +2 -0
- package/packages/public-runtime/src/content-named-asset-prefixes.mjs +16 -0
- package/packages/public-runtime/src/integration/lifecycle-host-asset.mjs +13 -6
- package/packages/public-runtime/src/static-bundle.ts +3 -2
- package/packages/public-runtime/src/integration/lifecycle-host-asset.lock.json +0 -4
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
* passes — the client pass included — runs with `build.ssr === true`, so a Vite plugin
|
|
22
22
|
* cannot tell them apart, while `config.build.client` says it outright.
|
|
23
23
|
*/
|
|
24
|
-
import {
|
|
25
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
24
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
26
25
|
import { createRequire } from "node:module";
|
|
27
26
|
import { dirname } from "node:path";
|
|
28
27
|
import { fileURLToPath } from "node:url";
|
|
@@ -30,7 +29,6 @@ import {
|
|
|
30
29
|
LIFECYCLE_HOST_ASSET_PATH,
|
|
31
30
|
LIFECYCLE_HOST_COMPATIBILITY_ASSET_PATHS,
|
|
32
31
|
} from "@tot/public-runtime/integration/lifecycle-host-asset";
|
|
33
|
-
import { decideLifecycleHostLock, formatLifecycleHostLockReport } from "../../../scripts/lib/lifecycle-host-lock.mjs";
|
|
34
32
|
|
|
35
33
|
const HOST_ASSET_PATHS = Object.freeze([
|
|
36
34
|
...LIFECYCLE_HOST_COMPATIBILITY_ASSET_PATHS,
|
|
@@ -44,11 +42,6 @@ const HOST_ENTRY = fileURLToPath(
|
|
|
44
42
|
),
|
|
45
43
|
);
|
|
46
44
|
|
|
47
|
-
const LOCK_URL = new URL(
|
|
48
|
-
"../../../packages/public-runtime/src/integration/lifecycle-host-asset.lock.json",
|
|
49
|
-
import.meta.url,
|
|
50
|
-
);
|
|
51
|
-
|
|
52
45
|
/**
|
|
53
46
|
* Bundle the host to a single self-contained ES module.
|
|
54
47
|
*
|
|
@@ -131,30 +124,6 @@ export function lifecycleHostAsset() {
|
|
|
131
124
|
if (!clientDir) throw new Error("the lifecycle host has no resolved client output dir");
|
|
132
125
|
const outputDir = clientDir;
|
|
133
126
|
const code = await bundleLifecycleHost();
|
|
134
|
-
const hash = createHash("sha256").update(code, "utf8").digest("hex");
|
|
135
|
-
|
|
136
|
-
// Every HOST_ASSET_PATH is served under an `immutable, max-age=1yr` Cache-Control
|
|
137
|
-
// (scripts/publish/lib/s3-publish.mjs PLATFORM_ASSET_PREFIX) — once published, a
|
|
138
|
-
// path's bytes may never change, or visitors who already cached it are stuck on
|
|
139
|
-
// stale tracking/consent behavior for up to a year with nothing to notice it. This
|
|
140
|
-
// is the guard for that: refuse the build rather than silently rewrite a path that
|
|
141
|
-
// already shipped different bytes.
|
|
142
|
-
const lock = JSON.parse(await readFile(LOCK_URL, "utf8"));
|
|
143
|
-
const decision = decideLifecycleHostLock(
|
|
144
|
-
lock,
|
|
145
|
-
HOST_ASSET_PATHS.map((assetPath) => ({ assetPath, hash })),
|
|
146
|
-
);
|
|
147
|
-
if (!decision.ok) {
|
|
148
|
-
throw new Error(formatLifecycleHostLockReport(decision));
|
|
149
|
-
}
|
|
150
|
-
if (JSON.stringify(decision.nextLock) !== JSON.stringify(lock)) {
|
|
151
|
-
await writeFile(LOCK_URL, `${JSON.stringify(decision.nextLock, null, 2)}\n`, "utf8");
|
|
152
|
-
logger.warn(
|
|
153
|
-
"lifecycle host lock recorded a new path — commit " +
|
|
154
|
-
"packages/public-runtime/src/integration/lifecycle-host-asset.lock.json",
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
127
|
await Promise.all(HOST_ASSET_PATHS.map(async (assetPath) => {
|
|
159
128
|
const target = fileURLToPath(new URL(assetPath, outputDir));
|
|
160
129
|
await mkdir(dirname(target), { recursive: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.22",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
|
|
6
6
|
"packageManager": "pnpm@11.9.0",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle-relative prefixes whose URL is derived from the file's own bytes, and therefore
|
|
3
|
+
* the ONLY paths that may be served `Cache-Control: immutable`:
|
|
4
|
+
* `_astro/` — Astro/Vite put a content hash in every filename.
|
|
5
|
+
* `_a/` — the content-addressed asset pool (`/_a/<sha256><ext>`).
|
|
6
|
+
*
|
|
7
|
+
* `immutable` tells a browser it will never need to revalidate, so it is only correct when a
|
|
8
|
+
* byte change necessarily changes the URL. A path-VERSIONED prefix such as `platform/` does
|
|
9
|
+
* not qualify: its `v{N}` names a contract, compatible changes rebuild it in place, and a
|
|
10
|
+
* returning visitor would keep the old bytes for a year.
|
|
11
|
+
*
|
|
12
|
+
* One list for both CDNs. The S3/CloudFront publish plane (`scripts/publish/lib/s3-publish.mjs`)
|
|
13
|
+
* and the Cloudflare serve plane (`src/static-bundle.ts`) both read it, so they cannot
|
|
14
|
+
* disagree about what is immutable.
|
|
15
|
+
*/
|
|
16
|
+
export const CONTENT_NAMED_ASSET_PREFIXES = Object.freeze(["_astro/", "_a/"]);
|
|
@@ -8,18 +8,25 @@
|
|
|
8
8
|
* disagree — a mismatch would leave every static tenant page with plan data and no host,
|
|
9
9
|
* which fails silently in exactly the way it is not allowed to.
|
|
10
10
|
*
|
|
11
|
-
* The
|
|
12
|
-
*
|
|
11
|
+
* The `/v4/` segment names the boot CONTRACT, not the bytes: a compatible runtime change
|
|
12
|
+
* rebuilds this same path, which is why `platform/` is served with a revalidating cache
|
|
13
|
+
* tier rather than `immutable`. A host with a different boot contract ships at the next
|
|
14
|
+
* `v{N}` alongside this one.
|
|
15
|
+
*
|
|
16
|
+
* The segment must also advance once whenever earlier bytes at a path were served under an
|
|
17
|
+
* `immutable` header, since nothing the server does reaches a browser that cached them that
|
|
18
|
+
* way. v3 was, which is why v4 exists.
|
|
13
19
|
*/
|
|
14
|
-
export const LIFECYCLE_HOST_ASSET_PATH = "platform/lifecycle/
|
|
20
|
+
export const LIFECYCLE_HOST_ASSET_PATH = "platform/lifecycle/v4/boot.mjs";
|
|
15
21
|
|
|
16
22
|
/**
|
|
17
|
-
* Earlier
|
|
18
|
-
*
|
|
19
|
-
*
|
|
23
|
+
* Earlier URLs that keep serving the current host bytes. Cached HTML may still reference
|
|
24
|
+
* one of these paths after a pointer flip, so dropping it would turn a cache refresh into a
|
|
25
|
+
* lifecycle 404.
|
|
20
26
|
*/
|
|
21
27
|
export const LIFECYCLE_HOST_COMPATIBILITY_ASSET_PATHS = Object.freeze([
|
|
22
28
|
"platform/lifecycle/v2/boot.mjs",
|
|
29
|
+
"platform/lifecycle/v3/boot.mjs",
|
|
23
30
|
]);
|
|
24
31
|
|
|
25
32
|
/** The root-absolute, same-origin URL the served markup references. */
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
import { assetContentType } from "./tenant-assets.js";
|
|
44
44
|
import { formatHtmlCacheControl } from "./html-cache-policy.js";
|
|
45
45
|
import { NATIVE_GA4_SANDBOX_ASSET_PATH } from "./integration/native-ga4-sandbox-asset.mjs";
|
|
46
|
+
import { CONTENT_NAMED_ASSET_PREFIXES } from "./content-named-asset-prefixes.mjs";
|
|
46
47
|
|
|
47
48
|
// ---------------------------------------------------------------------------
|
|
48
49
|
// R2 seam — same structural subset tenant-assets.ts uses (no workers-types dep)
|
|
@@ -302,8 +303,8 @@ const IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
|
302
303
|
*/
|
|
303
304
|
const STABLE_ASSET_CACHE_CONTROL = "public, max-age=86400, stale-while-revalidate=604800";
|
|
304
305
|
|
|
305
|
-
/** Bundle prefixes whose stable paths are
|
|
306
|
-
const IMMUTABLE_STABLE_PREFIXES =
|
|
306
|
+
/** Bundle prefixes whose stable paths are immutable — shared with the S3 plane, see that module. */
|
|
307
|
+
const IMMUTABLE_STABLE_PREFIXES = CONTENT_NAMED_ASSET_PREFIXES;
|
|
307
308
|
|
|
308
309
|
/**
|
|
309
310
|
* URL prefix of a content-addressed asset (`/_a/<sha256><ext>`) — kept in lockstep with
|