@tokenoftrust/storefront-runner 2.0.16 → 2.0.18

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.
Files changed (90) hide show
  1. package/apps/storefront/env.d.ts +18 -0
  2. package/apps/storefront/migrations-apps/0012_test_destinations.sql +29 -0
  3. package/apps/storefront/src/components/blog/ReactionBar.astro +1 -1
  4. package/apps/storefront/src/components/islands/CheckoutComplianceGate.tsx +365 -49
  5. package/apps/storefront/src/components/islands/checkoutVerificationFlow.ts +251 -0
  6. package/apps/storefront/src/config/compliance/rulesets.ts +18 -7
  7. package/apps/storefront/src/config/devTenantSeed.ts +24 -1
  8. package/apps/storefront/src/config/evidenceTenantRoster.ts +25 -0
  9. package/apps/storefront/src/config/publicationSpaceConfig.ts +25 -0
  10. package/apps/storefront/src/config/resolver.ts +5 -0
  11. package/apps/storefront/src/config/tenantAnalyticsFiles.ts +43 -0
  12. package/apps/storefront/src/config/tenants.ts +11 -0
  13. package/apps/storefront/src/layouts/Layout.astro +5 -1
  14. package/apps/storefront/src/lib/activity/killSwitch.ts +1 -1
  15. package/apps/storefront/src/lib/admin/consentSettingsClient.ts +113 -0
  16. package/apps/storefront/src/lib/apps/consentConfigRead.ts +24 -0
  17. package/apps/storefront/src/lib/apps/gtmMigrationDraft.ts +103 -0
  18. package/apps/storefront/src/lib/apps/routeParams.ts +45 -0
  19. package/apps/storefront/src/lib/auth/loginGate.ts +25 -0
  20. package/apps/storefront/src/lib/checkoutCommerce.ts +1 -1
  21. package/apps/storefront/src/lib/compliance/enforcement.ts +25 -3
  22. package/apps/storefront/src/lib/d1/schema-apps.ts +44 -0
  23. package/apps/storefront/src/lib/env.ts +13 -111
  24. package/apps/storefront/src/lib/fixtures/regulated-commerce-truth/index.ts +540 -0
  25. package/apps/storefront/src/lib/fixtures/ws3-readonly-clone-preflight/index.ts +495 -0
  26. package/apps/storefront/src/lib/integration/tenantAnalyticsDeclarations.ts +198 -0
  27. package/apps/storefront/src/lib/monitoring/manifest.ts +1 -1
  28. package/apps/storefront/src/lib/rawMarketingHtml.ts +9 -1
  29. package/apps/storefront/src/lib/runtimeEnv.ts +124 -0
  30. package/apps/storefront/src/lib/verification/totVerificationClient.ts +485 -0
  31. package/apps/storefront/src/middleware/candidatePin.ts +35 -0
  32. package/apps/storefront/src/middleware/controlPlane.ts +270 -0
  33. package/apps/storefront/src/middleware/index.ts +100 -796
  34. package/apps/storefront/src/middleware/publicRender.ts +43 -0
  35. package/apps/storefront/src/middleware/renderChain.ts +685 -0
  36. package/apps/storefront/src/middleware/routeBranch.ts +160 -0
  37. package/apps/storefront/src/middleware/staticBundle.ts +109 -0
  38. package/apps/storefront/src/pages/[...slug].astro +1 -0
  39. package/apps/storefront/src/pages/api/compliance/preflight.ts +179 -2
  40. package/apps/storefront/src/pages/index.astro +1 -0
  41. package/apps/storefront/vitest.config.ts +5 -0
  42. package/package.json +1 -1
  43. package/packages/public-runtime/package.json +1 -0
  44. package/packages/public-runtime/schemas/managed-analytics/v1/deliver-test-event-request.schema.json +122 -0
  45. package/packages/public-runtime/schemas/managed-analytics/v1/get-test-destination-delivery-request.schema.json +79 -0
  46. package/packages/public-runtime/schemas/managed-analytics/v1/register-test-destination-request.schema.json +93 -0
  47. package/packages/public-runtime/schemas/managed-analytics/v1/test-destination-delivery.schema.json +106 -0
  48. package/packages/public-runtime/schemas/managed-analytics/v1/test-destination.schema.json +77 -0
  49. package/packages/public-runtime/schemas/publication-space/v1/manifest.schema.json +195 -0
  50. package/packages/public-runtime/schemas/publication-space/v1/normalized-mount.schema.json +80 -0
  51. package/packages/public-runtime/schemas/publication-space/v1/ref.schema.json +20 -0
  52. package/packages/public-runtime/schemas/publication-version/v1/pointer.schema.json +28 -0
  53. package/packages/public-runtime/schemas/publication-version/v1/transition-request.schema.json +44 -0
  54. package/packages/public-runtime/schemas/publication-version/v1/transition.schema.json +47 -0
  55. package/packages/public-runtime/schemas/publication-version/v1/version.schema.json +58 -0
  56. package/packages/public-runtime/src/activity/catalog.ts +1 -1
  57. package/packages/public-runtime/src/candidate-index.ts +6 -0
  58. package/packages/public-runtime/src/customization-reconcile.ts +8 -0
  59. package/packages/public-runtime/src/html-cache-policy.ts +57 -0
  60. package/packages/public-runtime/src/index.ts +7 -0
  61. package/packages/public-runtime/src/integration/consent-broker.ts +115 -0
  62. package/packages/public-runtime/src/integration/interim-bridge.ts +111 -27
  63. package/packages/public-runtime/src/integration/managed-analytics-api-v1.schemas.ts +65 -0
  64. package/packages/public-runtime/src/integration/managed-analytics-api-v1.ts +81 -0
  65. package/packages/public-runtime/src/integration/render-phases.ts +8 -3
  66. package/packages/public-runtime/src/publication-artifact.ts +203 -0
  67. package/packages/public-runtime/src/publication-space.ts +853 -0
  68. package/packages/public-runtime/src/publication-version.ts +587 -0
  69. package/packages/public-runtime/src/route-tier.ts +257 -0
  70. package/packages/public-runtime/src/static-bundle.ts +18 -5
  71. package/packages/public-runtime/src/tenant-assets.ts +85 -17
  72. package/packages/public-runtime/src/tenant.ts +70 -0
  73. package/packages/public-runtime/tests/conformance/fake-destination.ts +402 -0
  74. package/packages/public-runtime/tests/fixtures/publication-spaces/internal.json +32 -0
  75. package/packages/public-runtime/tests/fixtures/publication-spaces/mounted-public.json +38 -0
  76. package/packages/public-runtime/tests/fixtures/publication-spaces/normalized-mounts.json +39 -0
  77. package/packages/public-runtime/tests/fixtures/publication-spaces/ref.json +5 -0
  78. package/packages/public-runtime/tests/fixtures/publication-spaces/root-public.json +31 -0
  79. package/packages/public-runtime/tests/fixtures/publication-versions/articles-v1.json +20 -0
  80. package/packages/public-runtime/tests/fixtures/publication-versions/articles-v2.json +20 -0
  81. package/packages/public-runtime/tests/fixtures/publication-versions/internal-v1.json +20 -0
  82. package/packages/public-runtime/tests/fixtures/publication-versions/live-pointer.json +11 -0
  83. package/packages/public-runtime/tests/fixtures/publication-versions/live-transition-request.json +14 -0
  84. package/packages/public-runtime/tests/fixtures/publication-versions/live-transition.json +17 -0
  85. package/packages/public-runtime/tests/fixtures/publication-versions/root-v1.json +20 -0
  86. package/packages/public-runtime/tests/fixtures/publication-versions/root-v2.json +20 -0
  87. package/scripts/dev/ai-edit.mjs +16 -3
  88. package/scripts/dev/port-check.mjs +18 -3
  89. package/scripts/dev/publish.mjs +26 -3
  90. package/scripts/tenant/validate.mjs +14 -1
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "versionId": "pv_root-version-0001",
4
+ "tenant": "fixture.example",
5
+ "spaceId": "root",
6
+ "source": {
7
+ "forge": "fixture",
8
+ "repo": "fixture.example",
9
+ "commitSha": "1111111111111111111111111111111111111111"
10
+ },
11
+ "renderer": {
12
+ "contractVersion": "storefront-v1",
13
+ "themeContractVersion": "theme-v1"
14
+ },
15
+ "artifactDigest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
16
+ "createdAt": "2026-09-01T12:00:00.000Z",
17
+ "metadata": {
18
+ "buildId": "build-root-0001"
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "versionId": "pv_root-version-0002",
4
+ "tenant": "fixture.example",
5
+ "spaceId": "root",
6
+ "source": {
7
+ "forge": "fixture",
8
+ "repo": "fixture.example",
9
+ "commitSha": "2222222222222222222222222222222222222222"
10
+ },
11
+ "renderer": {
12
+ "contractVersion": "storefront-v1",
13
+ "themeContractVersion": "theme-v1"
14
+ },
15
+ "artifactDigest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
16
+ "createdAt": "2026-09-01T12:01:00.000Z",
17
+ "metadata": {
18
+ "buildId": "build-root-0002"
19
+ }
20
+ }
@@ -25,6 +25,7 @@ import { createMcpClient } from "../../packages/cli/src/mcp.mjs";
25
25
  import { resolveDeveloperSession, AuthUnavailableError } from "../../packages/cli/src/auth.mjs";
26
26
  import { applyUnifiedDiff } from "./unified-diff.mjs";
27
27
  import { tenantDirSegments } from "../lib/tenant-dirs.mjs";
28
+ import { recordDiagnostic } from "../../packages/cli/src/diagnostics.mjs";
28
29
 
29
30
  const DEFAULT_MCP_URL = "https://mcp.tokenoftrust.com";
30
31
 
@@ -83,7 +84,7 @@ async function resolveClient(mcpBaseUrl) {
83
84
  * not-configured all come back as `{ ok:false, status, message }`).
84
85
  */
85
86
  export async function handleAiEdit({ repoRoot, tenantId, prompt, mcpBaseUrl }, deps = {}) {
86
- const { resolveClientImpl = resolveClient } = deps;
87
+ const { resolveClientImpl = resolveClient, env = process.env } = deps;
87
88
  const paths = tenantPaths(repoRoot, tenantId);
88
89
  const files = [
89
90
  { path: "content/home.html", content: readFileIfPresent(paths.home) },
@@ -98,14 +99,26 @@ export async function handleAiEdit({ repoRoot, tenantId, prompt, mcpBaseUrl }, d
98
99
  try {
99
100
  client = await resolveClientImpl(mcpBaseUrl);
100
101
  } catch (e) {
101
- return { ok: false, status: "unauthenticated", message: e.message };
102
+ const diagnostic = recordDiagnostic(e, {
103
+ command: "dev-ai-edit", operation: "session_initialize", required: true,
104
+ }, env);
105
+ return {
106
+ ok: false, status: "unauthenticated", message: e.message,
107
+ diagnosticId: diagnostic.diagnosticId,
108
+ };
102
109
  }
103
110
 
104
111
  let result;
105
112
  try {
106
113
  result = await client.callTool("content_edit", { prompt, files });
107
114
  } catch (e) {
108
- return { ok: false, status: "error", message: e.message };
115
+ const diagnostic = recordDiagnostic(e, {
116
+ command: "dev-ai-edit", operation: "content_edit", required: true,
117
+ }, env);
118
+ return {
119
+ ok: false, status: "error", message: e.message,
120
+ diagnosticId: diagnostic.diagnosticId,
121
+ };
109
122
  }
110
123
  if (result?.status && result.status !== "ok") {
111
124
  return { ok: false, status: result.status, message: result.message || "content_edit refused the request." };
@@ -18,19 +18,34 @@ import net from "node:net";
18
18
  * @param {number} port
19
19
  * @returns {Promise<boolean>}
20
20
  */
21
- export function isPortFree(port) {
21
+ /**
22
+ * @param {number} port
23
+ * @param {string | undefined} [host]
24
+ * @param {boolean} [unsupportedIsFree]
25
+ */
26
+ function canBind(port, host = undefined, unsupportedIsFree = false) {
22
27
  return new Promise((resolve) => {
23
28
  const srv = net.createServer();
24
- srv.once("error", () => resolve(false));
29
+ srv.once("error", (error) => {
30
+ const code = /** @type {NodeJS.ErrnoException} */ (error).code;
31
+ const unsupported = code === "EAFNOSUPPORT" || code === "EADDRNOTAVAIL";
32
+ resolve(unsupportedIsFree && unsupported);
33
+ });
25
34
  srv.once("listening", () => srv.close(() => resolve(true)));
26
35
  try {
27
- srv.listen(port);
36
+ srv.listen({ port, ...(host ? { host } : {}) });
28
37
  } catch {
29
38
  resolve(false);
30
39
  }
31
40
  });
32
41
  }
33
42
 
43
+ export async function isPortFree(port) {
44
+ if (!(await canBind(port))) return false;
45
+ if (!(await canBind(port, "127.0.0.1"))) return false;
46
+ return canBind(port, "::1", true);
47
+ }
48
+
34
49
  /**
35
50
  * The first free port at or after `preferred` (scanning upward). Lets `tot dev`
36
51
  * boot on a busy default port by moving to the next open one and printing it —
@@ -32,6 +32,7 @@ import { matchesWriteAllowlist } from "./safe-path.mjs";
32
32
  import { resolveTenantSourceRoot } from "./tenant-source-root.mjs";
33
33
  import { createMcpClient } from "../../packages/cli/src/mcp.mjs";
34
34
  import { resolveDeveloperSession, AuthUnavailableError } from "../../packages/cli/src/auth.mjs";
35
+ import { recordDiagnostic } from "../../packages/cli/src/diagnostics.mjs";
35
36
 
36
37
  const DEFAULT_MCP_URL = "https://mcp.tokenoftrust.com";
37
38
 
@@ -90,13 +91,26 @@ export async function publishFile(env, sourceRoot, tenantId, relPath, deps = {})
90
91
  session = await (deps.resolveSession || resolveDeveloperSession)(client, env);
91
92
  await client.initialize();
92
93
  } catch (e) {
94
+ const diagnostic = recordDiagnostic(e, {
95
+ command: "dev-publish", operation: "session_initialize", required: true,
96
+ }, env);
93
97
  if (e instanceof AuthUnavailableError) {
94
98
  return {
95
99
  status: 503,
96
- json: { ok: false, status: "not_signed_in", message: `${e.message}${e.hint ? ` — ${e.hint}` : ""}` },
100
+ json: {
101
+ ok: false, status: "not_signed_in",
102
+ message: `${e.message}${e.hint ? ` — ${e.hint}` : ""}`,
103
+ diagnosticId: diagnostic.diagnosticId,
104
+ },
97
105
  };
98
106
  }
99
- return { status: 502, json: { ok: false, status: "error", message: String(e?.message || e) } };
107
+ return {
108
+ status: 502,
109
+ json: {
110
+ ok: false, status: "error", message: String(e?.message || e),
111
+ diagnosticId: diagnostic.diagnosticId,
112
+ },
113
+ };
100
114
  }
101
115
 
102
116
  const repo = `${tenantId}-main`;
@@ -127,7 +141,16 @@ export async function publishFile(env, sourceRoot, tenantId, relPath, deps = {})
127
141
  },
128
142
  };
129
143
  } catch (e) {
130
- return { status: 502, json: { ok: false, status: "error", message: String(e?.message || e) } };
144
+ const diagnostic = recordDiagnostic(e, {
145
+ command: "dev-publish", operation: "candidate_open", required: true,
146
+ }, env);
147
+ return {
148
+ status: 502,
149
+ json: {
150
+ ok: false, status: "error", message: String(e?.message || e),
151
+ diagnosticId: diagnostic.diagnosticId,
152
+ },
153
+ };
131
154
  }
132
155
  }
133
156
 
@@ -738,7 +738,12 @@ export function discoverTenantIds() {
738
738
 
739
739
  // --- link / asset extraction -------------------------------------------------
740
740
  const HREF_RE = /\bhref\s*=\s*"([^"]*)"/gi;
741
- const SRC_RE = /\b(?:src|srcset)\s*=\s*"([^"]*)"/gi;
741
+ const SRC_RE = /\bsrc\s*=\s*"([^"]*)"/gi;
742
+ // `srcset` carries a comma-separated list of `url descriptor` pairs (e.g.
743
+ // "a.webp 480w, b.webp 800w"), not a single URL — each candidate must be split
744
+ // off its descriptor before being checked as an asset. Mirrors
745
+ // scripts/publish/lib/asset-reachability.mjs's srcset handling.
746
+ const SRCSET_RE = /\bsrcset\s*=\s*"([^"]*)"/gi;
742
747
  const STYLE_OPEN_WITH_ATTRS_RE = /<style\s+[^>]*>/i;
743
748
  /** An in-page skip link: an anchor to a #main-ish target, or one carrying a skip class. */
744
749
  const SKIP_LINK_RE = /<a\b[^>]*(?:class="[^"]*\bskip[-\w]*\b[^"]*"|href="#(?:main|content|main-content)\b")/i;
@@ -981,6 +986,14 @@ export function validateTenant(tenantDir, opts = {}) {
981
986
  const f = checkAsset(m[1].trim(), r, publicDir, opts.tenantId || config?.tenant);
982
987
  if (f) findings.push(f);
983
988
  }
989
+ for (const m of html.matchAll(SRCSET_RE)) {
990
+ for (const candidate of m[1].split(",")) {
991
+ const url = candidate.trim().split(/\s+/)[0];
992
+ if (!url) continue;
993
+ const f = checkAsset(url, r, publicDir, opts.tenantId || config?.tenant);
994
+ if (f) findings.push(f);
995
+ }
996
+ }
984
997
  }
985
998
 
986
999
  // 5. git conflict markers — advisory (never blocks), but LOUD: a half-resolved