@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
@@ -3,7 +3,7 @@
3
3
  * <SiteHeader> — logo/wordmark + search island + account/auth + cart-count
4
4
  * affordance, with the primary <MegaMenu> nav below and a mobile drawer (the
5
5
  * <MobileNav> island). Tenant-agnostic; theme-token skinned. This is the
6
- * CANONICAL site header (unit I4) — the former `components/nav/Header.astro`
6
+ * CANONICAL site header — the former `components/nav/Header.astro`
7
7
  * app-Layout implementation is retired; every feature it had (search typeahead,
8
8
  * mobile drawer with focus-trap/scroll-lock, the session-aware auth entry point,
9
9
  * the saved-items/wishlist cue, marketing header CTAs, a dark header variant)
@@ -13,8 +13,9 @@
13
13
  * COMMERCE BOUNDARY: the cart is a LINK only — no cart state, no add-to-cart.
14
14
  * The count is a static affordance the managed cart can hydrate later.
15
15
  */
16
- import type { ChromeNavItem, ChromeLogo, ChromeCta } from "@/lib/chrome/model";
16
+ import type { ChromeNavItem, ChromeLogo, ChromeCta, HeaderVariant } from "@/lib/chrome/model";
17
17
  import MegaMenu from "@/components/chrome/MegaMenu.astro";
18
+ import NavDropdown from "@/components/chrome/NavDropdown.astro";
18
19
  import SearchTypeahead from "@/components/islands/SearchTypeahead.tsx";
19
20
  import MobileNav from "@/components/islands/MobileNav.tsx";
20
21
  import { withBase } from "@/lib/basePath";
@@ -23,6 +24,11 @@ interface Props {
23
24
  logo?: ChromeLogo;
24
25
  /** Fallback wordmark text when no logo image. */
25
26
  wordmark?: string;
27
+ /**
28
+ * Home/brand link target (lib/chrome/model.ts ChromeBrand.href). Run through
29
+ * `withBase` same as every other same-origin href. Omit to default to "/".
30
+ */
31
+ brandHref?: string;
26
32
  nav?: ChromeNavItem[];
27
33
  /** Search form action (GET). Omit to hide search. Mounts the live SearchTypeahead island. */
28
34
  searchAction?: string;
@@ -41,6 +47,15 @@ interface Props {
41
47
  cartCount?: number;
42
48
  /** A brand-fixed "dark" header bar (e.g. a navy bar with a light logo) vs. the default light bar. */
43
49
  variant?: "light" | "dark";
50
+ /**
51
+ * Content-shape variant (lib/chrome/model.ts HeaderVariant) — independent of
52
+ * `variant`'s light/dark TONE above. "minimal" (e.g. checkout/policy pages)
53
+ * renders brand + a reduced action set only: no search, no marketing CTAs,
54
+ * no saved-items affordance, no primary-nav bar, no mobile-menu toggle.
55
+ * Defaults to "primary" (the full header) so every existing caller is
56
+ * unaffected.
57
+ */
58
+ layout?: HeaderVariant;
44
59
  sticky?: boolean;
45
60
  class?: string;
46
61
  }
@@ -48,6 +63,7 @@ interface Props {
48
63
  const {
49
64
  logo,
50
65
  wordmark,
66
+ brandHref,
51
67
  nav = [],
52
68
  searchAction,
53
69
  announcement,
@@ -58,14 +74,16 @@ const {
58
74
  cartHref,
59
75
  cartCount = 0,
60
76
  variant = "light",
77
+ layout = "primary",
61
78
  sticky = true,
62
79
  class: className,
63
80
  } = Astro.props;
64
81
 
65
82
  const { basePath } = Astro.locals;
66
- const homeHref = withBase(basePath, "/");
83
+ const homeHref = withBase(basePath, brandHref ?? "/");
67
84
  const showLogo = !!logo && /^(https?:|\/)/.test(logo.src);
68
85
  const dark = variant === "dark";
86
+ const minimal = layout === "minimal";
69
87
 
70
88
  const ctaClass = (v?: string) =>
71
89
  v === "secondary" || v === "ghost"
@@ -86,6 +104,11 @@ const mobileNav = nav.map((item) => ({
86
104
  href: withBase(basePath, child.href),
87
105
  })),
88
106
  }));
107
+
108
+ // Current-page path, for aria-current="page" — threaded to the MobileNav
109
+ // island (which can't read Astro.url itself) so it marks the same link the
110
+ // server-rendered nav (NavDropdown, via Astro.url internally) marks.
111
+ const currentPath = Astro.url.pathname;
89
112
  ---
90
113
 
91
114
  <header class:list={[sticky && "sticky top-0 z-40", className]}>
@@ -133,7 +156,7 @@ const mobileNav = nav.map((item) => ({
133
156
 
134
157
  <!-- Search (live typeahead island) -->
135
158
  {
136
- searchAction && (
159
+ !minimal && searchAction && (
137
160
  <div class="hidden flex-1 md:flex">
138
161
  <SearchTypeahead client:idle action={searchAction} />
139
162
  </div>
@@ -143,7 +166,7 @@ const mobileNav = nav.map((item) => ({
143
166
  <!-- Actions: saved items + marketing CTAs + auth + account + cart (link only) + mobile menu -->
144
167
  <div class="ml-auto flex items-center gap-1">
145
168
  {
146
- savedItemsHref && (
169
+ !minimal && savedItemsHref && (
147
170
  <a
148
171
  href={withBase(basePath, savedItemsHref)}
149
172
  aria-label="Saved items"
@@ -161,7 +184,7 @@ const mobileNav = nav.map((item) => ({
161
184
  )
162
185
  }
163
186
  {
164
- headerCtas.length > 0 && (
187
+ !minimal && headerCtas.length > 0 && (
165
188
  <div class="hidden items-center gap-2 sm:flex">
166
189
  {headerCtas.map((cta) => (
167
190
  <a href={withBase(basePath, cta.href)} class={ctaClass(cta.variant)}>
@@ -220,9 +243,9 @@ const mobileNav = nav.map((item) => ({
220
243
 
221
244
  <!-- Mobile menu: the MobileNav island (focus-trap, scroll-lock, Escape-to-close) -->
222
245
  {
223
- nav.length > 0 && (
246
+ !minimal && nav.length > 0 && (
224
247
  <div class="md:hidden">
225
- <MobileNav client:idle nav={mobileNav} announcement={announcement} />
248
+ <MobileNav client:idle nav={mobileNav} announcement={announcement} currentPath={currentPath} />
226
249
  </div>
227
250
  )
228
251
  }
@@ -230,12 +253,25 @@ const mobileNav = nav.map((item) => ({
230
253
  </div>
231
254
  </div>
232
255
 
233
- <!-- Primary nav bar -->
256
+ <!-- Primary nav bar: desktop MegaMenu (hidden md:block) + a no-JS-safe mobile
257
+ fallback (md:hidden) below it. The fallback renders the SAME nav data as
258
+ real, crawlable <a href> links via a native <details>/<summary> accordion
259
+ (NavDropdown mode="accordion") — it works with zero JavaScript, since it
260
+ is below the `md` breakpoint the ONLY nav affordance a no-JS visitor has
261
+ (the MobileNav drawer above is a client:idle island and renders nothing
262
+ without JS). Once MobileNav hydrates it hides this fallback (see its
263
+ [data-mobile-nav-fallback] effect) so JS-enabled visitors get the drawer
264
+ as the primary/enhanced experience; this is additive, not a replacement. -->
234
265
  {
235
- nav.length > 0 && (
266
+ !minimal && nav.length > 0 && (
236
267
  <div class="border-b border-border bg-surface">
237
268
  <div class="container-prose">
238
269
  <MegaMenu items={nav} />
270
+ <nav aria-label="Mobile" data-mobile-nav-fallback class="md:hidden">
271
+ <ul class="grid">
272
+ {nav.map((item) => <NavDropdown item={item} mode="accordion" />)}
273
+ </ul>
274
+ </nav>
239
275
  </div>
240
276
  </div>
241
277
  )
@@ -4,7 +4,7 @@
4
4
  * require an of-age adult to sign; the wording is fixed here and the age
5
5
  * reflects tenant.compliance.minAge (defaults to 21). Renders NOTHING when
6
6
  * `enabled` is false. Driven by tenant.compliance.adultSignature — never hand-
7
- * authored on a marketing page (decision compliance-widgets-platform-owned).
7
+ * authored on a marketing page.
8
8
  */
9
9
  import ComplianceNotice from "./ComplianceNotice.astro";
10
10
 
@@ -5,8 +5,7 @@
5
5
  * FDA NicotineWarning follows). It owns ONLY the chrome: the fixed legal text
6
6
  * is supplied by each sibling widget via <slot />, and every sibling renders it
7
7
  * ONLY when its tenant.compliance data is present. This component adds no copy
8
- * of its own — it never fabricates legal wording (decision
9
- * compliance-widgets-platform-owned).
8
+ * of its own — it never fabricates legal wording.
10
9
  *
11
10
  * Variants — one visual treatment per placement, token-styled so they re-skin
12
11
  * with the theme and never carry a hardcoded brand color:
@@ -3,8 +3,7 @@
3
3
  * Excise-tax DISPLAY cue. Presentational only — it surfaces that applicable
4
4
  * excise taxes apply (and, optionally, a per-jurisdiction breakdown for shopper
5
5
  * transparency); it NEVER computes tax. The actual excise-tax CALCULATION is
6
- * product/commerce-owned (decision compliance-widgets-platform-owned). Renders
7
- * NOTHING when no note is supplied.
6
+ * product/commerce-owned. Renders NOTHING when no note is supplied.
8
7
  *
9
8
  * The optional jurisdiction breakdown is rendered as inline "label detail"
10
9
  * spans (valid inside the primitive's paragraph) so it re-skins with the theme
@@ -6,7 +6,7 @@
6
6
  * Postal Service carriage; only whether it renders (and the age) comes from
7
7
  * tenant.compliance.pactAct / .minAge. Renders NOTHING when `enabled` is false,
8
8
  * so absent data never shows placeholder legal text. Never hand-author this on a
9
- * marketing page (decision compliance-widgets-platform-owned).
9
+ * marketing page.
10
10
  */
11
11
  import ComplianceNotice from "./ComplianceNotice.astro";
12
12
 
@@ -5,8 +5,7 @@
5
5
  * ("WARNING: … known to the State of California to cause …"), the ⚠ symbol, and
6
6
  * the official warnings URL. Only the variable slots — harm endpoint(s) and the
7
7
  * chemical name(s) named in the long form — come from tenant.compliance.prop65.
8
- * Renders NOTHING when the config is absent, so it never fabricates a warning
9
- * (decision compliance-widgets-platform-owned).
8
+ * Renders NOTHING when the config is absent, so it never fabricates a warning.
10
9
  *
11
10
  * `true` → short cancer + reproductive-harm warning. A Prop65Config selects the
12
11
  * harm endpoint(s); providing `chemicals` switches to the long form.
@@ -3,9 +3,8 @@
3
3
  * Purchase-quantity-limit DISPLAY. Surfaces a shopper-facing limit (e.g. state
4
4
  * or PACT-Act order caps). Display surface ONLY — the limit text comes from
5
5
  * tenant.compliance.purchaseLimit and the actual enforcement stays in the
6
- * product/commerce layer, never hand-built here (decision
7
- * compliance-widgets-platform-owned). Renders NOTHING when the config (or its
8
- * text) is absent.
6
+ * product/commerce layer, never hand-built here. Renders NOTHING when the
7
+ * config (or its text) is absent.
9
8
  */
10
9
  import type { PurchaseLimitConfig } from "@tot/public-runtime";
11
10
  import ComplianceNotice from "./ComplianceNotice.astro";
@@ -3,8 +3,8 @@
3
3
  * Shipping-restriction DISPLAY notice (e.g. PACT Act no-ship states, adult
4
4
  * signature, carrier limits). Presentational only — it renders the tenant's
5
5
  * configured `compliance.shippingRestriction` text; the actual ship/no-ship
6
- * DECISION for an address stays in the product/commerce layer (decision
7
- * compliance-widgets-platform-owned). Renders NOTHING when `text` is absent.
6
+ * DECISION for an address stays in the product/commerce layer. Renders
7
+ * NOTHING when `text` is absent.
8
8
  *
9
9
  * This is the platform component behind the footer shipping band the app Layout
10
10
  * previously inlined — same data, same footer placement, now token-styled via
@@ -3,9 +3,8 @@
3
3
  * State/jurisdiction sale-eligibility DISPLAY notice. Presentational only — it
4
4
  * SHOWS the tenant-configured eligibility messaging (which states a product is /
5
5
  * isn't available in); it does NOT decide whether a given cart/address is
6
- * eligible — that computation stays product-owned (decision
7
- * compliance-widgets-platform-owned). Renders NOTHING when no eligibility data
8
- * is supplied, so absent config never shows a placeholder.
6
+ * eligible — that computation stays product-owned. Renders NOTHING when no
7
+ * eligibility data is supplied, so absent config never shows a placeholder.
9
8
  *
10
9
  * Message precedence: an explicit `note` wins; otherwise a sentence is composed
11
10
  * from `restrictedStates` ("Not available for sale in: …") or, failing that,
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  /**
3
3
  * <TrustStrip> — the quiet row of proof tokens a store repeats across pages
4
- * ("Ships from USA", "Lab-tested", a rating). REAL-OR-ABSENT by construction
5
- * (f09): sanitizeTrustStrip() drops any claim that is scraped review-widget
6
- * markup and any rating that isn't a real positive aggregate, reusing f09's
4
+ * ("Ships from USA", "Lab-tested", a rating). REAL-OR-ABSENT by construction:
5
+ * sanitizeTrustStrip() drops any claim that is scraped review-widget
6
+ * markup and any rating that isn't a real positive aggregate, reusing the same
7
7
  * detector. If nothing real is left the strip renders NOTHING — never a
8
- * fabricated badge. Plain text + one rating glyph; styled from f06 tokens.
8
+ * fabricated badge. Plain text + one rating glyph; styled from design tokens.
9
9
  * data-widget="trust-strip".
10
10
  */
11
11
  import type { TrustStripItem } from "@/lib/content/trustStrip";
@@ -11,6 +11,7 @@
11
11
  * prefers-reduced-motion.
12
12
  */
13
13
  import { useCallback, useEffect, useRef, useState } from "preact/hooks";
14
+ import { isCurrentNavHref } from "@/lib/chrome/navCurrent";
14
15
 
15
16
  interface NavChild {
16
17
  label: string;
@@ -25,9 +26,13 @@ interface NavItem {
25
26
  interface Props {
26
27
  nav: NavItem[];
27
28
  announcement?: string;
29
+ /** Current request path (Astro.url.pathname), for aria-current="page" — see navCurrent.ts. */
30
+ currentPath?: string;
28
31
  }
29
32
 
30
33
  const DRAWER_ID = "mobile-drawer";
34
+ /** Matches SiteHeader.astro's no-JS fallback <nav data-mobile-nav-fallback>. */
35
+ const FALLBACK_NAV_SELECTOR = "[data-mobile-nav-fallback]";
31
36
 
32
37
  function prefersReducedMotion(): boolean {
33
38
  return (
@@ -37,7 +42,7 @@ function prefersReducedMotion(): boolean {
37
42
  );
38
43
  }
39
44
 
40
- export default function MobileNav({ nav, announcement }: Props) {
45
+ export default function MobileNav({ nav, announcement, currentPath }: Props) {
41
46
  const [open, setOpen] = useState(false);
42
47
  const buttonRef = useRef<HTMLButtonElement>(null);
43
48
  const panelRef = useRef<HTMLDivElement>(null);
@@ -45,6 +50,17 @@ export default function MobileNav({ nav, announcement }: Props) {
45
50
 
46
51
  const close = useCallback(() => setOpen(false), []);
47
52
 
53
+ // The no-JS fallback nav is only needed when JS never runs. Since this
54
+ // component mounting IS JS running, hide it in favor of the drawer above —
55
+ // additive progressive enhancement, not a replacement of either layer.
56
+ useEffect(() => {
57
+ document
58
+ .querySelectorAll<HTMLElement>(FALLBACK_NAV_SELECTOR)
59
+ .forEach((el) => {
60
+ el.hidden = true;
61
+ });
62
+ }, []);
63
+
48
64
  // Body scroll lock while open.
49
65
  useEffect(() => {
50
66
  if (!open) return;
@@ -202,6 +218,9 @@ export default function MobileNav({ nav, announcement }: Props) {
202
218
  <div class="px-3 py-2">
203
219
  <a
204
220
  href={item.href}
221
+ aria-current={
222
+ currentPath && isCurrentNavHref(currentPath, item.href) ? "page" : undefined
223
+ }
205
224
  class="block font-display text-base font-medium text-text hover:text-primary"
206
225
  >
207
226
  {item.label}
@@ -211,6 +230,9 @@ export default function MobileNav({ nav, announcement }: Props) {
211
230
  <li key={child.href}>
212
231
  <a
213
232
  href={child.href}
233
+ aria-current={
234
+ currentPath && isCurrentNavHref(currentPath, child.href) ? "page" : undefined
235
+ }
214
236
  class="block rounded px-2 py-1.5 font-body text-sm text-muted hover:bg-border/40 hover:text-text"
215
237
  >
216
238
  {child.label}
@@ -222,6 +244,9 @@ export default function MobileNav({ nav, announcement }: Props) {
222
244
  ) : (
223
245
  <a
224
246
  href={item.href}
247
+ aria-current={
248
+ currentPath && isCurrentNavHref(currentPath, item.href) ? "page" : undefined
249
+ }
225
250
  class="block rounded px-3 py-2.5 font-display text-base font-medium text-text hover:bg-border/40 hover:text-primary"
226
251
  >
227
252
  {item.label}
@@ -27,6 +27,7 @@ import type {
27
27
  } from "@tot/public-runtime";
28
28
  import { priceForPurchaseOption } from "@tot/public-runtime";
29
29
  import { formatPrice } from "@/lib/format";
30
+ import { useCheckoutHandoffCorrelation } from "@/components/islands/useCheckoutHandoffCorrelation";
30
31
 
31
32
  interface OptionDef {
32
33
  name: string;
@@ -55,7 +56,7 @@ interface Props {
55
56
  byVariantId: Record<string, Record<string, VariantCartPayload>>;
56
57
  };
57
58
  /**
58
- * Membership pricing (F10). Present only when an eligible member is resolved
59
+ * Membership pricing. Present only when an eligible member is resolved
59
60
  * for this request (Phase 2 shopper login). Undefined → list pricing only,
60
61
  * which is the Phase-1 anonymous behavior.
61
62
  */
@@ -63,6 +64,13 @@ interface Props {
63
64
  membershipRule: MembershipTierRule;
64
65
  stacking: MembershipStackingPolicy;
65
66
  };
67
+ /**
68
+ * Base-path-aware URL of the checkout-correlation mint endpoint
69
+ * (ext-commerce-10). When a store is wired the island posts the shopper's live
70
+ * consent snapshot here and, if the server attributes, carries the returned
71
+ * passthrough field on the managed-cart form. Undefined → no correlation.
72
+ */
73
+ handoffUrl?: string;
66
74
  }
67
75
 
68
76
  const LOW_STOCK_THRESHOLD = 5;
@@ -89,7 +97,14 @@ export default function VariantSelector({
89
97
  productTitle,
90
98
  checkoutCart,
91
99
  pricing,
100
+ handoffUrl,
92
101
  }: Props) {
102
+ // Checkout-correlation handoff mint (ext-commerce-10): resolved once the server
103
+ // attributes this shopper (analytics consent granted + signing secret present),
104
+ // else null → the buy form carries no correlation and the order is unattributed.
105
+ const correlationField = useCheckoutHandoffCorrelation(
106
+ checkoutCart ? handoffUrl : undefined,
107
+ );
93
108
  const sortedOptions = useMemo(
94
109
  () => [...options].sort((a, b) => a.position - b.position),
95
110
  [options],
@@ -219,7 +234,7 @@ export default function VariantSelector({
219
234
  }
220
235
  }
221
236
 
222
- // Compose member + subscription pricing (F10). The pricing context carries the
237
+ // Compose member + subscription pricing. The pricing context carries the
223
238
  // resolved member tier only when an eligible member was resolved server-side;
224
239
  // otherwise it is a non-member and list pricing stands.
225
240
  const pricingCtx = pricing
@@ -474,6 +489,16 @@ export default function VariantSelector({
474
489
  value={String(quantity)}
475
490
  />
476
491
  )}
492
+ {/* Checkout-correlation passthrough field (ext-commerce-10). Rides the
493
+ handoff as a never-signed hidden field the provider echoes back on
494
+ the order webhook; absent when unattributed. */}
495
+ {canBuy && correlationField && (
496
+ <input
497
+ type="hidden"
498
+ name={correlationField.name}
499
+ value={correlationField.value}
500
+ />
501
+ )}
477
502
  <button
478
503
  type="submit"
479
504
  disabled={!canBuy}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Client hook for the checkout-correlation handoff mint (ext-commerce-10).
3
+ *
4
+ * The shopper's analytics consent is a live CLIENT-side value, but the correlation
5
+ * token is minted under the SERVER-only signing secret. So at the handoff this hook
6
+ * posts the current consent snapshot (the renderer-owned `__TOT_INTEGRATION_CONSENT__`
7
+ * global) to `POST /api/commerce/checkout-handoff` and, when the server attributes,
8
+ * returns the opaque passthrough cart field for the managed-cart form to carry.
9
+ *
10
+ * Fail-safe by construction: no handoff URL, a network error, or an unattributed
11
+ * response yields `null` — the buy form renders and submits with NO correlation field,
12
+ * so the order is simply unattributed and checkout is never blocked.
13
+ */
14
+ import { useEffect, useState } from "preact/hooks";
15
+
16
+ /** The renderer-owned frozen consent-snapshot global (`render-phases.ts`). */
17
+ const INTEGRATION_CONSENT_GLOBAL = "__TOT_INTEGRATION_CONSENT__";
18
+
19
+ /** The opaque passthrough cart field to attach to the managed-cart form. */
20
+ export interface HandoffCartField {
21
+ name: string;
22
+ value: string;
23
+ }
24
+
25
+ /**
26
+ * Read the `{ attributed, cartField }` handoff response fail-closed into a cart field,
27
+ * or `null` for any non-attributed / malformed shape. Pure — unit-tested directly.
28
+ */
29
+ export function parseHandoffCartField(data: unknown): HandoffCartField | null {
30
+ if (!data || typeof data !== "object") return null;
31
+ const d = data as Record<string, unknown>;
32
+ if (d.attributed !== true) return null;
33
+ const field = d.cartField;
34
+ if (!field || typeof field !== "object") return null;
35
+ const { name, value } = field as Record<string, unknown>;
36
+ return typeof name === "string" && name.length > 0 && typeof value === "string" && value.length > 0
37
+ ? { name, value }
38
+ : null;
39
+ }
40
+
41
+ /** The live consent snapshot the renderer inlined + the CMP/native banner updates. */
42
+ function readClientConsent(): unknown {
43
+ return (globalThis as Record<string, unknown>)[INTEGRATION_CONSENT_GLOBAL] ?? null;
44
+ }
45
+
46
+ /**
47
+ * Fetch the handoff correlation for this page. Returns the cart field to attach once
48
+ * the server attributes, else `null`. `handoffUrl` absent (no store / marketing
49
+ * tenant) is a no-op.
50
+ */
51
+ export function useCheckoutHandoffCorrelation(handoffUrl?: string): HandoffCartField | null {
52
+ const [field, setField] = useState<HandoffCartField | null>(null);
53
+
54
+ useEffect(() => {
55
+ if (!handoffUrl) return;
56
+ let cancelled = false;
57
+ fetch(handoffUrl, {
58
+ method: "POST",
59
+ headers: { "content-type": "application/json" },
60
+ body: JSON.stringify({ consent: readClientConsent() }),
61
+ })
62
+ .then((res) => res.json())
63
+ .then((data) => {
64
+ if (!cancelled) setField(parseHandoffCartField(data));
65
+ })
66
+ .catch(() => {
67
+ // Fail-safe: leave the order unattributed; never disturb the buy form.
68
+ });
69
+ return () => {
70
+ cancelled = true;
71
+ };
72
+ }, [handoffUrl]);
73
+
74
+ return field;
75
+ }
@@ -4,8 +4,7 @@
4
4
  * offer" affordance shared by <TierCards>, <TierComparisonTable>, and the
5
5
  * subscription <SavingsExplainer>. When a group shows illustrative figures,
6
6
  * the widgets render this so an example price / savings number is never
7
- * mistaken for a live offer (decision compliance-widgets-platform-owned
8
- * education only, no pricing mechanics).
7
+ * mistaken for a live offer education only, no pricing mechanics.
9
8
  *
10
9
  * Two forms:
11
10
  * - "badge" a compact pill placed at the group header (the visible marker)
@@ -6,8 +6,8 @@
6
6
  * checkout, or subscription mechanics — each tier's CTA is a plain handoff link
7
7
  * into the tenant's own (product-owned) subscribe/learn flow.
8
8
  *
9
- * Illustrative-figures affordance (decision compliance-widgets-platform-owned):
10
- * a tier's figure is treated as an EXAMPLE by default (isIllustrative). When any
9
+ * Illustrative-figures affordance: a tier's figure is treated as an EXAMPLE
10
+ * by default (isIllustrative). When any
11
11
  * shown tier is illustrative the group header carries a first-class
12
12
  * <IllustrativeLabel> badge, each such figure is prefixed with an "e.g."
13
13
  * affordance + data-illustrative hook, and a footnote spells it out — so an
@@ -6,8 +6,8 @@
6
6
  * subscription mechanics; a tier's optional figure and CTA are display/handoff
7
7
  * only.
8
8
  *
9
- * Illustrative-figures affordance (decision compliance-widgets-platform-owned):
10
- * when any tier shows an illustrative figure the header carries a first-class
9
+ * Illustrative-figures affordance: when any tier shows an illustrative
10
+ * figure the header carries a first-class
11
11
  * <IllustrativeLabel> badge, each such figure gets an "e.g." affordance +
12
12
  * data-illustrative hook, and a footnote spells it out — an example number is
13
13
  * never presented as a live offer.
@@ -6,8 +6,8 @@
6
6
  * subscription mechanics — the CTA is a link into the tenant's own
7
7
  * (product-owned) subscribe/learn flow.
8
8
  *
9
- * Illustrative-figure affordance (decision compliance-widgets-platform-owned):
10
- * the figure is treated as an EXAMPLE by default (isIllustrative). When
9
+ * Illustrative-figure affordance: the figure is treated as an EXAMPLE by
10
+ * default (isIllustrative). When
11
11
  * illustrative, the figure carries an "e.g." affordance + a first-class
12
12
  * <IllustrativeLabel> badge/footnote so an example number is never presented
13
13
  * as a live offer. A tenant opts out only by asserting `real: true` on a
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Admin integration plane — arbitrary-tenant lookup provider (ext-kernel-09).
3
+ *
4
+ * The `/api/apps/admin/*` integration routes resolve a tenant named in the operator
5
+ * session (`auth.tenantId` — a vendor may administer a tenant that is NOT the
6
+ * request's own host scope, so `Astro.locals.tenant` does not apply). Materializing
7
+ * a tenant's OWN (tenant-local) declarations needs its full config (`compliance`,
8
+ * `siteType`, `integrations`), which requires the concrete resolver selection — and
9
+ * the `tenancy-resolver-fence` extractability invariant forbids pages/lib from
10
+ * importing that directly.
11
+ *
12
+ * This module lives in `src/config` (an approved location) and encapsulates
13
+ * `getTenantResolver()` + `staticTenants`, exposing exactly the by-id lookup the
14
+ * admin routes need, typed against the public `TenantConfig`. Mirrors
15
+ * `previewTenantLookup.ts`; the concrete resolver selection stays in `config`, so a
16
+ * constant single-tenant resolver remains a drop-in and the codebase stays
17
+ * always-extractable.
18
+ */
19
+ import type { TenantConfig } from "@tot/public-runtime";
20
+ import { getTenantResolver } from "@/config/resolver";
21
+ import { staticTenants } from "@/config/tenants";
22
+
23
+ /**
24
+ * Resolve the admin operator's tenant id (== appDomain for the built-in tenants) to
25
+ * its config. Strict domain match first (KV-backed in prod, static in dev), then the
26
+ * static registry by appDomain or tenant_id. Null for an unknown tenant.
27
+ */
28
+ export async function resolveAdminTenant(tenantId: string): Promise<TenantConfig | null> {
29
+ const resolver = await getTenantResolver();
30
+ return (
31
+ (await resolver.resolveStrict(tenantId)) ??
32
+ staticTenants.find((t) => t.appDomain === tenantId || t.tenant_id === tenantId) ??
33
+ null
34
+ );
35
+ }
@@ -27,14 +27,14 @@ import type { DeepPartial, TenantConfig, ThemeTokens } from "@tot/public-runtime
27
27
  /** Per-dir overrides the resolver derives from disk before synthesis. */
28
28
  export interface DevTenantHints {
29
29
  /**
30
- * (E3) The resolvable appDomain for a SLUG tenant whose dir name isn't its
30
+ * The resolvable appDomain for a SLUG tenant whose dir name isn't its
31
31
  * domain. Read from the checkout's `.tot/config.json` `scope` when that scope
32
32
  * looks like a hostname (has a dot) — mirrors scripts/tot-dev.mjs resolveDomain.
33
33
  * Undefined ⇒ the colocation convention (dir == appDomain == scope).
34
34
  */
35
35
  appDomain?: string;
36
36
  /**
37
- * (E2) True when catalog fixtures for this tenant's data scope are committed on
37
+ * True when catalog fixtures for this tenant's data scope are committed on
38
38
  * disk (the same `packages/migration/out/catalog/<scope>/` the FixtureToTClient
39
39
  * reads). When true we serve a real COMMERCE tenant so /collections + /products
40
40
  * render from them; when false we degrade to a marketing home (no catalog).
@@ -45,9 +45,9 @@ export interface DevTenantHints {
45
45
  /**
46
46
  * A servable TenantConfig for a local dev-loop checkout. Identity defaults to the
47
47
  * colocated dir name (dir == id == appDomain == tot_data_scope); a slug tenant can
48
- * override the resolvable appDomain via `hints.appDomain` (E3). No Storyblok space
48
+ * override the resolvable appDomain via `hints.appDomain`. No Storyblok space
49
49
  * (a "PLACEHOLDER" token → LocalContentProvider serves the checkout's content/).
50
- * Commerce is data-driven (E2): with catalog fixtures on disk the tenant is
50
+ * Commerce is data-driven: with catalog fixtures on disk the tenant is
51
51
  * COMMERCE (catalog on); without them it degrades to a marketing home (siteType
52
52
  * "marketing" → no catalog required, so the root renders instead of 404ing).
53
53
  * Theme tokens come from the checkout's theme.json.
@@ -57,7 +57,7 @@ export function synthesizeDevTenant(
57
57
  themeTokens: DeepPartial<ThemeTokens>,
58
58
  hints: DevTenantHints = {},
59
59
  ): TenantConfig {
60
- // (E3) Prefer the .tot/config.json scope for a slug tenant; else colocation.
60
+ // Prefer the .tot/config.json scope for a slug tenant; else colocation.
61
61
  const appDomain = hints.appDomain ?? id;
62
62
  const base: TenantConfig = {
63
63
  tenant_id: id,
@@ -74,7 +74,7 @@ export function synthesizeDevTenant(
74
74
  theme_tokens: themeTokens,
75
75
  };
76
76
  if (hints.hasCatalog) {
77
- // (E2) Catalog fixtures on disk → a real commerce tenant (siteType omitted ==
77
+ // Catalog fixtures on disk → a real commerce tenant (siteType omitted ==
78
78
  // commerce → catalog on). Cart wires to the shared ToT demo checkout store
79
79
  // (test mode, no secret), the same as the bundled demo tenants — so
80
80
  // /collections + /products resolve and add-to-cart works on localhost.
@@ -90,9 +90,9 @@ export function synthesizeDevTenant(
90
90
 
91
91
  /** Per-dir disk facts the resolver supplies so synthesis can go beyond colocation. */
92
92
  export interface DevTenantSeedOptions {
93
- /** (E3) Resolved appDomain for a slug tenant (from `.tot/config.json` scope). */
93
+ /** Resolved appDomain for a slug tenant (from `.tot/config.json` scope). */
94
94
  scopeFor?: (id: string) => string | undefined;
95
- /** (E2) Whether catalog fixtures are committed on disk for a given data scope. */
95
+ /** Whether catalog fixtures are committed on disk for a given data scope. */
96
96
  hasCatalog?: (scope: string) => boolean;
97
97
  }
98
98
 
@@ -100,7 +100,7 @@ export interface DevTenantSeedOptions {
100
100
  * The dev tenants to seed ALONGSIDE staticTenants: one synthesized config per
101
101
  * local tenant dir that isn't already a static tenant (those keep their richer
102
102
  * hardcoded config). `themeFor` supplies each dir's theme tokens; `opts` carries
103
- * the per-dir disk facts (E2 catalog presence, E3 slug scope) the resolver reads.
103
+ * the per-dir disk facts (catalog presence, slug scope) the resolver reads.
104
104
  *
105
105
  * @param localDirIds dir names discovered under `tenants/*` (dir == tenant id)
106
106
  * @param staticIds tenant_ids already in the static registry (skipped)