@tokenoftrust/storefront-runner 1.4.2-rc.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/storefront/astro.config.mjs +3 -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 +4 -4
- 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 +97 -10
- package/apps/storefront/src/lib/blog/markdown.ts +1 -1
- package/apps/storefront/src/lib/blog/provider.ts +57 -3
- 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 +168 -60
- 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 +31 -27
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +1 -1
- 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/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 +45 -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/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 +1 -1
- package/scripts/tot-dev.mjs +2 -2
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic, offline proof for the tokenoftrust.com GTM-migration clone.
|
|
4
|
+
*
|
|
5
|
+
* This program deliberately has no configuration, network client, secret reader,
|
|
6
|
+
* renderer, GTM loader, or production binding. It exercises the supported
|
|
7
|
+
* tenant-key layouts against in-memory KV/R2 destinations, records sanitized
|
|
8
|
+
* hashes for the source before and after clone work, then applies the same
|
|
9
|
+
* bounded-prefix ownership rules as the diagnostic clone reaper.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import {
|
|
14
|
+
cloneKvKeyPrefixes,
|
|
15
|
+
reapClone,
|
|
16
|
+
} from "../src/lib/preview/clone-reap.js";
|
|
17
|
+
import { reconcileTraceKey } from "../src/lib/preview/reconcileTrace.js";
|
|
18
|
+
import { releaseTruthKey as releaseKey } from "../src/lib/change/store/aggregate-release-store.js";
|
|
19
|
+
import { DEFAULT_AGGREGATE_ID } from "../src/lib/change/orchestrators/integration-queue.js";
|
|
20
|
+
import {
|
|
21
|
+
assetsPointerKey,
|
|
22
|
+
customizationArtifactKey as artifactKey,
|
|
23
|
+
customizationPointerKey as contentPointerKey,
|
|
24
|
+
previewStateKey,
|
|
25
|
+
reviewEnvironmentIndexKey as candidateIndexKey,
|
|
26
|
+
reviewEnvironmentKey as candidateKey,
|
|
27
|
+
siteVersionIndexKey as versionsKey,
|
|
28
|
+
siteVersionKey as versionKey,
|
|
29
|
+
tenantAssetKey as assetKey,
|
|
30
|
+
} from "@tot/public-runtime";
|
|
31
|
+
import {
|
|
32
|
+
V84_REPLAY_SESSION_ID,
|
|
33
|
+
type V84CleanCloneReplayContext,
|
|
34
|
+
} from "../src/lib/apps/v84CleanCloneReplayContext.js";
|
|
35
|
+
|
|
36
|
+
export const SOURCE_TENANT = "tokenoftrust.com";
|
|
37
|
+
export const CLONE_TENANT = "tokenoftrust.com~clone~gtm-migration-v84";
|
|
38
|
+
|
|
39
|
+
const SOURCE_VERSION = "1".repeat(40);
|
|
40
|
+
const CLONE_VERSION = "2".repeat(40);
|
|
41
|
+
const SOURCE_DESIRED = "3".repeat(40);
|
|
42
|
+
const CLONE_ARTIFACT = "4".repeat(64);
|
|
43
|
+
// Keep this aligned with DEFAULT_AGGREGATE_ID in integration-queue.ts: the
|
|
44
|
+
// source release invariant is meaningful only when it hashes the canonical
|
|
45
|
+
// release-truth namespace used by reconcile/aggregate shipping.
|
|
46
|
+
const AGGREGATE = DEFAULT_AGGREGATE_ID;
|
|
47
|
+
const CANDIDATE = "gtm-migration-proof";
|
|
48
|
+
const FIXED_AT = "2026-08-29T00:00:00.000Z";
|
|
49
|
+
|
|
50
|
+
function stable(value: unknown): unknown {
|
|
51
|
+
if (Array.isArray(value)) return value.map(stable);
|
|
52
|
+
if (value && typeof value === "object") {
|
|
53
|
+
return Object.fromEntries(
|
|
54
|
+
Object.entries(value as Record<string, unknown>)
|
|
55
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
56
|
+
.map(([key, child]) => [key, stable(child)]),
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function digest(value: unknown): string {
|
|
63
|
+
return `sha256:${createHash("sha256").update(JSON.stringify(stable(value))).digest("hex")}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function json(value: unknown): string {
|
|
67
|
+
return JSON.stringify(value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class MemoryKv {
|
|
71
|
+
store = new Map<string, string>();
|
|
72
|
+
reads: string[] = [];
|
|
73
|
+
writes: string[] = [];
|
|
74
|
+
|
|
75
|
+
seed(key: string, value: unknown): void {
|
|
76
|
+
this.store.set(key, typeof value === "string" ? value : json(value));
|
|
77
|
+
}
|
|
78
|
+
get(key: string): string | null {
|
|
79
|
+
this.reads.push(key);
|
|
80
|
+
return this.store.get(key) ?? null;
|
|
81
|
+
}
|
|
82
|
+
put(key: string, value: unknown): void {
|
|
83
|
+
this.writes.push(key);
|
|
84
|
+
this.store.set(key, typeof value === "string" ? value : json(value));
|
|
85
|
+
}
|
|
86
|
+
async list({ prefix = "" }: { prefix?: string; cursor?: string; limit?: number } = {}) {
|
|
87
|
+
const keys = [...this.store.keys()]
|
|
88
|
+
.filter((key) => key.startsWith(prefix))
|
|
89
|
+
.sort()
|
|
90
|
+
.map((name) => ({ name }));
|
|
91
|
+
return { keys, list_complete: true };
|
|
92
|
+
}
|
|
93
|
+
async delete(key: string): Promise<void> {
|
|
94
|
+
this.writes.push(key);
|
|
95
|
+
this.store.delete(key);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
class MemoryR2 {
|
|
100
|
+
store = new Map<string, Uint8Array>();
|
|
101
|
+
writes: string[] = [];
|
|
102
|
+
deletes: string[] = [];
|
|
103
|
+
put(key: string, bytes: readonly number[]): void {
|
|
104
|
+
this.writes.push(key);
|
|
105
|
+
this.store.set(key, Uint8Array.from(bytes));
|
|
106
|
+
}
|
|
107
|
+
async list({ prefix = "" }: { prefix?: string; cursor?: string } = {}) {
|
|
108
|
+
const objects = [...this.store.keys()]
|
|
109
|
+
.filter((key) => key.startsWith(prefix))
|
|
110
|
+
.sort()
|
|
111
|
+
.map((key) => ({ key }));
|
|
112
|
+
return { objects, truncated: false };
|
|
113
|
+
}
|
|
114
|
+
async delete(keys: string | string[]): Promise<void> {
|
|
115
|
+
for (const key of Array.isArray(keys) ? keys : [keys]) {
|
|
116
|
+
this.deletes.push(key);
|
|
117
|
+
this.store.delete(key);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function ownedKvKey(key: string, tenantId: string): boolean {
|
|
123
|
+
return cloneKvKeyPrefixes(tenantId)
|
|
124
|
+
.some((bound) => key === bound || key.startsWith(`${bound}:`));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Scan the fake KV independently of the reaper registry. The tenant must be a
|
|
129
|
+
* complete colon-delimited key component, so a source tenant never matches its
|
|
130
|
+
* clone and one clone label never matches a sibling with a longer label.
|
|
131
|
+
*/
|
|
132
|
+
function exactTenantKvKey(key: string, tenantId: string): boolean {
|
|
133
|
+
const marker = `:${tenantId}`;
|
|
134
|
+
let offset = key.indexOf(marker);
|
|
135
|
+
while (offset >= 0) {
|
|
136
|
+
const end = offset + marker.length;
|
|
137
|
+
if (end === key.length || key[end] === ":") return true;
|
|
138
|
+
offset = key.indexOf(marker, offset + 1);
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function tenantKvKeys(kv: MemoryKv, tenantId: string): string[] {
|
|
144
|
+
return [...kv.store.keys()].filter((key) => exactTenantKvKey(key, tenantId)).sort();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function tenantR2Keys(r2: MemoryR2, tenantId: string): string[] {
|
|
148
|
+
const prefix = `tenants/${tenantId}/`;
|
|
149
|
+
return [...r2.store.keys()].filter((key) => key.startsWith(prefix)).sort();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function parseRecord(kv: MemoryKv, key: string): Record<string, unknown> {
|
|
153
|
+
const raw = kv.get(key);
|
|
154
|
+
if (raw === null) throw new Error(`missing proof fixture record: ${key}`);
|
|
155
|
+
return JSON.parse(raw);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function captureSource(kv: MemoryKv) {
|
|
159
|
+
const preview = parseRecord(kv, previewStateKey(SOURCE_TENANT));
|
|
160
|
+
const releaseTruthKey = releaseKey(SOURCE_TENANT, AGGREGATE);
|
|
161
|
+
const release = parseRecord(kv, releaseTruthKey);
|
|
162
|
+
return {
|
|
163
|
+
tenant: SOURCE_TENANT,
|
|
164
|
+
releaseTruthKey,
|
|
165
|
+
desired: digest(preview.target),
|
|
166
|
+
actual: digest(preview.actual),
|
|
167
|
+
release: digest({ liveReceiptId: release.liveReceiptId, lastGreenRunId: release.lastGreenRunId }),
|
|
168
|
+
combined: digest({
|
|
169
|
+
desired: preview.target,
|
|
170
|
+
actual: preview.actual,
|
|
171
|
+
releaseTruthKey,
|
|
172
|
+
release: { liveReceiptId: release.liveReceiptId, lastGreenRunId: release.lastGreenRunId },
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function captureCloneBefore(kv: MemoryKv, r2: MemoryR2) {
|
|
178
|
+
const kvKeys = tenantKvKeys(kv, CLONE_TENANT);
|
|
179
|
+
const r2Keys = tenantR2Keys(r2, CLONE_TENANT);
|
|
180
|
+
return {
|
|
181
|
+
tenant: CLONE_TENANT,
|
|
182
|
+
kvKeyCount: kvKeys.length,
|
|
183
|
+
r2ObjectCount: r2Keys.length,
|
|
184
|
+
namespace: digest({ kvKeys, r2Keys }),
|
|
185
|
+
state: "absent",
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function copyPointer(kv: MemoryKv, fromKey: string, toKey: string): void {
|
|
190
|
+
const source = parseRecord(kv, fromKey);
|
|
191
|
+
kv.put(toKey, { ...source, tenantId: CLONE_TENANT });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function provisionClone(kv: MemoryKv): void {
|
|
195
|
+
copyPointer(kv, previewStateKey(SOURCE_TENANT), previewStateKey(CLONE_TENANT));
|
|
196
|
+
copyPointer(kv, contentPointerKey(SOURCE_TENANT), contentPointerKey(CLONE_TENANT));
|
|
197
|
+
copyPointer(kv, assetsPointerKey(SOURCE_TENANT), assetsPointerKey(CLONE_TENANT));
|
|
198
|
+
kv.put(`cust:diag-clone:${CLONE_TENANT}`, {
|
|
199
|
+
cloneId: CLONE_TENANT,
|
|
200
|
+
base: SOURCE_TENANT,
|
|
201
|
+
label: "gtm-migration-v84",
|
|
202
|
+
mode: "offline-proof",
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function reconcileCloneLocally(kv: MemoryKv, r2: MemoryR2): void {
|
|
207
|
+
kv.put(previewStateKey(CLONE_TENANT), {
|
|
208
|
+
tenantId: CLONE_TENANT,
|
|
209
|
+
target: CLONE_VERSION,
|
|
210
|
+
actual: CLONE_VERSION,
|
|
211
|
+
lastError: null,
|
|
212
|
+
lastReconcileAt: FIXED_AT,
|
|
213
|
+
});
|
|
214
|
+
kv.put(contentPointerKey(CLONE_TENANT), {
|
|
215
|
+
tenantId: CLONE_TENANT,
|
|
216
|
+
rev: 8,
|
|
217
|
+
live: {},
|
|
218
|
+
test: {},
|
|
219
|
+
channels: { live: SOURCE_VERSION, preview: CLONE_VERSION },
|
|
220
|
+
});
|
|
221
|
+
kv.put(assetsPointerKey(CLONE_TENANT), {
|
|
222
|
+
tenantId: CLONE_TENANT,
|
|
223
|
+
rev: 8,
|
|
224
|
+
live: SOURCE_VERSION,
|
|
225
|
+
test: CLONE_VERSION,
|
|
226
|
+
});
|
|
227
|
+
kv.put(versionKey(CLONE_TENANT, CLONE_VERSION), {
|
|
228
|
+
tenantId: CLONE_TENANT,
|
|
229
|
+
versionId: CLONE_VERSION,
|
|
230
|
+
source: "commit",
|
|
231
|
+
createdAt: FIXED_AT,
|
|
232
|
+
artifacts: { "content/home.html": CLONE_ARTIFACT },
|
|
233
|
+
assets: { versionId: CLONE_VERSION, count: 1 },
|
|
234
|
+
});
|
|
235
|
+
kv.put(versionsKey(CLONE_TENANT), [{
|
|
236
|
+
versionId: CLONE_VERSION,
|
|
237
|
+
source: "commit",
|
|
238
|
+
createdAt: FIXED_AT,
|
|
239
|
+
artifactCount: 1,
|
|
240
|
+
}]);
|
|
241
|
+
kv.put(artifactKey(CLONE_TENANT, CLONE_ARTIFACT), "<sanitized-offline-artifact>");
|
|
242
|
+
kv.put(candidateKey(CLONE_TENANT, CANDIDATE), {
|
|
243
|
+
tenantId: CLONE_TENANT,
|
|
244
|
+
changeId: CANDIDATE,
|
|
245
|
+
prNumber: null,
|
|
246
|
+
branch: null,
|
|
247
|
+
headSha: CLONE_VERSION,
|
|
248
|
+
baseSha: null,
|
|
249
|
+
versionId: CLONE_VERSION,
|
|
250
|
+
status: "ready",
|
|
251
|
+
previewUrl: null,
|
|
252
|
+
evidence: null,
|
|
253
|
+
mergeable: false,
|
|
254
|
+
lastError: null,
|
|
255
|
+
updatedAt: FIXED_AT,
|
|
256
|
+
});
|
|
257
|
+
kv.put(candidateIndexKey(CLONE_TENANT), [CANDIDATE]);
|
|
258
|
+
kv.put(reconcileTraceKey(CLONE_TENANT, CLONE_VERSION), {
|
|
259
|
+
tenantId: CLONE_TENANT,
|
|
260
|
+
stage: "done",
|
|
261
|
+
mode: "offline-proof",
|
|
262
|
+
});
|
|
263
|
+
r2.put(
|
|
264
|
+
assetKey(CLONE_TENANT, CLONE_VERSION, "apps/managed-analytics/proof.js"),
|
|
265
|
+
[111, 102, 102, 108, 105, 110, 101],
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function assertProof(condition: unknown, message: string): asserts condition {
|
|
270
|
+
if (!condition) throw new Error(`clone isolation proof failed: ${message}`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const COMPLETE_REPLAY_STAGES = ["import", "native", "dogfood", "lifecycle"] as const;
|
|
274
|
+
type CompleteReplayStage = (typeof COMPLETE_REPLAY_STAGES)[number];
|
|
275
|
+
|
|
276
|
+
/** Create one supported fake clone state that remains active across replay stages. */
|
|
277
|
+
export function createOfflineCloneReplaySession() {
|
|
278
|
+
const kv = new MemoryKv();
|
|
279
|
+
const r2 = new MemoryR2();
|
|
280
|
+
assertProof(
|
|
281
|
+
exactTenantKvKey(`cust:future-proof:${CLONE_TENANT}:child`, CLONE_TENANT),
|
|
282
|
+
"independent residual scan missed an unknown clone prefix",
|
|
283
|
+
);
|
|
284
|
+
assertProof(
|
|
285
|
+
!exactTenantKvKey(`cust:future-proof:${CLONE_TENANT}x:child`, CLONE_TENANT),
|
|
286
|
+
"independent residual scan crossed a sibling clone boundary",
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
kv.seed(previewStateKey(SOURCE_TENANT), {
|
|
290
|
+
tenantId: SOURCE_TENANT,
|
|
291
|
+
target: SOURCE_DESIRED,
|
|
292
|
+
actual: SOURCE_VERSION,
|
|
293
|
+
lastError: null,
|
|
294
|
+
lastReconcileAt: FIXED_AT,
|
|
295
|
+
});
|
|
296
|
+
kv.seed(contentPointerKey(SOURCE_TENANT), {
|
|
297
|
+
tenantId: SOURCE_TENANT,
|
|
298
|
+
rev: 7,
|
|
299
|
+
live: {},
|
|
300
|
+
test: {},
|
|
301
|
+
channels: { live: SOURCE_VERSION, preview: SOURCE_VERSION },
|
|
302
|
+
});
|
|
303
|
+
kv.seed(assetsPointerKey(SOURCE_TENANT), {
|
|
304
|
+
tenantId: SOURCE_TENANT,
|
|
305
|
+
rev: 7,
|
|
306
|
+
live: SOURCE_VERSION,
|
|
307
|
+
test: SOURCE_VERSION,
|
|
308
|
+
});
|
|
309
|
+
kv.seed(versionKey(SOURCE_TENANT, SOURCE_VERSION), {
|
|
310
|
+
tenantId: SOURCE_TENANT,
|
|
311
|
+
versionId: SOURCE_VERSION,
|
|
312
|
+
source: "commit",
|
|
313
|
+
createdAt: FIXED_AT,
|
|
314
|
+
artifacts: {},
|
|
315
|
+
});
|
|
316
|
+
kv.seed(releaseKey(SOURCE_TENANT, AGGREGATE), {
|
|
317
|
+
tenantId: SOURCE_TENANT,
|
|
318
|
+
aggregateId: AGGREGATE,
|
|
319
|
+
liveReceiptId: "receipt-source-6",
|
|
320
|
+
lastGreenRunId: "run-source-7",
|
|
321
|
+
rev: 6,
|
|
322
|
+
updatedAt: FIXED_AT,
|
|
323
|
+
});
|
|
324
|
+
r2.put(assetKey(SOURCE_TENANT, SOURCE_VERSION, "assets/source.css"), [115, 114, 99]);
|
|
325
|
+
const before = {
|
|
326
|
+
source: captureSource(kv),
|
|
327
|
+
clone: captureCloneBefore(kv, r2),
|
|
328
|
+
};
|
|
329
|
+
const writeAuditStart = kv.writes.length;
|
|
330
|
+
const readAuditStart = kv.reads.length;
|
|
331
|
+
const r2WriteAuditStart = r2.writes.length;
|
|
332
|
+
let state: "absent" | "active" | "cleaned" = "absent";
|
|
333
|
+
const sessionId = V84_REPLAY_SESSION_ID;
|
|
334
|
+
const sharedStatePrefix = `cust:diag-clone:${CLONE_TENANT}:shared-state:`;
|
|
335
|
+
let activeStage: CompleteReplayStage | null = null;
|
|
336
|
+
const context: V84CleanCloneReplayContext = Object.freeze({
|
|
337
|
+
sessionId,
|
|
338
|
+
cloneTenant: CLONE_TENANT,
|
|
339
|
+
read<T>(key: string): T | undefined {
|
|
340
|
+
assertProof(state === "active", "shared replay state was read outside the active session");
|
|
341
|
+
const raw = kv.get(`${sharedStatePrefix}${key}`);
|
|
342
|
+
return raw === null ? undefined : JSON.parse(raw) as T;
|
|
343
|
+
},
|
|
344
|
+
write(key: string, value: unknown): void {
|
|
345
|
+
assertProof(state === "active" && activeStage !== null, "shared replay state was written outside a stage");
|
|
346
|
+
assertProof(key.startsWith(`stage/${activeStage}/`), "stage wrote outside its shared replay namespace");
|
|
347
|
+
kv.put(`${sharedStatePrefix}${key}`, json(value));
|
|
348
|
+
},
|
|
349
|
+
delete(key: string): void {
|
|
350
|
+
assertProof(state === "active" && activeStage !== null, "shared replay state was deleted outside a stage");
|
|
351
|
+
assertProof(key.startsWith(`stage/${activeStage}/`), "stage deleted outside its shared replay namespace");
|
|
352
|
+
kv.writes.push(`${sharedStatePrefix}${key}`);
|
|
353
|
+
kv.store.delete(`${sharedStatePrefix}${key}`);
|
|
354
|
+
},
|
|
355
|
+
keys(prefix = ""): readonly string[] {
|
|
356
|
+
assertProof(state === "active", "shared replay state was listed outside the active session");
|
|
357
|
+
return [...kv.store.keys()]
|
|
358
|
+
.filter((key) => key.startsWith(`${sharedStatePrefix}${prefix}`))
|
|
359
|
+
.map((key) => key.slice(sharedStatePrefix.length))
|
|
360
|
+
.sort();
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
const stageLedger: {
|
|
364
|
+
stage: CompleteReplayStage;
|
|
365
|
+
evidenceSha256: string;
|
|
366
|
+
cloneTenant: typeof CLONE_TENANT;
|
|
367
|
+
cloneState: "active";
|
|
368
|
+
sessionId: typeof sessionId;
|
|
369
|
+
sharedStateKeyCount: number;
|
|
370
|
+
}[] = [];
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
provisionAndReconcile() {
|
|
374
|
+
assertProof(state === "absent", "clone session did not start absent");
|
|
375
|
+
provisionClone(kv);
|
|
376
|
+
reconcileCloneLocally(kv, r2);
|
|
377
|
+
state = "active";
|
|
378
|
+
return {
|
|
379
|
+
state,
|
|
380
|
+
cloneTenant: CLONE_TENANT,
|
|
381
|
+
kvKeys: tenantKvKeys(kv, CLONE_TENANT),
|
|
382
|
+
r2Keys: tenantR2Keys(r2, CLONE_TENANT),
|
|
383
|
+
};
|
|
384
|
+
},
|
|
385
|
+
async runStage<T>(stage: CompleteReplayStage, operation: (context: V84CleanCloneReplayContext) => T | Promise<T>) {
|
|
386
|
+
assertProof(state === "active", "stage executed outside the active clone session");
|
|
387
|
+
assertProof(COMPLETE_REPLAY_STAGES[stageLedger.length] === stage, "complete replay stage order changed");
|
|
388
|
+
activeStage = stage;
|
|
389
|
+
let evidence: T;
|
|
390
|
+
try {
|
|
391
|
+
evidence = await operation(context);
|
|
392
|
+
} finally {
|
|
393
|
+
activeStage = null;
|
|
394
|
+
}
|
|
395
|
+
assertProof(state === "active", "stage changed the shared clone-session lifecycle");
|
|
396
|
+
const evidenceSha256 = `sha256:${createHash("sha256").update(JSON.stringify(evidence)).digest("hex")}`;
|
|
397
|
+
const sharedHandoff = context.read<T>(`stage/${stage}/handoff`);
|
|
398
|
+
assertProof(sharedHandoff !== undefined, "stage did not persist its handoff in shared clone state");
|
|
399
|
+
assertProof(
|
|
400
|
+
JSON.stringify(sharedHandoff) === JSON.stringify(evidence),
|
|
401
|
+
"stage shared-state handoff did not match its returned evidence",
|
|
402
|
+
);
|
|
403
|
+
const sharedStateKeyCount = context.keys(`stage/${stage}/`).length;
|
|
404
|
+
assertProof(sharedStateKeyCount > 0, "stage did not use the shared clone-state adapter");
|
|
405
|
+
const record: (typeof stageLedger)[number] = {
|
|
406
|
+
stage, evidenceSha256, cloneTenant: CLONE_TENANT, cloneState: "active", sessionId,
|
|
407
|
+
sharedStateKeyCount,
|
|
408
|
+
};
|
|
409
|
+
stageLedger.push(record);
|
|
410
|
+
kv.put(`cust:diag-clone:${CLONE_TENANT}:stage:${stageLedger.length}:${stage}`, record);
|
|
411
|
+
return { evidence, handoff: { ...record, ordinal: stageLedger.length } };
|
|
412
|
+
},
|
|
413
|
+
activeSnapshot() {
|
|
414
|
+
assertProof(state === "active", "clone session is not active");
|
|
415
|
+
return {
|
|
416
|
+
state,
|
|
417
|
+
cloneTenant: CLONE_TENANT,
|
|
418
|
+
stageLedger: stageLedger.map((record) => ({ ...record })),
|
|
419
|
+
kvKeys: tenantKvKeys(kv, CLONE_TENANT),
|
|
420
|
+
r2Keys: tenantR2Keys(r2, CLONE_TENANT),
|
|
421
|
+
source: captureSource(kv),
|
|
422
|
+
};
|
|
423
|
+
},
|
|
424
|
+
async cleanup(requireCompleteReplay = false) {
|
|
425
|
+
assertProof(state === "active", "cleanup requires one active clone session");
|
|
426
|
+
if (requireCompleteReplay) {
|
|
427
|
+
assertProof(stageLedger.length === COMPLETE_REPLAY_STAGES.length, "complete replay stage ledger is partial");
|
|
428
|
+
}
|
|
429
|
+
const materializedKvKeys = tenantKvKeys(kv, CLONE_TENANT);
|
|
430
|
+
const materializedR2Keys = tenantR2Keys(r2, CLONE_TENANT);
|
|
431
|
+
const sourceAfterCloneWork = captureSource(kv);
|
|
432
|
+
const sourceWrites = kv.writes.slice(writeAuditStart).filter((key) => exactTenantKvKey(key, SOURCE_TENANT));
|
|
433
|
+
const sourceReads = kv.reads.slice(readAuditStart).filter((key) => exactTenantKvKey(key, SOURCE_TENANT));
|
|
434
|
+
const sourceR2Writes = r2.writes.slice(r2WriteAuditStart)
|
|
435
|
+
.filter((key) => key.startsWith(`tenants/${SOURCE_TENANT}/`));
|
|
436
|
+
assertProof(before.source.combined === sourceAfterCloneWork.combined, "source state hash changed");
|
|
437
|
+
assertProof(sourceWrites.length === 0, "source namespace received a write");
|
|
438
|
+
assertProof(sourceR2Writes.length === 0, "source R2 namespace received a write");
|
|
439
|
+
assertProof(materializedKvKeys.every((key) => ownedKvKey(key, CLONE_TENANT)), "foreign KV key in clone set");
|
|
440
|
+
assertProof(materializedR2Keys.every((key) => key.startsWith(`tenants/${CLONE_TENANT}/`)), "foreign R2 key in clone set");
|
|
441
|
+
const cleanup = await reapClone({ kv, bucket: r2, cloneId: CLONE_TENANT });
|
|
442
|
+
state = "cleaned";
|
|
443
|
+
const sourceFinal = captureSource(kv);
|
|
444
|
+
const cloneResidual = { kvKeys: tenantKvKeys(kv, CLONE_TENANT), r2Keys: tenantR2Keys(r2, CLONE_TENANT) };
|
|
445
|
+
assertProof(sourceFinal.combined === before.source.combined, "source changed during cleanup");
|
|
446
|
+
assertProof(cloneResidual.kvKeys.length === 0 && cloneResidual.r2Keys.length === 0, "clone residual remains");
|
|
447
|
+
return {
|
|
448
|
+
schemaVersion: 1,
|
|
449
|
+
proof: "ws3-prove-source-clone-isolation",
|
|
450
|
+
constraints: {
|
|
451
|
+
mode: "offline-in-memory-only", sourceAccess: "read-only", network: "none",
|
|
452
|
+
secrets: "none", pii: "none", gtmExecution: "forbidden", rendering: "forbidden",
|
|
453
|
+
production: "forbidden",
|
|
454
|
+
},
|
|
455
|
+
before,
|
|
456
|
+
sourceInvariant: {
|
|
457
|
+
before: before.source, afterCloneWork: sourceAfterCloneWork, afterCleanup: sourceFinal,
|
|
458
|
+
readsObserved: sourceReads.length, kvWritesObserved: sourceWrites.length,
|
|
459
|
+
r2WritesObserved: sourceR2Writes.length, unchanged: true,
|
|
460
|
+
},
|
|
461
|
+
cloneIsolation: {
|
|
462
|
+
tenant: CLONE_TENANT,
|
|
463
|
+
kv: { keys: materializedKvKeys, distinctFromSource: true },
|
|
464
|
+
r2: { keys: materializedR2Keys, prefix: `tenants/${CLONE_TENANT}/`, distinctFromSource: true },
|
|
465
|
+
revisionVersion: {
|
|
466
|
+
versionKey: versionKey(CLONE_TENANT, CLONE_VERSION),
|
|
467
|
+
versionIndexKey: versionsKey(CLONE_TENANT),
|
|
468
|
+
artifactKey: artifactKey(CLONE_TENANT, CLONE_ARTIFACT),
|
|
469
|
+
},
|
|
470
|
+
candidateStaged: {
|
|
471
|
+
candidateKey: candidateKey(CLONE_TENANT, CANDIDATE),
|
|
472
|
+
candidateIndexKey: candidateIndexKey(CLONE_TENANT),
|
|
473
|
+
stagedContentPointerKey: contentPointerKey(CLONE_TENANT),
|
|
474
|
+
stagedAssetsPointerKey: assetsPointerKey(CLONE_TENANT),
|
|
475
|
+
},
|
|
476
|
+
sharedStageLedger: stageLedger.map((record) => ({ ...record })),
|
|
477
|
+
},
|
|
478
|
+
cleanup: {
|
|
479
|
+
ownership: "supported reapClone exact-tenant KV bounds and exact R2 tenant prefix",
|
|
480
|
+
kvKeysDeleted: cleanup.kvKeysDeleted, r2KeysDeleted: materializedR2Keys,
|
|
481
|
+
r2ObjectsDeleted: cleanup.r2ObjectsDeleted, cloneResidual, sourcePreserved: true,
|
|
482
|
+
},
|
|
483
|
+
result: "pass",
|
|
484
|
+
};
|
|
485
|
+
},
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Run the fixed, fake-only proof and return a sanitized evidence record. */
|
|
490
|
+
export async function runOfflineCloneIsolationProof() {
|
|
491
|
+
const session = createOfflineCloneReplaySession();
|
|
492
|
+
session.provisionAndReconcile();
|
|
493
|
+
return session.cleanup();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const invokedPath = import.meta.url.startsWith("file:") && process.argv[1]
|
|
497
|
+
? fileURLToPath(import.meta.url) === process.argv[1]
|
|
498
|
+
: false;
|
|
499
|
+
if (invokedPath) {
|
|
500
|
+
if (process.argv.length !== 2) {
|
|
501
|
+
process.stderr.write("usage: pnpm run diag:prove-clone-isolation\n");
|
|
502
|
+
process.exitCode = 64;
|
|
503
|
+
} else {
|
|
504
|
+
process.stdout.write(`${JSON.stringify(await runOfflineCloneIsolationProof(), null, 2)}\n`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/** One composed v84 replay pass over one active supported fake clone session. */
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import type { GetAdapterDefinitionRequest, GetAdapterDefinitionResponse } from "@tot/public-runtime";
|
|
6
|
+
import { buildV84CloneMigrationEvidence } from "../src/lib/apps/v84CloneMigrationEvidence.js";
|
|
7
|
+
import { buildV84CloneLifecycleEvidence } from "../src/lib/apps/v84CloneLifecycleEvidence.js";
|
|
8
|
+
import { buildV84NonportableRouteDogfood } from "../src/lib/apps/v84NonportableRouteDogfood.js";
|
|
9
|
+
import { v84PublicAdapterDefinitions } from "../src/lib/apps/v84CloneNativeInstallEvidence.js";
|
|
10
|
+
import { buildFixedV84NativeInstallEvidence } from "./install-v84-native-through-ws1.js";
|
|
11
|
+
import { createOfflineCloneReplaySession } from "./prove-clone-isolation.js";
|
|
12
|
+
import {
|
|
13
|
+
V84_CLEAN_CLONE_GRAPH_COUNT,
|
|
14
|
+
V84_CLEAN_CLONE_GRAPH_SHA256,
|
|
15
|
+
type V84CleanCloneGraphIdentity,
|
|
16
|
+
} from "./v84CleanCloneGraphPin.js";
|
|
17
|
+
|
|
18
|
+
const SOURCE = "tokenoftrust.com";
|
|
19
|
+
const CLONE = "tokenoftrust.com~clone~gtm-migration-v84";
|
|
20
|
+
const FIXTURE_SHA256 = "57d28f3ed5da4215599bfb4b74f984d8b0cd8bf7d8b31e0e1172877308e9b688";
|
|
21
|
+
|
|
22
|
+
function assertPass(condition: unknown): asserts condition {
|
|
23
|
+
if (!condition) throw new Error("The composed clean-clone pass failed safely.");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Run import -> native -> dogfood -> lifecycle before reaping the same clone. */
|
|
27
|
+
export async function buildComposedV84CleanClonePass(
|
|
28
|
+
options: {
|
|
29
|
+
readonly resolveGraph: () => V84CleanCloneGraphIdentity;
|
|
30
|
+
readonly fixtureText?: string;
|
|
31
|
+
readonly executionSnapshotSha256?: string;
|
|
32
|
+
},
|
|
33
|
+
) {
|
|
34
|
+
const fixturePath = options.fixtureText === undefined ? fileURLToPath(new URL(
|
|
35
|
+
"../../../packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.redacted.json",
|
|
36
|
+
import.meta.url,
|
|
37
|
+
)) : undefined;
|
|
38
|
+
const fixture = options.fixtureText ?? readFileSync(fixturePath!, "utf8");
|
|
39
|
+
const fixtureBefore = createHash("sha256").update(fixture).digest("hex");
|
|
40
|
+
assertPass(fixtureBefore === FIXTURE_SHA256);
|
|
41
|
+
const graph = options.resolveGraph();
|
|
42
|
+
assertPass(graph.count === V84_CLEAN_CLONE_GRAPH_COUNT && graph.sha256 === V84_CLEAN_CLONE_GRAPH_SHA256);
|
|
43
|
+
const executionSnapshotSha256 = options.executionSnapshotSha256 ?? "source-module-test";
|
|
44
|
+
assertPass(executionSnapshotSha256 === "source-module-test" || /^[a-f0-9]{64}$/.test(executionSnapshotSha256));
|
|
45
|
+
|
|
46
|
+
const definitions = v84PublicAdapterDefinitions();
|
|
47
|
+
const catalog = {
|
|
48
|
+
async getAdapterDefinition(request: GetAdapterDefinitionRequest): Promise<GetAdapterDefinitionResponse> {
|
|
49
|
+
const found = definitions.find((definition) => definition.adapterId === request.query.adapterId);
|
|
50
|
+
if (!found) {
|
|
51
|
+
return { apiVersion: "v1", requestId: "req-composed-missing", error: { code: "not_found", message: "The requested adapter was not found." } };
|
|
52
|
+
}
|
|
53
|
+
return { apiVersion: "v1", requestId: "req-composed-catalog", data: found };
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const session = createOfflineCloneReplaySession();
|
|
57
|
+
const provisioned = session.provisionAndReconcile();
|
|
58
|
+
assertPass(provisioned.state === "active" && provisioned.cloneTenant === CLONE);
|
|
59
|
+
|
|
60
|
+
const executionLedger: Array<{
|
|
61
|
+
stage: "import" | "native" | "dogfood" | "lifecycle";
|
|
62
|
+
sourceGraphCount: number;
|
|
63
|
+
sourceGraphSha256: string;
|
|
64
|
+
executionSnapshotSha256: string;
|
|
65
|
+
}> = [];
|
|
66
|
+
const runVerifiedStage = async <T>(
|
|
67
|
+
stage: (typeof executionLedger)[number]["stage"],
|
|
68
|
+
operation: () => T | Promise<T>,
|
|
69
|
+
): Promise<T> => {
|
|
70
|
+
const result = await operation();
|
|
71
|
+
executionLedger.push({
|
|
72
|
+
stage,
|
|
73
|
+
sourceGraphCount: graph.count,
|
|
74
|
+
sourceGraphSha256: graph.sha256,
|
|
75
|
+
executionSnapshotSha256,
|
|
76
|
+
});
|
|
77
|
+
return result;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const importStage = await runVerifiedStage("import",
|
|
81
|
+
() => session.runStage("import", (context) => buildV84CloneMigrationEvidence(fixture, catalog, context)),
|
|
82
|
+
);
|
|
83
|
+
const nativeStage = await runVerifiedStage("native",
|
|
84
|
+
() => session.runStage("native", (context) => buildFixedV84NativeInstallEvidence(importStage.evidence, context)),
|
|
85
|
+
);
|
|
86
|
+
const dogfoodStage = await runVerifiedStage("dogfood",
|
|
87
|
+
() => session.runStage("dogfood", (context) => buildV84NonportableRouteDogfood(
|
|
88
|
+
importStage.evidence,
|
|
89
|
+
definitions.map((item) => item.adapterId),
|
|
90
|
+
context,
|
|
91
|
+
)),
|
|
92
|
+
);
|
|
93
|
+
const lifecycleStage = await runVerifiedStage("lifecycle",
|
|
94
|
+
() => session.runStage("lifecycle", (context) =>
|
|
95
|
+
buildV84CloneLifecycleEvidence(nativeStage.evidence, undefined, context)),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const activeAfterStages = session.activeSnapshot();
|
|
99
|
+
assertPass(activeAfterStages.stageLedger.length === 4);
|
|
100
|
+
const isolation = await session.cleanup(true);
|
|
101
|
+
const fixtureAfter = createHash("sha256")
|
|
102
|
+
.update(fixturePath === undefined ? fixture : readFileSync(fixturePath, "utf8"))
|
|
103
|
+
.digest("hex");
|
|
104
|
+
assertPass(fixtureAfter === fixtureBefore);
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
schemaVersion: 1 as const,
|
|
108
|
+
proof: "ws3-composed-clean-clone-pass" as const,
|
|
109
|
+
scope: {
|
|
110
|
+
sourceTenant: SOURCE,
|
|
111
|
+
sourceMode: "read-only-fixed-fixture" as const,
|
|
112
|
+
cloneTenant: CLONE,
|
|
113
|
+
destinationMode: "offline-in-memory-fake-local-only" as const,
|
|
114
|
+
},
|
|
115
|
+
stateHandoff: {
|
|
116
|
+
startsAbsent: isolation.before.clone.state === "absent",
|
|
117
|
+
provisioned,
|
|
118
|
+
stageLedger: activeAfterStages.stageLedger,
|
|
119
|
+
immutableExecution: {
|
|
120
|
+
exactBytesReadOnceAndExecuted: executionSnapshotSha256 !== "source-module-test",
|
|
121
|
+
sourceGraphCount: graph.count,
|
|
122
|
+
sourceGraphSha256: graph.sha256,
|
|
123
|
+
executionSnapshotSha256,
|
|
124
|
+
ledger: executionLedger,
|
|
125
|
+
},
|
|
126
|
+
activeThroughFinalStage: activeAfterStages.state === "active",
|
|
127
|
+
sourceAtFinalStage: activeAfterStages.source,
|
|
128
|
+
cleanup: isolation.cleanup,
|
|
129
|
+
},
|
|
130
|
+
stages: {
|
|
131
|
+
import: { evidenceSha256: importStage.handoff.evidenceSha256, evidence: importStage.evidence },
|
|
132
|
+
native: { evidenceSha256: nativeStage.handoff.evidenceSha256, evidence: nativeStage.evidence },
|
|
133
|
+
dogfood: { evidenceSha256: dogfoodStage.handoff.evidenceSha256, evidence: dogfoodStage.evidence },
|
|
134
|
+
lifecycle: { evidenceSha256: lifecycleStage.handoff.evidenceSha256, evidence: lifecycleStage.evidence },
|
|
135
|
+
},
|
|
136
|
+
isolation,
|
|
137
|
+
sourceInvariant: {
|
|
138
|
+
fixtureSha256Before: fixtureBefore,
|
|
139
|
+
fixtureSha256After: fixtureAfter,
|
|
140
|
+
sourceStateBefore: isolation.sourceInvariant.before.combined,
|
|
141
|
+
sourceStateAtFinalStage: activeAfterStages.source.combined,
|
|
142
|
+
sourceStateAfterCleanup: isolation.sourceInvariant.afterCleanup.combined,
|
|
143
|
+
sourceWrites: isolation.sourceInvariant.kvWritesObserved + isolation.sourceInvariant.r2WritesObserved,
|
|
144
|
+
unchanged: isolation.sourceInvariant.unchanged,
|
|
145
|
+
},
|
|
146
|
+
result: "pass" as const,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Build the exact replay entirely from the single launcher-attested bundle snapshot. */
|
|
2
|
+
import { installV84CleanCloneStandaloneCapabilityBoundary } from "./deny-v84-clean-clone-standalone-capabilities.mjs";
|
|
3
|
+
import { buildComposedV84CleanClonePass } from "./replay-v84-clean-clone-pass.js";
|
|
4
|
+
import { composeV84CleanCloneReplayEvidence } from "./replay-v84-clean-clone.js";
|
|
5
|
+
import {
|
|
6
|
+
V84_CLEAN_CLONE_GRAPH_COUNT,
|
|
7
|
+
V84_CLEAN_CLONE_GRAPH_SHA256,
|
|
8
|
+
} from "./v84CleanCloneGraphPin.js";
|
|
9
|
+
|
|
10
|
+
declare const __V84_FIXED_FIXTURE_TEXT__: string;
|
|
11
|
+
|
|
12
|
+
const snapshotSha256 = process.env.V84_REPLAY_SNAPSHOT_SHA256;
|
|
13
|
+
if (typeof snapshotSha256 !== "string" || !/^[a-f0-9]{64}$/.test(snapshotSha256)) {
|
|
14
|
+
throw new Error("The fixed clean-clone replay failed safely.");
|
|
15
|
+
}
|
|
16
|
+
if (Object.keys(process.env).some((key) => /^(?:NODE_|ESBUILD_|NPM_|PNPM_)/i.test(key))) {
|
|
17
|
+
throw new Error("The fixed clean-clone replay failed safely.");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const writeOutput = process.stdout.write.bind(process.stdout);
|
|
21
|
+
await installV84CleanCloneStandaloneCapabilityBoundary();
|
|
22
|
+
const graph = Object.freeze({
|
|
23
|
+
paths: Object.freeze([] as string[]),
|
|
24
|
+
count: V84_CLEAN_CLONE_GRAPH_COUNT,
|
|
25
|
+
sha256: V84_CLEAN_CLONE_GRAPH_SHA256,
|
|
26
|
+
});
|
|
27
|
+
const passOptions = Object.freeze({
|
|
28
|
+
resolveGraph: () => graph,
|
|
29
|
+
fixtureText: __V84_FIXED_FIXTURE_TEXT__,
|
|
30
|
+
executionSnapshotSha256: snapshotSha256,
|
|
31
|
+
});
|
|
32
|
+
const first = await buildComposedV84CleanClonePass(passOptions);
|
|
33
|
+
const second = await buildComposedV84CleanClonePass(passOptions);
|
|
34
|
+
const evidence = composeV84CleanCloneReplayEvidence(first, second, graph, snapshotSha256);
|
|
35
|
+
writeOutput(`${JSON.stringify(evidence, null, 2)}\n`);
|