@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
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The no-secret-in-the-browser guard — charter invariant 3 (secrets, bindings,
3
+ * preview tokens, signed URLs, and raw PII never enter browser configuration)
4
+ * and ADR 0018 (a CSP nonce is per-response and never serialized).
5
+ *
6
+ * A secret field is made impossible two ways:
7
+ * 1. Every browser-facing contract is CLOSED (`rejectUnknownKeys`), so a field
8
+ * such as `nonce` is not in the schema and is rejected as unknown.
9
+ * 2. This scanner is defense-in-depth: any object about to cross into a
10
+ * serialized surface — evidence artifact, cache entry, log line, API
11
+ * response, or cross-request persistence — runs through
12
+ * `findForbiddenFields`, so a secret introduced by a nested or opaque value
13
+ * is caught even where the schema is open.
14
+ */
15
+ import type { ContractViolation } from "./result.js";
16
+ import { isPlainObject } from "./result.js";
17
+
18
+ /** Single-word key tokens that denote secret material. */
19
+ const FORBIDDEN_WORDS: readonly string[] = [
20
+ "nonce",
21
+ "token",
22
+ "secret",
23
+ "credential",
24
+ "bearer",
25
+ "password",
26
+ "passwd",
27
+ "passphrase",
28
+ "signature",
29
+ ];
30
+
31
+ /** Multi-word key forms (compared against the collapsed, tokenized key). */
32
+ const FORBIDDEN_COLLAPSED: readonly string[] = [
33
+ "signedurl",
34
+ "apikey",
35
+ "privatekey",
36
+ "sessionkey",
37
+ "accesskey",
38
+ "clientsecret",
39
+ "accesstoken",
40
+ "refreshtoken",
41
+ ];
42
+
43
+ function tokenize(key: string): string[] {
44
+ return key
45
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
46
+ .replace(/[_\-.$]/g, " ")
47
+ .toLowerCase()
48
+ .split(/\s+/)
49
+ .filter(Boolean);
50
+ }
51
+
52
+ /** True when a field name denotes a nonce, token, credential, or signed URL. */
53
+ export function isForbiddenKey(key: string): boolean {
54
+ const tokens = tokenize(key);
55
+ if (tokens.some((t) => FORBIDDEN_WORDS.includes(t))) return true;
56
+ const collapsed = tokens.join("");
57
+ return FORBIDDEN_COLLAPSED.some((c) => collapsed.includes(c));
58
+ }
59
+
60
+ /**
61
+ * Recursively report every field whose name denotes secret material. Returns an
62
+ * empty array for a browser-safe payload. Scans keys only; values are validated
63
+ * by field-level format checks (e.g. exact-origin CSP sources reject query-param
64
+ * signed URLs).
65
+ */
66
+ export function findForbiddenFields(value: unknown, path = ""): ContractViolation[] {
67
+ const out: ContractViolation[] = [];
68
+ walk(value, path, out);
69
+ return out;
70
+ }
71
+
72
+ function walk(value: unknown, path: string, out: ContractViolation[]): void {
73
+ if (Array.isArray(value)) {
74
+ value.forEach((item, i) => walk(item, `${path}[${i}]`, out));
75
+ return;
76
+ }
77
+ if (!isPlainObject(value)) return;
78
+ for (const [key, child] of Object.entries(value)) {
79
+ const childPath = path ? `${path}.${key}` : key;
80
+ if (isForbiddenKey(key)) {
81
+ out.push({
82
+ path: childPath,
83
+ code: "secret_field",
84
+ message:
85
+ `Field "${key}" names secret material; nonces, tokens, credentials, ` +
86
+ `signed URLs, and secrets must never appear in browser configuration, ` +
87
+ `effective plans, evidence, events, or assurance records.`,
88
+ });
89
+ }
90
+ walk(child, childPath, out);
91
+ }
92
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * The tamper-evidence beacon contract — the durable, secret-free record a
3
+ * protected-surface sentinel emits when it detects and recovers from third-party
4
+ * mutation of a platform-owned compliance/commerce surface (D-R7,
5
+ * `integration-protected-tamper-recovery`).
6
+ *
7
+ * This is the wire shape shared by the browser sentinel (which BUILDS and EMITS a
8
+ * beacon) and the server recovery path (which VALIDATES it, records it, and
9
+ * suspends the attributable integration). It is scoped to `tenant` + integration
10
+ * `attribution` (appId + version + origin) so a recovery action names exactly what
11
+ * to suspend.
12
+ *
13
+ * This is a DETECTIVE control. Full-parent DOM reach cannot be enforceably
14
+ * narrowed (WS2 security model), so a sentinel cannot PREVENT mutation — it
15
+ * detects it, restores safe state, and attributes it after the fact. The `control`
16
+ * field is the literal `"detective"` and the validator REJECTS any other value, so
17
+ * a beacon can never claim preventative isolation on the wire.
18
+ *
19
+ * Like every browser-facing contract here it is CLOSED and FAIL-CLOSED (unknown
20
+ * fields, unknown enum members, malformed shapes rejected) and secret-free
21
+ * (`findForbiddenFields`): a beacon carries structural facts about WHICH surface
22
+ * was tampered and HOW, never the altered copy itself, so no customer PII or
23
+ * secret can ride it.
24
+ */
25
+ import type { ContractResult } from "./result.js";
26
+ import {
27
+ Violations,
28
+ reqObject,
29
+ reqString,
30
+ reqEnum,
31
+ reqBool,
32
+ reqLiteral,
33
+ reqIsoTimestamp,
34
+ rejectUnknownKeys,
35
+ } from "./result.js";
36
+ import { TAMPER_EVIDENCE_SCHEMA_VERSION } from "./version.js";
37
+ import { INTEGRATION_ENVIRONMENTS, INTEGRATION_SITE_SURFACES } from "./environment.js";
38
+ import type { IntegrationEnvironment, IntegrationSiteSurface } from "./environment.js";
39
+ import { findForbiddenFields } from "./secrets.js";
40
+ import { PROTECTED_SURFACES, type ProtectedSurface } from "../compliance-obligations.js";
41
+
42
+ /**
43
+ * The one honest label for this class of control. A sentinel recovers safe state
44
+ * AFTER a mutation; it never prevents one. Any other value is rejected by
45
+ * {@link validateTamperEvidenceBeacon}, so "preventative"/"isolation" cannot be
46
+ * asserted on the wire.
47
+ */
48
+ export const TAMPER_CONTROL = "detective" as const;
49
+ export type TamperControl = typeof TAMPER_CONTROL;
50
+
51
+ /**
52
+ * The observed mutation classes a sentinel distinguishes. Every one is a DETECTED
53
+ * tamper that was RECOVERED; the taxonomy drives operator triage, not enforcement.
54
+ * - `removed` — the protected node was detached from the document.
55
+ * - `displaced` — a different node now claims the surface marker.
56
+ * - `listener-stripped` — the node was replaced by an identical-markup clone,
57
+ * dropping its event listeners.
58
+ * - `hidden` — visually suppressed (display/visibility/opacity/hidden/aria-hidden).
59
+ * - `overlaid` — a foreign covering element was inserted over the surface.
60
+ * - `text-altered` — the protected copy/state text was changed in place.
61
+ * - `subtree-mutated` — any other structural mutation within the surface.
62
+ */
63
+ export const TAMPER_KINDS = [
64
+ "removed",
65
+ "displaced",
66
+ "listener-stripped",
67
+ "hidden",
68
+ "overlaid",
69
+ "text-altered",
70
+ "subtree-mutated",
71
+ ] as const;
72
+ export type TamperKind = (typeof TAMPER_KINDS)[number];
73
+
74
+ /**
75
+ * The integration a tamper is attributed to — the exact `appId` + `version` +
76
+ * `origin` a recovery action suspends. `null` attribution is HONEST and expected:
77
+ * anonymous full-parent DOM reach cannot always be pinned to one integration, so
78
+ * an unattributable tamper is still detected, recovered, and alerted, but no
79
+ * specific integration is auto-suspended.
80
+ */
81
+ export interface TamperAttribution {
82
+ appId: string;
83
+ version: string;
84
+ origin: string;
85
+ }
86
+
87
+ /**
88
+ * The durable evidence a sentinel emits per detected+recovered tamper. Scoped to
89
+ * `tenant` + `attribution` (app/version) and stamped with `environment` +
90
+ * `siteSurface` so the record is unambiguous across tiers.
91
+ */
92
+ export interface TamperEvidenceBeacon {
93
+ schemaVersion: typeof TAMPER_EVIDENCE_SCHEMA_VERSION;
94
+ /** Always `"detective"` — see {@link TAMPER_CONTROL}. */
95
+ control: TamperControl;
96
+ tenant: string;
97
+ environment: IntegrationEnvironment;
98
+ siteSurface: IntegrationSiteSurface;
99
+ /** The platform-owned protected anchor (policy-04 `PROTECTED_SURFACES`) that was tampered. */
100
+ surface: ProtectedSurface;
101
+ kind: TamperKind;
102
+ /** ISO-8601 instant the tamper was detected. */
103
+ detectedAt: string;
104
+ /** True when the sentinel restored safe state (re-inspected clean after recovery). */
105
+ recovered: boolean;
106
+ /** The attributable integration, or `null` when the mutation is unattributable. */
107
+ attribution: TamperAttribution | null;
108
+ }
109
+
110
+ /** The fields a caller supplies to {@link buildTamperEvidenceBeacon}. */
111
+ export type TamperEvidenceInput = Omit<
112
+ TamperEvidenceBeacon,
113
+ "schemaVersion" | "control"
114
+ >;
115
+
116
+ /**
117
+ * Assemble a beacon with the fixed `schemaVersion` + `control` stamped. The only
118
+ * constructor — so a beacon can never be built claiming a non-detective control.
119
+ */
120
+ export function buildTamperEvidenceBeacon(
121
+ input: TamperEvidenceInput,
122
+ ): TamperEvidenceBeacon {
123
+ return {
124
+ schemaVersion: TAMPER_EVIDENCE_SCHEMA_VERSION,
125
+ control: TAMPER_CONTROL,
126
+ ...input,
127
+ };
128
+ }
129
+
130
+ function validateAttribution(value: unknown, v: Violations): void {
131
+ if (value === null) return;
132
+ const obj = reqObject(value, v, "attribution");
133
+ if (!obj) return;
134
+ rejectUnknownKeys(obj, ["appId", "version", "origin"], v, "attribution");
135
+ reqString(obj, "appId", v, "attribution");
136
+ reqString(obj, "version", v, "attribution");
137
+ reqString(obj, "origin", v, "attribution");
138
+ }
139
+
140
+ /**
141
+ * The single fail-CLOSED authority for "is this a well-formed tamper beacon?".
142
+ * Rejects an unknown schema version, a non-`detective` control (so no beacon can
143
+ * claim prevention), an unknown surface or kind, a malformed attribution, or any
144
+ * secret-bearing field. The server recovery path validates every inbound beacon
145
+ * through this before acting on it.
146
+ */
147
+ export function validateTamperEvidenceBeacon(
148
+ input: unknown,
149
+ ): ContractResult<TamperEvidenceBeacon> {
150
+ const v = new Violations();
151
+ const obj = reqObject(input, v, "");
152
+ if (!obj) return { ok: false, violations: v.items };
153
+
154
+ rejectUnknownKeys(
155
+ obj,
156
+ [
157
+ "schemaVersion",
158
+ "control",
159
+ "tenant",
160
+ "environment",
161
+ "siteSurface",
162
+ "surface",
163
+ "kind",
164
+ "detectedAt",
165
+ "recovered",
166
+ "attribution",
167
+ ],
168
+ v,
169
+ "",
170
+ );
171
+
172
+ reqLiteral(obj, "schemaVersion", TAMPER_EVIDENCE_SCHEMA_VERSION, v, "");
173
+ reqLiteral(obj, "control", TAMPER_CONTROL, v, "");
174
+ reqString(obj, "tenant", v, "");
175
+ reqEnum(obj, "environment", INTEGRATION_ENVIRONMENTS, v, "");
176
+ reqEnum(obj, "siteSurface", INTEGRATION_SITE_SURFACES, v, "");
177
+ reqEnum(obj, "surface", PROTECTED_SURFACES, v, "");
178
+ reqEnum(obj, "kind", TAMPER_KINDS, v, "");
179
+ reqIsoTimestamp(obj, "detectedAt", v, "");
180
+ reqBool(obj, "recovered", v, "");
181
+ if (!("attribution" in obj)) {
182
+ v.add("attribution", "type", 'Expected "attribution" to be an object or null.');
183
+ } else {
184
+ validateAttribution(obj["attribution"], v);
185
+ }
186
+
187
+ for (const violation of findForbiddenFields(obj)) v.items.push(violation);
188
+
189
+ if (!v.ok) return { ok: false, violations: v.items };
190
+ return { ok: true, value: input as TamperEvidenceBeacon };
191
+ }
192
+
193
+ /**
194
+ * Resolve attribution from the integrations that could be responsible. Anonymous
195
+ * DOM mutation carries no provenance, so attribution is the honest SOLE-SUSPECT
196
+ * rule: attribute to the one integration when exactly one is present, otherwise
197
+ * `null` (unattributable — recover + alert, but auto-suspend nothing). A caller
198
+ * that positively identifies the actor (e.g. an injected node carrying an
199
+ * integration's marker) resolves it directly instead of relying on this.
200
+ */
201
+ export function attributeSoleSuspect(
202
+ candidates: readonly TamperAttribution[],
203
+ ): TamperAttribution | null {
204
+ return candidates.length === 1 ? candidates[0]! : null;
205
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Edge recovery decisions for protected-surface tamper beacons (D-R7,
3
+ * `integration-protected-tamper-recovery`).
4
+ *
5
+ * The browser sentinel restores safe state IN the document and posts a
6
+ * {@link TamperEvidenceBeacon}. This is the trusted receiver's pure decision core:
7
+ * it VALIDATES the beacon fail-closed, turns it into a durable append-only
8
+ * {@link TamperEvidenceRecord}, and resolves the SUSPEND directive that disables the
9
+ * attributable integration's install. It is edge-safe (no Node) so the storefront
10
+ * Worker — where the beacon lands — can run it directly; the actuation (the actual
11
+ * registry suspend + audit write) belongs to the caller.
12
+ *
13
+ * This is a DETECTIVE control. Suspension happens AFTER a detected+recovered tamper,
14
+ * keyed on the beacon's `attribution` (appId + version), and is deliberately
15
+ * conservative: it suspends only when exactly one ACTIVE install matches. An
16
+ * unattributable beacon, or an ambiguous match, records the evidence and alerts but
17
+ * suspends nothing — recovery never suspends the wrong app.
18
+ */
19
+ import type { ContractViolation } from "./result.js";
20
+ import {
21
+ validateTamperEvidenceBeacon,
22
+ type TamperEvidenceBeacon,
23
+ } from "./tamper-evidence.js";
24
+
25
+ /** The minimal install facts suspension resolution needs (the registry row projection). */
26
+ export interface AttributableInstall {
27
+ installId: string;
28
+ appId: string;
29
+ appVersion: string;
30
+ status: "active" | "suspended" | "uninstalled";
31
+ }
32
+
33
+ /** The durable, append-only record a validated beacon becomes on the server. */
34
+ export interface TamperEvidenceRecord {
35
+ recordId: string;
36
+ /** ISO instant the server received the beacon. */
37
+ receivedAt: string;
38
+ beacon: TamperEvidenceBeacon;
39
+ }
40
+
41
+ /** The suspension a recovery drives — names exactly one install to disable. */
42
+ export interface SuspendDirective {
43
+ installId: string;
44
+ appId: string;
45
+ version: string;
46
+ reason: string;
47
+ }
48
+
49
+ export interface TamperRecoveryPlan {
50
+ record: TamperEvidenceRecord;
51
+ /** The install to suspend, or `null` when unattributable / no single active match. */
52
+ suspend: SuspendDirective | null;
53
+ /** Always true — every detected tamper is surfaced to operations. */
54
+ alert: boolean;
55
+ }
56
+
57
+ export type TamperRecoveryResult =
58
+ | { ok: true; plan: TamperRecoveryPlan }
59
+ | { ok: false; violations: ContractViolation[] };
60
+
61
+ export interface PlanTamperRecoveryOptions {
62
+ recordId: string;
63
+ /** ISO server receive time; passed in so the record is deterministic/testable. */
64
+ receivedAt: string;
65
+ }
66
+
67
+ /**
68
+ * Resolve which install to suspend for a beacon, or `null`. Fail-SAFE: suspends
69
+ * only when the beacon is attributed AND exactly one ACTIVE install matches that
70
+ * app id and version. Zero matches, an already-suspended/uninstalled install, or an
71
+ * ambiguous multi-match resolves to `null` — the evidence still stands, but no app
72
+ * is auto-suspended on a guess.
73
+ */
74
+ export function resolveSuspendTarget(
75
+ beacon: TamperEvidenceBeacon,
76
+ installs: readonly AttributableInstall[],
77
+ ): SuspendDirective | null {
78
+ const attribution = beacon.attribution;
79
+ if (!attribution) return null;
80
+
81
+ const matches = installs.filter(
82
+ (i) =>
83
+ i.status === "active" &&
84
+ i.appId === attribution.appId &&
85
+ i.appVersion === attribution.version,
86
+ );
87
+ if (matches.length !== 1) return null;
88
+
89
+ const install = matches[0]!;
90
+ return {
91
+ installId: install.installId,
92
+ appId: attribution.appId,
93
+ version: attribution.version,
94
+ reason: `Detective tamper recovery: integration mutated the protected "${beacon.surface}" surface (${beacon.kind}); auto-suspended.`,
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Validate an inbound beacon and produce the recovery plan: a durable evidence
100
+ * record, the (optional) suspend directive, and the always-on alert. Returns the
101
+ * structured violations on a malformed/secret-bearing/non-detective beacon so the
102
+ * caller can 400 it rather than act on unvalidated input.
103
+ */
104
+ export function planTamperRecovery(
105
+ rawBeacon: unknown,
106
+ installs: readonly AttributableInstall[],
107
+ opts: PlanTamperRecoveryOptions,
108
+ ): TamperRecoveryResult {
109
+ const validated = validateTamperEvidenceBeacon(rawBeacon);
110
+ if (!validated.ok) return { ok: false, violations: validated.violations };
111
+
112
+ const beacon = validated.value;
113
+ const record: TamperEvidenceRecord = {
114
+ recordId: opts.recordId,
115
+ receivedAt: opts.receivedAt,
116
+ beacon,
117
+ };
118
+
119
+ return {
120
+ ok: true,
121
+ plan: {
122
+ record,
123
+ suspend: resolveSuspendTarget(beacon, installs),
124
+ alert: true,
125
+ },
126
+ };
127
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Semver-versioned browser-integration contract (ADR 0006).
3
+ *
4
+ * The browser contract carries a single MAJOR.MINOR.PATCH version. A manifest
5
+ * declares the range it supports in `compatibility.storefrontBrowserContract`;
6
+ * compatibility is resolved fail-closed — an unparseable range, or a current
7
+ * contract version outside the range, is rejected rather than assumed
8
+ * compatible.
9
+ *
10
+ * Each payload family additionally pins an integer `schemaVersion`. Unknown
11
+ * schema versions fail closed.
12
+ */
13
+
14
+ export const BROWSER_INTEGRATION_CONTRACT_VERSION = "2.0.0" as const;
15
+
16
+ export const ENVIRONMENT_SCHEMA_VERSION = 1 as const;
17
+ export const INTEGRATION_MANIFEST_SCHEMA_VERSION = 2 as const;
18
+ export const EFFECTIVE_PLAN_SCHEMA_VERSION = 1 as const;
19
+ export const COMMERCE_EVENT_STOREFRONT_SCHEMA_VERSION = 1 as const;
20
+ export const CONSENT_SNAPSHOT_SCHEMA_VERSION = 1 as const;
21
+ export const RECEIPT_MEASUREMENT_GRANT_SCHEMA_VERSION = 1 as const;
22
+ export const CONSENT_CONFIG_SCHEMA_VERSION = 1 as const;
23
+ export const ASSURANCE_RECORD_SCHEMA_VERSION = 1 as const;
24
+ export const TAMPER_EVIDENCE_SCHEMA_VERSION = 1 as const;
25
+ export const OBSERVABILITY_SIGNAL_SCHEMA_VERSION = 1 as const;
26
+
27
+ export interface SemVer {
28
+ major: number;
29
+ minor: number;
30
+ patch: number;
31
+ }
32
+
33
+ export function parseSemVer(input: string): SemVer | null {
34
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(input.trim());
35
+ if (!match) return null;
36
+ return {
37
+ major: Number(match[1]),
38
+ minor: Number(match[2]),
39
+ patch: Number(match[3]),
40
+ };
41
+ }
42
+
43
+ export function compareSemVer(a: SemVer, b: SemVer): number {
44
+ if (a.major !== b.major) return a.major < b.major ? -1 : 1;
45
+ if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;
46
+ if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;
47
+ return 0;
48
+ }
49
+
50
+ type Comparator = ">=" | "<=" | ">" | "<" | "=";
51
+
52
+ function satisfiesComparator(version: SemVer, op: Comparator, target: SemVer): boolean {
53
+ const cmp = compareSemVer(version, target);
54
+ switch (op) {
55
+ case ">=":
56
+ return cmp >= 0;
57
+ case "<=":
58
+ return cmp <= 0;
59
+ case ">":
60
+ return cmp > 0;
61
+ case "<":
62
+ return cmp < 0;
63
+ case "=":
64
+ return cmp === 0;
65
+ }
66
+ }
67
+
68
+ /**
69
+ * True only when `version` satisfies every space-separated comparator in
70
+ * `range` (AND semantics), e.g. `>=1.0.0 <2.0.0`. A bare version means `=`.
71
+ * Any unparseable comparator makes the whole range unsatisfied (fail closed).
72
+ */
73
+ export function satisfiesRange(version: string, range: string): boolean {
74
+ const parsed = parseSemVer(version);
75
+ if (!parsed) return false;
76
+ const parts = range.trim().split(/\s+/).filter(Boolean);
77
+ if (parts.length === 0) return false;
78
+ for (const part of parts) {
79
+ const match = /^(>=|<=|>|<|=)?(\d+\.\d+\.\d+)$/.exec(part);
80
+ if (!match) return false;
81
+ const target = parseSemVer(match[2] ?? "");
82
+ if (!target) return false;
83
+ const op = (match[1] ?? "=") as Comparator;
84
+ if (!satisfiesComparator(parsed, op, target)) return false;
85
+ }
86
+ return true;
87
+ }
88
+
89
+ /** Whether the current browser contract version satisfies a manifest's declared range. */
90
+ export function isCompatibleWithCurrentContract(range: string): boolean {
91
+ return satisfiesRange(BROWSER_INTEGRATION_CONTRACT_VERSION, range);
92
+ }