@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
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Canonical admin tenant-landing decision (pure).
3
+ *
4
+ * The admin console is Host-routed: each tenant's admin lives at that tenant's
5
+ * host (or the DNS-free `/<tenant>/admin` path form). "Which tenant" is therefore
6
+ * carried by the URL, never inferred from an ambient global. The ambiguity this
7
+ * module resolves is the ONE case the URL alone can't settle: an authenticated
8
+ * viewer who lands on the admin of a tenant they are NOT a member of — because
9
+ * they followed a stale/shared deep link, or the host fell back to the registry
10
+ * default tenant. The wrong answers are (a) bounce them to /auth/login even though
11
+ * they hold a valid session (a sign-in loop), or (b) silently show them the wrong
12
+ * tenant's data. The canonical answer:
13
+ *
14
+ * - member/owner/staff of the routed tenant → ENTER (render admin here).
15
+ * - no session → LOGIN (gate, `next` preserved).
16
+ * - authed, not here, exactly ONE tenant → AUTO (their sole tenant's /admin).
17
+ * - authed, not here, zero OR many tenants → SELECT (the /admin/select picker;
18
+ * the page differentiates 0 vs many).
19
+ *
20
+ * PURE (no I/O, no Astro): it COMPOSES `sessionAdmitsHost` (the host-bound
21
+ * admission the middleware gate already uses) and `selectTenant` (the vendor
22
+ * single-vs-picker rule) so the console, the gate, and this landing can never
23
+ * drift on "does this viewer belong to this tenant". Unit-testable in isolation.
24
+ */
25
+ import type { SessionRecord } from "./session.js";
26
+ import { sessionAdmitsHost } from "./loginGate.js";
27
+ import { safeNext } from "./route.js";
28
+ import { selectTenant } from "@/lib/dashboard/tenantSelection";
29
+
30
+ /** The tenant-selection surface, in both host-routed and tenant-first path forms. */
31
+ export function isAdminSelectPath(pathname: string): boolean {
32
+ if (pathname === "/admin/select") return true;
33
+ return /^\/[^/]+\/admin\/select$/.test(pathname);
34
+ }
35
+
36
+ /**
37
+ * The DNS-free path-form URL of a tenant's admin on the current host. A leading
38
+ * `/<resource>/` segment middleware-selects that tenant regardless of which host
39
+ * the request arrived on, so this reaches ANOTHER tenant's admin from here.
40
+ */
41
+ export function adminUrlForTenant(resource: string): string {
42
+ return `/${resource.trim()}/admin`;
43
+ }
44
+
45
+ export type AdminLanding =
46
+ | { action: "enter" }
47
+ | { action: "login"; location: string }
48
+ | { action: "auto"; location: string }
49
+ | { action: "select"; location: string };
50
+
51
+ export interface AdminLandingInput {
52
+ /** The viewer's full session (all memberships), or null when unauthenticated. */
53
+ record: SessionRecord | null | undefined;
54
+ /** The Host-resolved tenant's appDomain (server-derived, never client input). */
55
+ routedTenant: string;
56
+ /** locals.basePath: "" (host-form) or "/<domain>" (tenant-first path form). */
57
+ basePath: string;
58
+ /** The intended admin destination (`pathname + search`), preserved as `next`. */
59
+ intended: string;
60
+ /** Epoch seconds, for the staff-selection expiry check. */
61
+ nowSeconds: number;
62
+ }
63
+
64
+ export function resolveAdminLanding(input: AdminLandingInput): AdminLanding {
65
+ const { record, routedTenant, basePath, intended, nowSeconds } = input;
66
+
67
+ if (!record) {
68
+ const next = encodeURIComponent(safeNext(intended));
69
+ return { action: "login", location: `/auth/login?next=${next}` };
70
+ }
71
+
72
+ // Member/owner of the routed tenant, or a ToT-staff viewer → this IS their
73
+ // admin context. Identical admission to the middleware gate, by construction.
74
+ if (sessionAdmitsHost(record, routedTenant, nowSeconds)) {
75
+ return { action: "enter" };
76
+ }
77
+
78
+ // Authenticated, but with no standing for the routed tenant. Route them to
79
+ // their OWN tenant(s) rather than the wrong one or a sign-in loop. A sole
80
+ // membership auto-selects; zero or several go to the picker (which honestly
81
+ // renders "nothing to manage" for zero).
82
+ const selection = selectTenant(record.tenants);
83
+ const selectLocation = `${basePath || ""}/admin/select`;
84
+ if (selection.mode === "single") {
85
+ return { action: "auto", location: adminUrlForTenant(selection.tenant.resource) };
86
+ }
87
+ return { action: "select", location: selectLocation };
88
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Offline verification of tot's identity assertion (`id_token`) — the consuming
3
- * half of the decoupled-authZ architecture (Phase 3).
3
+ * half of the decoupled-authZ architecture.
4
4
  *
5
5
  * tot signs a short-lived ES256 assertion ONCE at sign-in with its PRIVATE key
6
6
  * (`/api/internal/access-code/verify` → `id_token`). This module verifies it
@@ -10,20 +10,12 @@
10
10
  * after sign-in must not break authorization; the token's own `exp` bounds
11
11
  * staleness.
12
12
  *
13
- * This mirrors the Phase-2 launchpad kernel's lightweight offline verifier
14
- * (`launchpad src/modules/authz/jwks-verifier.ts` + `identity-claims.ts`) and the
15
- * tot-internal verify path proven in
16
- * `tot20 services/InternalAuthService/identityTokenService.jest.js`.
13
+ * SCOPE: this does ONLY the JWKS offline-verify + a coarse claims→session
14
+ * derivation. Do NOT vendor the Cedar-wasm PDP into the Worker; it is
15
+ * unnecessary for the current coarse gate.
17
16
  *
18
- * PROTOTYPE SCOPE: this replicates ONLY the JWKS offline-verify + a coarse
19
- * claims→session derivation. The full Cedar PDP (`can()` policy engine, staff
20
- * sandbox) and consuming the launchpad kernel as an installed package are
21
- * Phase 4 — see branch `feat/authz-cedar-kernel`. Do NOT vendor the Cedar-wasm
22
- * PDP into the Worker; it is unnecessary for the current coarse gate.
23
- *
24
- * Contract: /tmp/authz-token-claims-contract.md (AS-BUILT). Key points mirrored
25
- * here: §2 (ES256 + jose), §3 (claim set), §5 (consumer verify algorithm),
26
- * §6 (field name `id_token`), §6b (JWKS host is per-env app config; jose
17
+ * Contract points as-built: ES256 + jose, the claim set, the consumer verify
18
+ * algorithm, field name `id_token`, and JWKS host is per-env app config (jose
27
19
  * cross-version 4↔6 is wire-compatible by construction).
28
20
  */
29
21
  import {
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Login-gate decision (pure) — the "Sign in with ToT" enforcement mode for a
3
- * gated demo host, the eventual replacement for the interim Basic-Auth password
4
- * (see `@/lib/demoGate`). Same `DEMO_GATE_HOSTS` list, switched by `DEMO_GATE_MODE`:
3
+ * gated demo host (see `@/lib/demoGate`). Same `DEMO_GATE_HOSTS` list, switched
4
+ * by `DEMO_GATE_MODE`:
5
5
  *
6
- * DEMO_GATE_MODE = "password" → interim Basic-Auth gate (evaluateDemoGate)
6
+ * DEMO_GATE_MODE = "password" → Basic-Auth gate (evaluateDemoGate)
7
7
  * DEMO_GATE_MODE = "login" → this: redirect to /auth/login unless a valid,
8
8
  * resource-bound tot_session cookie is present.
9
9
  *
@@ -29,7 +29,7 @@ export const PUBLIC_HOME_TENANT_ID = "home";
29
29
 
30
30
  /**
31
31
  * The record fields the host-admission + host-capability checks read. All optional
32
- * — these readers tolerate a partial/legacy record and are deny-closed on absence.
32
+ * — these readers tolerate a partial record and are deny-closed on absence.
33
33
  */
34
34
  type HostAdmissionRecord = Partial<
35
35
  Pick<SessionRecord, "tenants" | "staffSelection" | "staff" | "resource" | "capability">
@@ -144,6 +144,18 @@ export function isPublicPath(pathname: string): boolean {
144
144
  return pathname === "/api/cli/policy";
145
145
  }
146
146
 
147
+ /**
148
+ * The authenticated static-bundle staging upload (`/api/publish/stage-bundle`).
149
+ * Like the candidate-preview control plane, it governs its OWN, stricter auth (a
150
+ * CI `private_key_jwt` assertion — see `@/lib/publish/stageBundleUpload`), so it
151
+ * must reach its handler server-to-server rather than being masked behind the
152
+ * demo login gate's "Coming soon" holding page. Gate-exemption does NOT weaken
153
+ * it: an unauthenticated request still gets a 401 from the route's own check.
154
+ */
155
+ export function isStaticBundleUploadPath(pathname: string): boolean {
156
+ return pathname === "/api/publish/stage-bundle";
157
+ }
158
+
147
159
  /**
148
160
  * The candidate-preview CONTROL-PLANE routes — the per-change hosted review
149
161
  * surfaces that carry their OWN, stricter auth (the cockpit gate: signed-in +
@@ -158,20 +170,56 @@ export function isPublicPath(pathname: string): boolean {
158
170
  * blocker naming the head SHA), never a misleading "Coming soon". A demo BROWSE of
159
171
  * the tenant's own pages stays gated as before.
160
172
  *
161
- * Matched (prefix, so sub-paths are covered):
162
- * /preview/render/<tenant>/<changeId>/... the candidate content renderer (s4)
163
- * /preview/change/<changeId> the per-change review dashboard (s5)
164
- * /preview/<tenant>/pr/<n> the friendly PR-number alias (u4)
165
- * /preview/<tenant>/rev/<sha>/... the immutable per-revision renderer (u4)
173
+ * Matched (prefix, so sub-paths are covered). The PR/rev aliases are tenant-first
174
+ * (`/<tenant>/preview/...`, the leading segment middleware-selects the tenant),
175
+ * matched here on the pre-strip request path:
176
+ * /preview/render/<tenant>/<changeId>/... the candidate content renderer
177
+ * /preview/change/<changeId> the per-change review dashboard
178
+ * /<tenant>/preview/pr/<n> the friendly PR-number alias
179
+ * /<tenant>/preview/rev/<sha>/... the immutable per-revision renderer
166
180
  */
167
181
  export function isCandidatePreviewPath(pathname: string): boolean {
168
182
  if (pathname.startsWith("/preview/render/")) return true;
169
183
  if (pathname === "/preview/change" || pathname.startsWith("/preview/change/")) return true;
170
- // /preview/<tenant>/pr and /preview/<tenant>/pr/<n> — the PR-number alias.
171
- if (/^\/preview\/[^/]+\/pr(?:\/|$)/.test(pathname)) return true;
172
- // /preview/<tenant>/rev/<sha> and /preview/<tenant>/rev/<sha>/<path...> — the
184
+ // /<tenant>/preview/pr and /<tenant>/preview/pr/<n> — the PR-number alias.
185
+ if (/^\/[^/]+\/preview\/pr(?:\/|$)/.test(pathname)) return true;
186
+ // /<tenant>/preview/rev/<sha> and /<tenant>/preview/rev/<sha>/<path...> — the
173
187
  // immutable per-revision alias.
174
- return /^\/preview\/[^/]+\/rev(?:\/|$)/.test(pathname);
188
+ return /^\/[^/]+\/preview\/rev(?:\/|$)/.test(pathname);
189
+ }
190
+
191
+ /**
192
+ * Admin surfaces, in BOTH the bare host-routed form (`/admin`, `/admin/...`) and
193
+ * the tenant-first path form (`/<tenant>/admin`, `/<tenant>/admin/...`, where the
194
+ * leading segment middleware-selects the tenant). Admin reuses the same
195
+ * loginGate/sessionAdmitsHost mechanism as public content — there is no separate
196
+ * password layer — so this predicate is what keeps the QA content bypass from ever
197
+ * reaching admin: /admin ALWAYS requires a real, valid session.
198
+ */
199
+ export function isAdminPath(pathname: string): boolean {
200
+ if (pathname === "/admin" || pathname.startsWith("/admin/")) return true;
201
+ return /^\/[^/]+\/admin(?:\/|$)/.test(pathname);
202
+ }
203
+
204
+ /**
205
+ * Paths the QA content bypass must NEVER cover — everything privileged or
206
+ * state-mutating. The bypass is a convenience for browsing public tenant content
207
+ * (product/marketing pages) only; these fail toward requiring a real session:
208
+ * - admin ({@link isAdminPath}) — the hard security requirement.
209
+ * - the cockpit control-plane (`/cockpit`, `/<tenant>/cockpit`) and its `/dev`
210
+ * redirect alias.
211
+ * - every `/api/` route (tenant-state mutation). Genuinely-public API endpoints
212
+ * are already gate-exempt via {@link isPublicPath}/{@link isAuthPath}, so
213
+ * excluding all of `/api/` here costs nothing and fails safe.
214
+ */
215
+ export function isBypassPrivilegedPath(pathname: string): boolean {
216
+ if (isAdminPath(pathname)) return true;
217
+ if (pathname === "/cockpit" || pathname.startsWith("/cockpit/")) return true;
218
+ if (/^\/[^/]+\/cockpit(?:\/|$)/.test(pathname)) return true;
219
+ if (pathname === "/dev" || pathname.startsWith("/dev/")) return true;
220
+ if (/^\/[^/]+\/dev(?:\/|$)/.test(pathname)) return true;
221
+ if (pathname === "/api" || pathname.startsWith("/api/")) return true;
222
+ return false;
175
223
  }
176
224
 
177
225
  export type LoginGateDecision =
@@ -192,6 +240,14 @@ export interface LoginGateInput {
192
240
  * exempt from the gate so it renders publicly. See {@link PUBLIC_HOME_TENANT_ID}.
193
241
  */
194
242
  tenantExempt?: boolean;
243
+ /**
244
+ * True when the request presented the server-configured QA bypass token (see
245
+ * `DEMO_GATE_BYPASS_TOKEN` in middleware). Only ever set in a QA/test deploy — an
246
+ * unset server token leaves it false, so this is fully inert by default. Passes
247
+ * the gate for PUBLIC CONTENT paths only; {@link isBypassPrivilegedPath} paths
248
+ * (admin, cockpit, /api) are never bypassed regardless of this flag.
249
+ */
250
+ qaBypass?: boolean;
195
251
  }
196
252
 
197
253
  /**
@@ -208,6 +264,12 @@ export function evaluateLoginGate(input: LoginGateInput): LoginGateDecision {
208
264
  // Candidate-preview control-plane routes govern their OWN (stricter, honest) auth
209
265
  // and must never fall to the "Coming soon" holding page for a real candidate.
210
266
  if (isCandidatePreviewPath(input.pathname)) return { action: "pass" };
267
+ // The static-bundle staging upload carries its own private_key_jwt auth.
268
+ if (isStaticBundleUploadPath(input.pathname)) return { action: "pass" };
269
+ // QA content-bypass: a request presenting the server-configured token passes for
270
+ // public content only. NEVER for admin/cockpit/api — that guard lives here (not
271
+ // just in middleware) so /admin stays gated even if the flag is set upstream.
272
+ if (input.qaBypass && !isBypassPrivilegedPath(input.pathname)) return { action: "pass" };
211
273
  if (input.hasValidSession) return { action: "pass" };
212
274
  const next = input.pathname + (input.search ?? "");
213
275
  return { action: "redirect", location: `/auth/login?next=${encodeURIComponent(next)}` };
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * MCP client-assertion MINTER + signing-key loader — the storefront half of the
3
- * "MCP machine identity" contract (workstream `mcp-machine-identity`, unit B1
4
- * `sf-client-assertion`).
3
+ * "MCP machine identity" contract.
5
4
  *
6
5
  * The deployed storefront Worker is a browserless, multi-tenant service with no
7
6
  * human in the loop. It authenticates to the MCP's `client_credentials` grant
@@ -10,8 +9,7 @@
10
9
  * it holds `MCP_CLIENT_ASSERTION_PRIVATE_KEY_B64`, and the MCP verifies the
11
10
  * signature against storefront's PUBLISHED public key (fetched by `kid` from the
12
11
  * JWKS this module derives — see `loadMcpClientAssertionJwks` + the sibling
13
- * `.well-known/mcp-client-jwks.json` route, binding decision
14
- * `c0-client-key-resolution`).
12
+ * `.well-known/mcp-client-jwks.json` route).
15
13
  *
16
14
  * Claims (RFC 7523 §3): `iss = sub = client_id`, `aud = <mcp token endpoint>`,
17
15
  * `exp ~= iat + 60s`, a fresh `jti` every call (one-time-use, verified server-side
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Shared machinery for storefront's two-path operator-session resolvers: a
3
+ * signed-in host-bound tenant viewer (path 1), else a Bearer operator secret
4
+ * (path 2), fail-closed if neither validates. The grants owner session
5
+ * (`../grants/session.ts`) and the Private Apps admin session
6
+ * (`../apps/adminSession.ts`) are both configured from these primitives, so the
7
+ * fail-closed ordering and the host-bound tenant derivation live in ONE audited
8
+ * place. Each resolver supplies only what genuinely differs — the result shape,
9
+ * the Bearer secret/env sourcing, the operator-capability set, and how a present
10
+ * viewer that lacks that capability is treated.
11
+ */
12
+ import type { APIContext } from "astro";
13
+
14
+ /** The host-bound viewer chrome the middleware sets on `locals.viewer`. */
15
+ type Viewer = NonNullable<APIContext["locals"]["viewer"]>;
16
+
17
+ /** The fail-closed shape both resolvers share for a refused session. */
18
+ export type SessionFailure = { ok: false; status: number; message: string };
19
+
20
+ /** Pure inputs to the Bearer-fallback authorization decision (env + request, no I/O). */
21
+ export interface BearerOperatorInput {
22
+ /** The request `Authorization` header, if any. */
23
+ authHeader: string | null;
24
+ /** The configured operator gate secret (or undefined if unconfigured). */
25
+ gateSecret: string | undefined;
26
+ /** Server-configured principal for this deployment, preferred over the header. */
27
+ configuredPrincipal: string | undefined;
28
+ /** Requested-principal header — honoured ONLY once the Bearer authenticates. */
29
+ requestedPrincipal: string | null;
30
+ /** 503 message when the gate secret is unconfigured. */
31
+ unconfiguredMessage: string;
32
+ /** 400 message when no principal can be resolved. */
33
+ unresolvedMessage: string;
34
+ }
35
+
36
+ export type BearerOperatorResult = { ok: true; principal: string } | SessionFailure;
37
+
38
+ /**
39
+ * The fail-closed Bearer-operator core, with NO I/O — unit-testable. The
40
+ * ordering is the security contract: unconfigured gate → 503, bad/absent Bearer
41
+ * → 401 (BEFORE any principal is read, so a bare caller cannot target another
42
+ * tenant by naming it in the requested-principal header), no resolvable
43
+ * principal → 400. The server-configured principal is preferred over the
44
+ * request header so a single-principal deploy cannot be redirected cross-tenant.
45
+ */
46
+ export function authorizeBearerOperator(
47
+ input: BearerOperatorInput,
48
+ ): BearerOperatorResult {
49
+ if (!input.gateSecret) {
50
+ return { ok: false, status: 503, message: input.unconfiguredMessage };
51
+ }
52
+ if (input.authHeader !== `Bearer ${input.gateSecret}`) {
53
+ return { ok: false, status: 401, message: "Unauthorized" };
54
+ }
55
+ const principal = (
56
+ input.configuredPrincipal ??
57
+ input.requestedPrincipal ??
58
+ ""
59
+ ).trim();
60
+ if (!principal) {
61
+ return { ok: false, status: 400, message: input.unresolvedMessage };
62
+ }
63
+ return { ok: true, principal };
64
+ }
65
+
66
+ /**
67
+ * How to treat a signed-in viewer that IS present on the resolved host but lacks
68
+ * an operator capability. The two resolvers deliberately differ here:
69
+ * - `fallThrough` — continue to the Bearer gate (grants' owner session), so a
70
+ * lower-capability viewer that also presents a valid operator secret is
71
+ * admitted via path 2 exactly as an unauthenticated headless caller is.
72
+ * - `failClosed` — return the supplied 403 and do NOT consult the Bearer gate
73
+ * (apps admin session), so an authenticated-but-insufficient viewer is never
74
+ * silently admitted by a secret it happens to also present.
75
+ */
76
+ export type InsufficientCapabilityPolicy =
77
+ | { mode: "fallThrough" }
78
+ | { mode: "failClosed"; failure: SessionFailure };
79
+
80
+ export interface HostBoundSessionConfig<T> {
81
+ /** Capabilities that make a host-bound viewer an operator for their tenant. */
82
+ capabilities: ReadonlySet<string>;
83
+ /** How to treat a present-but-insufficient viewer (see the type). */
84
+ onInsufficientCapability: InsufficientCapabilityPolicy;
85
+ /** Build the success result from the authorized viewer + resolved host appDomain. */
86
+ resolveViewer: (viewer: Viewer, tenant: string) => Promise<T> | T;
87
+ /** The Bearer path (path 2), consulted whenever path 1 does not resolve. */
88
+ resolveBearer: (context: APIContext) => Promise<T | SessionFailure>;
89
+ }
90
+
91
+ /**
92
+ * Two-path host-bound operator session: a signed-in `locals.viewer` on the
93
+ * middleware-resolved `locals.tenant` (path 1), else the Bearer gate (path 2).
94
+ * The tenant is ALWAYS the resolved host `appDomain` — never the request body.
95
+ * When no viewer/tenant pair is present, or a present viewer is insufficient
96
+ * under a `fallThrough` policy, path 2 decides.
97
+ */
98
+ export async function resolveHostBoundSession<T>(
99
+ context: APIContext,
100
+ config: HostBoundSessionConfig<T>,
101
+ ): Promise<T | SessionFailure> {
102
+ const viewer = context.locals?.viewer;
103
+ const tenant = context.locals?.tenant?.appDomain;
104
+ if (viewer && tenant) {
105
+ if (config.capabilities.has(viewer.capability)) {
106
+ return config.resolveViewer(viewer, tenant);
107
+ }
108
+ if (config.onInsufficientCapability.mode === "failClosed") {
109
+ return config.onInsufficientCapability.failure;
110
+ }
111
+ }
112
+ return config.resolveBearer(context);
113
+ }
@@ -20,7 +20,7 @@ export const SESSION_COOKIE = "tot_session";
20
20
 
21
21
  /**
22
22
  * A ToT-staff viewer's ACTIVE vendor selection — the two-phase-admission marker
23
- * (#8425 staff cross-vendor access). This is a DISTINCT access path from
23
+ * for staff cross-vendor access. This is a DISTINCT access path from
24
24
  * `tenants[]`: a staff user isn't a member of a bounded set of vendors, so we
25
25
  * NEVER synthesize a `tenants[]` entry for them. Instead, after the staff viewer
26
26
  * explicitly searches + enters a vendor and tot20's `staffVendorAccess` writes
@@ -43,25 +43,24 @@ export const DEFAULT_SESSION_TTL_SECONDS = 7 * 24 * 3600;
43
43
  /**
44
44
  * What we know about a signed-in viewer.
45
45
  *
46
- * Phase 3: `email`/`resource`/`roles`/`capability` are now derived from tot's
46
+ * `email`/`resource`/`roles`/`capability` are derived from tot's
47
47
  * OFFLINE-VERIFIED `id_token` claims (see `@/lib/auth/identityToken`
48
48
  * `sessionFromClaims`), not from trusting tot's flat `/verify` JSON. `capability`
49
49
  * is the coarse standing on `resource` (owner|admin|member). `tenants`/`staff`
50
- * are the multi-tenant claims carried in the verified token (present when the
51
- * session was minted via the Phase-3 path; optional for backward compatibility).
50
+ * are the multi-tenant claims carried in the verified token.
52
51
  */
53
52
  export interface SessionRecord {
54
53
  /** Verified email (lowercased) — the principal that passed the grant check. */
55
54
  email: string;
56
55
  /** The resource (appDomain/tenant, e.g. "sample-store.example") this session authorizes. */
57
56
  resource: string;
58
- /** Display roles for `resource` (Phase 3: the coarse role from verified claims). */
57
+ /** Display roles for `resource` (the coarse role from verified claims). */
59
58
  roles: string[];
60
- /** Coarse capability on `resource` (owner|admin|member; legacy: developer|inviter|staff|none). */
59
+ /** Coarse capability on `resource` (owner|admin|member). */
61
60
  capability: string;
62
- /** All tenant memberships from the verified assertion (policy input). Phase-3 path only. */
61
+ /** All tenant memberships from the verified assertion (policy input). */
63
62
  tenants?: { resource: string; role: string }[];
64
- /** ToT-staff scope from the verified assertion (sandboxed; grants nothing today). Phase-3 path only. */
63
+ /** ToT-staff scope from the verified assertion (sandboxed; grants nothing). */
65
64
  staff?: string[];
66
65
  /**
67
66
  * A staff viewer's active, explicitly-entered vendor selection (the two-phase
@@ -28,6 +28,7 @@
28
28
  */
29
29
  import { readEnv } from "@/lib/env";
30
30
  import { diagEmail } from "@/lib/diag/redact";
31
+ import { FetchHttpTransport, type HttpResponseLike, type HttpTransport } from "@/lib/http/fetchTransport";
31
32
  import { classifyStepUp, type StepUpChallenge, type StepUpObligation } from "./stepUpChallenge.js";
32
33
 
33
34
  /** `send` is deliberately opaque — it never reveals whether the email was eligible. */
@@ -150,24 +151,13 @@ export type SmsVerifyResult =
150
151
 
151
152
  // --- HTTP transport seam (injected by tests) --------------------------------
152
153
 
153
- export interface HttpResponseLike {
154
- status: number;
155
- json(): Promise<unknown>;
156
- }
157
- export interface HttpTransport {
158
- post(url: string, headers: Record<string, string>, body: unknown): Promise<HttpResponseLike>;
159
- }
154
+ export type { HttpResponseLike, HttpTransport };
160
155
 
161
- /** Default transport: a JSON `fetch` POST. */
162
- export class FetchHttpTransport implements HttpTransport {
163
- async post(url: string, headers: Record<string, string>, body: unknown) {
164
- return fetch(url, {
165
- method: "POST",
166
- headers: { "content-type": "application/json", accept: "application/json", ...headers },
167
- body: JSON.stringify(body),
168
- });
169
- }
170
- }
156
+ /** Default transport: a JSON `fetch` POST that also sends `accept: application/json`. */
157
+ const defaultTransport = () =>
158
+ new FetchHttpTransport({
159
+ defaultHeaders: { "content-type": "application/json", accept: "application/json" },
160
+ });
171
161
 
172
162
  export interface HttpTotAccessClientConfig {
173
163
  /** tot20 core API base (no trailing slash), e.g. https://qa.tokenoftrust.com */
@@ -193,7 +183,7 @@ export class HttpTotAccessClient implements TotAccessClient {
193
183
  this.baseUrl = config.baseUrl.replace(/\/+$/, "");
194
184
  this.apiKey = config.apiKey;
195
185
  this.secretKey = config.secretKey;
196
- this.transport = config.transport ?? new FetchHttpTransport();
186
+ this.transport = config.transport ?? defaultTransport();
197
187
  }
198
188
 
199
189
  /**
@@ -13,13 +13,20 @@
13
13
  *
14
14
  * It is idempotent and conservative: only root-absolute single-slash paths are
15
15
  * prefixed. Protocol-relative URLs ("//cdn…"), absolute URLs ("https://…"),
16
- * fragments/queries ("#x", "?x"), and already-prefixed paths pass through. This
17
- * mirrors the defense-in-depth client script in Layout.astro.
16
+ * fragments/queries ("#x", "?x"), and already-prefixed paths pass through. The
17
+ * GLOBAL static-asset namespaces are also left untouched — they are served at root
18
+ * under both routing modes and must NOT carry a tenant prefix:
19
+ * - `/tenants/…` — per-tenant static assets (logo, favicon, theme/mkt css);
20
+ * - `/shared/…` — platform-shipped shared assets (shared commerce-chrome css).
21
+ * This mirrors both `prefixTenantLinks` (lib/rawMarketingHtml.ts) and the
22
+ * defense-in-depth client script in Layout.astro.
18
23
  */
19
24
  export function withBase(basePath: string, href: string): string {
20
25
  if (!basePath || !href) return href;
21
26
  // Only same-origin root-absolute paths; skip protocol-relative "//".
22
27
  if (href.charAt(0) !== "/" || href.charAt(1) === "/") return href;
28
+ // Global asset namespaces are root-served under every tenant; never prefix them.
29
+ if (href.startsWith("/tenants/") || href.startsWith("/shared/")) return href;
23
30
  // Already inside the prefix.
24
31
  if (href === basePath || href.startsWith(`${basePath}/`)) return href;
25
32
  return `${basePath}${href}`;
@@ -0,0 +1,29 @@
1
+ import type { SessionRecord } from "@/lib/auth/session.js";
2
+ import type { BlogAccess } from "./types.js";
3
+
4
+ /**
5
+ * Whether a signed-in viewer counts as a paid member. v1: authenticated ⇒ member,
6
+ * because there is no consumer entitlement source yet. This is the single seam a
7
+ * future billing/entitlement integration plugs into — keep it a named export so
8
+ * routes and predicates never re-implement the "is a member" decision inline.
9
+ */
10
+ export function isConsumerMember(_viewer: SessionRecord): boolean {
11
+ return true;
12
+ }
13
+
14
+ /**
15
+ * Entitlement chokepoint: may this viewer read the post's body? Orthogonal to
16
+ * visibility (`isVisibleOnLive`) — a gated post is still published/listed; this
17
+ * only decides full body vs teaser. Every reader path calls this one function.
18
+ */
19
+ export function viewerHasBlogAccess(
20
+ viewer: SessionRecord | null,
21
+ post: { access?: BlogAccess },
22
+ ): boolean {
23
+ const need = post.access ?? "public";
24
+ if (need === "public") return true;
25
+ if (!viewer) return false;
26
+ if (need === "authenticated") return true;
27
+ if (need === "members") return isConsumerMember(viewer);
28
+ return false;
29
+ }