@tokenoftrust/storefront-runner 2.2.97 → 2.2.98

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "2.2.97",
3
+ "version": "2.2.98",
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",
@@ -44,6 +44,7 @@ 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
46
  import { CONTENT_NAMED_ASSET_PREFIXES } from "./content-named-asset-prefixes.mjs";
47
+ import { resolveRedirect } from "./publication-redirects.mjs";
47
48
 
48
49
  // ---------------------------------------------------------------------------
49
50
  // R2 seam — same structural subset tenant-assets.ts uses (no workers-types dep)
@@ -189,41 +190,15 @@ function isManifestRedirectRule(value: string): boolean {
189
190
  }
190
191
 
191
192
  /**
192
- * Where a rule sends a request whose path continues `capture` past the rule's directory; null
193
- * unless the result is a same-origin path. Same semantics as `ruleLocation` in
194
- * `publication-redirects.mjs` and the CloudFront function — the three are held together by
195
- * `tests/fixtures/redirect-match-cases.json`.
196
- */
197
- function ruleLocation(to: string, capture: string): string | null {
198
- const location = to.endsWith("/*") ? `${to.slice(0, -1)}${capture}` : to;
199
- return location.startsWith("/") && !location.startsWith("//") && !location.includes("\\")
200
- ? location
201
- : null;
202
- }
203
-
204
- /**
205
- * The redirect the manifest declares for `pathname`, as a location, or null. An exact entry wins
206
- * outright; otherwise the rule with the longest directory that the trailing-slash form of the path
207
- * starts with decides — and when its location is unusable there is no redirect.
193
+ * The redirect the manifest declares for `pathname`, as a location, or null — the redirect
194
+ * contract's own matcher (`publication-redirects.mjs`), so this plane cannot answer differently.
208
195
  */
209
196
  function staticBundleRedirectLocation(
210
197
  redirects: StaticBundleManifest["redirects"],
211
198
  pathname: string,
212
199
  ): string | null {
213
200
  if (!redirects?.length) return null;
214
- const path = pathname === "/" || pathname.split("/").pop()?.includes(".")
215
- ? pathname
216
- : pathname.endsWith("/") ? pathname : `${pathname}/`;
217
- let rule: { from: string; to: string } | null = null;
218
- for (const redirect of redirects) {
219
- if (redirect.from.endsWith("/*")) {
220
- const dir = redirect.from.slice(0, -1);
221
- if (path.startsWith(dir) && (rule === null || dir.length > rule.from.length - 1)) rule = redirect;
222
- } else if (redirect.from === pathname || redirect.from === path) {
223
- return redirect.to;
224
- }
225
- }
226
- return rule === null ? null : ruleLocation(rule.to, path.slice(rule.from.length - 1));
201
+ return resolveRedirect(redirects, pathname)?.location ?? null;
227
202
  }
228
203
 
229
204
  function isManifestRedirectDestination(value: string): boolean {
@@ -1386,21 +1386,24 @@ if (isMain) {
1386
1386
  })()
1387
1387
  : baseline;
1388
1388
  const { ok, findings } = result;
1389
+ // exitCode, never exit(): a report written to a pipe is flushed asynchronously, and exit() cuts a
1390
+ // large one off mid-JSON for whoever parses it.
1389
1391
  if (asJson) {
1390
1392
  console.log(JSON.stringify({ ok, findings }, null, 2));
1391
- process.exit(ok ? 0 : 1);
1392
- }
1393
- const errors = findings.filter((f) => f.level === ERROR);
1394
- const warns = findings.filter((f) => f.level === WARN);
1395
- console.log(`\ntot validate${profile ? ` --profile ${profile}` : ""} — ${tenantId ?? dir}\n`);
1396
- // Named, grouped callouts FIRST — see printLoudAdvisories above.
1397
- printLoudAdvisories(findings, { log: (s) => console.log(s) });
1398
- for (const f of findings) {
1399
- const tag = f.level === ERROR ? "✗" : "⚠";
1400
- console.log(` ${tag} [${f.rule}] ${f.file}\n ${f.message}${f.fix ? `\n → ${f.fix}` : ""}`);
1401
- }
1402
- console.log(
1403
- `\n${errors.length === 0 ? "✔" : "✖"} ${errors.length} error(s), ${warns.length} warning(s).\n`,
1404
- );
1405
- process.exit(errors.length === 0 ? 0 : 1);
1393
+ process.exitCode = ok ? 0 : 1;
1394
+ } else {
1395
+ const errors = findings.filter((f) => f.level === ERROR);
1396
+ const warns = findings.filter((f) => f.level === WARN);
1397
+ console.log(`\ntot validate${profile ? ` --profile ${profile}` : ""} — ${tenantId ?? dir}\n`);
1398
+ // Named, grouped callouts FIRST — see printLoudAdvisories above.
1399
+ printLoudAdvisories(findings, { log: (s) => console.log(s) });
1400
+ for (const f of findings) {
1401
+ const tag = f.level === ERROR ? "✗" : "⚠";
1402
+ console.log(` ${tag} [${f.rule}] ${f.file}\n ${f.message}${f.fix ? `\n → ${f.fix}` : ""}`);
1403
+ }
1404
+ console.log(
1405
+ `\n${errors.length === 0 ? "✔" : "✖"} ${errors.length} error(s), ${warns.length} warning(s).\n`,
1406
+ );
1407
+ process.exitCode = errors.length === 0 ? 0 : 1;
1408
+ }
1406
1409
  }