@tokenoftrust/storefront-runner 1.4.1 → 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 (474) hide show
  1. package/apps/storefront/astro.config.mjs +17 -1
  2. package/apps/storefront/env.d.ts +54 -5
  3. package/apps/storefront/integrations/materialize-guard.mjs +54 -0
  4. package/apps/storefront/migrations-apps/0002_good_switch.sql +26 -0
  5. package/apps/storefront/migrations-apps/0003_mute_marauders.sql +12 -0
  6. package/apps/storefront/migrations-apps/0004_deep_morph.sql +36 -0
  7. package/apps/storefront/migrations-apps/0005_common_mystique.sql +23 -0
  8. package/apps/storefront/migrations-apps/0006_broad_microchip.sql +16 -0
  9. package/apps/storefront/migrations-apps/0007_brave_outlaw_kid.sql +15 -0
  10. package/apps/storefront/migrations-apps/0008_blue_dazzler.sql +11 -0
  11. package/apps/storefront/migrations-apps/0009_bored_shinobi_shaw.sql +15 -0
  12. package/apps/storefront/migrations-apps/0010_ws4_verified_provider_measurement.sql +35 -0
  13. package/apps/storefront/migrations-apps/meta/0002_snapshot.json +1160 -0
  14. package/apps/storefront/migrations-apps/meta/0003_snapshot.json +1235 -0
  15. package/apps/storefront/migrations-apps/meta/0004_snapshot.json +1474 -0
  16. package/apps/storefront/migrations-apps/meta/0005_snapshot.json +1617 -0
  17. package/apps/storefront/migrations-apps/meta/0006_snapshot.json +1716 -0
  18. package/apps/storefront/migrations-apps/meta/0007_snapshot.json +1812 -0
  19. package/apps/storefront/migrations-apps/meta/0008_snapshot.json +1881 -0
  20. package/apps/storefront/migrations-apps/meta/0009_snapshot.json +1979 -0
  21. package/apps/storefront/migrations-apps/meta/_journal.json +56 -0
  22. package/apps/storefront/public/apps/tot.demo.analytics/0.1.0/entry.js +42 -0
  23. package/apps/storefront/public/js/dashboard-team.js +38 -2
  24. package/apps/storefront/public/platform/amplitude-http/v1/entry.mjs +19 -0
  25. package/apps/storefront/public/platform/google-measurement/v1/entry.mjs +19 -0
  26. package/apps/storefront/public/shared/commerce-chrome.css +20 -2
  27. package/apps/storefront/scripts/build-v84-clean-clone-standalone.mjs +68 -0
  28. package/apps/storefront/scripts/deny-v84-clean-clone-standalone-capabilities.mjs +111 -0
  29. package/apps/storefront/scripts/deny-v84-dogfood-capabilities.mjs +2 -0
  30. package/apps/storefront/scripts/deny-v84-lifecycle-capabilities.mjs +247 -0
  31. package/apps/storefront/scripts/dogfood-v84-nonportable-routes.ts +73 -0
  32. package/apps/storefront/scripts/fixed-v84-native-install-producer.ts +79 -0
  33. package/apps/storefront/scripts/generated/v84-clean-clone-replay.bundle.mjs +10982 -0
  34. package/apps/storefront/scripts/import-v84-through-ws2.ts +38 -0
  35. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling-dependency.ts +2 -0
  36. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling.ts +4 -0
  37. package/apps/storefront/scripts/install-v84-native-through-ws1.ts +185 -0
  38. package/apps/storefront/scripts/prove-clone-isolation.ts +506 -0
  39. package/apps/storefront/scripts/replay-v84-clean-clone-pass.ts +148 -0
  40. package/apps/storefront/scripts/replay-v84-clean-clone-standalone.ts +35 -0
  41. package/apps/storefront/scripts/replay-v84-clean-clone.ts +214 -0
  42. package/apps/storefront/scripts/run-fixed-v84-native-install-producer.mjs +18 -0
  43. package/apps/storefront/scripts/run-v84-clone-isolation-proof.mjs +18 -0
  44. package/apps/storefront/scripts/run-v84-clone-lifecycle-proof.mjs +18 -0
  45. package/apps/storefront/scripts/run-v84-import-through-ws2-proof.mjs +17 -0
  46. package/apps/storefront/scripts/run-v84-nonportable-route-dogfood.mjs +15 -0
  47. package/apps/storefront/scripts/sanitize-v84-proof-environment.mjs +21 -0
  48. package/apps/storefront/scripts/v84CleanCloneGraphPin.ts +42 -0
  49. package/apps/storefront/scripts/v84CleanCloneSourceGraph.ts +145 -0
  50. package/apps/storefront/scripts/validate-v84-clone-lifecycle.ts +18 -0
  51. package/apps/storefront/src/components/Img.astro +1 -1
  52. package/apps/storefront/src/components/Seo.astro +65 -1
  53. package/apps/storefront/src/components/admin/AdminBlogDetailRail.astro +878 -0
  54. package/apps/storefront/src/components/admin/AdminBlogTab.astro +1435 -0
  55. package/apps/storefront/src/components/admin/AdminCustomersTab.astro +3 -7
  56. package/apps/storefront/src/components/admin/AdminIntegrationsTab.astro +105 -0
  57. package/apps/storefront/src/components/admin/AdminPublishTab.astro +1980 -2564
  58. package/apps/storefront/src/components/admin/AdminSettingsTab.astro +2 -2
  59. package/apps/storefront/src/components/admin/AdminSubscriptionsTab.astro +1 -3
  60. package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +5 -5
  61. package/apps/storefront/src/components/blog/BlogPaywall.astro +87 -0
  62. package/apps/storefront/src/components/blog/PostAccessBadge.astro +43 -0
  63. package/apps/storefront/src/components/blog/PostGrid.astro +57 -0
  64. package/apps/storefront/src/components/blog/ReactionBar.astro +214 -0
  65. package/apps/storefront/src/components/chrome/NavDropdown.astro +12 -0
  66. package/apps/storefront/src/components/chrome/SiteFooter.astro +7 -2
  67. package/apps/storefront/src/components/chrome/SiteHeader.astro +46 -10
  68. package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +1 -1
  69. package/apps/storefront/src/components/compliance/ComplianceNotice.astro +1 -2
  70. package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +1 -2
  71. package/apps/storefront/src/components/compliance/PactActNotice.astro +1 -1
  72. package/apps/storefront/src/components/compliance/Prop65Warning.astro +1 -2
  73. package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +2 -3
  74. package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +2 -2
  75. package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +2 -3
  76. package/apps/storefront/src/components/content/TrustStrip.astro +4 -4
  77. package/apps/storefront/src/components/islands/MobileNav.tsx +26 -1
  78. package/apps/storefront/src/components/islands/VariantSelector.tsx +27 -2
  79. package/apps/storefront/src/components/islands/useCheckoutHandoffCorrelation.ts +75 -0
  80. package/apps/storefront/src/components/membership/IllustrativeLabel.astro +1 -2
  81. package/apps/storefront/src/components/membership/TierCards.astro +2 -2
  82. package/apps/storefront/src/components/membership/TierComparisonTable.astro +2 -2
  83. package/apps/storefront/src/components/subscription/SavingsExplainer.astro +2 -2
  84. package/apps/storefront/src/config/adminTenantLookup.ts +35 -0
  85. package/apps/storefront/src/config/devTenantSeed.ts +9 -9
  86. package/apps/storefront/src/config/resolver.ts +4 -4
  87. package/apps/storefront/src/layouts/Layout.astro +146 -21
  88. package/apps/storefront/src/lib/activity/alerts.ts +17 -19
  89. package/apps/storefront/src/lib/activity/candidateSubmitLease.ts +87 -0
  90. package/apps/storefront/src/lib/activity/changeActorAttribution.ts +89 -9
  91. package/apps/storefront/src/lib/activity/deployVersion.ts +20 -27
  92. package/apps/storefront/src/lib/activity/ingest.ts +8 -8
  93. package/apps/storefront/src/lib/activity/ingestAuth.ts +1 -1
  94. package/apps/storefront/src/lib/activity/killSwitch.ts +6 -6
  95. package/apps/storefront/src/lib/activity/query.ts +9 -9
  96. package/apps/storefront/src/lib/activity/recordActivity.ts +11 -15
  97. package/apps/storefront/src/lib/activity/store.ts +4 -6
  98. package/apps/storefront/src/lib/activity/uiActor.ts +12 -12
  99. package/apps/storefront/src/lib/activity/workerCommit.ts +6 -6
  100. package/apps/storefront/src/lib/admin/adminShell.ts +292 -0
  101. package/apps/storefront/src/lib/admin/ai/approvalMode.ts +2 -3
  102. package/apps/storefront/src/lib/admin/ai/audit.ts +3 -5
  103. package/apps/storefront/src/lib/admin/checkoutStyleInput.ts +7 -7
  104. package/apps/storefront/src/lib/admin/checkoutStyleTarget.ts +3 -3
  105. package/apps/storefront/src/lib/admin/envelope.ts +1 -2
  106. package/apps/storefront/src/lib/admin/orderClient.ts +3 -5
  107. package/apps/storefront/src/lib/admin/services/orders.ts +17 -19
  108. package/apps/storefront/src/lib/admin/viewmodels/aiWorkflows.ts +4 -6
  109. package/apps/storefront/src/lib/admin/viewmodels/settings.ts +1 -1
  110. package/apps/storefront/src/lib/apps/adminService.ts +14 -4
  111. package/apps/storefront/src/lib/apps/adminSession.ts +54 -45
  112. package/apps/storefront/src/lib/apps/apiAuth.ts +2 -2
  113. package/apps/storefront/src/lib/apps/apiRoute.ts +2 -2
  114. package/apps/storefront/src/lib/apps/appVersionStore.ts +281 -0
  115. package/apps/storefront/src/lib/apps/catalogMapper.ts +1 -1
  116. package/apps/storefront/src/lib/apps/consentConfigStore.ts +228 -0
  117. package/apps/storefront/src/lib/apps/credentials.ts +2 -2
  118. package/apps/storefront/src/lib/apps/gatewayKeys.ts +4 -4
  119. package/apps/storefront/src/lib/apps/gtmMigrationInstall.ts +447 -0
  120. package/apps/storefront/src/lib/apps/gtmMigrationReport.ts +367 -0
  121. package/apps/storefront/src/lib/apps/gtmMigrationTab.ts +315 -0
  122. package/apps/storefront/src/lib/apps/healthAggregate.ts +5 -5
  123. package/apps/storefront/src/lib/apps/integrationLifecycle.ts +614 -0
  124. package/apps/storefront/src/lib/apps/integrationLifecycleController.ts +125 -0
  125. package/apps/storefront/src/lib/apps/integrationReadModel.ts +563 -0
  126. package/apps/storefront/src/lib/apps/integrationsTab.ts +547 -0
  127. package/apps/storefront/src/lib/apps/integrationsView.ts +106 -0
  128. package/apps/storefront/src/lib/apps/managedAnalyticsService.ts +599 -0
  129. package/apps/storefront/src/lib/apps/orders/attributionService.ts +2 -2
  130. package/apps/storefront/src/lib/apps/orders/customerHash.ts +1 -1
  131. package/apps/storefront/src/lib/apps/orders/foxyOrderClient.ts +12 -12
  132. package/apps/storefront/src/lib/apps/orders/idempotency.ts +7 -7
  133. package/apps/storefront/src/lib/apps/orders/orderConversionD1.ts +150 -0
  134. package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +9 -1
  135. package/apps/storefront/src/lib/apps/orders/orderMapper.ts +2 -2
  136. package/apps/storefront/src/lib/apps/orders/ordersStore.ts +7 -7
  137. package/apps/storefront/src/lib/apps/orders/verifiedProviderMeasurement.ts +117 -0
  138. package/apps/storefront/src/lib/apps/registryService.ts +270 -16
  139. package/apps/storefront/src/lib/apps/scopes.ts +2 -2
  140. package/apps/storefront/src/lib/apps/tenantIntegrationMaterialization.ts +170 -0
  141. package/apps/storefront/src/lib/apps/tokenIssuer.ts +4 -4
  142. package/apps/storefront/src/lib/apps/tokenVerifier.ts +6 -6
  143. package/apps/storefront/src/lib/apps/v84CleanCloneReplayContext.ts +16 -0
  144. package/apps/storefront/src/lib/apps/v84CloneLifecycleCacheEvidence.ts +105 -0
  145. package/apps/storefront/src/lib/apps/v84CloneLifecycleEvidence.ts +177 -0
  146. package/apps/storefront/src/lib/apps/v84CloneLifecycleMaterialization.ts +251 -0
  147. package/apps/storefront/src/lib/apps/v84CloneLifecycleSemantics.ts +241 -0
  148. package/apps/storefront/src/lib/apps/v84CloneMigrationEvidence.ts +211 -0
  149. package/apps/storefront/src/lib/apps/v84CloneNativeInstallEvidence.ts +409 -0
  150. package/apps/storefront/src/lib/apps/v84NonportableCodeCoaching.ts +368 -0
  151. package/apps/storefront/src/lib/apps/v84NonportableRouteContract.ts +188 -0
  152. package/apps/storefront/src/lib/apps/v84NonportableRouteDogfood.ts +291 -0
  153. package/apps/storefront/src/lib/apps/widgets/eligibility.ts +2 -2
  154. package/apps/storefront/src/lib/apps/widgets/frameProps.ts +3 -3
  155. package/apps/storefront/src/lib/apps/widgets/launchToken.ts +4 -4
  156. package/apps/storefront/src/lib/apps/widgets/placements.ts +2 -2
  157. package/apps/storefront/src/lib/apps/widgets/renderSlot.ts +1 -1
  158. package/apps/storefront/src/lib/apps/ws1ManagedAnalyticsClient.ts +95 -0
  159. package/apps/storefront/src/lib/auth/adminApiGuard.ts +66 -0
  160. package/apps/storefront/src/lib/auth/adminEntry.ts +11 -11
  161. package/apps/storefront/src/lib/auth/adminLanding.ts +88 -0
  162. package/apps/storefront/src/lib/auth/identityToken.ts +6 -14
  163. package/apps/storefront/src/lib/auth/loginGate.ts +75 -13
  164. package/apps/storefront/src/lib/auth/mcpClientAssertion.ts +2 -4
  165. package/apps/storefront/src/lib/auth/operatorSession.ts +113 -0
  166. package/apps/storefront/src/lib/auth/session.ts +7 -8
  167. package/apps/storefront/src/lib/auth/totAccessClient.ts +8 -18
  168. package/apps/storefront/src/lib/basePath.ts +9 -2
  169. package/apps/storefront/src/lib/blog/access.ts +29 -0
  170. package/apps/storefront/src/lib/blog/collection.ts +400 -0
  171. package/apps/storefront/src/lib/blog/markdown.ts +174 -0
  172. package/apps/storefront/src/lib/blog/provider.ts +62 -3
  173. package/apps/storefront/src/lib/blog/reactions.ts +87 -0
  174. package/apps/storefront/src/lib/blog/rss.ts +92 -0
  175. package/apps/storefront/src/lib/blog/teaser.ts +83 -0
  176. package/apps/storefront/src/lib/blog/types.ts +34 -0
  177. package/apps/storefront/src/lib/blog/viewCounts.ts +243 -0
  178. package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome-assignments.example.json +6 -0
  179. package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome.example.json +79 -0
  180. package/apps/storefront/src/lib/chrome/model.ts +48 -253
  181. package/apps/storefront/src/lib/chrome/navCurrent.ts +29 -0
  182. package/apps/storefront/src/lib/chrome/parseConfig.ts +18 -32
  183. package/apps/storefront/src/lib/chrome/variant.ts +39 -0
  184. package/apps/storefront/src/lib/commerce/checkoutHandoffCorrelation.ts +105 -0
  185. package/apps/storefront/src/lib/compliance/tamper-sentinel-boot.ts +152 -0
  186. package/apps/storefront/src/lib/compliance/tamper-sentinel.ts +327 -0
  187. package/apps/storefront/src/lib/content/index.ts +5 -5
  188. package/apps/storefront/src/lib/content-edit/applyDiff.ts +1 -1
  189. package/apps/storefront/src/lib/content-edit/route.ts +1 -1
  190. package/apps/storefront/src/lib/d1/catalog.ts +14 -2
  191. package/apps/storefront/src/lib/d1/schema-apps.ts +372 -17
  192. package/apps/storefront/src/lib/dev/activityIngestToken.ts +2 -4
  193. package/apps/storefront/src/lib/dev/activityStore.ts +3 -5
  194. package/apps/storefront/src/lib/dev/apiBase.ts +1 -4
  195. package/apps/storefront/src/lib/dev/cockpit/ask.ts +49 -0
  196. package/apps/storefront/src/lib/dev/cockpit/clickToSource.ts +71 -0
  197. package/apps/storefront/src/lib/dev/cockpit/copyCommand.ts +227 -0
  198. package/apps/storefront/src/lib/dev/cockpit/files.ts +249 -0
  199. package/apps/storefront/src/lib/dev/cockpit/hostedActivity.ts +500 -0
  200. package/apps/storefront/src/lib/dev/cockpit/infoPopover.ts +12 -0
  201. package/apps/storefront/src/lib/dev/cockpit/mcpCopy.ts +34 -0
  202. package/apps/storefront/src/lib/dev/cockpit/monitor.ts +107 -0
  203. package/apps/storefront/src/lib/dev/cockpit/stepper.ts +116 -0
  204. package/apps/storefront/src/lib/dev/cockpit/themeToggle.ts +23 -0
  205. package/apps/storefront/src/lib/dev/cockpitStore.ts +1 -9
  206. package/apps/storefront/src/lib/dev/devDraft.ts +1 -1
  207. package/apps/storefront/src/lib/dev/previewStatus.ts +9 -21
  208. package/apps/storefront/src/lib/dev/rendezvousBroker.ts +9 -24
  209. package/apps/storefront/src/lib/dev/runtimeStore.ts +1 -1
  210. package/apps/storefront/src/lib/edgeCache.ts +34 -5
  211. package/apps/storefront/src/lib/email/candidateConflictEmail.ts +80 -0
  212. package/apps/storefront/src/lib/http/fetchTransport.ts +63 -0
  213. package/apps/storefront/src/lib/i18n.ts +25 -0
  214. package/apps/storefront/src/lib/integration/browserEnvironment.ts +137 -0
  215. package/apps/storefront/src/lib/integration/managedInstallDeclarations.ts +72 -0
  216. package/apps/storefront/src/lib/integration/nonceStamp.ts +49 -0
  217. package/apps/storefront/src/lib/integration/tenantDeclarations.ts +116 -0
  218. package/apps/storefront/src/lib/jsonld.ts +118 -0
  219. package/apps/storefront/src/lib/membership/eligibility.ts +1 -1
  220. package/apps/storefront/src/lib/membership/model.ts +1 -2
  221. package/apps/storefront/src/lib/monitoring/manifest.ts +11 -11
  222. package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +30 -0
  223. package/apps/storefront/src/lib/newsletter/consent.ts +23 -0
  224. package/apps/storefront/src/lib/newsletter/digest.ts +117 -0
  225. package/apps/storefront/src/lib/newsletter/resendClient.ts +79 -0
  226. package/apps/storefront/src/lib/newsletter/send.ts +265 -0
  227. package/apps/storefront/src/lib/newsletter/subscribers.ts +156 -0
  228. package/apps/storefront/src/lib/previewReload.ts +57 -1
  229. package/apps/storefront/src/lib/publish/adminPublishTab.ts +4625 -0
  230. package/apps/storefront/src/lib/publish/apex-readiness.ts +41 -18
  231. package/apps/storefront/src/lib/publish/buildStream.ts +269 -0
  232. package/apps/storefront/src/lib/publish/collapsePersistence.ts +72 -0
  233. package/apps/storefront/src/lib/publish/dispatchHealth.ts +5 -7
  234. package/apps/storefront/src/lib/publish/domainState.ts +22 -13
  235. package/apps/storefront/src/lib/publish/lifecycleState.ts +369 -0
  236. package/apps/storefront/src/lib/publish/liveReleaseSummary.ts +29 -0
  237. package/apps/storefront/src/lib/publish/mergeDoctorOnFailure.ts +78 -0
  238. package/apps/storefront/src/lib/publish/mergeHealthBanner.ts +62 -0
  239. package/apps/storefront/src/lib/publish/mergeRowFindings.ts +124 -0
  240. package/apps/storefront/src/lib/publish/mergeSupportEscalation.ts +75 -0
  241. package/apps/storefront/src/lib/publish/panelPolling.ts +78 -0
  242. package/apps/storefront/src/lib/publish/publish-guard.ts +88 -0
  243. package/apps/storefront/src/lib/publish/publishFormat.ts +165 -0
  244. package/apps/storefront/src/lib/publish/publishHero.ts +177 -0
  245. package/apps/storefront/src/lib/publish/reviewRelease/changeState.ts +66 -0
  246. package/apps/storefront/src/lib/publish/reviewRelease/copy.ts +141 -0
  247. package/apps/storefront/src/lib/publish/reviewRelease/index.ts +41 -0
  248. package/apps/storefront/src/lib/publish/reviewRelease/permissions.ts +47 -0
  249. package/apps/storefront/src/lib/publish/reviewRelease/releaseState.ts +42 -0
  250. package/apps/storefront/src/lib/publish/reviewRelease/types.ts +59 -0
  251. package/apps/storefront/src/lib/publish/reviewRelease/viewModel.ts +440 -0
  252. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/actions.ts +161 -0
  253. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/controller.ts +325 -0
  254. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/render.ts +241 -0
  255. package/apps/storefront/src/lib/publish/shipWorkspace.ts +121 -51
  256. package/apps/storefront/src/lib/publish/sseRoute.ts +119 -0
  257. package/apps/storefront/src/lib/publish/stageBundleUpload.ts +215 -0
  258. package/apps/storefront/src/lib/publish/streamLogConsole.ts +142 -0
  259. package/apps/storefront/src/lib/publish/versionNumber.ts +52 -0
  260. package/apps/storefront/src/lib/rate/kvWindow.ts +53 -0
  261. package/apps/storefront/src/lib/rawChrome.ts +125 -47
  262. package/apps/storefront/src/lib/rawMarketingHtml.ts +74 -3
  263. package/apps/storefront/src/lib/search/index.ts +2 -2
  264. package/apps/storefront/src/lib/seo/alternates.ts +42 -0
  265. package/apps/storefront/src/lib/seo/meta.ts +65 -0
  266. package/apps/storefront/src/lib/social/golive.ts +212 -0
  267. package/apps/storefront/src/lib/social/notify.ts +32 -0
  268. package/apps/storefront/src/lib/social/tokenStore.ts +171 -0
  269. package/apps/storefront/src/lib/storyblok/content-model.ts +7 -33
  270. package/apps/storefront/src/lib/storyblok/provider.ts +168 -60
  271. package/apps/storefront/src/lib/subscription/model.ts +4 -4
  272. package/apps/storefront/src/lib/the-build/provider.ts +32 -0
  273. package/apps/storefront/src/lib/the-build/readingTime.ts +35 -0
  274. package/apps/storefront/src/lib/the-build/toc.ts +95 -0
  275. package/apps/storefront/src/lib/tot/ToTClient.ts +1 -1
  276. package/apps/storefront/src/lib/tot/d1Client.ts +2 -2
  277. package/apps/storefront/src/lib/tot/totClientInterface.ts +3 -4
  278. package/apps/storefront/src/lib/webhooks/deliveryStore.ts +16 -17
  279. package/apps/storefront/src/middleware/index.ts +385 -52
  280. package/apps/storefront/src/pages/[...slug].astro +9 -4
  281. package/apps/storefront/src/pages/admin/review-release.astro +265 -0
  282. package/apps/storefront/src/pages/admin/select.astro +96 -0
  283. package/apps/storefront/src/pages/admin.astro +25 -1313
  284. package/apps/storefront/src/pages/api/activity.ts +8 -8
  285. package/apps/storefront/src/pages/api/admin/activity-alerts.ts +5 -20
  286. package/apps/storefront/src/pages/api/admin/orders/[id].ts +7 -2
  287. package/apps/storefront/src/pages/api/admin/orders.ts +8 -2
  288. package/apps/storefront/src/pages/api/apps/admin/gtm-migration-install.ts +174 -0
  289. package/apps/storefront/src/pages/api/apps/admin/gtm-migration.ts +96 -0
  290. package/apps/storefront/src/pages/api/apps/admin/integration-lifecycle.ts +118 -0
  291. package/apps/storefront/src/pages/api/apps/admin/integrations.ts +89 -0
  292. package/apps/storefront/src/pages/api/apps/admin/platform-adapters.ts +85 -0
  293. package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +74 -2
  294. package/apps/storefront/src/pages/api/blog/[collection]/[slug]/react.ts +104 -0
  295. package/apps/storefront/src/pages/api/commerce/checkout-handoff.ts +77 -0
  296. package/apps/storefront/src/pages/api/compliance/tamper.ts +88 -0
  297. package/apps/storefront/src/pages/api/integrations/v1/[operation].ts +108 -0
  298. package/apps/storefront/src/pages/api/newsletter/[collection]/subscribe.ts +146 -0
  299. package/apps/storefront/src/pages/api/newsletter/confirm.ts +75 -0
  300. package/apps/storefront/src/pages/api/newsletter/unsubscribe.ts +90 -0
  301. package/apps/storefront/src/pages/api/publish/stage-bundle.ts +70 -0
  302. package/apps/storefront/src/pages/api/rum/vitals.ts +20 -2
  303. package/apps/storefront/src/pages/blog/[slug].astro +99 -19
  304. package/apps/storefront/src/pages/blog/author/[author].astro +140 -0
  305. package/apps/storefront/src/pages/blog/category/[category].astro +67 -0
  306. package/apps/storefront/src/pages/blog/index.astro +4 -2
  307. package/apps/storefront/src/pages/blog/tag/[tag].astro +65 -0
  308. package/apps/storefront/src/pages/cockpit.astro +77 -1353
  309. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +15 -11
  310. package/apps/storefront/src/pages/index.astro +10 -5
  311. package/apps/storefront/src/pages/llms.txt.ts +1 -1
  312. package/apps/storefront/src/pages/products/[handle].astro +7 -6
  313. package/apps/storefront/src/pages/search.astro +1 -1
  314. package/apps/storefront/src/pages/sitemap.xml.ts +21 -1
  315. package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +31 -27
  316. package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +1 -1
  317. package/apps/storefront/src/pages/tenants/[id]/[...path].ts +38 -2
  318. package/apps/storefront/src/pages/the-build/[slug].astro +129 -0
  319. package/apps/storefront/src/pages/the-build/index.astro +146 -0
  320. package/apps/storefront/src/pages/the-build/rss.xml.ts +33 -0
  321. package/apps/storefront/src/styles/admin.css +1106 -0
  322. package/apps/storefront/tsconfig.json +6 -1
  323. package/package.json +1 -1
  324. package/packages/public-runtime/package.json +3 -1
  325. package/packages/public-runtime/schemas/managed-analytics/v1/adapter-definition.schema.json +427 -0
  326. package/packages/public-runtime/schemas/managed-analytics/v1/create-integration-install-request.schema.json +161 -0
  327. package/packages/public-runtime/schemas/managed-analytics/v1/create-migration-draft-request.schema.json +157 -0
  328. package/packages/public-runtime/schemas/managed-analytics/v1/delete-integration-install-request.schema.json +84 -0
  329. package/packages/public-runtime/schemas/managed-analytics/v1/delete-migration-draft-request.schema.json +84 -0
  330. package/packages/public-runtime/schemas/managed-analytics/v1/error-envelope.schema.json +180 -0
  331. package/packages/public-runtime/schemas/managed-analytics/v1/get-adapter-definition-request.schema.json +52 -0
  332. package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-install-request.schema.json +52 -0
  333. package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-revision-request.schema.json +79 -0
  334. package/packages/public-runtime/schemas/managed-analytics/v1/get-migration-draft-request.schema.json +52 -0
  335. package/packages/public-runtime/schemas/managed-analytics/v1/integration-install.schema.json +167 -0
  336. package/packages/public-runtime/schemas/managed-analytics/v1/integration-revision.schema.json +208 -0
  337. package/packages/public-runtime/schemas/managed-analytics/v1/list-adapter-definitions-request.schema.json +53 -0
  338. package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-installs-request.schema.json +53 -0
  339. package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-revisions-request.schema.json +82 -0
  340. package/packages/public-runtime/schemas/managed-analytics/v1/migration-draft.schema.json +218 -0
  341. package/packages/public-runtime/schemas/managed-analytics/v1/mutation-request.schema.json +52 -0
  342. package/packages/public-runtime/schemas/managed-analytics/v1/mutation-success-envelope.schema.json +49 -0
  343. package/packages/public-runtime/schemas/managed-analytics/v1/read-request.schema.json +20 -0
  344. package/packages/public-runtime/schemas/managed-analytics/v1/read-success-envelope.schema.json +45 -0
  345. package/packages/public-runtime/schemas/managed-analytics/v1/revise-integration-install-request.schema.json +156 -0
  346. package/packages/public-runtime/schemas/managed-analytics/v1/set-integration-install-status-request.schema.json +92 -0
  347. package/packages/public-runtime/schemas/managed-analytics/v1/update-migration-draft-request.schema.json +184 -0
  348. package/packages/public-runtime/scripts/generate-managed-analytics-api-v1-schemas.mjs +13 -0
  349. package/packages/public-runtime/src/activity/catalog.ts +89 -33
  350. package/packages/public-runtime/src/activity/event.ts +6 -6
  351. package/packages/public-runtime/src/activity/index.ts +2 -2
  352. package/packages/public-runtime/src/activity/redaction.ts +4 -4
  353. package/packages/public-runtime/src/candidate-index.ts +42 -8
  354. package/packages/public-runtime/src/catalog-d1.ts +1 -1
  355. package/packages/public-runtime/src/checkout-orders.ts +2 -2
  356. package/packages/public-runtime/src/checkout-style-publish.ts +2 -2
  357. package/packages/public-runtime/src/checkout-style.ts +7 -7
  358. package/packages/public-runtime/src/checkout.ts +3 -3
  359. package/packages/public-runtime/src/chrome.ts +777 -0
  360. package/packages/public-runtime/src/compliance-obligations.ts +310 -0
  361. package/packages/public-runtime/src/csp.ts +99 -0
  362. package/packages/public-runtime/src/customization-preview.ts +25 -2
  363. package/packages/public-runtime/src/customization-runtime.ts +156 -3
  364. package/packages/public-runtime/src/customization-versioning.ts +10 -0
  365. package/packages/public-runtime/src/destination-webhook/contract.ts +353 -0
  366. package/packages/public-runtime/src/embed-catalog.d.mts +9 -0
  367. package/packages/public-runtime/src/embed-catalog.mjs +40 -0
  368. package/packages/public-runtime/src/evidence.ts +288 -0
  369. package/packages/public-runtime/src/gtm-migration/bounds.ts +138 -0
  370. package/packages/public-runtime/src/gtm-migration/disposition-rules.ts +361 -0
  371. package/packages/public-runtime/src/gtm-migration/dispositions.ts +181 -0
  372. package/packages/public-runtime/src/gtm-migration/draft-generator.ts +400 -0
  373. package/packages/public-runtime/src/gtm-migration/graph.ts +468 -0
  374. package/packages/public-runtime/src/gtm-migration/index.ts +95 -0
  375. package/packages/public-runtime/src/gtm-migration/parse.ts +410 -0
  376. package/packages/public-runtime/src/gtm-migration/references.ts +266 -0
  377. package/packages/public-runtime/src/gtm-migration/types.ts +86 -0
  378. package/packages/public-runtime/src/index.ts +17 -1
  379. package/packages/public-runtime/src/integration/assurance-decision.ts +259 -0
  380. package/packages/public-runtime/src/integration/assurance.ts +228 -0
  381. package/packages/public-runtime/src/integration/candidate-evidence.ts +377 -0
  382. package/packages/public-runtime/src/integration/commerce-broker.ts +497 -0
  383. package/packages/public-runtime/src/integration/consent-broker.ts +337 -0
  384. package/packages/public-runtime/src/integration/consent-cmp-demand.ts +115 -0
  385. package/packages/public-runtime/src/integration/consent-config.ts +260 -0
  386. package/packages/public-runtime/src/integration/consent-preview.ts +125 -0
  387. package/packages/public-runtime/src/integration/correlation-token.ts +444 -0
  388. package/packages/public-runtime/src/integration/csp-compiler.ts +267 -0
  389. package/packages/public-runtime/src/integration/csp.ts +105 -0
  390. package/packages/public-runtime/src/integration/digest.ts +43 -0
  391. package/packages/public-runtime/src/integration/environment.ts +228 -0
  392. package/packages/public-runtime/src/integration/events-catalog.ts +186 -0
  393. package/packages/public-runtime/src/integration/events.ts +701 -0
  394. package/packages/public-runtime/src/integration/g2-action-boundary.ts +106 -0
  395. package/packages/public-runtime/src/integration/index.ts +90 -0
  396. package/packages/public-runtime/src/integration/interim-bridge.ts +138 -0
  397. package/packages/public-runtime/src/integration/lifecycle-boot.ts +317 -0
  398. package/packages/public-runtime/src/integration/lifecycle-runtime.ts +393 -0
  399. package/packages/public-runtime/src/integration/lifecycle.ts +94 -0
  400. package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.d.mts +2 -0
  401. package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.mjs +10 -0
  402. package/packages/public-runtime/src/integration/managed-analytics-api-v1.schemas.ts +382 -0
  403. package/packages/public-runtime/src/integration/managed-analytics-api-v1.ts +684 -0
  404. package/packages/public-runtime/src/integration/managed-analytics-bridge.ts +383 -0
  405. package/packages/public-runtime/src/integration/managed-analytics-value-safety.ts +14 -0
  406. package/packages/public-runtime/src/integration/managed-analytics.ts +277 -0
  407. package/packages/public-runtime/src/integration/manifest.ts +470 -0
  408. package/packages/public-runtime/src/integration/native-amplitude.ts +362 -0
  409. package/packages/public-runtime/src/integration/native-ga4.ts +352 -0
  410. package/packages/public-runtime/src/integration/observability.ts +451 -0
  411. package/packages/public-runtime/src/integration/order-conversion.ts +0 -0
  412. package/packages/public-runtime/src/integration/phases.ts +182 -0
  413. package/packages/public-runtime/src/integration/plan.ts +112 -0
  414. package/packages/public-runtime/src/integration/platform-adapter-runtime.ts +146 -0
  415. package/packages/public-runtime/src/integration/platform-adapters.ts +671 -0
  416. package/packages/public-runtime/src/integration/promotion-gate.ts +451 -0
  417. package/packages/public-runtime/src/integration/provider-checkout-extension.ts +425 -0
  418. package/packages/public-runtime/src/integration/receipt-measurement.ts +370 -0
  419. package/packages/public-runtime/src/integration/regulated-parent-cert.ts +311 -0
  420. package/packages/public-runtime/src/integration/render-phases.ts +267 -0
  421. package/packages/public-runtime/src/integration/resolve.ts +465 -0
  422. package/packages/public-runtime/src/integration/result.ts +239 -0
  423. package/packages/public-runtime/src/integration/secrets.ts +92 -0
  424. package/packages/public-runtime/src/integration/tamper-evidence.ts +205 -0
  425. package/packages/public-runtime/src/integration/tamper-recovery.ts +127 -0
  426. package/packages/public-runtime/src/integration/version.ts +92 -0
  427. package/packages/public-runtime/src/integration-capabilities.ts +520 -0
  428. package/packages/public-runtime/src/membership.ts +2 -2
  429. package/packages/public-runtime/src/raw-html-policy.ts +2 -4
  430. package/packages/public-runtime/src/regulated-commerce/broker/consent-dedupe.ts +144 -0
  431. package/packages/public-runtime/src/regulated-commerce/correlation/contract.ts +177 -0
  432. package/packages/public-runtime/src/regulated-commerce/diagnostics/local-dispatch.ts +24 -0
  433. package/packages/public-runtime/src/regulated-commerce/diagnostics/read-model.ts +69 -0
  434. package/packages/public-runtime/src/regulated-commerce/dispatch/core.ts +134 -0
  435. package/packages/public-runtime/src/regulated-commerce/events/contract.ts +113 -0
  436. package/packages/public-runtime/src/regulated-commerce/ledger/core.ts +81 -0
  437. package/packages/public-runtime/src/regulated-commerce/mappings/ga4-ads.ts +87 -0
  438. package/packages/public-runtime/src/regulated-commerce/provider-order/bridge.ts +52 -0
  439. package/packages/public-runtime/src/regulated-commerce/purchase-truth/contract.ts +252 -0
  440. package/packages/public-runtime/src/regulated-commerce/sources/accepted-browser-operation.ts +67 -0
  441. package/packages/public-runtime/src/regulated-commerce/testing/fake-destination.ts +93 -0
  442. package/packages/public-runtime/src/static-bundle.ts +357 -0
  443. package/packages/public-runtime/src/tenant-assets.ts +143 -4
  444. package/packages/public-runtime/src/tenant.ts +81 -17
  445. package/packages/public-runtime/tests/fixtures/integration/browser-environment.example.json +8 -0
  446. package/packages/public-runtime/tests/fixtures/integration/commerce-event.example.json +44 -0
  447. package/packages/public-runtime/tests/fixtures/integration/commerce-order-event.example.json +44 -0
  448. package/packages/public-runtime/tests/fixtures/integration/compliance-assurance-record.example.json +50 -0
  449. package/packages/public-runtime/tests/fixtures/integration/integration-manifest-v2.example.json +120 -0
  450. package/packages/public-runtime/tests/fixtures/integration/managed-analytics-v1/fake-adapter-catalog.json +35 -0
  451. package/packages/public-runtime/tests/fixtures/integration/tenant-action-registry.example.json +11 -0
  452. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/README.md +22 -0
  453. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/entry.js +30 -0
  454. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/manifest.json +75 -0
  455. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/public-config.json +3 -0
  456. package/packages/public-runtime/tests/fixtures/regulated-commerce/fake-destinations.ts +38 -0
  457. package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.provenance.json +29 -0
  458. package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.redacted.json +3397 -0
  459. package/scripts/build/copy-tenant-assets.mjs +14 -4
  460. package/scripts/dev/ai-edit.mjs +1 -1
  461. package/scripts/dev/checkout-watch.mjs +2 -2
  462. package/scripts/dev/file-browser.mjs +4 -6
  463. package/scripts/dev/file-writer.mjs +3 -3
  464. package/scripts/dev/git-status.mjs +2 -2
  465. package/scripts/dev/integration-guardrails.mjs +498 -0
  466. package/scripts/dev/locate-handler.mjs +3 -3
  467. package/scripts/dev/port-check.mjs +3 -3
  468. package/scripts/dev/publish.mjs +5 -9
  469. package/scripts/dev/safe-path.mjs +2 -2
  470. package/scripts/dev/shot.mjs +1 -1
  471. package/scripts/dev/tenant-source-root.mjs +1 -1
  472. package/scripts/dev/unified-diff.mjs +8 -3
  473. package/scripts/tot-dev.mjs +8 -11
  474. package/apps/storefront/src/lib/dev/vcBinding.ts +0 -80
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Machine-verifiable apex-cutover READINESS gate (unit u9) — the green
2
+ * Machine-verifiable apex-cutover READINESS gate — the green
3
3
  * preconditions that MUST all pass before an owner apex (DNS) cutover is
4
- * permitted. This is the DELTA on top of the go-live session's apex machinery:
4
+ * permitted. It consumes the go-live apex machinery:
5
5
  * go-live owns the admin Domain Connect/Rollback button, the DNS cutover/rollback
6
6
  * CI (`www-domain.yml` → `cutover-dns.mjs`, prior-records persisted to
7
- * `s3://.../meta/`), and the HMAC completion callback; u9 CONSUMES those and
7
+ * `s3://.../meta/`), and the HMAC completion callback; this gate CONSUMES those and
8
8
  * GATES them. Nothing here mutates DNS — it decides whether a cutover is ALLOWED.
9
9
  *
10
10
  * The gate is a PURE function over a signals bundle so the exact policy is
@@ -12,7 +12,7 @@
12
12
  * `change/ship`'s CLI and the `acceptGate`/`apexCutoverGate` pure decisions). The
13
13
  * server endpoint (`GET /api/domain/readiness`) assembles the signals from the
14
14
  * live sources via {@link assembleApexReadinessSignals} — the owner capability
15
- * (u10 `resolveShipCapabilities`), the per-tenant `DomainState` (in-flight run +
15
+ * (`resolveShipCapabilities`), the per-tenant `DomainState` (in-flight run +
16
16
  * the CAPTURED revert target), and the consumed dual-run parity / target-health /
17
17
  * live-digest evidence record — and the admin Domain display + the `tot go-live`
18
18
  * CLI both read the SAME endpoint, so the enforcement gate and the surfaces never
@@ -20,24 +20,24 @@
20
20
  *
21
21
  * EVIDENCE CONTRACT (the seam the go-live dual-run/health CI feeds): the parity,
22
22
  * target-health and live-digest signals are CONSUMED from a per-tenant evidence
23
- * record persisted at {@link readinessEvidenceKey} (KV). u9 does not RE-RUN
23
+ * record persisted at {@link readinessEvidenceKey} (KV). The gate does not RE-RUN
24
24
  * dual-run — it reads the record `scripts/publish/dual-run.mjs` + the health
25
25
  * probe produce. An absent/garbage record normalises fail-closed (no parity, no
26
26
  * digest, unhealthy), so readiness BLOCKS until the go-live CI writes real
27
27
  * evidence — never a false "ready" from a missing feed.
28
28
  *
29
- * FAIL-CLOSED throughout (decision `static-publish-fails-closed-reviewed-sha`):
29
+ * FAIL-CLOSED throughout:
30
30
  * a missing, stale, or failed signal BLOCKS the cutover with an honest,
31
31
  * itemized reason — never a false "ready". Absence denies. The gate is
32
32
  * ADVISORY-vs-authoritative honest: it reports readiness, but the actual cutover
33
- * is still owner-gated at `apexCutoverGate`/`guardApexCutover` (u10) and executed
33
+ * is still owner-gated at `apexCutoverGate`/`guardApexCutover` and executed
34
34
  * only by the go-live CI — a green readiness verdict never bypasses those.
35
35
  */
36
36
 
37
37
  /**
38
38
  * The consumed dual-run parity evidence (produced by `scripts/publish/dual-run.mjs`
39
- * — the T7 CloudFront-vs-baseline structural diff the pending-dns-cutover gate
40
- * wants). u9 CONSUMES this shape; it does not re-run dual-run. Green = the hard
39
+ * — the CloudFront-vs-baseline structural diff the pending-dns-cutover gate
40
+ * wants). This shape is consumed here; dual-run is not re-run. Green = the hard
41
41
  * gate dual-run itself enforces: zero CloudFront route failures. `statusMismatches`
42
42
  * are surfaced for review (content legitimately differs during a migration) but do
43
43
  * NOT block, exactly as `dual-run.mjs` treats them. `digest` ties the evidence to
@@ -73,7 +73,7 @@ export interface RevertTarget {
73
73
  export interface ApexReadinessSignals {
74
74
  /**
75
75
  * The acting principal holds the OWNER-ONLY apex-cutover capability
76
- * (`resolveShipCapabilities(principal).apexCutover`, u10). A `ship-on-behalf`
76
+ * (`resolveShipCapabilities(principal).apexCutover`). A `ship-on-behalf`
77
77
  * developer or an unauthenticated caller is false → denied.
78
78
  */
79
79
  ownerCapable: boolean;
@@ -96,8 +96,8 @@ export interface ApexReadinessSignals {
96
96
  targetHealthy: boolean;
97
97
  /**
98
98
  * The digest currently published live (the reviewed tree the cutover would
99
- * point traffic at). Evidence must be tied to THIS digest to count as fresh
100
- * (`static-publish-fails-closed-reviewed-sha`). Null ⇒ freshness fails closed.
99
+ * point traffic at). Evidence must be tied to THIS digest to count as fresh.
100
+ * Null ⇒ freshness fails closed.
101
101
  */
102
102
  liveDigest: string | null;
103
103
  /** The captured revert target — a rollback must have somewhere to restore FROM. */
@@ -122,6 +122,14 @@ export interface ApexReadinessCheck {
122
122
  ok: boolean;
123
123
  /** Why it passed or, more importantly, why it's blocking — always actionable. */
124
124
  detail: string;
125
+ /**
126
+ * The concrete action that clears this precondition when it's blocking — the
127
+ * "how to get ready" guide, carried on the gate itself so the admin panel and
128
+ * `tot go-live` surface identical remediation (never a divergent side doc). Only
129
+ * meaningful/shown when `ok` is false; the full operator walkthrough (secret
130
+ * provisioning, IAM) lives in `docs/runbooks/apex-cutover-readiness.md`.
131
+ */
132
+ remedy: string;
125
133
  }
126
134
 
127
135
  /** The full readiness verdict: ready iff EVERY check passed; itemized either way. */
@@ -146,7 +154,7 @@ export interface ApexReadiness {
146
154
  export function computeApexReadiness(signals: ApexReadinessSignals): ApexReadiness {
147
155
  const checks: ApexReadinessCheck[] = [];
148
156
 
149
- // 1. Owner-only capability (u10). A non-owner is denied outright — this is the
157
+ // 1. Owner-only capability. A non-owner is denied outright — this is the
150
158
  // same floor `apexCutoverGate` enforces, surfaced as a readiness item.
151
159
  checks.push({
152
160
  id: "owner-capability",
@@ -155,6 +163,7 @@ export function computeApexReadiness(signals: ApexReadinessSignals): ApexReadine
155
163
  detail: signals.ownerCapable
156
164
  ? "you hold the owner-only apex-cutover capability"
157
165
  : "apex cutover is owner-only — a ship-on-behalf developer cannot cut over the apex",
166
+ remedy: "Sign in as the store owner — apex cutover cannot be delegated to a ship-on-behalf developer.",
158
167
  });
159
168
 
160
169
  // 2. No run in flight — two concurrent DNS mutations is the race DomainState guards.
@@ -165,6 +174,7 @@ export function computeApexReadiness(signals: ApexReadinessSignals): ApexReadine
165
174
  detail: signals.runInFlight
166
175
  ? "a domain connect/rollback run is already in flight — wait for it to complete"
167
176
  : "no domain run is in flight",
177
+ remedy: "Wait for the in-flight connect/rollback run to finish (watch the run log), then re-check.",
168
178
  });
169
179
 
170
180
  // 3. Dual-run parity — zero CloudFront route failures (the hard gate dual-run.mjs
@@ -186,6 +196,10 @@ export function computeApexReadiness(signals: ApexReadinessSignals): ApexReadine
186
196
  (dr.statusMismatches > 0
187
197
  ? ` (${dr.statusMismatches} status mismatch(es) surfaced for review — non-blocking)`
188
198
  : ""),
199
+ remedy:
200
+ "Publish tokenoftrust.com (a www-publish run) so the dual-run records fresh evidence. " +
201
+ "First time only: provision the WWW_READINESS_EVIDENCE_URL variable + WWW_READINESS_EVIDENCE_SECRET " +
202
+ "secret (see the apex-cutover-readiness runbook).",
189
203
  });
190
204
 
191
205
  // 4. Target health — the apex target (CloudFront/static origin) is serving.
@@ -196,11 +210,14 @@ export function computeApexReadiness(signals: ApexReadinessSignals): ApexReadine
196
210
  detail: signals.targetHealthy
197
211
  ? "apex target health check passed"
198
212
  : "apex target health check failing or unestablished",
213
+ remedy:
214
+ "Cleared by the same www-publish evidence run as Dual-run parity — every route serving " +
215
+ "correctly on CloudFront is what proves the target healthy.",
199
216
  });
200
217
 
201
- // 5. Evidence freshness — the parity evidence is tied to the CURRENT live digest
202
- // (`static-publish-fails-closed-reviewed-sha`). Stale evidence (a different
203
- // digest) or a missing digest on either side fails closed.
218
+ // 5. Evidence freshness — the parity evidence is tied to the CURRENT live digest.
219
+ // Stale evidence (a different digest) or a missing digest on either side fails
220
+ // closed.
204
221
  const evidenceDigest = dr?.digest ?? null;
205
222
  const freshOk =
206
223
  !!evidenceDigest && !!signals.liveDigest && evidenceDigest === signals.liveDigest;
@@ -216,6 +233,8 @@ export function computeApexReadiness(signals: ApexReadinessSignals): ApexReadine
216
233
  ? "parity evidence carries no digest — cannot confirm it matches the live tree"
217
234
  : `parity evidence is stale: it was produced against ${short(evidenceDigest)}, ` +
218
235
  `not the live digest ${short(signals.liveDigest)}`,
236
+ remedy:
237
+ "Re-publish tokenoftrust.com so the dual-run evidence is re-tied to the current live digest.",
219
238
  });
220
239
 
221
240
  // 6. Captured revert target — a rollback must have persisted prior DNS records to
@@ -230,6 +249,9 @@ export function computeApexReadiness(signals: ApexReadinessSignals): ApexReadine
230
249
  signals.revert.capturedAt ? ` @ ${signals.revert.capturedAt}` : ""
231
250
  })`
232
251
  : "no captured revert target — prior DNS records are not persisted, so there is no tested rollback",
252
+ remedy:
253
+ "Run a rehearsal (dry-run connect) from the Domain section — it captures the current DNS " +
254
+ "records as the rollback target without changing live DNS.",
233
255
  });
234
256
 
235
257
  const blockedReasons = checks.filter((c) => !c.ok).map((c) => c.detail);
@@ -267,9 +289,10 @@ function num(v: unknown): number | null {
267
289
 
268
290
  /**
269
291
  * The consumed readiness-evidence record the go-live dual-run/health CI persists
270
- * per tenant. u9 READS it; it does not produce it. Bundles the three signals u9
292
+ * per tenant. Bundles the three signals the gate
271
293
  * cannot derive from `DomainState` alone: the dual-run parity result, the apex
272
294
  * target's health, and the digest currently live (so freshness can be checked).
295
+ * The gate READS it; it does not produce it.
273
296
  */
274
297
  export interface ReadinessEvidence {
275
298
  dualRun: DualRunEvidence | null;
@@ -311,7 +334,7 @@ export interface ReadinessDomainState {
311
334
 
312
335
  /**
313
336
  * Assemble the {@link ApexReadinessSignals} the gate decides over from the three
314
- * live sources — the owner capability (u10), the per-tenant domain state (revert +
337
+ * live sources — the owner capability, the per-tenant domain state (revert +
315
338
  * in-flight), and the consumed evidence record — PURE so the endpoint's mapping is
316
339
  * unit-testable without KV/session I/O. The endpoint does the reads; this does the
317
340
  * mapping.
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Pure logic for the admin Publish tab's real-time build/check streaming (SSE).
3
+ *
4
+ * The build endpoint (`POST /api/preview/build` with `Accept: text/event-stream`)
5
+ * streams coarse lifecycle PHASES as it materializes a candidate — resolve head →
6
+ * read+validate tenant files → publish the immutable version → run evidence checks —
7
+ * then a terminal `result` event carrying the full outcome. This module is the tested
8
+ * source of truth for:
9
+ * - parsing the raw SSE byte-frames into events (partial-chunk safe);
10
+ * - mapping a phase to its human label + rail position;
11
+ * - reducing the event sequence into a render-ready progress state;
12
+ * - assembling the "Copy for your AI agent" prompt from a build FAILURE.
13
+ * The DOM wiring that drives the dialog from these is verified on a live preview, per
14
+ * this codebase's client-island convention (see reviewReleaseWorkspace/controller.ts).
15
+ */
16
+
17
+ /** One decoded SSE event: its `event:` name and the concatenated `data:` payload. */
18
+ export interface SseEvent {
19
+ event: string;
20
+ data: string;
21
+ }
22
+
23
+ /**
24
+ * Parse an accumulated SSE text buffer into complete events, returning any trailing
25
+ * INCOMPLETE frame as `rest` for the next chunk to prepend. Partial-chunk safe: a
26
+ * frame is complete only once its blank-line terminator (`\n\n`) has arrived.
27
+ * Lines with no field (`:` comments, stray blanks) are ignored; multiple `data:`
28
+ * lines in one frame join with `\n` (the SSE spec). A frame with no fields yields
29
+ * nothing.
30
+ */
31
+ export function parseSseChunk(buffer: string): { events: SseEvent[]; rest: string } {
32
+ const normalized = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
33
+ const events: SseEvent[] = [];
34
+ const lastSep = normalized.lastIndexOf("\n\n");
35
+ if (lastSep === -1) return { events, rest: normalized };
36
+
37
+ const complete = normalized.slice(0, lastSep);
38
+ const rest = normalized.slice(lastSep + 2);
39
+
40
+ for (const frame of complete.split("\n\n")) {
41
+ let eventName = "message";
42
+ const dataLines: string[] = [];
43
+ let sawField = false;
44
+ for (const rawLine of frame.split("\n")) {
45
+ if (!rawLine || rawLine.startsWith(":")) continue;
46
+ const colon = rawLine.indexOf(":");
47
+ const field = colon === -1 ? rawLine : rawLine.slice(0, colon);
48
+ // Per spec a single leading space after the colon is stripped.
49
+ let value = colon === -1 ? "" : rawLine.slice(colon + 1);
50
+ if (value.startsWith(" ")) value = value.slice(1);
51
+ if (field === "event") {
52
+ eventName = value;
53
+ sawField = true;
54
+ } else if (field === "data") {
55
+ dataLines.push(value);
56
+ sawField = true;
57
+ }
58
+ }
59
+ if (sawField) events.push({ event: eventName, data: dataLines.join("\n") });
60
+ }
61
+ return { events, rest };
62
+ }
63
+
64
+ /** The ordered build lifecycle stages the flight rail renders (mirrors the dialog). */
65
+ export const BUILD_STAGES = ["resolve", "read", "publish", "check"] as const;
66
+ export type BuildStage = (typeof BUILD_STAGES)[number];
67
+
68
+ /** The `phase` values the server emits, in lifecycle order. */
69
+ export type BuildPhase = "resolving" | "reading" | "publishing" | "checking";
70
+
71
+ const PHASE_TO_STAGE: Record<BuildPhase, BuildStage> = {
72
+ resolving: "resolve",
73
+ reading: "read",
74
+ publishing: "publish",
75
+ checking: "check",
76
+ };
77
+
78
+ const PHASE_LABEL: Record<BuildPhase, string> = {
79
+ resolving: "Locating the pull request's latest commit…",
80
+ reading: "Reading and validating your store's files…",
81
+ publishing: "Publishing this version's preview…",
82
+ checking: "Running the checks on this version…",
83
+ };
84
+
85
+ const STAGE_LABEL: Record<BuildStage, string> = {
86
+ resolve: "Locate commit",
87
+ read: "Read & validate",
88
+ publish: "Publish version",
89
+ check: "Run checks",
90
+ };
91
+
92
+ export function buildPhaseLabel(phase: BuildPhase): string {
93
+ return PHASE_LABEL[phase];
94
+ }
95
+
96
+ export function buildStageLabel(stage: BuildStage): string {
97
+ return STAGE_LABEL[stage];
98
+ }
99
+
100
+ export function isBuildPhase(value: unknown): value is BuildPhase {
101
+ return value === "resolving" || value === "reading" || value === "publishing" || value === "checking";
102
+ }
103
+
104
+ /** The terminal outcome the server reports on its `result` event. */
105
+ export type BuildOutcome = "ok" | "blocked" | "failed";
106
+
107
+ /** The full terminal payload of a build (mirrors the endpoint's JSON body). */
108
+ export interface BuildResult {
109
+ ok: boolean;
110
+ outcome: BuildOutcome;
111
+ tenantId?: string | null;
112
+ changeId?: string | null;
113
+ headSha?: string | null;
114
+ prNumber?: number | null;
115
+ previewUrl?: string | null;
116
+ errors?: string[];
117
+ error?: string | null;
118
+ findings?: BuildFinding[];
119
+ }
120
+
121
+ export interface BuildFinding {
122
+ id?: string;
123
+ label?: string;
124
+ detail?: string;
125
+ disposition?: string;
126
+ }
127
+
128
+ /** Render-ready progress the dialog reads. `stageState` is a per-stage rail map. */
129
+ export interface BuildProgress {
130
+ phase: BuildPhase | null;
131
+ liveLabel: string;
132
+ stageState: Record<BuildStage, "pending" | "active" | "done" | "fail">;
133
+ terminal: boolean;
134
+ result: BuildResult | null;
135
+ }
136
+
137
+ export function initialBuildProgress(): BuildProgress {
138
+ return {
139
+ phase: null,
140
+ liveLabel: "Starting…",
141
+ stageState: { resolve: "pending", read: "pending", publish: "pending", check: "pending" },
142
+ terminal: false,
143
+ result: null,
144
+ };
145
+ }
146
+
147
+ /**
148
+ * Advance the flight rail to `stage`: everything before it is `done`, it is `active`,
149
+ * everything after stays `pending`. A `fail` mark is never un-done. Pure.
150
+ */
151
+ function railTo(
152
+ prev: Record<BuildStage, "pending" | "active" | "done" | "fail">,
153
+ stage: BuildStage,
154
+ ): Record<BuildStage, "pending" | "active" | "done" | "fail"> {
155
+ const idx = BUILD_STAGES.indexOf(stage);
156
+ const next = { ...prev };
157
+ BUILD_STAGES.forEach((s, i) => {
158
+ if (next[s] === "fail") return;
159
+ next[s] = i < idx ? "done" : i === idx ? "active" : "pending";
160
+ });
161
+ return next;
162
+ }
163
+
164
+ /**
165
+ * Fold one SSE event into the progress state. A `phase` event advances the rail + live
166
+ * label; a `result` event is terminal (all reached stages `done` on success, the active
167
+ * stage `fail` on a blocked/failed outcome). Unknown events are ignored (state
168
+ * unchanged). Pure — the dialog calls this per event and re-renders from the result.
169
+ */
170
+ export function reduceBuildProgress(prev: BuildProgress, ev: SseEvent): BuildProgress {
171
+ if (ev.event === "phase") {
172
+ const parsed = safeParse(ev.data);
173
+ const phase = parsed && (parsed as { phase?: unknown }).phase;
174
+ if (!isBuildPhase(phase)) return prev;
175
+ const stage = PHASE_TO_STAGE[phase];
176
+ const label =
177
+ (parsed && typeof (parsed as { label?: unknown }).label === "string"
178
+ ? (parsed as { label: string }).label
179
+ : "") || buildPhaseLabel(phase);
180
+ return {
181
+ ...prev,
182
+ phase,
183
+ liveLabel: label,
184
+ stageState: railTo(prev.stageState, stage),
185
+ };
186
+ }
187
+
188
+ if (ev.event === "result") {
189
+ const parsed = (safeParse(ev.data) as BuildResult | null) ?? {
190
+ ok: false,
191
+ outcome: "failed",
192
+ errors: ["build ended without a result"],
193
+ };
194
+ const result: BuildResult = {
195
+ ...parsed,
196
+ outcome: parsed.outcome ?? (parsed.ok ? "ok" : "failed"),
197
+ };
198
+ let stageState = prev.stageState;
199
+ if (result.ok) {
200
+ stageState = { resolve: "done", read: "done", publish: "done", check: "done" };
201
+ } else {
202
+ // Fail the stage that was active (the phase we got furthest into); if none was
203
+ // active yet, fail the first stage so the rail shows an honest stop point.
204
+ const active = BUILD_STAGES.find((s) => prev.stageState[s] === "active") ?? BUILD_STAGES[0];
205
+ stageState = { ...prev.stageState, [active]: "fail" };
206
+ }
207
+ return {
208
+ ...prev,
209
+ liveLabel: result.ok ? "Done." : "Stopped.",
210
+ stageState,
211
+ terminal: true,
212
+ result,
213
+ };
214
+ }
215
+
216
+ return prev;
217
+ }
218
+
219
+ /** The human-readable failure detail (the honest reason), joined from errors/findings. */
220
+ export function buildFailureDetail(result: BuildResult): string {
221
+ const parts: string[] = [];
222
+ for (const e of result.errors ?? []) if (e && e.trim()) parts.push(e.trim());
223
+ if (result.error && result.error.trim()) parts.push(result.error.trim());
224
+ for (const f of result.findings ?? []) {
225
+ const line = [f.label || f.id, f.detail].filter(Boolean).join(": ");
226
+ if (line) parts.push((f.disposition === "blocking-safety" ? "[blocking] " : "") + line);
227
+ }
228
+ return parts.join("\n");
229
+ }
230
+
231
+ /**
232
+ * Assemble the "Copy for your AI agent" prompt from a build FAILURE — the honest,
233
+ * paste-ready brief an operator hands to a coding agent to diagnose why the preview
234
+ * build/checks failed. Mirrors the merge-conflict copy pattern (a framed ask + the
235
+ * system's own words), never a bare error dump.
236
+ */
237
+ export function assembleBuildFailureCopy(input: {
238
+ tenant: string;
239
+ prNumber?: number | null;
240
+ changeId?: string | null;
241
+ result: BuildResult;
242
+ }): string {
243
+ const { tenant, prNumber, changeId, result } = input;
244
+ const pr = prNumber != null ? `PR #${prNumber}` : changeId ? `change ${changeId}` : "my open candidate PR";
245
+ const stage = result.outcome === "blocked" ? "was blocked by a check" : "failed to build";
246
+ const detail = buildFailureDetail(result) || "(no detail was reported)";
247
+ return [
248
+ `In my ${tenant} store, the preview build for ${pr} ${stage}. ` +
249
+ `Diagnose why from the detail below, then tell me the exact file(s) to change and the fix.`,
250
+ "",
251
+ "What the build reported:",
252
+ detail,
253
+ "",
254
+ result.headSha ? `Head commit: ${result.headSha}` : "",
255
+ "Context: this is a Token of Trust storefront tenant repo — customization files are " +
256
+ "mapped to artifacts and validated against the tenant-editable manifest before the " +
257
+ "version is published. A blocking finding or a validation error stops the build.",
258
+ ]
259
+ .filter((l) => l !== "")
260
+ .join("\n");
261
+ }
262
+
263
+ function safeParse(text: string): unknown {
264
+ try {
265
+ return JSON.parse(text);
266
+ } catch {
267
+ return null;
268
+ }
269
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * r05 — persist each Publish-tab collapsible section's open/closed state per user,
3
+ * scoped per store so a power user's layout survives reloads without bleeding across
4
+ * stores. Pure key/read/write logic, extracted from the DOM wiring in
5
+ * `adminPublishTab.ts` so it is unit-testable and storage-agnostic.
6
+ *
7
+ * The persisted value is the human-legible "open"/"closed" (not a boolean string).
8
+ * `readPersistedOpen` returns `null` when nothing is stored (or storage is
9
+ * unreadable) — the caller then leaves the section at its SSR default, so the
10
+ * default open/closed state is preserved when a user has never toggled a section.
11
+ */
12
+
13
+ /** The slice of the Web Storage API this helper needs (localStorage satisfies it). */
14
+ export interface CollapseStorage {
15
+ getItem(key: string): string | null;
16
+ setItem(key: string, value: string): void;
17
+ }
18
+
19
+ /** Stable identifiers for the collapsible sections on the Publish tab. */
20
+ export type CollapseSectionId =
21
+ | "review-queue"
22
+ | "closed-changes"
23
+ | "next-release"
24
+ | "live-site"
25
+ | "rollback";
26
+
27
+ const KEY_PREFIX = "tot.publish.collapse";
28
+ const OPEN = "open";
29
+ const CLOSED = "closed";
30
+
31
+ /**
32
+ * Per-store, per-section storage key. The store scope (appDomain) keeps one store's
33
+ * layout from bleeding into another; an empty tenant collapses to a shared "_" scope
34
+ * rather than producing a dangling key.
35
+ */
36
+ export function collapseStorageKey(tenant: string, sectionId: CollapseSectionId): string {
37
+ return `${KEY_PREFIX}.${tenant || "_"}.${sectionId}`;
38
+ }
39
+
40
+ /**
41
+ * The stored open/closed state, or `null` when nothing is stored, the value is
42
+ * unrecognized, or storage throws (private mode / disabled). Never throws.
43
+ */
44
+ export function readPersistedOpen(
45
+ storage: CollapseStorage,
46
+ tenant: string,
47
+ sectionId: CollapseSectionId,
48
+ ): boolean | null {
49
+ let raw: string | null;
50
+ try {
51
+ raw = storage.getItem(collapseStorageKey(tenant, sectionId));
52
+ } catch {
53
+ return null;
54
+ }
55
+ if (raw === OPEN) return true;
56
+ if (raw === CLOSED) return false;
57
+ return null;
58
+ }
59
+
60
+ /** Persist a section's open/closed state. Swallows storage errors (never throws). */
61
+ export function writePersistedOpen(
62
+ storage: CollapseStorage,
63
+ tenant: string,
64
+ sectionId: CollapseSectionId,
65
+ open: boolean,
66
+ ): void {
67
+ try {
68
+ storage.setItem(collapseStorageKey(tenant, sectionId), open ? OPEN : CLOSED);
69
+ } catch {
70
+ /* storage unavailable (private mode / disabled) — persistence is best-effort */
71
+ }
72
+ }
@@ -1,11 +1,10 @@
1
1
  /**
2
- * Dispatch-health assessment (dg5) — is the static-publish `repository_dispatch`
2
+ * Dispatch-health assessment — is the static-publish `repository_dispatch`
3
3
  * path actually WIRED and HEALTHY, or would a "go-live" silently hand the publish
4
4
  * to a dead-end? The Worker fires a `repository_dispatch` and gets a 204 back
5
5
  * having verified NOTHING about the target (see `createRepositoryDispatchSink` —
6
6
  * it is fire-and-forget by construction). This module is the HONEST pre-flight
7
- * surface that answers, per binding decision `static-publish-fails-closed-
8
- * reviewed-sha`, whether that path can carry a publish at all — reporting each
7
+ * surface that answers whether that path can carry a publish at all — reporting each
9
8
  * concrete signal pass/fail/unknown with a reason, never a silent assumption.
10
9
  *
11
10
  * FOUR SIGNALS:
@@ -19,14 +18,13 @@
19
18
  * that lives only on the deploy branch is
20
19
  * NOT yet reachable. A 404 here is the
21
20
  * honest "not yet promoted to main" state
22
- * (the HELD main-promotion gate,
23
- * `pending-main-promotion-and-production-
24
- * publish-activation`) — surfaced, not papered.
21
+ * (the HELD main-promotion gate) —
22
+ * surfaced, not papered.
25
23
  * - `target-reachable` — does the published `live/manifest.json`
26
24
  * answer? DIAGNOSTIC ONLY: a pre-first-
27
25
  * publish target legitimately has none, so
28
26
  * this never blocks a ship (the post-merge
29
- * VERIFY in dg4's orchestrator is the real
27
+ * VERIFY in the orchestrator is the real
30
28
  * no-false-live gate).
31
29
  *
32
30
  * FAIL-CLOSED SEMANTICS:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Apex domain-connect state + dispatch (handoff 2026-08-05-domain-connect-ux).
2
+ * Apex domain-connect state + dispatch.
3
3
  *
4
4
  * The admin Publish tab's "Domain" section drives the apex DNS cutover
5
5
  * (tokenoftrust.com → CloudFront) and its rollback as PRODUCT actions, not a
@@ -212,8 +212,11 @@ export interface DomainRunCallback {
212
212
  * overwrite an existing pointer with null — the FIRST capture is
213
213
  * the true pre-platform state)
214
214
  * rollback → `pantheon`
215
- * Rehearsal (wire: dryRun) runs never move state — only the run outcome is
216
- * recorded.
215
+ * Rehearsal (wire: dryRun) runs never move `state`but a rehearsal CONNECT
216
+ * that reports a `priorKey` DOES record the revert target (prior-records pointer),
217
+ * because persisting a metadata capture mutates no live DNS, and it's what lets
218
+ * the apex-cutover readiness gate's "revert captured" precondition go green BEFORE
219
+ * the real cutover. Capturing the revert target is decoupled from moving state.
217
220
  */
218
221
  export function completeDomainRun(
219
222
  state: DomainState,
@@ -245,19 +248,25 @@ export function completeDomainRun(
245
248
  };
246
249
 
247
250
  let next: DomainState = { ...state, lastRun: updatedRun };
248
- if (cb.status === "succeeded" && !run.rehearsal) {
249
- const reported =
250
- cb.state === "cloudfront" || cb.state === "pantheon" ? cb.state : null;
251
- next = {
252
- ...next,
253
- state: reported ?? (run.action === "connect" ? "cloudfront" : "pantheon"),
254
- since: updatedRun.finishedAt,
255
- };
251
+ if (cb.status === "succeeded") {
252
+ // Platform state flips only on a REAL (non-rehearsal) run — a rehearsal
253
+ // changes no DNS, so it must never claim the apex moved.
254
+ if (!run.rehearsal) {
255
+ const reported =
256
+ cb.state === "cloudfront" || cb.state === "pantheon" ? cb.state : null;
257
+ next = {
258
+ ...next,
259
+ state: reported ?? (run.action === "connect" ? "cloudfront" : "pantheon"),
260
+ since: updatedRun.finishedAt,
261
+ };
262
+ }
263
+ // Capturing the revert target is DECOUPLED from moving state: any successful
264
+ // connect that carries a priorKey records it — a rehearsal included — so the
265
+ // readiness gate can confirm a tested rollback before the real cutover. Never
266
+ // regress an existing pointer to null (the FIRST capture is the true origin).
256
267
  if (run.action === "connect") {
257
268
  next = {
258
269
  ...next,
259
- // Keep the FIRST capture if the callback carries none — never regress
260
- // the pointer to null once a real capture exists.
261
270
  priorRecordsKey: cb.priorKey ?? state.priorRecordsKey,
262
271
  priorCapturedAt: cb.priorKey
263
272
  ? (cb.completedAt ?? at)