@tokenoftrust/storefront-runner 1.4.2-rc.0 → 2.0.0

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 (363) hide show
  1. package/apps/storefront/astro.config.mjs +3 -3
  2. package/apps/storefront/env.d.ts +54 -5
  3. package/apps/storefront/integrations/materialize-guard.mjs +12 -14
  4. package/apps/storefront/migrations-apps/0004_deep_morph.sql +36 -0
  5. package/apps/storefront/migrations-apps/0005_common_mystique.sql +23 -0
  6. package/apps/storefront/migrations-apps/0006_broad_microchip.sql +16 -0
  7. package/apps/storefront/migrations-apps/0007_brave_outlaw_kid.sql +15 -0
  8. package/apps/storefront/migrations-apps/0008_blue_dazzler.sql +11 -0
  9. package/apps/storefront/migrations-apps/0009_bored_shinobi_shaw.sql +15 -0
  10. package/apps/storefront/migrations-apps/0010_ws4_verified_provider_measurement.sql +35 -0
  11. package/apps/storefront/migrations-apps/meta/0004_snapshot.json +1474 -0
  12. package/apps/storefront/migrations-apps/meta/0005_snapshot.json +1617 -0
  13. package/apps/storefront/migrations-apps/meta/0006_snapshot.json +1716 -0
  14. package/apps/storefront/migrations-apps/meta/0007_snapshot.json +1812 -0
  15. package/apps/storefront/migrations-apps/meta/0008_snapshot.json +1881 -0
  16. package/apps/storefront/migrations-apps/meta/0009_snapshot.json +1979 -0
  17. package/apps/storefront/migrations-apps/meta/_journal.json +42 -0
  18. package/apps/storefront/public/apps/tot.demo.analytics/0.1.0/entry.js +42 -0
  19. package/apps/storefront/public/platform/amplitude-http/v1/entry.mjs +19 -0
  20. package/apps/storefront/public/platform/google-measurement/v1/entry.mjs +19 -0
  21. package/apps/storefront/public/shared/commerce-chrome.css +20 -2
  22. package/apps/storefront/scripts/build-v84-clean-clone-standalone.mjs +68 -0
  23. package/apps/storefront/scripts/deny-v84-clean-clone-standalone-capabilities.mjs +111 -0
  24. package/apps/storefront/scripts/deny-v84-dogfood-capabilities.mjs +2 -0
  25. package/apps/storefront/scripts/deny-v84-lifecycle-capabilities.mjs +247 -0
  26. package/apps/storefront/scripts/dogfood-v84-nonportable-routes.ts +73 -0
  27. package/apps/storefront/scripts/fixed-v84-native-install-producer.ts +79 -0
  28. package/apps/storefront/scripts/generated/v84-clean-clone-replay.bundle.mjs +10982 -0
  29. package/apps/storefront/scripts/import-v84-through-ws2.ts +38 -0
  30. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling-dependency.ts +2 -0
  31. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling.ts +4 -0
  32. package/apps/storefront/scripts/install-v84-native-through-ws1.ts +185 -0
  33. package/apps/storefront/scripts/prove-clone-isolation.ts +506 -0
  34. package/apps/storefront/scripts/replay-v84-clean-clone-pass.ts +148 -0
  35. package/apps/storefront/scripts/replay-v84-clean-clone-standalone.ts +35 -0
  36. package/apps/storefront/scripts/replay-v84-clean-clone.ts +214 -0
  37. package/apps/storefront/scripts/run-fixed-v84-native-install-producer.mjs +18 -0
  38. package/apps/storefront/scripts/run-v84-clone-isolation-proof.mjs +18 -0
  39. package/apps/storefront/scripts/run-v84-clone-lifecycle-proof.mjs +18 -0
  40. package/apps/storefront/scripts/run-v84-import-through-ws2-proof.mjs +17 -0
  41. package/apps/storefront/scripts/run-v84-nonportable-route-dogfood.mjs +15 -0
  42. package/apps/storefront/scripts/sanitize-v84-proof-environment.mjs +21 -0
  43. package/apps/storefront/scripts/v84CleanCloneGraphPin.ts +42 -0
  44. package/apps/storefront/scripts/v84CleanCloneSourceGraph.ts +145 -0
  45. package/apps/storefront/scripts/validate-v84-clone-lifecycle.ts +18 -0
  46. package/apps/storefront/src/components/Img.astro +1 -1
  47. package/apps/storefront/src/components/admin/AdminBlogTab.astro +19 -16
  48. package/apps/storefront/src/components/admin/AdminIntegrationsTab.astro +105 -0
  49. package/apps/storefront/src/components/admin/AdminPublishTab.astro +1057 -412
  50. package/apps/storefront/src/components/admin/AdminSettingsTab.astro +2 -2
  51. package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +5 -5
  52. package/apps/storefront/src/components/chrome/NavDropdown.astro +12 -0
  53. package/apps/storefront/src/components/chrome/SiteFooter.astro +7 -2
  54. package/apps/storefront/src/components/chrome/SiteHeader.astro +46 -10
  55. package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +1 -1
  56. package/apps/storefront/src/components/compliance/ComplianceNotice.astro +1 -2
  57. package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +1 -2
  58. package/apps/storefront/src/components/compliance/PactActNotice.astro +1 -1
  59. package/apps/storefront/src/components/compliance/Prop65Warning.astro +1 -2
  60. package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +2 -3
  61. package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +2 -2
  62. package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +2 -3
  63. package/apps/storefront/src/components/content/TrustStrip.astro +4 -4
  64. package/apps/storefront/src/components/islands/MobileNav.tsx +26 -1
  65. package/apps/storefront/src/components/islands/VariantSelector.tsx +27 -2
  66. package/apps/storefront/src/components/islands/useCheckoutHandoffCorrelation.ts +75 -0
  67. package/apps/storefront/src/components/membership/IllustrativeLabel.astro +1 -2
  68. package/apps/storefront/src/components/membership/TierCards.astro +2 -2
  69. package/apps/storefront/src/components/membership/TierComparisonTable.astro +2 -2
  70. package/apps/storefront/src/components/subscription/SavingsExplainer.astro +2 -2
  71. package/apps/storefront/src/config/adminTenantLookup.ts +35 -0
  72. package/apps/storefront/src/config/devTenantSeed.ts +9 -9
  73. package/apps/storefront/src/config/resolver.ts +4 -4
  74. package/apps/storefront/src/layouts/Layout.astro +100 -20
  75. package/apps/storefront/src/lib/activity/candidateSubmitLease.ts +87 -0
  76. package/apps/storefront/src/lib/activity/changeActorAttribution.ts +86 -6
  77. package/apps/storefront/src/lib/activity/deployVersion.ts +1 -1
  78. package/apps/storefront/src/lib/admin/adminShell.ts +2 -0
  79. package/apps/storefront/src/lib/admin/envelope.ts +1 -2
  80. package/apps/storefront/src/lib/apps/adminService.ts +10 -0
  81. package/apps/storefront/src/lib/apps/adminSession.ts +1 -1
  82. package/apps/storefront/src/lib/apps/appVersionStore.ts +281 -0
  83. package/apps/storefront/src/lib/apps/consentConfigStore.ts +228 -0
  84. package/apps/storefront/src/lib/apps/gtmMigrationInstall.ts +447 -0
  85. package/apps/storefront/src/lib/apps/gtmMigrationReport.ts +367 -0
  86. package/apps/storefront/src/lib/apps/gtmMigrationTab.ts +315 -0
  87. package/apps/storefront/src/lib/apps/integrationLifecycle.ts +614 -0
  88. package/apps/storefront/src/lib/apps/integrationLifecycleController.ts +125 -0
  89. package/apps/storefront/src/lib/apps/integrationReadModel.ts +563 -0
  90. package/apps/storefront/src/lib/apps/integrationsTab.ts +547 -0
  91. package/apps/storefront/src/lib/apps/integrationsView.ts +106 -0
  92. package/apps/storefront/src/lib/apps/managedAnalyticsService.ts +599 -0
  93. package/apps/storefront/src/lib/apps/orders/orderConversionD1.ts +150 -0
  94. package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +8 -0
  95. package/apps/storefront/src/lib/apps/orders/ordersStore.ts +1 -1
  96. package/apps/storefront/src/lib/apps/orders/verifiedProviderMeasurement.ts +117 -0
  97. package/apps/storefront/src/lib/apps/registryService.ts +264 -10
  98. package/apps/storefront/src/lib/apps/tenantIntegrationMaterialization.ts +170 -0
  99. package/apps/storefront/src/lib/apps/v84CleanCloneReplayContext.ts +16 -0
  100. package/apps/storefront/src/lib/apps/v84CloneLifecycleCacheEvidence.ts +105 -0
  101. package/apps/storefront/src/lib/apps/v84CloneLifecycleEvidence.ts +177 -0
  102. package/apps/storefront/src/lib/apps/v84CloneLifecycleMaterialization.ts +251 -0
  103. package/apps/storefront/src/lib/apps/v84CloneLifecycleSemantics.ts +241 -0
  104. package/apps/storefront/src/lib/apps/v84CloneMigrationEvidence.ts +211 -0
  105. package/apps/storefront/src/lib/apps/v84CloneNativeInstallEvidence.ts +409 -0
  106. package/apps/storefront/src/lib/apps/v84NonportableCodeCoaching.ts +368 -0
  107. package/apps/storefront/src/lib/apps/v84NonportableRouteContract.ts +188 -0
  108. package/apps/storefront/src/lib/apps/v84NonportableRouteDogfood.ts +291 -0
  109. package/apps/storefront/src/lib/apps/ws1ManagedAnalyticsClient.ts +95 -0
  110. package/apps/storefront/src/lib/auth/adminApiGuard.ts +66 -0
  111. package/apps/storefront/src/lib/auth/adminEntry.ts +2 -2
  112. package/apps/storefront/src/lib/auth/adminLanding.ts +88 -0
  113. package/apps/storefront/src/lib/blog/collection.ts +97 -10
  114. package/apps/storefront/src/lib/blog/markdown.ts +1 -1
  115. package/apps/storefront/src/lib/blog/provider.ts +57 -3
  116. package/apps/storefront/src/lib/blog/types.ts +9 -9
  117. package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome-assignments.example.json +6 -0
  118. package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome.example.json +79 -0
  119. package/apps/storefront/src/lib/chrome/model.ts +48 -253
  120. package/apps/storefront/src/lib/chrome/navCurrent.ts +29 -0
  121. package/apps/storefront/src/lib/chrome/parseConfig.ts +18 -32
  122. package/apps/storefront/src/lib/chrome/variant.ts +39 -0
  123. package/apps/storefront/src/lib/commerce/checkoutHandoffCorrelation.ts +105 -0
  124. package/apps/storefront/src/lib/compliance/tamper-sentinel-boot.ts +152 -0
  125. package/apps/storefront/src/lib/compliance/tamper-sentinel.ts +327 -0
  126. package/apps/storefront/src/lib/content/index.ts +5 -5
  127. package/apps/storefront/src/lib/content-edit/applyDiff.ts +1 -1
  128. package/apps/storefront/src/lib/content-edit/route.ts +1 -1
  129. package/apps/storefront/src/lib/d1/catalog.ts +12 -0
  130. package/apps/storefront/src/lib/d1/schema-apps.ts +276 -0
  131. package/apps/storefront/src/lib/dev/cockpit/ask.ts +49 -0
  132. package/apps/storefront/src/lib/dev/cockpit/clickToSource.ts +71 -0
  133. package/apps/storefront/src/lib/dev/cockpit/copyCommand.ts +227 -0
  134. package/apps/storefront/src/lib/dev/cockpit/files.ts +249 -0
  135. package/apps/storefront/src/lib/dev/cockpit/hostedActivity.ts +500 -0
  136. package/apps/storefront/src/lib/dev/cockpit/infoPopover.ts +12 -0
  137. package/apps/storefront/src/lib/dev/cockpit/mcpCopy.ts +34 -0
  138. package/apps/storefront/src/lib/dev/cockpit/monitor.ts +107 -0
  139. package/apps/storefront/src/lib/dev/cockpit/stepper.ts +116 -0
  140. package/apps/storefront/src/lib/dev/cockpit/themeToggle.ts +23 -0
  141. package/apps/storefront/src/lib/dev/runtimeStore.ts +1 -1
  142. package/apps/storefront/src/lib/edgeCache.ts +18 -6
  143. package/apps/storefront/src/lib/email/candidateConflictEmail.ts +80 -0
  144. package/apps/storefront/src/lib/integration/browserEnvironment.ts +137 -0
  145. package/apps/storefront/src/lib/integration/managedInstallDeclarations.ts +72 -0
  146. package/apps/storefront/src/lib/integration/nonceStamp.ts +49 -0
  147. package/apps/storefront/src/lib/integration/tenantDeclarations.ts +116 -0
  148. package/apps/storefront/src/lib/membership/eligibility.ts +1 -1
  149. package/apps/storefront/src/lib/membership/model.ts +1 -2
  150. package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +2 -2
  151. package/apps/storefront/src/lib/newsletter/consent.ts +2 -2
  152. package/apps/storefront/src/lib/newsletter/send.ts +3 -3
  153. package/apps/storefront/src/lib/previewReload.ts +57 -1
  154. package/apps/storefront/src/lib/publish/adminPublishTab.ts +1775 -669
  155. package/apps/storefront/src/lib/publish/buildStream.ts +269 -0
  156. package/apps/storefront/src/lib/publish/collapsePersistence.ts +72 -0
  157. package/apps/storefront/src/lib/publish/lifecycleState.ts +369 -0
  158. package/apps/storefront/src/lib/publish/liveReleaseSummary.ts +29 -0
  159. package/apps/storefront/src/lib/publish/mergeDoctorOnFailure.ts +78 -0
  160. package/apps/storefront/src/lib/publish/mergeHealthBanner.ts +62 -0
  161. package/apps/storefront/src/lib/publish/mergeRowFindings.ts +124 -0
  162. package/apps/storefront/src/lib/publish/mergeSupportEscalation.ts +75 -0
  163. package/apps/storefront/src/lib/publish/publish-guard.ts +88 -0
  164. package/apps/storefront/src/lib/publish/publishFormat.ts +165 -0
  165. package/apps/storefront/src/lib/publish/publishHero.ts +177 -0
  166. package/apps/storefront/src/lib/publish/reviewRelease/changeState.ts +66 -0
  167. package/apps/storefront/src/lib/publish/reviewRelease/copy.ts +141 -0
  168. package/apps/storefront/src/lib/publish/reviewRelease/index.ts +41 -0
  169. package/apps/storefront/src/lib/publish/reviewRelease/permissions.ts +47 -0
  170. package/apps/storefront/src/lib/publish/reviewRelease/releaseState.ts +42 -0
  171. package/apps/storefront/src/lib/publish/reviewRelease/types.ts +59 -0
  172. package/apps/storefront/src/lib/publish/reviewRelease/viewModel.ts +440 -0
  173. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/actions.ts +161 -0
  174. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/controller.ts +325 -0
  175. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/render.ts +241 -0
  176. package/apps/storefront/src/lib/publish/shipWorkspace.ts +22 -3
  177. package/apps/storefront/src/lib/publish/sseRoute.ts +119 -0
  178. package/apps/storefront/src/lib/publish/streamLogConsole.ts +142 -0
  179. package/apps/storefront/src/lib/publish/versionNumber.ts +52 -0
  180. package/apps/storefront/src/lib/rawChrome.ts +125 -47
  181. package/apps/storefront/src/lib/rawMarketingHtml.ts +74 -3
  182. package/apps/storefront/src/lib/seo/alternates.ts +1 -1
  183. package/apps/storefront/src/lib/social/notify.ts +4 -4
  184. package/apps/storefront/src/lib/storyblok/content-model.ts +7 -33
  185. package/apps/storefront/src/lib/storyblok/provider.ts +168 -60
  186. package/apps/storefront/src/lib/subscription/model.ts +4 -4
  187. package/apps/storefront/src/lib/the-build/provider.ts +9 -4
  188. package/apps/storefront/src/middleware/index.ts +273 -51
  189. package/apps/storefront/src/pages/[...slug].astro +9 -4
  190. package/apps/storefront/src/pages/admin/review-release.astro +265 -0
  191. package/apps/storefront/src/pages/admin/select.astro +96 -0
  192. package/apps/storefront/src/pages/admin.astro +16 -2
  193. package/apps/storefront/src/pages/api/activity.ts +8 -8
  194. package/apps/storefront/src/pages/api/admin/activity-alerts.ts +5 -20
  195. package/apps/storefront/src/pages/api/admin/orders/[id].ts +7 -2
  196. package/apps/storefront/src/pages/api/admin/orders.ts +8 -2
  197. package/apps/storefront/src/pages/api/apps/admin/gtm-migration-install.ts +174 -0
  198. package/apps/storefront/src/pages/api/apps/admin/gtm-migration.ts +96 -0
  199. package/apps/storefront/src/pages/api/apps/admin/integration-lifecycle.ts +118 -0
  200. package/apps/storefront/src/pages/api/apps/admin/integrations.ts +89 -0
  201. package/apps/storefront/src/pages/api/apps/admin/platform-adapters.ts +85 -0
  202. package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +74 -2
  203. package/apps/storefront/src/pages/api/commerce/checkout-handoff.ts +77 -0
  204. package/apps/storefront/src/pages/api/compliance/tamper.ts +88 -0
  205. package/apps/storefront/src/pages/api/integrations/v1/[operation].ts +108 -0
  206. package/apps/storefront/src/pages/api/rum/vitals.ts +1 -2
  207. package/apps/storefront/src/pages/blog/[slug].astro +5 -5
  208. package/apps/storefront/src/pages/blog/author/[author].astro +3 -3
  209. package/apps/storefront/src/pages/blog/category/[category].astro +2 -2
  210. package/apps/storefront/src/pages/blog/index.astro +2 -2
  211. package/apps/storefront/src/pages/blog/tag/[tag].astro +2 -2
  212. package/apps/storefront/src/pages/cockpit.astro +61 -1362
  213. package/apps/storefront/src/pages/index.astro +10 -5
  214. package/apps/storefront/src/pages/llms.txt.ts +1 -1
  215. package/apps/storefront/src/pages/products/[handle].astro +7 -6
  216. package/apps/storefront/src/pages/sitemap.xml.ts +2 -2
  217. package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +31 -27
  218. package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +1 -1
  219. package/apps/storefront/src/pages/tenants/[id]/[...path].ts +38 -2
  220. package/apps/storefront/src/pages/the-build/[slug].astro +4 -4
  221. package/apps/storefront/src/pages/the-build/index.astro +2 -2
  222. package/apps/storefront/src/pages/the-build/rss.xml.ts +2 -2
  223. package/apps/storefront/src/styles/admin.css +27 -1
  224. package/apps/storefront/tsconfig.json +1 -1
  225. package/package.json +1 -1
  226. package/packages/public-runtime/package.json +2 -1
  227. package/packages/public-runtime/schemas/managed-analytics/v1/adapter-definition.schema.json +427 -0
  228. package/packages/public-runtime/schemas/managed-analytics/v1/create-integration-install-request.schema.json +161 -0
  229. package/packages/public-runtime/schemas/managed-analytics/v1/create-migration-draft-request.schema.json +157 -0
  230. package/packages/public-runtime/schemas/managed-analytics/v1/delete-integration-install-request.schema.json +84 -0
  231. package/packages/public-runtime/schemas/managed-analytics/v1/delete-migration-draft-request.schema.json +84 -0
  232. package/packages/public-runtime/schemas/managed-analytics/v1/error-envelope.schema.json +180 -0
  233. package/packages/public-runtime/schemas/managed-analytics/v1/get-adapter-definition-request.schema.json +52 -0
  234. package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-install-request.schema.json +52 -0
  235. package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-revision-request.schema.json +79 -0
  236. package/packages/public-runtime/schemas/managed-analytics/v1/get-migration-draft-request.schema.json +52 -0
  237. package/packages/public-runtime/schemas/managed-analytics/v1/integration-install.schema.json +167 -0
  238. package/packages/public-runtime/schemas/managed-analytics/v1/integration-revision.schema.json +208 -0
  239. package/packages/public-runtime/schemas/managed-analytics/v1/list-adapter-definitions-request.schema.json +53 -0
  240. package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-installs-request.schema.json +53 -0
  241. package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-revisions-request.schema.json +82 -0
  242. package/packages/public-runtime/schemas/managed-analytics/v1/migration-draft.schema.json +218 -0
  243. package/packages/public-runtime/schemas/managed-analytics/v1/mutation-request.schema.json +52 -0
  244. package/packages/public-runtime/schemas/managed-analytics/v1/mutation-success-envelope.schema.json +49 -0
  245. package/packages/public-runtime/schemas/managed-analytics/v1/read-request.schema.json +20 -0
  246. package/packages/public-runtime/schemas/managed-analytics/v1/read-success-envelope.schema.json +45 -0
  247. package/packages/public-runtime/schemas/managed-analytics/v1/revise-integration-install-request.schema.json +156 -0
  248. package/packages/public-runtime/schemas/managed-analytics/v1/set-integration-install-status-request.schema.json +92 -0
  249. package/packages/public-runtime/schemas/managed-analytics/v1/update-migration-draft-request.schema.json +184 -0
  250. package/packages/public-runtime/scripts/generate-managed-analytics-api-v1-schemas.mjs +13 -0
  251. package/packages/public-runtime/src/activity/catalog.ts +41 -37
  252. package/packages/public-runtime/src/activity/event.ts +6 -6
  253. package/packages/public-runtime/src/activity/index.ts +2 -2
  254. package/packages/public-runtime/src/activity/redaction.ts +4 -4
  255. package/packages/public-runtime/src/candidate-index.ts +42 -8
  256. package/packages/public-runtime/src/checkout-orders.ts +2 -2
  257. package/packages/public-runtime/src/checkout-style-publish.ts +2 -2
  258. package/packages/public-runtime/src/checkout-style.ts +7 -7
  259. package/packages/public-runtime/src/checkout.ts +3 -3
  260. package/packages/public-runtime/src/chrome.ts +777 -0
  261. package/packages/public-runtime/src/compliance-obligations.ts +310 -0
  262. package/packages/public-runtime/src/csp.ts +99 -0
  263. package/packages/public-runtime/src/customization-runtime.ts +32 -1
  264. package/packages/public-runtime/src/destination-webhook/contract.ts +353 -0
  265. package/packages/public-runtime/src/embed-catalog.d.mts +9 -0
  266. package/packages/public-runtime/src/embed-catalog.mjs +40 -0
  267. package/packages/public-runtime/src/evidence.ts +288 -0
  268. package/packages/public-runtime/src/gtm-migration/bounds.ts +138 -0
  269. package/packages/public-runtime/src/gtm-migration/disposition-rules.ts +361 -0
  270. package/packages/public-runtime/src/gtm-migration/dispositions.ts +181 -0
  271. package/packages/public-runtime/src/gtm-migration/draft-generator.ts +400 -0
  272. package/packages/public-runtime/src/gtm-migration/graph.ts +468 -0
  273. package/packages/public-runtime/src/gtm-migration/index.ts +95 -0
  274. package/packages/public-runtime/src/gtm-migration/parse.ts +410 -0
  275. package/packages/public-runtime/src/gtm-migration/references.ts +266 -0
  276. package/packages/public-runtime/src/gtm-migration/types.ts +86 -0
  277. package/packages/public-runtime/src/index.ts +16 -1
  278. package/packages/public-runtime/src/integration/assurance-decision.ts +259 -0
  279. package/packages/public-runtime/src/integration/assurance.ts +228 -0
  280. package/packages/public-runtime/src/integration/candidate-evidence.ts +377 -0
  281. package/packages/public-runtime/src/integration/commerce-broker.ts +497 -0
  282. package/packages/public-runtime/src/integration/consent-broker.ts +337 -0
  283. package/packages/public-runtime/src/integration/consent-cmp-demand.ts +115 -0
  284. package/packages/public-runtime/src/integration/consent-config.ts +260 -0
  285. package/packages/public-runtime/src/integration/consent-preview.ts +125 -0
  286. package/packages/public-runtime/src/integration/correlation-token.ts +444 -0
  287. package/packages/public-runtime/src/integration/csp-compiler.ts +267 -0
  288. package/packages/public-runtime/src/integration/csp.ts +105 -0
  289. package/packages/public-runtime/src/integration/digest.ts +43 -0
  290. package/packages/public-runtime/src/integration/environment.ts +228 -0
  291. package/packages/public-runtime/src/integration/events-catalog.ts +186 -0
  292. package/packages/public-runtime/src/integration/events.ts +701 -0
  293. package/packages/public-runtime/src/integration/g2-action-boundary.ts +106 -0
  294. package/packages/public-runtime/src/integration/index.ts +90 -0
  295. package/packages/public-runtime/src/integration/interim-bridge.ts +138 -0
  296. package/packages/public-runtime/src/integration/lifecycle-boot.ts +317 -0
  297. package/packages/public-runtime/src/integration/lifecycle-runtime.ts +393 -0
  298. package/packages/public-runtime/src/integration/lifecycle.ts +94 -0
  299. package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.d.mts +2 -0
  300. package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.mjs +10 -0
  301. package/packages/public-runtime/src/integration/managed-analytics-api-v1.schemas.ts +382 -0
  302. package/packages/public-runtime/src/integration/managed-analytics-api-v1.ts +684 -0
  303. package/packages/public-runtime/src/integration/managed-analytics-bridge.ts +383 -0
  304. package/packages/public-runtime/src/integration/managed-analytics-value-safety.ts +14 -0
  305. package/packages/public-runtime/src/integration/managed-analytics.ts +277 -0
  306. package/packages/public-runtime/src/integration/manifest.ts +470 -0
  307. package/packages/public-runtime/src/integration/native-amplitude.ts +362 -0
  308. package/packages/public-runtime/src/integration/native-ga4.ts +352 -0
  309. package/packages/public-runtime/src/integration/observability.ts +451 -0
  310. package/packages/public-runtime/src/integration/order-conversion.ts +0 -0
  311. package/packages/public-runtime/src/integration/phases.ts +182 -0
  312. package/packages/public-runtime/src/integration/plan.ts +112 -0
  313. package/packages/public-runtime/src/integration/platform-adapter-runtime.ts +146 -0
  314. package/packages/public-runtime/src/integration/platform-adapters.ts +671 -0
  315. package/packages/public-runtime/src/integration/promotion-gate.ts +451 -0
  316. package/packages/public-runtime/src/integration/provider-checkout-extension.ts +425 -0
  317. package/packages/public-runtime/src/integration/receipt-measurement.ts +370 -0
  318. package/packages/public-runtime/src/integration/regulated-parent-cert.ts +311 -0
  319. package/packages/public-runtime/src/integration/render-phases.ts +267 -0
  320. package/packages/public-runtime/src/integration/resolve.ts +465 -0
  321. package/packages/public-runtime/src/integration/result.ts +239 -0
  322. package/packages/public-runtime/src/integration/secrets.ts +92 -0
  323. package/packages/public-runtime/src/integration/tamper-evidence.ts +205 -0
  324. package/packages/public-runtime/src/integration/tamper-recovery.ts +127 -0
  325. package/packages/public-runtime/src/integration/version.ts +92 -0
  326. package/packages/public-runtime/src/integration-capabilities.ts +520 -0
  327. package/packages/public-runtime/src/membership.ts +2 -2
  328. package/packages/public-runtime/src/raw-html-policy.ts +2 -4
  329. package/packages/public-runtime/src/regulated-commerce/broker/consent-dedupe.ts +144 -0
  330. package/packages/public-runtime/src/regulated-commerce/correlation/contract.ts +177 -0
  331. package/packages/public-runtime/src/regulated-commerce/diagnostics/local-dispatch.ts +24 -0
  332. package/packages/public-runtime/src/regulated-commerce/diagnostics/read-model.ts +69 -0
  333. package/packages/public-runtime/src/regulated-commerce/dispatch/core.ts +134 -0
  334. package/packages/public-runtime/src/regulated-commerce/events/contract.ts +113 -0
  335. package/packages/public-runtime/src/regulated-commerce/ledger/core.ts +81 -0
  336. package/packages/public-runtime/src/regulated-commerce/mappings/ga4-ads.ts +87 -0
  337. package/packages/public-runtime/src/regulated-commerce/provider-order/bridge.ts +52 -0
  338. package/packages/public-runtime/src/regulated-commerce/purchase-truth/contract.ts +252 -0
  339. package/packages/public-runtime/src/regulated-commerce/sources/accepted-browser-operation.ts +67 -0
  340. package/packages/public-runtime/src/regulated-commerce/testing/fake-destination.ts +93 -0
  341. package/packages/public-runtime/src/static-bundle.ts +5 -5
  342. package/packages/public-runtime/src/tenant-assets.ts +143 -4
  343. package/packages/public-runtime/src/tenant.ts +45 -9
  344. package/packages/public-runtime/tests/fixtures/integration/browser-environment.example.json +8 -0
  345. package/packages/public-runtime/tests/fixtures/integration/commerce-event.example.json +44 -0
  346. package/packages/public-runtime/tests/fixtures/integration/commerce-order-event.example.json +44 -0
  347. package/packages/public-runtime/tests/fixtures/integration/compliance-assurance-record.example.json +50 -0
  348. package/packages/public-runtime/tests/fixtures/integration/integration-manifest-v2.example.json +120 -0
  349. package/packages/public-runtime/tests/fixtures/integration/managed-analytics-v1/fake-adapter-catalog.json +35 -0
  350. package/packages/public-runtime/tests/fixtures/integration/tenant-action-registry.example.json +11 -0
  351. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/README.md +22 -0
  352. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/entry.js +30 -0
  353. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/manifest.json +75 -0
  354. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/public-config.json +3 -0
  355. package/packages/public-runtime/tests/fixtures/regulated-commerce/fake-destinations.ts +38 -0
  356. package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.provenance.json +29 -0
  357. package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.redacted.json +3397 -0
  358. package/scripts/dev/file-browser.mjs +2 -2
  359. package/scripts/dev/file-writer.mjs +2 -2
  360. package/scripts/dev/integration-guardrails.mjs +498 -0
  361. package/scripts/dev/safe-path.mjs +2 -2
  362. package/scripts/dev/tenant-source-root.mjs +1 -1
  363. package/scripts/tot-dev.mjs +2 -2
@@ -57,8 +57,13 @@ if (rawHtml && rawHtmlPolicy(tenant).allowed) {
57
57
  // Shared chrome: if the tenant ships a chrome.html wrapper AND this home is a
58
58
  // body-only fragment, rawHtmlResponse splices it in; a full document serves
59
59
  // verbatim (backward-compatible).
60
- const chromeWrapper = await content.getChromeHtml();
61
- return rawHtmlResponse(rawHtml, { nonce: Astro.locals.cspNonce, basePath, chromeWrapper });
60
+ const chromeWrapper = await content.getChromeHtml("/");
61
+ return rawHtmlResponse(rawHtml, {
62
+ nonce: Astro.locals.cspNonce,
63
+ basePath,
64
+ chromeWrapper,
65
+ plan: Astro.locals.integrationPlan,
66
+ });
62
67
  }
63
68
 
64
69
  const home = await content.getHome();
@@ -143,9 +148,9 @@ for (const block of marketing ? [] : home.blocks) {
143
148
  }
144
149
  }
145
150
 
146
- // Private-app widgets (D5) — home.section slot. Commerce-home only; marketing-
151
+ // Private-app widgets — home.section slot. Commerce-home only; marketing-
147
152
  // tenant homes (raw HTML, above, and the marketing-block home) are out of
148
- // scope for D5 (deferred). No dark-mode preference infra exists yet — "light"
153
+ // scope (deferred). No dark-mode preference infra exists yet — "light"
149
154
  // is the only theme hint until that lands.
150
155
  const homeSectionWidgets = marketing
151
156
  ? []
@@ -326,7 +331,7 @@ const homeSectionWidgets = marketing
326
331
  return null;
327
332
  })
328
333
  }
329
- {/* Private-app widgets (D5, home.section) — sandboxed per install. */}
334
+ {/* Private-app widgets (home.section) — sandboxed per install. */}
330
335
  {homeSectionWidgets.map((w) => (
331
336
  <Section>
332
337
  <AppWidgetFrame
@@ -34,7 +34,7 @@ export async function GET(context: APIContext): Promise<Response> {
34
34
  content.listPages(),
35
35
  tot.getFeatured(12),
36
36
  content.getHome().catch(() => null),
37
- listBlogPosts(tenant.tenant_id),
37
+ listBlogPosts(tenant.tenant_id, content),
38
38
  ]);
39
39
  // Empty synthesized collections (no active members) never make the guide —
40
40
  // an LLM shouldn't be pointed at a URL that resolves to zero products.
@@ -60,7 +60,7 @@ if (!product || product.status === "archived") {
60
60
  }
61
61
  const isDraft = product.status !== "active";
62
62
 
63
- // Private-app widgets (D5) — product.aside slot, one iframe per live install.
63
+ // Private-app widgets — product.aside slot, one iframe per live install.
64
64
  // No dark-mode preference is resolved anywhere in the storefront yet; "light"
65
65
  // is the only theme hint until that infra exists.
66
66
  const productAsideWidgets = await renderWidgetSlot(
@@ -111,7 +111,7 @@ const mf = (ns: string, key: string) =>
111
111
  product.metafields.find((m) => m.namespace === ns && m.key === key)?.value;
112
112
 
113
113
  // Reviews — REAL aggregate from the store's reviews app, mirrored to metafields.
114
- // readReviewAggregate is the single, real-or-absent reader (§F9): it parses both
114
+ // readReviewAggregate is the single, real-or-absent reader: it parses both
115
115
  // the bare and JSON-blob rating forms and the real count key, and returns {0,0}
116
116
  // unless BOTH numbers are real positives — so no fabricated rating can render.
117
117
  const { average: reviewAvg, count: reviewCount } = readReviewAggregate(product);
@@ -181,7 +181,7 @@ const available = isAvailable(product);
181
181
  // side so the island can render a signed, tamper-proof form. In `signed` mode a
182
182
  // missing secret means we render NO cart (never a tamperable form); the
183
183
  // `unsigned-demo` mode needs no secret. Drafts still get a cart (preview links).
184
- // Membership + Autopilot mechanics (F10). Member pricing renders only once a
184
+ // Membership + Autopilot mechanics. Member pricing renders only once a
185
185
  // real eligibility signal flows through resolveMemberContext (Phase 2); Phase 1
186
186
  // is anonymous. Autopilot (subscription options) is hidden when the tenant has
187
187
  // set commerce.autopilot.enabled = false (hide-at-launch).
@@ -198,7 +198,7 @@ const pricing: {
198
198
  ? { membershipRule, stacking: membershipProgram?.stacking ?? DEFAULT_STACKING_POLICY }
199
199
  : undefined;
200
200
  const autopilotEnabled = isAutopilotEnabled(tenant.commerce?.autopilot);
201
- // Server-side pricing context (F11b). The SIGNED price is the member-adjusted
201
+ // Server-side pricing context. The SIGNED price is the member-adjusted
202
202
  // effective price for THIS request's resolved eligibility — never the list price,
203
203
  // and never re-derived client-side. Phase 1 resolves anonymous, so this yields the
204
204
  // list/subscription price; a Phase-2 member request signs their member price.
@@ -366,8 +366,9 @@ const jsonLd = [productJsonLd, breadcrumbLd(crumbs, canonicalBase)];
366
366
  productTitle={product.title}
367
367
  checkoutCart={checkoutCart}
368
368
  pricing={pricing}
369
+ handoffUrl={withBase(basePath, "/api/commerce/checkout-handoff")}
369
370
  />
370
- {/* Regulated-tenant checkout ENFORCEMENT gate (F12/T5). Intercepts the
371
+ {/* Regulated-tenant checkout ENFORCEMENT gate. Intercepts the
371
372
  managed-cart handoff to clear age + ship-to compliance server-side
372
373
  before the external checkout. Only mounts when a store is wired AND
373
374
  the tenant is regulated. */}
@@ -392,7 +393,7 @@ const jsonLd = [productJsonLd, breadcrumbLd(crumbs, canonicalBase)];
392
393
  </button>
393
394
  </div>
394
395
 
395
- {/* Private-app widgets (D5, product.aside) — sandboxed per install. */}
396
+ {/* Private-app widgets (product.aside) — sandboxed per install. */}
396
397
  {productAsideWidgets.map((w) => (
397
398
  <div class="mt-7">
398
399
  <AppWidgetFrame
@@ -67,7 +67,7 @@ export async function GET(context: APIContext): Promise<Response> {
67
67
  urls.push({ loc: `${base}/${page.slug}` });
68
68
  }
69
69
 
70
- const blogPosts = await listBlogPosts(tenant.tenant_id);
70
+ const blogPosts = await listBlogPosts(tenant.tenant_id, content);
71
71
  if (blogPosts.length > 0) {
72
72
  urls.push({ loc: `${base}/blog/` });
73
73
  for (const post of blogPosts) {
@@ -85,7 +85,7 @@ export async function GET(context: APIContext): Promise<Response> {
85
85
  }
86
86
  }
87
87
 
88
- const buildPosts = await listBuildPosts(tenant.tenant_id);
88
+ const buildPosts = await listBuildPosts(tenant.tenant_id, { content });
89
89
  if (buildPosts.length > 0) {
90
90
  urls.push({ loc: `${base}/the-build/` });
91
91
  for (const post of buildPosts) {
@@ -88,26 +88,27 @@ const cspNonce = Astro.locals.cspNonce;
88
88
 
89
89
  // --- Sample chrome data (preview-only; no live tenant content) ----------------
90
90
  const sampleNav: ChromeNavItem[] = [
91
- { label: "New", href: "#", flag: true, badge: "NEW" },
91
+ { id: "nav-new", label: "New", href: "#", flag: true, badge: "NEW" },
92
92
  {
93
+ id: "nav-shop",
93
94
  label: "Shop",
94
95
  href: "#",
95
96
  columns: [
96
- { title: "Category", links: [{ label: "Disposables", href: "#" }, { label: "E-Liquid", href: "#" }, { label: "Devices", href: "#" }] },
97
- { title: "Featured", links: [{ label: "Best Sellers", href: "#" }, { label: "On Sale", href: "#", badge: "%" }] },
98
- { title: "Brands", links: [{ label: "Northwind", href: "#" }, { label: "Summit Co.", href: "#" }] },
97
+ { title: "Category", links: [{ id: "nav-shop-disposables", label: "Disposables", href: "#" }, { id: "nav-shop-eliquid", label: "E-Liquid", href: "#" }, { id: "nav-shop-devices", label: "Devices", href: "#" }] },
98
+ { title: "Featured", links: [{ id: "nav-shop-bestsellers", label: "Best Sellers", href: "#" }, { id: "nav-shop-onsale", label: "On Sale", href: "#", badge: "%" }] },
99
+ { title: "Brands", links: [{ id: "nav-shop-northwind", label: "Northwind", href: "#" }, { id: "nav-shop-summit", label: "Summit Co.", href: "#" }] },
99
100
  ],
100
101
  },
101
- { label: "Coils & Parts", href: "#", children: [{ label: "Coils", href: "#" }, { label: "Pods", href: "#" }, { label: "Batteries", href: "#" }] },
102
- { label: "On Sale", href: "#" },
102
+ { id: "nav-coils", label: "Coils & Parts", href: "#", children: [{ id: "nav-coils-coils", label: "Coils", href: "#" }, { id: "nav-coils-pods", label: "Pods", href: "#" }, { id: "nav-coils-batteries", label: "Batteries", href: "#" }] },
103
+ { id: "nav-sale", label: "On Sale", href: "#" },
103
104
  ];
104
105
  const sampleSocial = [
105
106
  { label: "X", href: "#", iconPath: "M18.9 2H22l-7.1 8.1L23 22h-6.6l-5-6.6L5.7 22H2.6l7.6-8.7L1.5 2h6.8l4.5 6 5.1-6z" },
106
107
  ];
107
108
  const sampleFooterCols = [
108
- { title: "Shop", links: [{ label: "Disposables", href: "#" }, { label: "E-Liquid", href: "#" }, { label: "Devices", href: "#" }] },
109
- { title: "Support", links: [{ label: "Contact", href: "#" }, { label: "Shipping", href: "#" }, { label: "Returns", href: "#" }] },
110
- { title: "Company", links: [{ label: "About", href: "#" }, { label: "Blog", href: "#" }] },
109
+ { title: "Shop", links: [{ id: "ftr-shop-disposables", label: "Disposables", href: "#" }, { id: "ftr-shop-eliquid", label: "E-Liquid", href: "#" }, { id: "ftr-shop-devices", label: "Devices", href: "#" }] },
110
+ { title: "Support", links: [{ id: "ftr-support-contact", label: "Contact", href: "#" }, { id: "ftr-support-shipping", label: "Shipping", href: "#" }, { id: "ftr-support-returns", label: "Returns", href: "#" }] },
111
+ { title: "Company", links: [{ id: "ftr-company-about", label: "About", href: "#" }, { id: "ftr-company-blog", label: "Blog", href: "#" }] },
111
112
  ];
112
113
  // BrandGrid samples: text-wordmark tiles and logo-image tiles (Img renders
113
114
  // deterministic placeholders offline so the image code path is exercised
@@ -125,7 +126,7 @@ const sampleBrandsLogo: Brand[] = [
125
126
  { label: "Pod King", href: "#", logoSrc: "#", logoWidth: 200, logoHeight: 100 },
126
127
  { label: "Flavor Beast", href: "#", logoSrc: "#", logoWidth: 200, logoHeight: 100 },
127
128
  ];
128
- // Review/UGC samples (P3 reviews-ugc-widgets): illustrative fixture reviews
129
+ // Review/UGC samples: illustrative fixture reviews
129
130
  // ONLY, for previewing ReviewSummary/ReviewList token styling in isolation —
130
131
  // never sourced from or rendered on a live product page (see
131
132
  // docs/architecture/review-markup-policy.md; real callers pass tot.getReviews()
@@ -135,7 +136,7 @@ const sampleReviews: Review[] = [
135
136
  { author: "Priya K.", rating: 4, body: "Good overall, battery life could be a bit longer.", date: "2026-05-18", verifiedBuyer: true },
136
137
  { author: "T. Nguyen", rating: 3, title: "Decent, not amazing", body: "Does the job but nothing stands out versus similar devices.", date: "2026-04-30" },
137
138
  ];
138
- // Blog/article samples (W4): featured-image cards (Img renders deterministic
139
+ // Blog/article samples: featured-image cards (Img renders deterministic
139
140
  // placeholders offline so the image path is exercised) + one image-less card
140
141
  // (token-tinted placeholder band). Meta is illustrative example copy only.
141
142
  const sampleArticles: Article[] = [
@@ -236,7 +237,7 @@ const sampleComparisonRows: ComparisonRow[] = [
236
237
  { label: "Cancel anytime", cells: [null, true, true] },
237
238
  ];
238
239
 
239
- // --- Sample structured content (F4) — the DATA a policy page is driven by,
240
+ // --- Sample structured content — the DATA a policy page is driven by,
240
241
  // replacing a hand-authored HTML/CSS fragment. Exercises headings (TOC),
241
242
  // rich-text links, lists, a definition glossary, tone callouts, a contact
242
243
  // block, and a needs-review flag (reviewer-only). ---------------------------
@@ -293,13 +294,13 @@ const sampleProseSections: ProseSection[] = [
293
294
  },
294
295
  ];
295
296
 
296
- // Trust strip (F4, f09-guarded): mixes real claims + a real rating with
297
+ // Trust strip: mixes real claims + a real rating with
297
298
  // fabrication vectors that MUST be dropped — the guide proves real-or-absent.
298
299
  const sampleTrustStrip: TrustStripItem[] = [
299
300
  { kind: "claim", label: "Ships from USA" },
300
301
  { kind: "claim", label: "Lab-tested" },
301
302
  { kind: "rating", average: 4.9, count: 369, label: "avg rating" },
302
- { kind: "claim", label: "Based on 369 reviews" }, // fabricated → dropped by f09
303
+ { kind: "claim", label: "Based on 369 reviews" }, // fabricated → dropped
303
304
  { kind: "rating", average: 5, count: 0 }, // half-populated → dropped
304
305
  ];
305
306
 
@@ -469,8 +470,8 @@ const t = Object.entries(themeModules)
469
470
 
470
471
  if (!t) return new Response(null, { status: 404 });
471
472
 
472
- // Has this tenant adopted the canonical shared chrome (unit F3)? If so it no
473
- // longer ships its own mkt.css (retired at integration, I1/I2/I3) — link the
473
+ // Has this tenant adopted the canonical shared chrome? If so it no
474
+ // longer ships its own mkt.css (retired at integration) — link the
474
475
  // platform /shared/commerce-chrome.css instead so the marketing-component
475
476
  // samples below still render in-brand.
476
477
  const chromeModules = import.meta.glob<Record<string, any>>(
@@ -479,7 +480,10 @@ const chromeModules = import.meta.glob<Record<string, any>>(
479
480
  );
480
481
  const chromeSeg = `/tenants/${tenant}/content/chrome.json`;
481
482
  const chromeConfig = Object.entries(chromeModules).find(([path]) => path.includes(chromeSeg))?.[1];
482
- const usesSharedChrome = chromeConfig?.sharedChrome === true;
483
+ // Adoption is now "does chrome.json carry the consolidated header/footer
484
+ // shape" (lib/chrome/model.ts ChromeConfig) — the old `sharedChrome: true`
485
+ // opt-in flag is retired; a successfully-shaped config IS the adopted signal.
486
+ const usesSharedChrome = !!chromeConfig?.header && !!chromeConfig?.footer;
483
487
 
484
488
  const tk = t.tokens ?? {};
485
489
  const storyboard = t.storyboard ?? null;
@@ -492,7 +496,7 @@ const REFERENCE_COMPONENT_VARS: Record<string, string> = {
492
496
  "--color-muted": "#5c6663", "--color-primary": "#1f3a34", "--color-primary-contrast": "#f4f1ea",
493
497
  "--color-accent": "#b5612f", "--color-border": "#dcd6c9", "--color-success": "#3f6b4f",
494
498
  "--color-sale": "#9e3b2e",
495
- // F1 semantic + F6 quality-bar interaction tokens — reference (Northwind)
499
+ // Semantic + quality-bar interaction tokens — reference (Northwind)
496
500
  // values so the text/icon-token samples render concretely and re-skin when a
497
501
  // descriptor overrides them via preview.componentVars.
498
502
  "--color-warning": "#8a5717", "--color-error": "#a22014", "--color-info": "#2c5b73",
@@ -610,7 +614,7 @@ const componentVarsInline = Object.entries(componentVars)
610
614
  .sg-commerce .sg-h { color: var(--color-primary); }
611
615
  .sg-commerce .sg-block { border-top-color: var(--color-border); }
612
616
 
613
- /* Semantic text & icon token samples (v1.1 · unit F6). Each swatch reads
617
+ /* Semantic text & icon token samples (v1.1). Each swatch reads
614
618
  ONE contract token so the guide proves text/icon roles resolve + re-skin
615
619
  from tokens alone — never a hard-coded color. */
616
620
  .sg-tok-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
@@ -952,7 +956,7 @@ const componentVarsInline = Object.entries(componentVars)
952
956
  </div>
953
957
  </section>
954
958
 
955
- {/* ── Semantic text & icon tokens (v1.1 · unit F6) ────────────────────
959
+ {/* ── Semantic text & icon tokens (v1.1) ──────────────────────────────
956
960
  The quality-bar coverage sample: every text role, icon tint, and
957
961
  interaction state renders from a NAMED contract token — nothing here
958
962
  hard-codes a color or borrows `accent`. Swap the theme (or a
@@ -1138,7 +1142,7 @@ const componentVarsInline = Object.entries(componentVars)
1138
1142
  <section class="sg-block">
1139
1143
  <p class="sg-h">Chrome — UtilityNav</p>
1140
1144
  <UtilityNav
1141
- links={[{ label: "News", href: "#" }, { label: "About", href: "#" }, { label: "Contact", href: "#" }]}
1145
+ links={[{ id: "util-news", label: "News", href: "#" }, { id: "util-about", label: "About", href: "#" }, { id: "util-contact", label: "Contact", href: "#" }]}
1142
1146
  locale="English"
1143
1147
  currency="United States (USD $)"
1144
1148
  social={sampleSocial}
@@ -1283,8 +1287,8 @@ const componentVarsInline = Object.entries(componentVars)
1283
1287
  — no pricing/checkout/subscription mechanics. Figures are ILLUSTRATIVE
1284
1288
  by default: unless a tier asserts real:true the widget renders a
1285
1289
  first-class "Illustrative figures" affordance (badge + "e.g." + note)
1286
- so an example number is never shown as a live offer (decision
1287
- compliance-widgets-platform-owned). Fed sample tiers here; a tenant
1290
+ so an example number is never shown as a live offer. Fed sample
1291
+ tiers here; a tenant
1288
1292
  supplies its own on a membership page. */}
1289
1293
  <section class="sg-block">
1290
1294
  <p class="sg-h">Membership tiers — <code>components/membership/</code></p>
@@ -1307,13 +1311,13 @@ const componentVarsInline = Object.entries(componentVars)
1307
1311
  />
1308
1312
  </section>
1309
1313
 
1310
- {/* ── Structured content widgets (components/content/, spec §F4) ───────
1314
+ {/* ── Structured content widgets (components/content/) ───────
1311
1315
  The DATA-driven promotion of repeated raw-page patterns. A tenant
1312
1316
  authors a policy/about/compliance page as structured `sections`
1313
1317
  (JSON) instead of copying an HTML/CSS fragment; these components
1314
1318
  render it with the a11y (headings, <dl>, <address>, roles, tap
1315
- targets) baked in and every color from f06 tokens. The trust strip is
1316
- f09-guarded — real-or-absent, fabricated proof dropped. */}
1319
+ targets) baked in and every color from tokens. The trust strip is
1320
+ guarded — real-or-absent, fabricated proof dropped. */}
1317
1321
  <section class="sg-block">
1318
1322
  <p class="sg-h">Structured content — <code>components/content/</code></p>
1319
1323
  <p class="lede" style="font-size:.95rem;color:var(--color-muted)">Data-driven framework widgets (F4): a policy page rendered from structured <code>sections</code> with no HTML/CSS to copy. Accessibility lives in the components; tenant content is pure data.</p>
@@ -1374,7 +1378,7 @@ const componentVarsInline = Object.entries(componentVars)
1374
1378
  {/* ── Interactive islands (components/islands/) ─────────────────────
1375
1379
  Client-hydrated Preact islands. Each is tenant-agnostic and reads
1376
1380
  only fixture/localStorage data here — no live catalog, cart, or ToT
1377
- calls (unit style-guide-full-coverage). */}
1381
+ calls. */}
1378
1382
  <section class="sg-block">
1379
1383
  <p class="sg-h">Islands — <code>components/islands/</code></p>
1380
1384
  <p class="lede" style="font-size:.95rem;color:var(--color-muted)">Client-hydrated Preact islands exercised with fixture data — no live catalog, cart, or ToT calls.</p>
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  /**
3
3
  * Preview/dev-only SHARED RAW-CHROME STYLE GUIDE —
4
- * `/_style-guide/<tenant>/chrome/<theme-id>/` (unit F4).
4
+ * `/_style-guide/<tenant>/chrome/<theme-id>/`.
5
5
  *
6
6
  * Renders the platform-shipped raw chrome set — the `/shared/commerce-chrome.css`
7
7
  * class vocabulary (announcement + utility bar, header + search + actions, primary
@@ -2,7 +2,7 @@
2
2
  * GET /tenants/<id>/<path> — serve a tenant's versioned static asset from R2.
3
3
  *
4
4
  * The version-scoped replacement for the build-time `copy-tenant-assets.mjs`
5
- * baking (decision `assets-r2-versioned`). Resolves the tenant's active
5
+ * baking. Resolves the tenant's active
6
6
  * channel→snapshot versionId from the `cust:assets-pointer:<id>` KV record and
7
7
  * streams `tenants/<id>/<versionId>/<rel>` from the TENANT_ASSETS R2 bucket with
8
8
  * the right content-type + a revalidating cache header + a versionId ETag.
@@ -17,12 +17,36 @@
17
17
  import type { APIContext } from "astro";
18
18
  import {
19
19
  serveTenantAsset,
20
+ verifyPreviewToken,
20
21
  type R2BucketLike,
21
22
  } from "@tot/public-runtime";
22
- import { readR2, readKv } from "@/lib/env";
23
+ import { readR2, readKv, readEnv } from "@/lib/env";
23
24
 
24
25
  export const prerender = false;
25
26
 
27
+ /** A versionId is a content sha — restrict to a safe R2 key segment (no traversal). */
28
+ const SAFE_VERSION_ID = /^[A-Za-z0-9._-]{1,128}$/;
29
+
30
+ /**
31
+ * Resolve a CANDIDATE-preview version override for this asset request, or null.
32
+ * A candidate/revision page sets `tot_preview_version` (its versionId) + the
33
+ * `tot_preview` capability token; when the token verifies for THIS tenant, we serve
34
+ * that exact snapshot (`tenants/<id>/<versionId>/…`) instead of the channel pointer,
35
+ * so a candidate's NEW assets — unreachable via the never-flipped channel — resolve.
36
+ * Token-gated + tenant-matched so it can never serve another tenant's snapshot.
37
+ */
38
+ async function resolvePreviewVersion(context: APIContext, urlTenant: string): Promise<string | null> {
39
+ const versionId = context.cookies.get("tot_preview_version")?.value ?? null;
40
+ const token = context.cookies.get("tot_preview")?.value ?? null;
41
+ if (!versionId || !token || !urlTenant) return null;
42
+ if (!SAFE_VERSION_ID.test(versionId) || versionId.includes("..")) return null;
43
+ const secret = (await readEnv("CUSTOMIZATION_PREVIEW_SECRET")) ?? null;
44
+ if (!secret) return null;
45
+ const verified = await verifyPreviewToken(secret, token, Math.floor(Date.now() / 1000));
46
+ if (!verified.ok || verified.claims.tenantId !== urlTenant) return null;
47
+ return versionId;
48
+ }
49
+
26
50
  export async function GET(context: APIContext): Promise<Response> {
27
51
  const [bucket, kv] = await Promise.all([
28
52
  readR2("TENANT_ASSETS"),
@@ -36,17 +60,29 @@ export async function GET(context: APIContext): Promise<Response> {
36
60
  });
37
61
  }
38
62
 
63
+ const previewVersionId = await resolvePreviewVersion(context, context.params.id ?? "");
64
+
39
65
  const res = await serveTenantAsset(
40
66
  {
41
67
  // Runtime binding structurally satisfies the shared-runtime R2 seam.
42
68
  bucket: bucket as unknown as R2BucketLike,
43
69
  kvGet: (key) => kv.get(key),
44
70
  channel: context.locals.customizationEnv ?? "live",
71
+ ...(previewVersionId ? { versionId: previewVersionId } : {}),
45
72
  ifNoneMatch: context.request.headers.get("if-none-match"),
46
73
  },
47
74
  new URL(context.request.url).pathname,
48
75
  );
49
76
 
77
+ // A candidate-preview asset must NEVER be edge/CDN-cached under its tokenless URL
78
+ // (that would poison the public asset with candidate bytes, and Vary doesn't cover
79
+ // the auth cookie). Force no-store for the preview-version path; the normal
80
+ // channel-served asset keeps its revalidating cache header.
81
+ if (res && previewVersionId) {
82
+ res.headers.set("cache-control", "no-store");
83
+ res.headers.set("x-robots-tag", "noindex, nofollow");
84
+ }
85
+
50
86
  return (
51
87
  res ??
52
88
  new Response("Not found", {
@@ -11,11 +11,11 @@ import { getTranslations } from "@/lib/blog/collection.js";
11
11
  import { buildAlternates } from "@/lib/seo/alternates.js";
12
12
  import { breadcrumbLd } from "@/lib/jsonld.js";
13
13
 
14
- const { tenant, canonicalBase, basePath } = Astro.locals;
14
+ const { tenant, canonicalBase, basePath, content } = Astro.locals;
15
15
  const slug = Astro.params.slug ?? "";
16
- const post = await getBuildPost(tenant.tenant_id, slug);
16
+ const post = await getBuildPost(tenant.tenant_id, slug, { content });
17
17
  if (!post) {
18
- const redirect = await resolveBuildRedirect(tenant.tenant_id, slug);
18
+ const redirect = await resolveBuildRedirect(tenant.tenant_id, slug, content);
19
19
  if (redirect) return Astro.redirect(`${basePath}/the-build/${redirect}/`, 301);
20
20
  return new Response(null, { status: 404 });
21
21
  }
@@ -45,7 +45,7 @@ const buildHref = `${basePath}/the-build/`;
45
45
  // the live-visible variant set (self + siblings); `buildAlternates` yields [] for
46
46
  // a singleton, so a non-translated post gets no alternates and no `lang` override
47
47
  // (byte-identical to today).
48
- const translations = await getTranslations(tenant.tenant_id, THE_BUILD.id, post.slug);
48
+ const translations = await getTranslations(tenant.tenant_id, THE_BUILD.id, post.slug, { content });
49
49
  const alternates = buildAlternates(translations, (s) =>
50
50
  new URL(`/the-build/${s}/`, canonicalBase + "/").toString(),
51
51
  );
@@ -8,8 +8,8 @@ import Layout from "@/layouts/Layout.astro";
8
8
  import PostAccessBadge from "@/components/blog/PostAccessBadge.astro";
9
9
  import { listBuildPosts } from "@/lib/the-build/provider.js";
10
10
 
11
- const { tenant, basePath, canonicalBase } = Astro.locals;
12
- const posts = await listBuildPosts(tenant.tenant_id);
11
+ const { tenant, basePath, canonicalBase, content } = Astro.locals;
12
+ const posts = await listBuildPosts(tenant.tenant_id, { content });
13
13
  if (posts.length === 0) return new Response(null, { status: 404 });
14
14
 
15
15
  const href = (path: string) => `${basePath}${path}` || "/";
@@ -11,8 +11,8 @@ import { listBuildPosts, THE_BUILD } from "@/lib/the-build/provider.js";
11
11
  import { renderRssFeed } from "@/lib/blog/rss.js";
12
12
 
13
13
  export async function GET(context: APIContext): Promise<Response> {
14
- const { tenant, canonicalBase } = context.locals;
15
- const posts = await listBuildPosts(tenant.tenant_id);
14
+ const { tenant, canonicalBase, content } = context.locals;
15
+ const posts = await listBuildPosts(tenant.tenant_id, { content });
16
16
  if (posts.length === 0) return new Response(null, { status: 404 });
17
17
 
18
18
  const body = renderRssFeed({
@@ -518,6 +518,7 @@ html.admin-tabs-ready[data-admin-mode="work-area"][data-admin-tab="reporting"] #
518
518
  html.admin-tabs-ready[data-admin-mode="work-area"][data-admin-tab="ai-workflows"] #ai-workflows,
519
519
  html.admin-tabs-ready[data-admin-mode="work-area"][data-admin-tab="blog"] #blog,
520
520
  html.admin-tabs-ready[data-admin-mode="work-area"][data-admin-tab="publish"] #publish,
521
+ html.admin-tabs-ready[data-admin-mode="work-area"][data-admin-tab="integrations"] #integrations,
521
522
  html.admin-tabs-ready[data-admin-mode="work-area"][data-admin-tab="settings"] #settings {
522
523
  display: grid;
523
524
  }
@@ -642,6 +643,14 @@ html[data-internal-admin-guide="false"] [data-admin-internal-only] {
642
643
  white-space: nowrap;
643
644
  }
644
645
 
646
+ /* The leading state glyph (✓ / ⚠ / ✕ / ●) on a status chip — decorative, so
647
+ status reads as icon + text and never relies on the tone colour alone. The
648
+ chip's own inline-flex `gap` spaces it from the word. */
649
+ .chip-glyph {
650
+ font-weight: 800;
651
+ line-height: 1;
652
+ }
653
+
645
654
  .chip.green {
646
655
  background: var(--admin-green-soft);
647
656
  color: var(--admin-green);
@@ -921,6 +930,12 @@ tr:last-child td {
921
930
  border-bottom: 1px solid var(--admin-line);
922
931
  }
923
932
 
933
+ /* Author-provided display wins over the user-agent [hidden] rule unless we
934
+ restate it. A green release must never show the failed-build retry action. */
935
+ .check-row[hidden] {
936
+ display: none;
937
+ }
938
+
924
939
  .check-row:last-child {
925
940
  border-bottom: 0;
926
941
  }
@@ -1015,9 +1030,14 @@ tr:last-child td {
1015
1030
 
1016
1031
  .sidebar {
1017
1032
  position: static;
1033
+ box-sizing: border-box;
1034
+ width: 100%;
1035
+ max-width: 100vw;
1018
1036
  height: auto;
1019
- overflow: visible;
1037
+ overflow-x: hidden;
1038
+ overflow-y: visible;
1020
1039
  flex-direction: row;
1040
+ flex-wrap: wrap;
1021
1041
  align-items: center;
1022
1042
  }
1023
1043
 
@@ -1029,12 +1049,18 @@ tr:last-child td {
1029
1049
  position: sticky;
1030
1050
  top: 0;
1031
1051
  z-index: 29;
1052
+ box-sizing: border-box;
1053
+ width: 100%;
1032
1054
  display: flex;
1033
1055
  padding-inline: 16px;
1034
1056
  background: rgba(245, 247, 246, 0.94);
1035
1057
  backdrop-filter: blur(16px);
1036
1058
  }
1037
1059
 
1060
+ .integrations-tab {
1061
+ overflow-x: hidden;
1062
+ }
1063
+
1038
1064
  .topbar,
1039
1065
  .ship-gate,
1040
1066
  .risk-alert,
@@ -16,6 +16,6 @@
16
16
  "@/*": ["src/*"]
17
17
  }
18
18
  },
19
- "include": [".astro/types.d.ts", "src/**/*", "perf/**/*.ts", "*.config.mjs", "env.d.ts"],
19
+ "include": [".astro/types.d.ts", "src/**/*", "scripts/**/*.ts", "perf/**/*.ts", "*.config.mjs", "env.d.ts"],
20
20
  "exclude": ["dist", "node_modules"]
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "1.4.2-rc.0",
3
+ "version": "2.0.0",
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",
@@ -14,7 +14,8 @@
14
14
  "typecheck": "tsc --noEmit",
15
15
  "build": "tsc",
16
16
  "test": "vitest run",
17
- "test:watch": "vitest"
17
+ "test:watch": "vitest",
18
+ "generate:managed-analytics-schemas": "node --experimental-strip-types scripts/generate-managed-analytics-api-v1-schemas.mjs"
18
19
  },
19
20
  "devDependencies": {
20
21
  "typescript": "^5.6.3",