@tokenoftrust/storefront-runner 1.4.2-rc.0 → 2.0.1
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.
- package/apps/storefront/astro.config.mjs +3 -3
- package/apps/storefront/dev-plugins/tenant-hot-reload.mjs +8 -3
- package/apps/storefront/env.d.ts +54 -5
- package/apps/storefront/integrations/materialize-guard.mjs +12 -14
- package/apps/storefront/migrations-apps/0004_deep_morph.sql +36 -0
- package/apps/storefront/migrations-apps/0005_common_mystique.sql +23 -0
- package/apps/storefront/migrations-apps/0006_broad_microchip.sql +16 -0
- package/apps/storefront/migrations-apps/0007_brave_outlaw_kid.sql +15 -0
- package/apps/storefront/migrations-apps/0008_blue_dazzler.sql +11 -0
- package/apps/storefront/migrations-apps/0009_bored_shinobi_shaw.sql +15 -0
- package/apps/storefront/migrations-apps/0010_ws4_verified_provider_measurement.sql +35 -0
- package/apps/storefront/migrations-apps/meta/0004_snapshot.json +1474 -0
- package/apps/storefront/migrations-apps/meta/0005_snapshot.json +1617 -0
- package/apps/storefront/migrations-apps/meta/0006_snapshot.json +1716 -0
- package/apps/storefront/migrations-apps/meta/0007_snapshot.json +1812 -0
- package/apps/storefront/migrations-apps/meta/0008_snapshot.json +1881 -0
- package/apps/storefront/migrations-apps/meta/0009_snapshot.json +1979 -0
- package/apps/storefront/migrations-apps/meta/_journal.json +42 -0
- package/apps/storefront/public/apps/tot.demo.analytics/0.1.0/entry.js +42 -0
- package/apps/storefront/public/platform/amplitude-http/v1/entry.mjs +19 -0
- package/apps/storefront/public/platform/google-measurement/v1/entry.mjs +19 -0
- package/apps/storefront/public/shared/commerce-chrome.css +20 -2
- package/apps/storefront/scripts/build-v84-clean-clone-standalone.mjs +68 -0
- package/apps/storefront/scripts/deny-v84-clean-clone-standalone-capabilities.mjs +111 -0
- package/apps/storefront/scripts/deny-v84-dogfood-capabilities.mjs +2 -0
- package/apps/storefront/scripts/deny-v84-lifecycle-capabilities.mjs +247 -0
- package/apps/storefront/scripts/dogfood-v84-nonportable-routes.ts +73 -0
- package/apps/storefront/scripts/fixed-v84-native-install-producer.ts +79 -0
- package/apps/storefront/scripts/generated/v84-clean-clone-replay.bundle.mjs +10982 -0
- package/apps/storefront/scripts/import-v84-through-ws2.ts +38 -0
- package/apps/storefront/scripts/initialize-v84-lifecycle-tooling-dependency.ts +2 -0
- package/apps/storefront/scripts/initialize-v84-lifecycle-tooling.ts +4 -0
- package/apps/storefront/scripts/install-v84-native-through-ws1.ts +185 -0
- package/apps/storefront/scripts/prove-clone-isolation.ts +506 -0
- package/apps/storefront/scripts/replay-v84-clean-clone-pass.ts +148 -0
- package/apps/storefront/scripts/replay-v84-clean-clone-standalone.ts +35 -0
- package/apps/storefront/scripts/replay-v84-clean-clone.ts +214 -0
- package/apps/storefront/scripts/run-fixed-v84-native-install-producer.mjs +18 -0
- package/apps/storefront/scripts/run-v84-clone-isolation-proof.mjs +18 -0
- package/apps/storefront/scripts/run-v84-clone-lifecycle-proof.mjs +18 -0
- package/apps/storefront/scripts/run-v84-import-through-ws2-proof.mjs +17 -0
- package/apps/storefront/scripts/run-v84-nonportable-route-dogfood.mjs +15 -0
- package/apps/storefront/scripts/sanitize-v84-proof-environment.mjs +21 -0
- package/apps/storefront/scripts/v84CleanCloneGraphPin.ts +42 -0
- package/apps/storefront/scripts/v84CleanCloneSourceGraph.ts +145 -0
- package/apps/storefront/scripts/validate-v84-clone-lifecycle.ts +18 -0
- package/apps/storefront/src/components/Img.astro +1 -1
- package/apps/storefront/src/components/admin/AdminBlogTab.astro +19 -16
- package/apps/storefront/src/components/admin/AdminIntegrationsTab.astro +105 -0
- package/apps/storefront/src/components/admin/AdminPublishTab.astro +1057 -412
- package/apps/storefront/src/components/admin/AdminSettingsTab.astro +2 -2
- package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +5 -5
- package/apps/storefront/src/components/chrome/NavDropdown.astro +12 -0
- package/apps/storefront/src/components/chrome/SiteFooter.astro +7 -2
- package/apps/storefront/src/components/chrome/SiteHeader.astro +46 -10
- package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +1 -1
- package/apps/storefront/src/components/compliance/ComplianceNotice.astro +1 -2
- package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +1 -2
- package/apps/storefront/src/components/compliance/PactActNotice.astro +1 -1
- package/apps/storefront/src/components/compliance/Prop65Warning.astro +1 -2
- package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +2 -3
- package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +2 -2
- package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +2 -3
- package/apps/storefront/src/components/content/TrustStrip.astro +4 -4
- package/apps/storefront/src/components/islands/MobileNav.tsx +26 -1
- package/apps/storefront/src/components/islands/VariantSelector.tsx +27 -2
- package/apps/storefront/src/components/islands/useCheckoutHandoffCorrelation.ts +75 -0
- package/apps/storefront/src/components/membership/IllustrativeLabel.astro +1 -2
- package/apps/storefront/src/components/membership/TierCards.astro +2 -2
- package/apps/storefront/src/components/membership/TierComparisonTable.astro +2 -2
- package/apps/storefront/src/components/subscription/SavingsExplainer.astro +2 -2
- package/apps/storefront/src/config/adminTenantLookup.ts +35 -0
- package/apps/storefront/src/config/devTenantSeed.ts +9 -9
- package/apps/storefront/src/config/resolver.ts +18 -10
- package/apps/storefront/src/layouts/Layout.astro +100 -20
- package/apps/storefront/src/lib/activity/candidateSubmitLease.ts +87 -0
- package/apps/storefront/src/lib/activity/changeActorAttribution.ts +86 -6
- package/apps/storefront/src/lib/activity/deployVersion.ts +1 -1
- package/apps/storefront/src/lib/admin/adminShell.ts +2 -0
- package/apps/storefront/src/lib/admin/envelope.ts +1 -2
- package/apps/storefront/src/lib/apps/adminService.ts +10 -0
- package/apps/storefront/src/lib/apps/adminSession.ts +1 -1
- package/apps/storefront/src/lib/apps/appVersionStore.ts +281 -0
- package/apps/storefront/src/lib/apps/consentConfigStore.ts +228 -0
- package/apps/storefront/src/lib/apps/gtmMigrationInstall.ts +447 -0
- package/apps/storefront/src/lib/apps/gtmMigrationReport.ts +367 -0
- package/apps/storefront/src/lib/apps/gtmMigrationTab.ts +315 -0
- package/apps/storefront/src/lib/apps/integrationLifecycle.ts +614 -0
- package/apps/storefront/src/lib/apps/integrationLifecycleController.ts +125 -0
- package/apps/storefront/src/lib/apps/integrationReadModel.ts +563 -0
- package/apps/storefront/src/lib/apps/integrationsTab.ts +547 -0
- package/apps/storefront/src/lib/apps/integrationsView.ts +106 -0
- package/apps/storefront/src/lib/apps/managedAnalyticsService.ts +599 -0
- package/apps/storefront/src/lib/apps/orders/orderConversionD1.ts +150 -0
- package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +8 -0
- package/apps/storefront/src/lib/apps/orders/ordersStore.ts +1 -1
- package/apps/storefront/src/lib/apps/orders/verifiedProviderMeasurement.ts +117 -0
- package/apps/storefront/src/lib/apps/registryService.ts +264 -10
- package/apps/storefront/src/lib/apps/tenantIntegrationMaterialization.ts +170 -0
- package/apps/storefront/src/lib/apps/v84CleanCloneReplayContext.ts +16 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleCacheEvidence.ts +105 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleEvidence.ts +177 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleMaterialization.ts +251 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleSemantics.ts +241 -0
- package/apps/storefront/src/lib/apps/v84CloneMigrationEvidence.ts +211 -0
- package/apps/storefront/src/lib/apps/v84CloneNativeInstallEvidence.ts +409 -0
- package/apps/storefront/src/lib/apps/v84NonportableCodeCoaching.ts +368 -0
- package/apps/storefront/src/lib/apps/v84NonportableRouteContract.ts +188 -0
- package/apps/storefront/src/lib/apps/v84NonportableRouteDogfood.ts +291 -0
- package/apps/storefront/src/lib/apps/ws1ManagedAnalyticsClient.ts +95 -0
- package/apps/storefront/src/lib/auth/adminApiGuard.ts +66 -0
- package/apps/storefront/src/lib/auth/adminEntry.ts +2 -2
- package/apps/storefront/src/lib/auth/adminLanding.ts +88 -0
- package/apps/storefront/src/lib/blog/collection.ts +114 -17
- package/apps/storefront/src/lib/blog/markdown.ts +1 -1
- package/apps/storefront/src/lib/blog/provider.ts +76 -9
- package/apps/storefront/src/lib/blog/types.ts +9 -9
- package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome-assignments.example.json +6 -0
- package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome.example.json +79 -0
- package/apps/storefront/src/lib/chrome/model.ts +48 -253
- package/apps/storefront/src/lib/chrome/navCurrent.ts +29 -0
- package/apps/storefront/src/lib/chrome/parseConfig.ts +18 -32
- package/apps/storefront/src/lib/chrome/variant.ts +39 -0
- package/apps/storefront/src/lib/commerce/checkoutHandoffCorrelation.ts +105 -0
- package/apps/storefront/src/lib/compliance/tamper-sentinel-boot.ts +152 -0
- package/apps/storefront/src/lib/compliance/tamper-sentinel.ts +327 -0
- package/apps/storefront/src/lib/content/index.ts +5 -5
- package/apps/storefront/src/lib/content-edit/applyDiff.ts +1 -1
- package/apps/storefront/src/lib/content-edit/route.ts +1 -1
- package/apps/storefront/src/lib/d1/catalog.ts +12 -0
- package/apps/storefront/src/lib/d1/schema-apps.ts +276 -0
- package/apps/storefront/src/lib/dev/cockpit/ask.ts +49 -0
- package/apps/storefront/src/lib/dev/cockpit/clickToSource.ts +71 -0
- package/apps/storefront/src/lib/dev/cockpit/copyCommand.ts +227 -0
- package/apps/storefront/src/lib/dev/cockpit/files.ts +249 -0
- package/apps/storefront/src/lib/dev/cockpit/hostedActivity.ts +500 -0
- package/apps/storefront/src/lib/dev/cockpit/infoPopover.ts +12 -0
- package/apps/storefront/src/lib/dev/cockpit/mcpCopy.ts +34 -0
- package/apps/storefront/src/lib/dev/cockpit/monitor.ts +107 -0
- package/apps/storefront/src/lib/dev/cockpit/stepper.ts +116 -0
- package/apps/storefront/src/lib/dev/cockpit/themeToggle.ts +23 -0
- package/apps/storefront/src/lib/dev/runtimeStore.ts +1 -1
- package/apps/storefront/src/lib/edgeCache.ts +18 -6
- package/apps/storefront/src/lib/email/candidateConflictEmail.ts +80 -0
- package/apps/storefront/src/lib/integration/browserEnvironment.ts +137 -0
- package/apps/storefront/src/lib/integration/managedInstallDeclarations.ts +72 -0
- package/apps/storefront/src/lib/integration/nonceStamp.ts +49 -0
- package/apps/storefront/src/lib/integration/tenantDeclarations.ts +116 -0
- package/apps/storefront/src/lib/membership/eligibility.ts +1 -1
- package/apps/storefront/src/lib/membership/model.ts +1 -2
- package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +2 -2
- package/apps/storefront/src/lib/newsletter/consent.ts +2 -2
- package/apps/storefront/src/lib/newsletter/send.ts +3 -3
- package/apps/storefront/src/lib/previewReload.ts +57 -1
- package/apps/storefront/src/lib/publish/adminPublishTab.ts +1775 -669
- package/apps/storefront/src/lib/publish/buildStream.ts +269 -0
- package/apps/storefront/src/lib/publish/collapsePersistence.ts +72 -0
- package/apps/storefront/src/lib/publish/lifecycleState.ts +369 -0
- package/apps/storefront/src/lib/publish/liveReleaseSummary.ts +29 -0
- package/apps/storefront/src/lib/publish/mergeDoctorOnFailure.ts +78 -0
- package/apps/storefront/src/lib/publish/mergeHealthBanner.ts +62 -0
- package/apps/storefront/src/lib/publish/mergeRowFindings.ts +124 -0
- package/apps/storefront/src/lib/publish/mergeSupportEscalation.ts +75 -0
- package/apps/storefront/src/lib/publish/publish-guard.ts +88 -0
- package/apps/storefront/src/lib/publish/publishFormat.ts +165 -0
- package/apps/storefront/src/lib/publish/publishHero.ts +177 -0
- package/apps/storefront/src/lib/publish/reviewRelease/changeState.ts +66 -0
- package/apps/storefront/src/lib/publish/reviewRelease/copy.ts +141 -0
- package/apps/storefront/src/lib/publish/reviewRelease/index.ts +41 -0
- package/apps/storefront/src/lib/publish/reviewRelease/permissions.ts +47 -0
- package/apps/storefront/src/lib/publish/reviewRelease/releaseState.ts +42 -0
- package/apps/storefront/src/lib/publish/reviewRelease/types.ts +59 -0
- package/apps/storefront/src/lib/publish/reviewRelease/viewModel.ts +440 -0
- package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/actions.ts +161 -0
- package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/controller.ts +325 -0
- package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/render.ts +241 -0
- package/apps/storefront/src/lib/publish/shipWorkspace.ts +22 -3
- package/apps/storefront/src/lib/publish/sseRoute.ts +119 -0
- package/apps/storefront/src/lib/publish/streamLogConsole.ts +142 -0
- package/apps/storefront/src/lib/publish/versionNumber.ts +52 -0
- package/apps/storefront/src/lib/rawChrome.ts +125 -47
- package/apps/storefront/src/lib/rawMarketingHtml.ts +74 -3
- package/apps/storefront/src/lib/seo/alternates.ts +1 -1
- package/apps/storefront/src/lib/social/notify.ts +4 -4
- package/apps/storefront/src/lib/storyblok/content-model.ts +7 -33
- package/apps/storefront/src/lib/storyblok/provider.ts +203 -69
- package/apps/storefront/src/lib/subscription/model.ts +4 -4
- package/apps/storefront/src/lib/the-build/provider.ts +9 -4
- package/apps/storefront/src/middleware/index.ts +273 -51
- package/apps/storefront/src/pages/[...slug].astro +9 -4
- package/apps/storefront/src/pages/admin/review-release.astro +265 -0
- package/apps/storefront/src/pages/admin/select.astro +96 -0
- package/apps/storefront/src/pages/admin.astro +16 -2
- package/apps/storefront/src/pages/api/activity.ts +8 -8
- package/apps/storefront/src/pages/api/admin/activity-alerts.ts +5 -20
- package/apps/storefront/src/pages/api/admin/orders/[id].ts +7 -2
- package/apps/storefront/src/pages/api/admin/orders.ts +8 -2
- package/apps/storefront/src/pages/api/apps/admin/gtm-migration-install.ts +174 -0
- package/apps/storefront/src/pages/api/apps/admin/gtm-migration.ts +96 -0
- package/apps/storefront/src/pages/api/apps/admin/integration-lifecycle.ts +118 -0
- package/apps/storefront/src/pages/api/apps/admin/integrations.ts +89 -0
- package/apps/storefront/src/pages/api/apps/admin/platform-adapters.ts +85 -0
- package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +74 -2
- package/apps/storefront/src/pages/api/commerce/checkout-handoff.ts +77 -0
- package/apps/storefront/src/pages/api/compliance/tamper.ts +88 -0
- package/apps/storefront/src/pages/api/integrations/v1/[operation].ts +108 -0
- package/apps/storefront/src/pages/api/rum/vitals.ts +1 -2
- package/apps/storefront/src/pages/blog/[slug].astro +5 -5
- package/apps/storefront/src/pages/blog/author/[author].astro +3 -3
- package/apps/storefront/src/pages/blog/category/[category].astro +2 -2
- package/apps/storefront/src/pages/blog/index.astro +2 -2
- package/apps/storefront/src/pages/blog/tag/[tag].astro +2 -2
- package/apps/storefront/src/pages/cockpit.astro +61 -1362
- package/apps/storefront/src/pages/index.astro +10 -5
- package/apps/storefront/src/pages/llms.txt.ts +1 -1
- package/apps/storefront/src/pages/products/[handle].astro +7 -6
- package/apps/storefront/src/pages/sitemap.xml.ts +2 -2
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +42 -31
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +8 -3
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +6 -2
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +6 -2
- package/apps/storefront/src/pages/style-guide/index.astro +19 -5
- package/apps/storefront/src/pages/tenants/[id]/[...path].ts +38 -2
- package/apps/storefront/src/pages/the-build/[slug].astro +4 -4
- package/apps/storefront/src/pages/the-build/index.astro +2 -2
- package/apps/storefront/src/pages/the-build/rss.xml.ts +2 -2
- package/apps/storefront/src/styles/admin.css +27 -1
- package/apps/storefront/src/themes/tenants/index.ts +19 -7
- package/apps/storefront/tsconfig.json +1 -1
- package/package.json +1 -1
- package/packages/public-runtime/package.json +2 -1
- package/packages/public-runtime/schemas/managed-analytics/v1/adapter-definition.schema.json +427 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/create-integration-install-request.schema.json +161 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/create-migration-draft-request.schema.json +157 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/delete-integration-install-request.schema.json +84 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/delete-migration-draft-request.schema.json +84 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/error-envelope.schema.json +180 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-adapter-definition-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-install-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-revision-request.schema.json +79 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-migration-draft-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/integration-install.schema.json +167 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/integration-revision.schema.json +208 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/list-adapter-definitions-request.schema.json +53 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-installs-request.schema.json +53 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-revisions-request.schema.json +82 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/migration-draft.schema.json +218 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/mutation-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/mutation-success-envelope.schema.json +49 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/read-request.schema.json +20 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/read-success-envelope.schema.json +45 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/revise-integration-install-request.schema.json +156 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/set-integration-install-status-request.schema.json +92 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/update-migration-draft-request.schema.json +184 -0
- package/packages/public-runtime/scripts/generate-managed-analytics-api-v1-schemas.mjs +13 -0
- package/packages/public-runtime/src/activity/catalog.ts +41 -37
- package/packages/public-runtime/src/activity/event.ts +6 -6
- package/packages/public-runtime/src/activity/index.ts +2 -2
- package/packages/public-runtime/src/activity/redaction.ts +4 -4
- package/packages/public-runtime/src/candidate-index.ts +42 -8
- package/packages/public-runtime/src/checkout-orders.ts +2 -2
- package/packages/public-runtime/src/checkout-style-publish.ts +2 -2
- package/packages/public-runtime/src/checkout-style.ts +7 -7
- package/packages/public-runtime/src/checkout.ts +3 -3
- package/packages/public-runtime/src/chrome.ts +777 -0
- package/packages/public-runtime/src/compliance-obligations.ts +310 -0
- package/packages/public-runtime/src/csp.ts +99 -0
- package/packages/public-runtime/src/customization-runtime.ts +32 -1
- package/packages/public-runtime/src/destination-webhook/contract.ts +353 -0
- package/packages/public-runtime/src/embed-catalog.d.mts +9 -0
- package/packages/public-runtime/src/embed-catalog.mjs +40 -0
- package/packages/public-runtime/src/evidence.ts +288 -0
- package/packages/public-runtime/src/gtm-migration/bounds.ts +138 -0
- package/packages/public-runtime/src/gtm-migration/disposition-rules.ts +361 -0
- package/packages/public-runtime/src/gtm-migration/dispositions.ts +181 -0
- package/packages/public-runtime/src/gtm-migration/draft-generator.ts +400 -0
- package/packages/public-runtime/src/gtm-migration/graph.ts +468 -0
- package/packages/public-runtime/src/gtm-migration/index.ts +95 -0
- package/packages/public-runtime/src/gtm-migration/parse.ts +410 -0
- package/packages/public-runtime/src/gtm-migration/references.ts +266 -0
- package/packages/public-runtime/src/gtm-migration/types.ts +86 -0
- package/packages/public-runtime/src/index.ts +16 -1
- package/packages/public-runtime/src/integration/assurance-decision.ts +259 -0
- package/packages/public-runtime/src/integration/assurance.ts +228 -0
- package/packages/public-runtime/src/integration/candidate-evidence.ts +377 -0
- package/packages/public-runtime/src/integration/commerce-broker.ts +497 -0
- package/packages/public-runtime/src/integration/consent-broker.ts +337 -0
- package/packages/public-runtime/src/integration/consent-cmp-demand.ts +115 -0
- package/packages/public-runtime/src/integration/consent-config.ts +260 -0
- package/packages/public-runtime/src/integration/consent-preview.ts +125 -0
- package/packages/public-runtime/src/integration/correlation-token.ts +444 -0
- package/packages/public-runtime/src/integration/csp-compiler.ts +267 -0
- package/packages/public-runtime/src/integration/csp.ts +105 -0
- package/packages/public-runtime/src/integration/digest.ts +43 -0
- package/packages/public-runtime/src/integration/environment.ts +228 -0
- package/packages/public-runtime/src/integration/events-catalog.ts +186 -0
- package/packages/public-runtime/src/integration/events.ts +701 -0
- package/packages/public-runtime/src/integration/g2-action-boundary.ts +106 -0
- package/packages/public-runtime/src/integration/index.ts +90 -0
- package/packages/public-runtime/src/integration/interim-bridge.ts +138 -0
- package/packages/public-runtime/src/integration/lifecycle-boot.ts +317 -0
- package/packages/public-runtime/src/integration/lifecycle-runtime.ts +393 -0
- package/packages/public-runtime/src/integration/lifecycle.ts +94 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.d.mts +2 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.mjs +10 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1.schemas.ts +382 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1.ts +684 -0
- package/packages/public-runtime/src/integration/managed-analytics-bridge.ts +383 -0
- package/packages/public-runtime/src/integration/managed-analytics-value-safety.ts +14 -0
- package/packages/public-runtime/src/integration/managed-analytics.ts +277 -0
- package/packages/public-runtime/src/integration/manifest.ts +470 -0
- package/packages/public-runtime/src/integration/native-amplitude.ts +362 -0
- package/packages/public-runtime/src/integration/native-ga4.ts +352 -0
- package/packages/public-runtime/src/integration/observability.ts +451 -0
- package/packages/public-runtime/src/integration/order-conversion.ts +0 -0
- package/packages/public-runtime/src/integration/phases.ts +182 -0
- package/packages/public-runtime/src/integration/plan.ts +112 -0
- package/packages/public-runtime/src/integration/platform-adapter-runtime.ts +146 -0
- package/packages/public-runtime/src/integration/platform-adapters.ts +671 -0
- package/packages/public-runtime/src/integration/promotion-gate.ts +451 -0
- package/packages/public-runtime/src/integration/provider-checkout-extension.ts +425 -0
- package/packages/public-runtime/src/integration/receipt-measurement.ts +370 -0
- package/packages/public-runtime/src/integration/regulated-parent-cert.ts +311 -0
- package/packages/public-runtime/src/integration/render-phases.ts +267 -0
- package/packages/public-runtime/src/integration/resolve.ts +465 -0
- package/packages/public-runtime/src/integration/result.ts +239 -0
- package/packages/public-runtime/src/integration/secrets.ts +92 -0
- package/packages/public-runtime/src/integration/tamper-evidence.ts +205 -0
- package/packages/public-runtime/src/integration/tamper-recovery.ts +127 -0
- package/packages/public-runtime/src/integration/version.ts +92 -0
- package/packages/public-runtime/src/integration-capabilities.ts +520 -0
- package/packages/public-runtime/src/membership.ts +2 -2
- package/packages/public-runtime/src/raw-html-policy.ts +2 -4
- package/packages/public-runtime/src/regulated-commerce/broker/consent-dedupe.ts +144 -0
- package/packages/public-runtime/src/regulated-commerce/correlation/contract.ts +177 -0
- package/packages/public-runtime/src/regulated-commerce/diagnostics/local-dispatch.ts +24 -0
- package/packages/public-runtime/src/regulated-commerce/diagnostics/read-model.ts +69 -0
- package/packages/public-runtime/src/regulated-commerce/dispatch/core.ts +134 -0
- package/packages/public-runtime/src/regulated-commerce/events/contract.ts +113 -0
- package/packages/public-runtime/src/regulated-commerce/ledger/core.ts +81 -0
- package/packages/public-runtime/src/regulated-commerce/mappings/ga4-ads.ts +87 -0
- package/packages/public-runtime/src/regulated-commerce/provider-order/bridge.ts +52 -0
- package/packages/public-runtime/src/regulated-commerce/purchase-truth/contract.ts +252 -0
- package/packages/public-runtime/src/regulated-commerce/sources/accepted-browser-operation.ts +67 -0
- package/packages/public-runtime/src/regulated-commerce/testing/fake-destination.ts +93 -0
- package/packages/public-runtime/src/static-bundle.ts +5 -5
- package/packages/public-runtime/src/tenant-assets.ts +143 -4
- package/packages/public-runtime/src/tenant.ts +136 -9
- package/packages/public-runtime/tests/fixtures/integration/browser-environment.example.json +8 -0
- package/packages/public-runtime/tests/fixtures/integration/commerce-event.example.json +44 -0
- package/packages/public-runtime/tests/fixtures/integration/commerce-order-event.example.json +44 -0
- package/packages/public-runtime/tests/fixtures/integration/compliance-assurance-record.example.json +50 -0
- package/packages/public-runtime/tests/fixtures/integration/integration-manifest-v2.example.json +120 -0
- package/packages/public-runtime/tests/fixtures/integration/managed-analytics-v1/fake-adapter-catalog.json +35 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-action-registry.example.json +11 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/README.md +22 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/entry.js +30 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/manifest.json +75 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/public-config.json +3 -0
- package/packages/public-runtime/tests/fixtures/regulated-commerce/fake-destinations.ts +38 -0
- package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.provenance.json +29 -0
- package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.redacted.json +3397 -0
- package/scripts/build/copy-tenant-assets.mjs +12 -5
- package/scripts/dev/ai-edit.mjs +2 -1
- package/scripts/dev/file-browser.mjs +2 -2
- package/scripts/dev/file-writer.mjs +2 -2
- package/scripts/dev/integration-guardrails.mjs +498 -0
- package/scripts/dev/safe-path.mjs +2 -2
- package/scripts/dev/tenant-source-root.mjs +3 -2
- package/scripts/tot-dev.mjs +5 -4
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closed policy for the evidence-rejected G2 account-interest gap.
|
|
3
|
+
*
|
|
4
|
+
* This is deliberately a first-party policy seam, not a G2 client: it has no
|
|
5
|
+
* endpoint, vendor identifier, browser loader, DOM input, mutable configuration,
|
|
6
|
+
* or side effect. A future owned destination may consume only an already-emitted,
|
|
7
|
+
* validated semantic action through this policy.
|
|
8
|
+
*/
|
|
9
|
+
import type { CommerceEvent } from "./events.js";
|
|
10
|
+
import {
|
|
11
|
+
APPROVED_MARKETING_ACTION_NAMES,
|
|
12
|
+
type ApprovedMarketingActionName,
|
|
13
|
+
} from "./events.js";
|
|
14
|
+
import {
|
|
15
|
+
emitManagedActionActivated,
|
|
16
|
+
type ManagedActionActivationInput,
|
|
17
|
+
type ManagedAnalyticsEmitResult,
|
|
18
|
+
} from "./managed-analytics.js";
|
|
19
|
+
import type { CommerceEventBroker } from "./commerce-broker.js";
|
|
20
|
+
|
|
21
|
+
/** Only these two actions are distinct G2 conversion candidates; never aggregate them. */
|
|
22
|
+
export const G2_CONVERSION_ACTION_NAMES = [
|
|
23
|
+
"user_clicked_contact_sales_mktg",
|
|
24
|
+
"user_clicked_create_account_mktg",
|
|
25
|
+
] as const satisfies readonly ApprovedMarketingActionName[];
|
|
26
|
+
|
|
27
|
+
/** These actions remain first-party product/service telemetry and are never G2 eligible. */
|
|
28
|
+
export const INTERNAL_ONLY_ACTION_NAMES = [
|
|
29
|
+
"user_clicked_login_mktg",
|
|
30
|
+
"user_clicked_contact_support_consumer_mktg",
|
|
31
|
+
"user_clicked_contact_support_partner_mktg",
|
|
32
|
+
] as const satisfies readonly ApprovedMarketingActionName[];
|
|
33
|
+
|
|
34
|
+
export type G2ActionDisposition =
|
|
35
|
+
| "g2-conversion-eligible"
|
|
36
|
+
| "internal-only"
|
|
37
|
+
| "withheld-marketing-consent";
|
|
38
|
+
|
|
39
|
+
export interface G2ActionBoundaryDecision {
|
|
40
|
+
readonly actionName: ApprovedMarketingActionName;
|
|
41
|
+
readonly disposition: G2ActionDisposition;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const G2_CONVERSION_ACTION_SET: ReadonlySet<string> = new Set(G2_CONVERSION_ACTION_NAMES);
|
|
45
|
+
const INTERNAL_ONLY_ACTION_SET: ReadonlySet<string> = new Set(INTERNAL_ONLY_ACTION_NAMES);
|
|
46
|
+
|
|
47
|
+
function approvedActionName(value: unknown): ApprovedMarketingActionName | undefined {
|
|
48
|
+
return (APPROVED_MARKETING_ACTION_NAMES as readonly string[]).includes(value as string)
|
|
49
|
+
? value as ApprovedMarketingActionName
|
|
50
|
+
: undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Classify an already-validated first-party action event for any future G2
|
|
55
|
+
* destination. Invalid/unrelated events are deliberately not classifiable.
|
|
56
|
+
*
|
|
57
|
+
* Marketing consent is a separate destination-purpose gate. The underlying
|
|
58
|
+
* first-party action event is already analytics-consent and broker-dedupe gated.
|
|
59
|
+
*/
|
|
60
|
+
export function decideG2ActionBoundary(event: CommerceEvent): G2ActionBoundaryDecision | undefined {
|
|
61
|
+
if (event.type !== "storefront.action.activated.v1") return undefined;
|
|
62
|
+
if (Object.keys(event.data).length !== 1) return undefined;
|
|
63
|
+
const actionName = approvedActionName(event.data["name"]);
|
|
64
|
+
if (!actionName) return undefined;
|
|
65
|
+
|
|
66
|
+
if (INTERNAL_ONLY_ACTION_SET.has(actionName)) {
|
|
67
|
+
return { actionName, disposition: "internal-only" };
|
|
68
|
+
}
|
|
69
|
+
if (!G2_CONVERSION_ACTION_SET.has(actionName)) return undefined;
|
|
70
|
+
if (!event.consent.eligiblePurposes.includes("marketing")) {
|
|
71
|
+
return { actionName, disposition: "withheld-marketing-consent" };
|
|
72
|
+
}
|
|
73
|
+
return { actionName, disposition: "g2-conversion-eligible" };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ConfirmedManagedActionInput extends ManagedActionActivationInput {
|
|
77
|
+
/** The platform handler must establish success; clicks and attempted submits are rejected. */
|
|
78
|
+
confirmedSuccess: true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type ConfirmedManagedActionResult = ManagedAnalyticsEmitResult | {
|
|
82
|
+
ok: true;
|
|
83
|
+
emitted: false;
|
|
84
|
+
skipReason: "not-confirmed-success";
|
|
85
|
+
deliveries: [];
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The only first-party collection entry point intended for the five G2-gap
|
|
90
|
+
* actions. It does not deliver to G2; it simply refuses non-success activity
|
|
91
|
+
* before passing the closed `{ name }` event to the existing consented,
|
|
92
|
+
* idempotent CommerceEventBroker.
|
|
93
|
+
*/
|
|
94
|
+
export function emitConfirmedManagedActionActivated(
|
|
95
|
+
broker: CommerceEventBroker,
|
|
96
|
+
input: Omit<ManagedActionActivationInput, "name"> & {
|
|
97
|
+
name: ApprovedMarketingActionName;
|
|
98
|
+
confirmedSuccess: boolean;
|
|
99
|
+
},
|
|
100
|
+
): ConfirmedManagedActionResult {
|
|
101
|
+
if (input.confirmedSuccess !== true) {
|
|
102
|
+
return { ok: true, emitted: false, skipReason: "not-confirmed-success", deliveries: [] };
|
|
103
|
+
}
|
|
104
|
+
const { confirmedSuccess: _confirmedSuccess, ...activation } = input;
|
|
105
|
+
return emitManagedActionActivated(broker, activation);
|
|
106
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tot/public-runtime — the versioned PUBLIC browser-integration contracts.
|
|
3
|
+
*
|
|
4
|
+
* The renderer-safe, semver-versioned surface (ADR 0006) that 35+ downstream
|
|
5
|
+
* cards build on. It is the single shared contract for both tenant-local
|
|
6
|
+
* configuration and managed apps (ADR 0014 C1 `integration-schema-shared`):
|
|
7
|
+
* promotion changes ownership and packaging, never the browser contract.
|
|
8
|
+
*
|
|
9
|
+
* Every contract here is CLOSED and FAIL-CLOSED — unknown fields, unknown
|
|
10
|
+
* enum members, malformed shapes, duplicates, and incompatible versions are
|
|
11
|
+
* rejected, never ignored or assumed safe — and none is secret-bearing (charter
|
|
12
|
+
* invariant 3, ADR 0018 nonce non-serialization).
|
|
13
|
+
*
|
|
14
|
+
* Charter/ADR traceability for the six source-card concerns:
|
|
15
|
+
* - environment → ./environment.ts (E1 / ADR 0017)
|
|
16
|
+
* - global hook + slots → ./phases.ts + ./manifest.ts (S1/S2, ADR 0016)
|
|
17
|
+
* - CSP → ./csp.ts (E2 / ADR 0018, 0019)
|
|
18
|
+
* - lifecycle → ./lifecycle.ts + navigation event (invariant 9)
|
|
19
|
+
* - migration → ./manifest.ts configurationMigrations + ./version.ts
|
|
20
|
+
* - authority/assurance → ./phases.ts tiers + ./assurance.ts (I1, G1/G2, 0023)
|
|
21
|
+
*
|
|
22
|
+
* Contract families:
|
|
23
|
+
* - version.ts — semver contract version + per-family schemaVersion pins
|
|
24
|
+
* - result.ts — the closed/fail-closed validation core
|
|
25
|
+
* - secrets.ts — the no-secret-in-the-browser guard
|
|
26
|
+
* - environment.ts — the universal four-stage browser environment
|
|
27
|
+
* - phases.ts — reserved phases, authority tiers, the contribution DAG
|
|
28
|
+
* - csp.ts — exact-origin CSP source contract
|
|
29
|
+
* - csp-compiler.ts — version-scoped compiler: curated profiles + advanced origins
|
|
30
|
+
* - manifest.ts — the shared integration declaration (tenant-local + app)
|
|
31
|
+
* - plan.ts — the server-computed effective plan + source references
|
|
32
|
+
* - resolve.ts — the pure resolver that merges declarations into a plan
|
|
33
|
+
* - render-phases.ts — the one fixed-phase render engine both mounts consume
|
|
34
|
+
* - lifecycle.ts — the exactly-once MPA lifecycle contract
|
|
35
|
+
* - lifecycle-runtime.ts — the browser runtime: exactly-once init, update/dispose,
|
|
36
|
+
* error isolation, and the reserved completed-navigation event seam
|
|
37
|
+
* - lifecycle-boot.ts — the guarded document.deferred boot binding for `window`
|
|
38
|
+
* - events.ts — the canonical semantic commerce + reserved navigation events
|
|
39
|
+
* - events-catalog.ts — per-field owner/purpose/sensitivity + retention classes
|
|
40
|
+
* - commerce-broker.ts — the platform-owned client emitter/subscription API:
|
|
41
|
+
* server-owned context stamped not caller-set, one-event-per-action dedupe,
|
|
42
|
+
* consent-filtered per-subscriber delivery, subscriber-fault isolation,
|
|
43
|
+
* and typed iframe-consumer messages
|
|
44
|
+
* - assurance.ts — compliance assurance metadata (non-waivable floor)
|
|
45
|
+
* - assurance-decision.ts — the enforcement layer over an assurance record
|
|
46
|
+
*/
|
|
47
|
+
export * from "./version.js";
|
|
48
|
+
export * from "./result.js";
|
|
49
|
+
export { stableStringify as stableIntegrationStringify } from "./digest.js";
|
|
50
|
+
export * from "./secrets.js";
|
|
51
|
+
export * from "./environment.js";
|
|
52
|
+
export * from "./phases.js";
|
|
53
|
+
export * from "./csp.js";
|
|
54
|
+
export * from "./csp-compiler.js";
|
|
55
|
+
export * from "./manifest.js";
|
|
56
|
+
export * from "./plan.js";
|
|
57
|
+
export * from "./resolve.js";
|
|
58
|
+
export * from "./platform-adapters.js";
|
|
59
|
+
export * from "./native-amplitude.js";
|
|
60
|
+
export * from "./native-ga4.js";
|
|
61
|
+
export * from "./platform-adapter-runtime.js";
|
|
62
|
+
export * from "./render-phases.js";
|
|
63
|
+
export * from "./interim-bridge.js";
|
|
64
|
+
export * from "./consent-broker.js";
|
|
65
|
+
export * from "./consent-cmp-demand.js";
|
|
66
|
+
export * from "./consent-config.js";
|
|
67
|
+
export * from "./consent-preview.js";
|
|
68
|
+
export * from "./candidate-evidence.js";
|
|
69
|
+
export * from "./lifecycle.js";
|
|
70
|
+
export * from "./lifecycle-runtime.js";
|
|
71
|
+
export * from "./lifecycle-boot.js";
|
|
72
|
+
export * from "./events.js";
|
|
73
|
+
export * from "./events-catalog.js";
|
|
74
|
+
export * from "./commerce-broker.js";
|
|
75
|
+
export * from "./managed-analytics.js";
|
|
76
|
+
export * from "./managed-analytics-bridge.js";
|
|
77
|
+
export * from "./g2-action-boundary.js";
|
|
78
|
+
export * from "./correlation-token.js";
|
|
79
|
+
export * from "./order-conversion.js";
|
|
80
|
+
export * from "./receipt-measurement.js";
|
|
81
|
+
export * from "./provider-checkout-extension.js";
|
|
82
|
+
export * from "./assurance.js";
|
|
83
|
+
export * from "./assurance-decision.js";
|
|
84
|
+
export * from "./tamper-evidence.js";
|
|
85
|
+
export * from "./tamper-recovery.js";
|
|
86
|
+
export * from "./observability.js";
|
|
87
|
+
export * from "./regulated-parent-cert.js";
|
|
88
|
+
export * from "./promotion-gate.js";
|
|
89
|
+
export * from "./managed-analytics-api-v1.js";
|
|
90
|
+
export * from "./managed-analytics-api-v1.schemas.js";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The supported interim MARKETING bridge (ext-kernel-07, WS1 roadmap "smallest
|
|
3
|
+
* supported interim bridge").
|
|
4
|
+
*
|
|
5
|
+
* This is the one seam that makes the whole browser-integration kernel observable
|
|
6
|
+
* end-to-end WITHOUT a page edit or a vendor branch: a tenant-local declaration's
|
|
7
|
+
* exact-version entry module flows through the resolver → the effective plan
|
|
8
|
+
* ({@link resolveEffectivePlan}) → the render-phase boot descriptor
|
|
9
|
+
* ({@link BootDescriptorIntegration}) → the lifecycle runtime, which dynamically
|
|
10
|
+
* imports and inits it — consent-gated, at a pinned version, in all four
|
|
11
|
+
* environments. Removing the declaration removes the code, the network, and the CSP
|
|
12
|
+
* with it (the plan carries no vendor runtime, and `planRevision` moves), so a
|
|
13
|
+
* rollback leaves no stale effect.
|
|
14
|
+
*
|
|
15
|
+
* It is deliberately narrow (ADR 0016/0023 Q6): the bridge is enabled ONLY on
|
|
16
|
+
* eligible unregulated-marketing tenants. A regulated tenant is REFUSED with an
|
|
17
|
+
* actionable explanation until a capability-specific certification exists — the
|
|
18
|
+
* regulated shared-runtime floor is non-waivable, and this bridge never opens an
|
|
19
|
+
* escape hatch around it. Promote-time enforcement still runs through the full
|
|
20
|
+
* fail-closed gate (`verifyIntegrationPromotable`); this module is the render-time
|
|
21
|
+
* tenant-eligibility decision that precedes it.
|
|
22
|
+
*/
|
|
23
|
+
import type { BrowserEnvironment } from "./environment.js";
|
|
24
|
+
import type { EffectivePlan } from "./plan.js";
|
|
25
|
+
import type { ContractViolation } from "./result.js";
|
|
26
|
+
import type { ConsentSnapshot } from "./consent-broker.js";
|
|
27
|
+
import { isPurposeEligible } from "./consent-broker.js";
|
|
28
|
+
import type { BootDescriptorIntegration } from "./render-phases.js";
|
|
29
|
+
import type { AssuranceSurface } from "./assurance.js";
|
|
30
|
+
import { resolveEffectivePlan, type IntegrationDeclarationInput } from "./resolve.js";
|
|
31
|
+
import type { ObligationTenant } from "../compliance-obligations.js";
|
|
32
|
+
import { isRegulated, resolveObligationSurface } from "../compliance-obligations.js";
|
|
33
|
+
import {
|
|
34
|
+
isRegulatedParentCertified,
|
|
35
|
+
type RegulatedParentCertification,
|
|
36
|
+
} from "./regulated-parent-cert.js";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Whether an integration's declared consent dependency permits loading its entry
|
|
40
|
+
* under `snapshot`. An `essential-only` entry always loads; any other entry loads
|
|
41
|
+
* only once EVERY declared purpose is eligible — so under the default-deny snapshot
|
|
42
|
+
* (only `essential`) a non-essential loader is held back until consent is granted.
|
|
43
|
+
* This is the predicate the lifecycle runtime's consent gate uses.
|
|
44
|
+
*/
|
|
45
|
+
export function integrationConsentEligible(
|
|
46
|
+
integration: Pick<BootDescriptorIntegration, "consent">,
|
|
47
|
+
snapshot: ConsentSnapshot,
|
|
48
|
+
): boolean {
|
|
49
|
+
if (integration.consent.loadWhen === "essential-only") return true;
|
|
50
|
+
return integration.consent.purposes.every((purpose) => isPurposeEligible(snapshot, purpose));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Why the interim bridge refused to enable for a tenant — actionable, non-secret. */
|
|
54
|
+
export interface InterimBridgeRefusal {
|
|
55
|
+
code: "regulated-tenant-not-certified";
|
|
56
|
+
/** The tenant's resolved compliance-authority surface. */
|
|
57
|
+
surface: AssuranceSurface;
|
|
58
|
+
/** An operator-facing explanation of the refusal and what unblocks it. */
|
|
59
|
+
message: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The interim bridge result: a resolved plan for an eligible tenant, an actionable
|
|
64
|
+
* refusal for a regulated one, or the resolver's fail-closed violations for an
|
|
65
|
+
* invalid declaration set. `reason` discriminates the two failure shapes.
|
|
66
|
+
*/
|
|
67
|
+
export type InterimBridgeResult =
|
|
68
|
+
| { ok: true; plan: EffectivePlan }
|
|
69
|
+
| { ok: false; reason: "regulated-refused"; refusal: InterimBridgeRefusal }
|
|
70
|
+
| { ok: false; reason: "invalid-plan"; violations: ContractViolation[] };
|
|
71
|
+
|
|
72
|
+
/** Everything the bridge needs to decide eligibility and resolve the plan. */
|
|
73
|
+
export interface InterimBridgeInput {
|
|
74
|
+
tenantPublicId: string;
|
|
75
|
+
/** The tenant's authoritative config — the ONLY source of its regulated classification. */
|
|
76
|
+
tenant: ObligationTenant;
|
|
77
|
+
environment: BrowserEnvironment;
|
|
78
|
+
declarations: readonly IntegrationDeclarationInput[];
|
|
79
|
+
/**
|
|
80
|
+
* G2: the regulated elevated-parent certification artifact for a regulated tenant.
|
|
81
|
+
* The bridge NEVER accepts a raw "certified" boolean — it runs
|
|
82
|
+
* {@link decideRegulatedParentCert} itself (via {@link isRegulatedParentCertified}),
|
|
83
|
+
* so `certifiedImmutable` has a SINGLE ORIGIN: a regulated tenant is enabled ONLY
|
|
84
|
+
* when the cert clears every clause (pinned, undrifted from `servedDigest`, every
|
|
85
|
+
* server-derived obligation proven). Absent/failed ⇒ the decision fails closed and
|
|
86
|
+
* the tenant stays refused. This is the WS2 forward seam, not a per-tenant bypass.
|
|
87
|
+
*/
|
|
88
|
+
regulatedCertification?: RegulatedParentCertification | null;
|
|
89
|
+
/**
|
|
90
|
+
* The content digest of the artifact currently resolved to serve — the drift anchor
|
|
91
|
+
* the certification decision compares against its pinned digest. When it differs, the
|
|
92
|
+
* served code has drifted and the certification no longer holds (fail closed).
|
|
93
|
+
*/
|
|
94
|
+
servedDigest?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the interim bridge's effective plan for a tenant, refusing a regulated one
|
|
99
|
+
* until certified. On an eligible tenant it delegates to the pure, hot-path
|
|
100
|
+
* {@link resolveEffectivePlan} (which fail-closes on an invalid/partial declaration
|
|
101
|
+
* set), so an eligible tenant's plan is exactly the kernel plan every mount serves —
|
|
102
|
+
* the bridge adds only the tenant-eligibility gate, not a second plan shape.
|
|
103
|
+
*/
|
|
104
|
+
export function resolveInterimBridgePlan(input: InterimBridgeInput): InterimBridgeResult {
|
|
105
|
+
const surface = resolveObligationSurface(input.tenant);
|
|
106
|
+
|
|
107
|
+
// The certification is the SINGLE ORIGIN of `certifiedImmutable`: derive it from the
|
|
108
|
+
// decision (never a raw external flag), so a regulated tenant is enabled only when the
|
|
109
|
+
// cert actually clears every clause. Absent/failed ⇒ false ⇒ refused.
|
|
110
|
+
const regulatedCertified = isRegulatedParentCertified(input.regulatedCertification, {
|
|
111
|
+
tenant: input.tenant,
|
|
112
|
+
servedDigest: input.servedDigest,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (isRegulated(input.tenant) && !regulatedCertified) {
|
|
116
|
+
return {
|
|
117
|
+
ok: false,
|
|
118
|
+
reason: "regulated-refused",
|
|
119
|
+
refusal: {
|
|
120
|
+
code: "regulated-tenant-not-certified",
|
|
121
|
+
surface,
|
|
122
|
+
message:
|
|
123
|
+
`The interim marketing bridge is not enabled for regulated tenants (resolved surface ` +
|
|
124
|
+
`"${surface}"). A regulated parent tier requires an immutable, version-pinned, ` +
|
|
125
|
+
`capability-specific certification — a mere acknowledgement cannot waive the ` +
|
|
126
|
+
`non-waivable regulated shared-runtime floor. Complete WS2 certification to enable it.`,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const result = resolveEffectivePlan({
|
|
132
|
+
tenantPublicId: input.tenantPublicId,
|
|
133
|
+
environment: input.environment,
|
|
134
|
+
declarations: input.declarations,
|
|
135
|
+
});
|
|
136
|
+
if (!result.ok) return { ok: false, reason: "invalid-plan", violations: result.violations };
|
|
137
|
+
return { ok: true, plan: result.value };
|
|
138
|
+
}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The thin browser binding that boots the {@link IntegrationLifecycle} from the
|
|
3
|
+
* document.deferred phase (ext-kernel-04 emits the `document.deferred` boundary; this is
|
|
4
|
+
* what its deferred script invokes). It is deliberately small and structural: it reads
|
|
5
|
+
* the renderer-published boot descriptor global, guarantees ONE lifecycle per document
|
|
6
|
+
* with a window-level singleton (so a nested layout that re-runs the boot island cannot
|
|
7
|
+
* double-init), wires same-document navigations to the reserved completed-navigation
|
|
8
|
+
* event, disposes on document teardown, and is a guarded no-op off the browser.
|
|
9
|
+
*
|
|
10
|
+
* The entry module for each integration is the same-origin, exact-version asset the
|
|
11
|
+
* boot descriptor carries (`integration.entry.url`): the default loader dynamically
|
|
12
|
+
* imports exactly that URL into the PARENT document and checks it exports the lifecycle
|
|
13
|
+
* contract, so no page edit or vendor branch is needed — the URL flows through the plan.
|
|
14
|
+
* Reviewed `platform-adapter` entries are admitted first through the closed runtime
|
|
15
|
+
* registry, which verifies their exact origin/tier/app/version/URL/format marker and
|
|
16
|
+
* constructs bundled platform code with host-owned capabilities. Every other entry goes
|
|
17
|
+
* through the authority-tier loader: it loads ONLY an `elevated-parent` entry (whose
|
|
18
|
+
* honest, review-only contract IS arbitrary parent-document JavaScript) and REFUSES every
|
|
19
|
+
* other tier. A `sandbox`-tier entry —
|
|
20
|
+
* whose contract is a null-origin iframe reachable only through the typed postMessage
|
|
21
|
+
* broker — is refused here and held back until the iframe host that actually isolates
|
|
22
|
+
* it ships, so third-party code labeled "sandboxed" is never executed with the parent
|
|
23
|
+
* authority its label does not grant. Loading is also consent-gated: the binding reads
|
|
24
|
+
* the renderer-inlined default-deny consent snapshot and holds a non-essential entry
|
|
25
|
+
* back until its declared purposes are eligible. With an environment-only plan there
|
|
26
|
+
* are no integrations, so the runtime boots inert and ready.
|
|
27
|
+
*/
|
|
28
|
+
import { IntegrationLifecycle, type IntegrationModuleLoader } from "./lifecycle-runtime.js";
|
|
29
|
+
import type { LifecycleObserver } from "./lifecycle-runtime.js";
|
|
30
|
+
import type { IntegrationLifecycleModule } from "./lifecycle.js";
|
|
31
|
+
import type { BootDescriptorIntegration, IntegrationBootDescriptor } from "./render-phases.js";
|
|
32
|
+
import { INTEGRATION_PLAN_GLOBAL, INTEGRATION_CONSENT_GLOBAL } from "./render-phases.js";
|
|
33
|
+
import { parseConsentSnapshot, defaultConsentSnapshot, type ConsentSnapshot } from "./consent-broker.js";
|
|
34
|
+
import { integrationConsentEligible } from "./interim-bridge.js";
|
|
35
|
+
import type { NavigationCompletedEvent, NavigationKind } from "./events.js";
|
|
36
|
+
import { CommerceEventBroker } from "./commerce-broker.js";
|
|
37
|
+
import { validateBrowserEnvironment, BROWSER_ENVIRONMENT_GLOBAL, type BrowserEnvironment } from "./environment.js";
|
|
38
|
+
import { makePlatformAdapterRuntimeLoader } from "./platform-adapter-runtime.js";
|
|
39
|
+
|
|
40
|
+
/** The window property holding the single per-document lifecycle (idempotent boot guard). */
|
|
41
|
+
export const LIFECYCLE_SINGLETON_GLOBAL = "__TOT_INTEGRATION_LIFECYCLE__";
|
|
42
|
+
/**
|
|
43
|
+
* An optional window-published loader the entry-asset layer may install to OVERRIDE the
|
|
44
|
+
* fail-closed same-origin default. It is the seam the null-origin sandboxed-iframe host
|
|
45
|
+
* (the tracked F3 follow-up) installs to actually isolate a `sandbox`-tier entry; until
|
|
46
|
+
* that host ships the seam is unused and the default loader refuses the sandbox tier.
|
|
47
|
+
*/
|
|
48
|
+
export const LIFECYCLE_MODULE_LOADER_GLOBAL = "__TOT_INTEGRATION_MODULE_LOADER__";
|
|
49
|
+
/** An optional window-published sink for the completed-navigation event. */
|
|
50
|
+
export const LIFECYCLE_NAVIGATION_SINK_GLOBAL = "__TOT_INTEGRATION_NAVIGATION__";
|
|
51
|
+
|
|
52
|
+
/** The narrow slice of `window` the binding depends on — structural, for edge-safe typing. */
|
|
53
|
+
export interface LifecycleWindow {
|
|
54
|
+
location: { pathname: string; search: string; hash: string; href: string };
|
|
55
|
+
addEventListener(type: string, listener: (event: unknown) => void): void;
|
|
56
|
+
fetch?: typeof fetch;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface BootLifecycleOptions {
|
|
61
|
+
loadModule?: IntegrationModuleLoader;
|
|
62
|
+
/** Consent gate override; defaults to the renderer-inlined default-deny snapshot. */
|
|
63
|
+
isEligible?: (integration: BootDescriptorIntegration) => boolean;
|
|
64
|
+
emitNavigation?: (event: NavigationCompletedEvent) => void;
|
|
65
|
+
observe?: LifecycleObserver;
|
|
66
|
+
/**
|
|
67
|
+
* The four-stage browser environment handed to every integration's `init`/`update`
|
|
68
|
+
* context; defaults to the renderer-published `__TOT_INTEGRATION_ENV__` global
|
|
69
|
+
* (fail closed to the descriptor-derived fallback if absent/tampered).
|
|
70
|
+
*/
|
|
71
|
+
environment?: BrowserEnvironment;
|
|
72
|
+
/**
|
|
73
|
+
* Reads the current consent snapshot handed to every integration's `init`/`update`
|
|
74
|
+
* context; defaults to the renderer-published `__TOT_INTEGRATION_CONSENT__` global
|
|
75
|
+
* (fail closed to the default-deny snapshot).
|
|
76
|
+
*/
|
|
77
|
+
getConsentSnapshot?: () => ConsentSnapshot;
|
|
78
|
+
/**
|
|
79
|
+
* The commerce-event broker whose scoped, receive-only subscribe handle is placed on
|
|
80
|
+
* each integration's lifecycle context; defaults to one constructed from the boot
|
|
81
|
+
* descriptor's server-derived trusted context (tenant/environment/surface) and the
|
|
82
|
+
* resolved consent snapshot source, so every envelope is server-stamped and
|
|
83
|
+
* consent-filtered exactly like the platform path. Injectable for tests.
|
|
84
|
+
*/
|
|
85
|
+
commerceBroker?: CommerceEventBroker;
|
|
86
|
+
/** Host-owned fetch capability for reviewed first-party platform adapters. */
|
|
87
|
+
fetchCapability?: typeof fetch;
|
|
88
|
+
/** Entry import capability; injectable for tests and non-browser hosts. */
|
|
89
|
+
importModule?: (url: string) => Promise<unknown>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Narrow the namespace of a dynamically-imported entry module to the lifecycle
|
|
94
|
+
* contract: an `init()` on the module namespace, or on its default export. Anything
|
|
95
|
+
* else is not a valid integration entry (fail closed — the caller rejects the load).
|
|
96
|
+
*/
|
|
97
|
+
function asLifecycleModule(ns: unknown): IntegrationLifecycleModule | null {
|
|
98
|
+
const candidate = (ns as { default?: unknown })?.default ?? ns;
|
|
99
|
+
if (candidate && typeof (candidate as { init?: unknown }).init === "function") {
|
|
100
|
+
return candidate as IntegrationLifecycleModule;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The one authority tier the same-origin (parent-realm) loader may run: an
|
|
107
|
+
* `elevated-parent` entry's honest contract IS arbitrary parent-document JavaScript, so
|
|
108
|
+
* importing it into the parent grants exactly what its (review-only) label already
|
|
109
|
+
* declares. Every other tier — above all `sandbox`, whose contract is a null-origin
|
|
110
|
+
* iframe reachable only through the typed postMessage broker — is refused here, so its
|
|
111
|
+
* isolation is never silently downgraded to full parent access.
|
|
112
|
+
*/
|
|
113
|
+
const PARENT_REALM_TIER = "elevated-parent" as const;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Build the same-origin entry-module loader: dynamically import an integration's
|
|
117
|
+
* declared, exact-version `entry.url` into the PARENT document and return its lifecycle
|
|
118
|
+
* module. Vendor-neutral — it imports whatever same-origin URL the plan resolved, never
|
|
119
|
+
* a hardcoded vendor path. `importModule` is injected so the loader is testable without
|
|
120
|
+
* a live network; it defaults to a native dynamic `import()`.
|
|
121
|
+
*
|
|
122
|
+
* FAIL-CLOSED BY TIER (design-partner finding F3): a parent-realm import gives the entry
|
|
123
|
+
* full parent-document authority, so the loader refuses any tier but `elevated-parent`
|
|
124
|
+
* BEFORE importing — a `sandbox`-tier entry throws without ever being fetched or
|
|
125
|
+
* evaluated, so code labeled "sandboxed" cannot run in the parent while its isolating
|
|
126
|
+
* iframe host is still the tracked follow-up. The throw is caught by the runtime's
|
|
127
|
+
* per-integration load isolation: the entry never becomes active, the page is unaffected,
|
|
128
|
+
* and every other integration still boots.
|
|
129
|
+
*/
|
|
130
|
+
export function makeSameOriginEntryLoader(
|
|
131
|
+
importModule: (url: string) => Promise<unknown> = (url) => import(/* @vite-ignore */ url),
|
|
132
|
+
): IntegrationModuleLoader {
|
|
133
|
+
return async (integration) => {
|
|
134
|
+
if (integration.executionTier !== PARENT_REALM_TIER) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Refusing to load "${integration.appId}@${integration.version}" (tier ` +
|
|
137
|
+
`"${integration.executionTier}") into the parent document: the same-origin loader ` +
|
|
138
|
+
`only runs the "${PARENT_REALM_TIER}" tier. A "sandbox"-tier entry must run inside a ` +
|
|
139
|
+
`null-origin iframe reachable only through the typed postMessage broker; that ` +
|
|
140
|
+
`isolating host is not yet wired, so the entry is held fail-closed rather than run ` +
|
|
141
|
+
`with parent-document authority its tier does not grant.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
const ns = await importModule(integration.entry.url);
|
|
145
|
+
const mod = asLifecycleModule(ns);
|
|
146
|
+
if (!mod) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`Entry module "${integration.entry.url}" for "${integration.appId}@${integration.version}" ` +
|
|
149
|
+
`does not export the integration lifecycle contract (init()).`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return mod;
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The default same-origin entry loader, over a native dynamic import. */
|
|
157
|
+
export const sameOriginEntryLoader: IntegrationModuleLoader = makeSameOriginEntryLoader();
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Construct the per-document commerce-event broker from the boot descriptor's
|
|
161
|
+
* server-derived trusted context (tenant/environment/surface) and the resolved consent
|
|
162
|
+
* snapshot source — so every envelope the broker stamps and every per-subscriber
|
|
163
|
+
* consent filter matches the platform path exactly. The broker backs the receive-only
|
|
164
|
+
* subscribe handle each sandbox entry gets; it never hands emit power to a vendor.
|
|
165
|
+
*/
|
|
166
|
+
function makeDocumentCommerceBroker(
|
|
167
|
+
descriptor: IntegrationBootDescriptor,
|
|
168
|
+
getConsentSnapshot: () => ConsentSnapshot,
|
|
169
|
+
): CommerceEventBroker {
|
|
170
|
+
return new CommerceEventBroker({
|
|
171
|
+
trusted: {
|
|
172
|
+
tenant: descriptor.tenantPublicId,
|
|
173
|
+
environment: descriptor.environment,
|
|
174
|
+
siteSurface: descriptor.siteSurface,
|
|
175
|
+
},
|
|
176
|
+
source: `//${descriptor.tenantPublicId}`,
|
|
177
|
+
consentSnapshot: getConsentSnapshot,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function readDescriptor(win: LifecycleWindow): IntegrationBootDescriptor | null {
|
|
182
|
+
const descriptor = win[INTEGRATION_PLAN_GLOBAL];
|
|
183
|
+
if (!descriptor || typeof descriptor !== "object") return null;
|
|
184
|
+
return descriptor as IntegrationBootDescriptor;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Read the current consent snapshot off the renderer-inlined global. A missing or
|
|
189
|
+
* tampered snapshot falls back to the default-deny snapshot (fail closed). This is
|
|
190
|
+
* the ONE read both the consent gate and the `init`/`update` context use, so they
|
|
191
|
+
* can never disagree about the current snapshot.
|
|
192
|
+
*/
|
|
193
|
+
function readConsentSnapshot(win: LifecycleWindow): ConsentSnapshot {
|
|
194
|
+
return parseConsentSnapshot(win[INTEGRATION_CONSENT_GLOBAL]) ?? defaultConsentSnapshot();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Read the renderer-published four-stage browser environment off `__TOT_INTEGRATION_ENV__`.
|
|
199
|
+
* `undefined` when the global is absent or fails {@link validateBrowserEnvironment} (fail
|
|
200
|
+
* closed) — the caller falls back to the descriptor-derived default.
|
|
201
|
+
*/
|
|
202
|
+
function readBrowserEnvironment(win: LifecycleWindow): BrowserEnvironment | undefined {
|
|
203
|
+
const result = validateBrowserEnvironment(win[BROWSER_ENVIRONMENT_GLOBAL]);
|
|
204
|
+
return result.ok ? result.value : undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The default consent gate: eligible iff the integration's declared purposes are all
|
|
209
|
+
* eligible under the renderer-inlined consent snapshot. A missing or tampered snapshot
|
|
210
|
+
* global falls back to the default-deny snapshot, so a non-essential entry stays gated
|
|
211
|
+
* (fail closed). A CMP/native banner that later grants a purpose updates this global and
|
|
212
|
+
* calls `lifecycle.update("consent-changed")`, which loads the newly-eligible entry.
|
|
213
|
+
*/
|
|
214
|
+
function defaultConsentGate(
|
|
215
|
+
win: LifecycleWindow,
|
|
216
|
+
): (integration: BootDescriptorIntegration) => boolean {
|
|
217
|
+
return (integration) => integrationConsentEligible(integration, readConsentSnapshot(win));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Boot the lifecycle for `win` exactly once. A second call returns the same instance
|
|
222
|
+
* (nested-layout safety). Returns `null` when there is no boot descriptor to act on.
|
|
223
|
+
*/
|
|
224
|
+
export function bootIntegrationLifecycle(
|
|
225
|
+
win: LifecycleWindow,
|
|
226
|
+
options: BootLifecycleOptions = {},
|
|
227
|
+
): IntegrationLifecycle | null {
|
|
228
|
+
const existing = win[LIFECYCLE_SINGLETON_GLOBAL];
|
|
229
|
+
if (existing instanceof IntegrationLifecycle) return existing;
|
|
230
|
+
|
|
231
|
+
const descriptor = readDescriptor(win);
|
|
232
|
+
if (!descriptor) return null;
|
|
233
|
+
|
|
234
|
+
const hostFetch = options.fetchCapability ??
|
|
235
|
+
(typeof win.fetch === "function" ? win.fetch.bind(win) : undefined);
|
|
236
|
+
const fallbackLoader = options.importModule
|
|
237
|
+
? makeSameOriginEntryLoader(options.importModule)
|
|
238
|
+
: sameOriginEntryLoader;
|
|
239
|
+
const ordinaryLoader =
|
|
240
|
+
options.loadModule ??
|
|
241
|
+
(win[LIFECYCLE_MODULE_LOADER_GLOBAL] as IntegrationModuleLoader | undefined) ??
|
|
242
|
+
fallbackLoader;
|
|
243
|
+
// Platform authority is resolved before any caller/window override: exact registry
|
|
244
|
+
// matches run; unknown/mismatched platform claims fail closed without delegation.
|
|
245
|
+
const loadModule = makePlatformAdapterRuntimeLoader({
|
|
246
|
+
fetchCapability: hostFetch,
|
|
247
|
+
importModule: options.importModule,
|
|
248
|
+
fallback: ordinaryLoader,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const isEligible = options.isEligible ?? defaultConsentGate(win);
|
|
252
|
+
|
|
253
|
+
const emitNavigation =
|
|
254
|
+
options.emitNavigation ??
|
|
255
|
+
(win[LIFECYCLE_NAVIGATION_SINK_GLOBAL] as ((e: NavigationCompletedEvent) => void) | undefined);
|
|
256
|
+
|
|
257
|
+
const environment = options.environment ?? readBrowserEnvironment(win);
|
|
258
|
+
const getConsentSnapshot = options.getConsentSnapshot ?? (() => readConsentSnapshot(win));
|
|
259
|
+
const commerceBroker =
|
|
260
|
+
options.commerceBroker ?? makeDocumentCommerceBroker(descriptor, getConsentSnapshot);
|
|
261
|
+
|
|
262
|
+
const lifecycle = new IntegrationLifecycle({
|
|
263
|
+
descriptor,
|
|
264
|
+
loadModule,
|
|
265
|
+
isEligible,
|
|
266
|
+
emitNavigation,
|
|
267
|
+
observe: options.observe,
|
|
268
|
+
environment,
|
|
269
|
+
getConsentSnapshot,
|
|
270
|
+
commerceBroker,
|
|
271
|
+
});
|
|
272
|
+
win[LIFECYCLE_SINGLETON_GLOBAL] = lifecycle;
|
|
273
|
+
|
|
274
|
+
wireNavigation(win, lifecycle);
|
|
275
|
+
wireTeardown(win, lifecycle);
|
|
276
|
+
void lifecycle.init();
|
|
277
|
+
return lifecycle;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Wire same-document navigations to the reserved completed-navigation event. In a
|
|
282
|
+
* traditional MPA a real document load re-inits by construction, so only the two
|
|
283
|
+
* navigations that DON'T reload the document — hash changes and history back/forward —
|
|
284
|
+
* need a completed-navigation signal, and neither re-initializes integrations.
|
|
285
|
+
*/
|
|
286
|
+
function wireNavigation(win: LifecycleWindow, lifecycle: IntegrationLifecycle): void {
|
|
287
|
+
let lastPath = win.location.pathname + win.location.hash;
|
|
288
|
+
win.addEventListener("hashchange", () => {
|
|
289
|
+
const to = win.location.pathname + win.location.hash;
|
|
290
|
+
lifecycle.notifyNavigationCompleted({ from: lastPath, to, kind: "hash" });
|
|
291
|
+
lastPath = to;
|
|
292
|
+
});
|
|
293
|
+
win.addEventListener("popstate", () => {
|
|
294
|
+
const to = win.location.pathname + win.location.hash;
|
|
295
|
+
const kind: NavigationKind = "back-forward";
|
|
296
|
+
lifecycle.notifyNavigationCompleted({ from: lastPath, to, kind });
|
|
297
|
+
lastPath = to;
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** Dispose the lifecycle when the document is torn down, so integrations clean up once. */
|
|
302
|
+
function wireTeardown(win: LifecycleWindow, lifecycle: IntegrationLifecycle): void {
|
|
303
|
+
win.addEventListener("pagehide", () => {
|
|
304
|
+
void lifecycle.dispose();
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* The document.deferred entrypoint: boot from the ambient `window`. A guarded no-op when
|
|
310
|
+
* there is no browser (SSR, the edge Worker bundle, tests that import the module).
|
|
311
|
+
*/
|
|
312
|
+
export function bootIntegrationLifecycleFromDocument(
|
|
313
|
+
options: BootLifecycleOptions = {},
|
|
314
|
+
): IntegrationLifecycle | null {
|
|
315
|
+
if (typeof window === "undefined") return null;
|
|
316
|
+
return bootIntegrationLifecycle(window as unknown as LifecycleWindow, options);
|
|
317
|
+
}
|