@tokenoftrust/storefront-runner 1.4.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/storefront/astro.config.mjs +17 -1
- package/apps/storefront/env.d.ts +54 -5
- package/apps/storefront/integrations/materialize-guard.mjs +54 -0
- package/apps/storefront/migrations-apps/0002_good_switch.sql +26 -0
- package/apps/storefront/migrations-apps/0003_mute_marauders.sql +12 -0
- 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/0002_snapshot.json +1160 -0
- package/apps/storefront/migrations-apps/meta/0003_snapshot.json +1235 -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 +56 -0
- package/apps/storefront/public/apps/tot.demo.analytics/0.1.0/entry.js +42 -0
- package/apps/storefront/public/js/dashboard-team.js +38 -2
- 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/Seo.astro +65 -1
- package/apps/storefront/src/components/admin/AdminBlogDetailRail.astro +878 -0
- package/apps/storefront/src/components/admin/AdminBlogTab.astro +1435 -0
- package/apps/storefront/src/components/admin/AdminCustomersTab.astro +3 -7
- package/apps/storefront/src/components/admin/AdminIntegrationsTab.astro +105 -0
- package/apps/storefront/src/components/admin/AdminPublishTab.astro +1980 -2564
- package/apps/storefront/src/components/admin/AdminSettingsTab.astro +2 -2
- package/apps/storefront/src/components/admin/AdminSubscriptionsTab.astro +1 -3
- package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +5 -5
- package/apps/storefront/src/components/blog/BlogPaywall.astro +87 -0
- package/apps/storefront/src/components/blog/PostAccessBadge.astro +43 -0
- package/apps/storefront/src/components/blog/PostGrid.astro +57 -0
- package/apps/storefront/src/components/blog/ReactionBar.astro +214 -0
- 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 +146 -21
- package/apps/storefront/src/lib/activity/alerts.ts +17 -19
- package/apps/storefront/src/lib/activity/candidateSubmitLease.ts +87 -0
- package/apps/storefront/src/lib/activity/changeActorAttribution.ts +89 -9
- package/apps/storefront/src/lib/activity/deployVersion.ts +20 -27
- package/apps/storefront/src/lib/activity/ingest.ts +8 -8
- package/apps/storefront/src/lib/activity/ingestAuth.ts +1 -1
- package/apps/storefront/src/lib/activity/killSwitch.ts +6 -6
- package/apps/storefront/src/lib/activity/query.ts +9 -9
- package/apps/storefront/src/lib/activity/recordActivity.ts +11 -15
- package/apps/storefront/src/lib/activity/store.ts +4 -6
- package/apps/storefront/src/lib/activity/uiActor.ts +12 -12
- package/apps/storefront/src/lib/activity/workerCommit.ts +6 -6
- package/apps/storefront/src/lib/admin/adminShell.ts +292 -0
- package/apps/storefront/src/lib/admin/ai/approvalMode.ts +2 -3
- package/apps/storefront/src/lib/admin/ai/audit.ts +3 -5
- package/apps/storefront/src/lib/admin/checkoutStyleInput.ts +7 -7
- package/apps/storefront/src/lib/admin/checkoutStyleTarget.ts +3 -3
- package/apps/storefront/src/lib/admin/envelope.ts +1 -2
- package/apps/storefront/src/lib/admin/orderClient.ts +3 -5
- package/apps/storefront/src/lib/admin/services/orders.ts +17 -19
- package/apps/storefront/src/lib/admin/viewmodels/aiWorkflows.ts +4 -6
- package/apps/storefront/src/lib/admin/viewmodels/settings.ts +1 -1
- package/apps/storefront/src/lib/apps/adminService.ts +14 -4
- package/apps/storefront/src/lib/apps/adminSession.ts +54 -45
- package/apps/storefront/src/lib/apps/apiAuth.ts +2 -2
- package/apps/storefront/src/lib/apps/apiRoute.ts +2 -2
- package/apps/storefront/src/lib/apps/appVersionStore.ts +281 -0
- package/apps/storefront/src/lib/apps/catalogMapper.ts +1 -1
- package/apps/storefront/src/lib/apps/consentConfigStore.ts +228 -0
- package/apps/storefront/src/lib/apps/credentials.ts +2 -2
- package/apps/storefront/src/lib/apps/gatewayKeys.ts +4 -4
- 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/healthAggregate.ts +5 -5
- 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/attributionService.ts +2 -2
- package/apps/storefront/src/lib/apps/orders/customerHash.ts +1 -1
- package/apps/storefront/src/lib/apps/orders/foxyOrderClient.ts +12 -12
- package/apps/storefront/src/lib/apps/orders/idempotency.ts +7 -7
- package/apps/storefront/src/lib/apps/orders/orderConversionD1.ts +150 -0
- package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +9 -1
- package/apps/storefront/src/lib/apps/orders/orderMapper.ts +2 -2
- package/apps/storefront/src/lib/apps/orders/ordersStore.ts +7 -7
- package/apps/storefront/src/lib/apps/orders/verifiedProviderMeasurement.ts +117 -0
- package/apps/storefront/src/lib/apps/registryService.ts +270 -16
- package/apps/storefront/src/lib/apps/scopes.ts +2 -2
- package/apps/storefront/src/lib/apps/tenantIntegrationMaterialization.ts +170 -0
- package/apps/storefront/src/lib/apps/tokenIssuer.ts +4 -4
- package/apps/storefront/src/lib/apps/tokenVerifier.ts +6 -6
- 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/widgets/eligibility.ts +2 -2
- package/apps/storefront/src/lib/apps/widgets/frameProps.ts +3 -3
- package/apps/storefront/src/lib/apps/widgets/launchToken.ts +4 -4
- package/apps/storefront/src/lib/apps/widgets/placements.ts +2 -2
- package/apps/storefront/src/lib/apps/widgets/renderSlot.ts +1 -1
- 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 +11 -11
- package/apps/storefront/src/lib/auth/adminLanding.ts +88 -0
- package/apps/storefront/src/lib/auth/identityToken.ts +6 -14
- package/apps/storefront/src/lib/auth/loginGate.ts +75 -13
- package/apps/storefront/src/lib/auth/mcpClientAssertion.ts +2 -4
- package/apps/storefront/src/lib/auth/operatorSession.ts +113 -0
- package/apps/storefront/src/lib/auth/session.ts +7 -8
- package/apps/storefront/src/lib/auth/totAccessClient.ts +8 -18
- package/apps/storefront/src/lib/basePath.ts +9 -2
- package/apps/storefront/src/lib/blog/access.ts +29 -0
- package/apps/storefront/src/lib/blog/collection.ts +400 -0
- package/apps/storefront/src/lib/blog/markdown.ts +174 -0
- package/apps/storefront/src/lib/blog/provider.ts +62 -3
- package/apps/storefront/src/lib/blog/reactions.ts +87 -0
- package/apps/storefront/src/lib/blog/rss.ts +92 -0
- package/apps/storefront/src/lib/blog/teaser.ts +83 -0
- package/apps/storefront/src/lib/blog/types.ts +34 -0
- package/apps/storefront/src/lib/blog/viewCounts.ts +243 -0
- 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 +14 -2
- package/apps/storefront/src/lib/d1/schema-apps.ts +372 -17
- package/apps/storefront/src/lib/dev/activityIngestToken.ts +2 -4
- package/apps/storefront/src/lib/dev/activityStore.ts +3 -5
- package/apps/storefront/src/lib/dev/apiBase.ts +1 -4
- 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/cockpitStore.ts +1 -9
- package/apps/storefront/src/lib/dev/devDraft.ts +1 -1
- package/apps/storefront/src/lib/dev/previewStatus.ts +9 -21
- package/apps/storefront/src/lib/dev/rendezvousBroker.ts +9 -24
- package/apps/storefront/src/lib/dev/runtimeStore.ts +1 -1
- package/apps/storefront/src/lib/edgeCache.ts +34 -5
- package/apps/storefront/src/lib/email/candidateConflictEmail.ts +80 -0
- package/apps/storefront/src/lib/http/fetchTransport.ts +63 -0
- package/apps/storefront/src/lib/i18n.ts +25 -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/jsonld.ts +118 -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/monitoring/manifest.ts +11 -11
- package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +30 -0
- package/apps/storefront/src/lib/newsletter/consent.ts +23 -0
- package/apps/storefront/src/lib/newsletter/digest.ts +117 -0
- package/apps/storefront/src/lib/newsletter/resendClient.ts +79 -0
- package/apps/storefront/src/lib/newsletter/send.ts +265 -0
- package/apps/storefront/src/lib/newsletter/subscribers.ts +156 -0
- package/apps/storefront/src/lib/previewReload.ts +57 -1
- package/apps/storefront/src/lib/publish/adminPublishTab.ts +4625 -0
- package/apps/storefront/src/lib/publish/apex-readiness.ts +41 -18
- 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/dispatchHealth.ts +5 -7
- package/apps/storefront/src/lib/publish/domainState.ts +22 -13
- 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/panelPolling.ts +78 -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 +121 -51
- package/apps/storefront/src/lib/publish/sseRoute.ts +119 -0
- package/apps/storefront/src/lib/publish/stageBundleUpload.ts +215 -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/rate/kvWindow.ts +53 -0
- package/apps/storefront/src/lib/rawChrome.ts +125 -47
- package/apps/storefront/src/lib/rawMarketingHtml.ts +74 -3
- package/apps/storefront/src/lib/search/index.ts +2 -2
- package/apps/storefront/src/lib/seo/alternates.ts +42 -0
- package/apps/storefront/src/lib/seo/meta.ts +65 -0
- package/apps/storefront/src/lib/social/golive.ts +212 -0
- package/apps/storefront/src/lib/social/notify.ts +32 -0
- package/apps/storefront/src/lib/social/tokenStore.ts +171 -0
- 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 +32 -0
- package/apps/storefront/src/lib/the-build/readingTime.ts +35 -0
- package/apps/storefront/src/lib/the-build/toc.ts +95 -0
- package/apps/storefront/src/lib/tot/ToTClient.ts +1 -1
- package/apps/storefront/src/lib/tot/d1Client.ts +2 -2
- package/apps/storefront/src/lib/tot/totClientInterface.ts +3 -4
- package/apps/storefront/src/lib/webhooks/deliveryStore.ts +16 -17
- package/apps/storefront/src/middleware/index.ts +385 -52
- 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 +25 -1313
- 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/blog/[collection]/[slug]/react.ts +104 -0
- 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/newsletter/[collection]/subscribe.ts +146 -0
- package/apps/storefront/src/pages/api/newsletter/confirm.ts +75 -0
- package/apps/storefront/src/pages/api/newsletter/unsubscribe.ts +90 -0
- package/apps/storefront/src/pages/api/publish/stage-bundle.ts +70 -0
- package/apps/storefront/src/pages/api/rum/vitals.ts +20 -2
- package/apps/storefront/src/pages/blog/[slug].astro +99 -19
- package/apps/storefront/src/pages/blog/author/[author].astro +140 -0
- package/apps/storefront/src/pages/blog/category/[category].astro +67 -0
- package/apps/storefront/src/pages/blog/index.astro +4 -2
- package/apps/storefront/src/pages/blog/tag/[tag].astro +65 -0
- package/apps/storefront/src/pages/cockpit.astro +77 -1353
- package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +15 -11
- 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/search.astro +1 -1
- package/apps/storefront/src/pages/sitemap.xml.ts +21 -1
- 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 +129 -0
- package/apps/storefront/src/pages/the-build/index.astro +146 -0
- package/apps/storefront/src/pages/the-build/rss.xml.ts +33 -0
- package/apps/storefront/src/styles/admin.css +1106 -0
- package/apps/storefront/tsconfig.json +6 -1
- package/package.json +1 -1
- package/packages/public-runtime/package.json +3 -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 +89 -33
- 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/catalog-d1.ts +1 -1
- 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-preview.ts +25 -2
- package/packages/public-runtime/src/customization-runtime.ts +156 -3
- package/packages/public-runtime/src/customization-versioning.ts +10 -0
- 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 +17 -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 +357 -0
- package/packages/public-runtime/src/tenant-assets.ts +143 -4
- package/packages/public-runtime/src/tenant.ts +81 -17
- 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 +14 -4
- package/scripts/dev/ai-edit.mjs +1 -1
- package/scripts/dev/checkout-watch.mjs +2 -2
- package/scripts/dev/file-browser.mjs +4 -6
- package/scripts/dev/file-writer.mjs +3 -3
- package/scripts/dev/git-status.mjs +2 -2
- package/scripts/dev/integration-guardrails.mjs +498 -0
- package/scripts/dev/locate-handler.mjs +3 -3
- package/scripts/dev/port-check.mjs +3 -3
- package/scripts/dev/publish.mjs +5 -9
- package/scripts/dev/safe-path.mjs +2 -2
- package/scripts/dev/shot.mjs +1 -1
- package/scripts/dev/tenant-source-root.mjs +1 -1
- package/scripts/dev/unified-diff.mjs +8 -3
- package/scripts/tot-dev.mjs +8 -11
- package/apps/storefront/src/lib/dev/vcBinding.ts +0 -80
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/** Validate and compose two exact passes produced by one attested immutable execution snapshot. */
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import {
|
|
4
|
+
V84_CLEAN_CLONE_GRAPH_COUNT,
|
|
5
|
+
V84_CLEAN_CLONE_GRAPH_SHA256,
|
|
6
|
+
V84_CLEAN_CLONE_LAUNCHER_ENTRY,
|
|
7
|
+
type V84CleanCloneGraphIdentity,
|
|
8
|
+
} from "./v84CleanCloneGraphPin.js";
|
|
9
|
+
|
|
10
|
+
const SOURCE = "tokenoftrust.com";
|
|
11
|
+
const CLONE = "tokenoftrust.com~clone~gtm-migration-v84";
|
|
12
|
+
const SESSION = "offline-v84-shared-clone-session";
|
|
13
|
+
const FAILURE = "The fixed clean-clone replay failed safely.";
|
|
14
|
+
const STAGE_ORDER = ["import", "native", "dogfood", "lifecycle"] as const;
|
|
15
|
+
|
|
16
|
+
type Json = null | boolean | number | string | Json[] | { [key: string]: Json };
|
|
17
|
+
function digest(value: string): string {
|
|
18
|
+
return createHash("sha256").update(value).digest("hex");
|
|
19
|
+
}
|
|
20
|
+
function assertSafe(condition: unknown): asserts condition {
|
|
21
|
+
if (!condition) throw new Error(FAILURE);
|
|
22
|
+
}
|
|
23
|
+
function validateJson(value: unknown): asserts value is Json {
|
|
24
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return;
|
|
25
|
+
if (typeof value === "number") return assertSafe(Number.isFinite(value));
|
|
26
|
+
assertSafe(typeof value === "object");
|
|
27
|
+
if (Array.isArray(value)) return value.forEach(validateJson);
|
|
28
|
+
assertSafe(Object.getPrototypeOf(value) === Object.prototype);
|
|
29
|
+
for (const [key, child] of Object.entries(value)) {
|
|
30
|
+
assertSafe(!["__proto__", "prototype", "constructor"].includes(key));
|
|
31
|
+
validateJson(child);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function object(value: unknown): Record<string, Json> {
|
|
35
|
+
validateJson(value);
|
|
36
|
+
assertSafe(value !== null && !Array.isArray(value) && typeof value === "object");
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function at(root: unknown, ...keys: readonly (string | number)[]): Json {
|
|
40
|
+
let current = root as Json;
|
|
41
|
+
for (const key of keys) {
|
|
42
|
+
if (typeof key === "number") {
|
|
43
|
+
assertSafe(Array.isArray(current) && key in current);
|
|
44
|
+
current = current[key]!;
|
|
45
|
+
} else {
|
|
46
|
+
assertSafe(current !== null && !Array.isArray(current) && typeof current === "object" && key in current);
|
|
47
|
+
current = current[key]!;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return current;
|
|
51
|
+
}
|
|
52
|
+
function arrayAt(root: unknown, ...keys: readonly (string | number)[]): Json[] {
|
|
53
|
+
const value = at(root, ...keys);
|
|
54
|
+
assertSafe(Array.isArray(value));
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
function validateSanitized(canonical: string): void {
|
|
58
|
+
assertSafe(!/(?:\/Users\/|\\Users\\|\/home\/|storefront-issue-|[A-Z]:\\)/i.test(canonical));
|
|
59
|
+
assertSafe(!/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i.test(canonical));
|
|
60
|
+
assertSafe(!/(?:-----BEGIN [A-Z ]+ PRIVATE KEY-----|\bBearer\s+[A-Za-z0-9._~-]+)/i.test(canonical));
|
|
61
|
+
}
|
|
62
|
+
function validateScope(evidence: Json, sourceMode: string, destinationMode: string): void {
|
|
63
|
+
assertSafe(at(evidence, "scope", "sourceTenant") === SOURCE);
|
|
64
|
+
assertSafe(at(evidence, "scope", "sourceMode") === sourceMode);
|
|
65
|
+
assertSafe(at(evidence, "scope", "cloneTenant") === CLONE);
|
|
66
|
+
assertSafe(at(evidence, "scope", "destinationMode") === destinationMode);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Validate that all product evidence belongs to one active, ordered clone session. */
|
|
70
|
+
export function validateComposedV84Pass(unsafe: unknown): asserts unsafe is Json {
|
|
71
|
+
const evidence = object(unsafe);
|
|
72
|
+
validateScope(evidence, "read-only-fixed-fixture", "offline-in-memory-fake-local-only");
|
|
73
|
+
assertSafe(at(evidence, "proof") === "ws3-composed-clean-clone-pass");
|
|
74
|
+
assertSafe(at(evidence, "stateHandoff", "startsAbsent") === true);
|
|
75
|
+
assertSafe(at(evidence, "stateHandoff", "provisioned", "state") === "active");
|
|
76
|
+
assertSafe(at(evidence, "stateHandoff", "provisioned", "cloneTenant") === CLONE);
|
|
77
|
+
assertSafe(at(evidence, "stateHandoff", "activeThroughFinalStage") === true);
|
|
78
|
+
const immutable = at(evidence, "stateHandoff", "immutableExecution");
|
|
79
|
+
assertSafe(at(immutable, "exactBytesReadOnceAndExecuted") === true);
|
|
80
|
+
assertSafe(at(immutable, "sourceGraphCount") === V84_CLEAN_CLONE_GRAPH_COUNT);
|
|
81
|
+
assertSafe(at(immutable, "sourceGraphSha256") === V84_CLEAN_CLONE_GRAPH_SHA256);
|
|
82
|
+
const snapshotSha256 = at(immutable, "executionSnapshotSha256");
|
|
83
|
+
assertSafe(typeof snapshotSha256 === "string" && /^[a-f0-9]{64}$/.test(snapshotSha256));
|
|
84
|
+
const executionLedger = arrayAt(immutable, "ledger");
|
|
85
|
+
assertSafe(executionLedger.length === STAGE_ORDER.length);
|
|
86
|
+
const ledger = arrayAt(evidence, "stateHandoff", "stageLedger");
|
|
87
|
+
assertSafe(ledger.length === STAGE_ORDER.length);
|
|
88
|
+
for (let index = 0; index < STAGE_ORDER.length; index += 1) {
|
|
89
|
+
const row = ledger[index]!;
|
|
90
|
+
const stage = STAGE_ORDER[index]!;
|
|
91
|
+
const executionRow = executionLedger[index]!;
|
|
92
|
+
assertSafe(at(executionRow, "stage") === stage);
|
|
93
|
+
assertSafe(at(executionRow, "sourceGraphCount") === V84_CLEAN_CLONE_GRAPH_COUNT);
|
|
94
|
+
assertSafe(at(executionRow, "sourceGraphSha256") === V84_CLEAN_CLONE_GRAPH_SHA256);
|
|
95
|
+
assertSafe(at(executionRow, "executionSnapshotSha256") === snapshotSha256);
|
|
96
|
+
assertSafe(at(row, "stage") === stage);
|
|
97
|
+
assertSafe(at(row, "cloneTenant") === CLONE);
|
|
98
|
+
assertSafe(at(row, "cloneState") === "active");
|
|
99
|
+
assertSafe(at(row, "sessionId") === SESSION);
|
|
100
|
+
assertSafe(at(row, "sharedStateKeyCount") === [1, 5, 9, 4][index]);
|
|
101
|
+
assertSafe(at(row, "evidenceSha256") === at(evidence, "stages", stage, "evidenceSha256"));
|
|
102
|
+
const stageEvidence = at(evidence, "stages", stage, "evidence");
|
|
103
|
+
assertSafe(at(row, "evidenceSha256") === `sha256:${digest(JSON.stringify(stageEvidence))}`);
|
|
104
|
+
}
|
|
105
|
+
assertSafe(arrayAt(evidence, "stateHandoff", "cleanup", "cloneResidual", "kvKeys").length === 0);
|
|
106
|
+
assertSafe(arrayAt(evidence, "stateHandoff", "cleanup", "cloneResidual", "r2Keys").length === 0);
|
|
107
|
+
assertSafe(at(evidence, "stateHandoff", "cleanup", "sourcePreserved") === true);
|
|
108
|
+
const deletedKvKeys = arrayAt(evidence, "stateHandoff", "cleanup", "kvKeysDeleted");
|
|
109
|
+
for (const required of [
|
|
110
|
+
"shared-state:stage/import/handoff",
|
|
111
|
+
"shared-state:stage/native/drafts/",
|
|
112
|
+
"shared-state:stage/native/installs/",
|
|
113
|
+
"shared-state:stage/native/handoff",
|
|
114
|
+
"shared-state:stage/dogfood/artifacts/",
|
|
115
|
+
"shared-state:stage/dogfood/handoff",
|
|
116
|
+
"shared-state:stage/lifecycle/materialization/",
|
|
117
|
+
"shared-state:stage/lifecycle/cache/",
|
|
118
|
+
"shared-state:stage/lifecycle/handoff",
|
|
119
|
+
]) {
|
|
120
|
+
assertSafe(deletedKvKeys.some((key) => typeof key === "string" && key.includes(required)));
|
|
121
|
+
}
|
|
122
|
+
assertSafe(at(evidence, "sourceInvariant", "fixtureSha256Before") === at(evidence, "sourceInvariant", "fixtureSha256After"));
|
|
123
|
+
assertSafe(at(evidence, "sourceInvariant", "sourceStateBefore") === at(evidence, "sourceInvariant", "sourceStateAtFinalStage"));
|
|
124
|
+
assertSafe(at(evidence, "sourceInvariant", "sourceStateBefore") === at(evidence, "sourceInvariant", "sourceStateAfterCleanup"));
|
|
125
|
+
assertSafe(at(evidence, "sourceInvariant", "sourceWrites") === 0);
|
|
126
|
+
assertSafe(at(evidence, "sourceInvariant", "unchanged") === true);
|
|
127
|
+
const imported = at(evidence, "stages", "import", "evidence");
|
|
128
|
+
validateScope(imported, "read-only-fixture", "offline-in-memory-only");
|
|
129
|
+
assertSafe(at(imported, "accounting", "accountedTotal") === 89);
|
|
130
|
+
assertSafe(arrayAt(imported, "codeExecutionUnsupported").length === 8);
|
|
131
|
+
assertSafe(at(imported, "safety", "sourceMutationCount") === 0);
|
|
132
|
+
assertSafe(at(imported, "safety", "networkRequestCount") === 0);
|
|
133
|
+
assertSafe(at(imported, "safety", "importedCodeExecuted") === false);
|
|
134
|
+
const native = at(evidence, "stages", "native", "evidence");
|
|
135
|
+
validateScope(native, "read-only", "offline-in-memory-fake-only");
|
|
136
|
+
assertSafe(arrayAt(native, "installations").length === 2);
|
|
137
|
+
assertSafe(at(native, "safety", "liveDestinationCount") === 0);
|
|
138
|
+
assertSafe(at(native, "safety", "externalNetworkRequestCount") === 0);
|
|
139
|
+
assertSafe(at(native, "operationCounts", "publish") === 0);
|
|
140
|
+
const dogfood = at(evidence, "stages", "dogfood", "evidence");
|
|
141
|
+
validateScope(dogfood, "read-only-fixture", "fake-local-only");
|
|
142
|
+
assertSafe(arrayAt(dogfood, "ledger").length === 8);
|
|
143
|
+
assertSafe(at(dogfood, "summary", "retired") === 3);
|
|
144
|
+
assertSafe(at(dogfood, "summary", "evidenceRejected") === 5);
|
|
145
|
+
assertSafe(at(dogfood, "summary", "unexplainedNotInstalled") === 0);
|
|
146
|
+
assertSafe(at(dogfood, "safety", "externalNetworkRequests") === 0);
|
|
147
|
+
assertSafe(at(dogfood, "safety", "dataLayerTouched") === false);
|
|
148
|
+
const lifecycle = at(evidence, "stages", "lifecycle", "evidence");
|
|
149
|
+
validateScope(lifecycle, "read-only", "offline-in-memory-callback-only");
|
|
150
|
+
assertSafe(at(lifecycle, "disabledDrafts", "materializedCount") === 0);
|
|
151
|
+
assertSafe(at(lifecycle, "operationCounts", "sourceWrites") === 0);
|
|
152
|
+
assertSafe(at(lifecycle, "operationCounts", "externalNetworkRequests") === 0);
|
|
153
|
+
assertSafe(at(lifecycle, "operationCounts", "lifecycleMutations") === 0);
|
|
154
|
+
assertSafe(at(lifecycle, "operationCounts", "publishes") === 0);
|
|
155
|
+
assertSafe(at(evidence, "result") === "pass");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function composeV84CleanCloneReplayEvidence(
|
|
159
|
+
firstUnsafe: unknown,
|
|
160
|
+
secondUnsafe: unknown,
|
|
161
|
+
graph: V84CleanCloneGraphIdentity,
|
|
162
|
+
executionSnapshotSha256: string,
|
|
163
|
+
) {
|
|
164
|
+
const firstCanonical = JSON.stringify(firstUnsafe);
|
|
165
|
+
const secondCanonical = JSON.stringify(secondUnsafe);
|
|
166
|
+
const first = object(JSON.parse(firstCanonical) as unknown);
|
|
167
|
+
const second = object(JSON.parse(secondCanonical) as unknown);
|
|
168
|
+
validateSanitized(firstCanonical);
|
|
169
|
+
validateSanitized(secondCanonical);
|
|
170
|
+
validateComposedV84Pass(first);
|
|
171
|
+
validateComposedV84Pass(second);
|
|
172
|
+
assertSafe(firstCanonical === secondCanonical);
|
|
173
|
+
assertSafe(graph.count === V84_CLEAN_CLONE_GRAPH_COUNT && graph.sha256 === V84_CLEAN_CLONE_GRAPH_SHA256);
|
|
174
|
+
assertSafe(/^[a-f0-9]{64}$/.test(executionSnapshotSha256));
|
|
175
|
+
assertSafe(at(first, "stateHandoff", "immutableExecution", "executionSnapshotSha256") === executionSnapshotSha256);
|
|
176
|
+
const passEvidenceSha256 = digest(firstCanonical);
|
|
177
|
+
const pass = first;
|
|
178
|
+
return {
|
|
179
|
+
schemaVersion: 2 as const,
|
|
180
|
+
proof: "ws3-composed-clean-clone-complete-replay" as const,
|
|
181
|
+
scope: at(pass, "scope"),
|
|
182
|
+
commandPin: {
|
|
183
|
+
entry: V84_CLEAN_CLONE_LAUNCHER_ENTRY,
|
|
184
|
+
resolvedSourceCount: graph.count,
|
|
185
|
+
resolvedSourceGraphSha256: graph.sha256,
|
|
186
|
+
executionSnapshotSha256,
|
|
187
|
+
composedPassEvidenceSha256: passEvidenceSha256,
|
|
188
|
+
exactBytesReadOnceAndExecuted: true as const,
|
|
189
|
+
runtimeTooling: "none" as const,
|
|
190
|
+
},
|
|
191
|
+
replay: { passes: 2 as const, exact: true as const },
|
|
192
|
+
stateHandoff: at(pass, "stateHandoff"),
|
|
193
|
+
sourceInvariant: at(pass, "sourceInvariant"),
|
|
194
|
+
accounting: at(pass, "stages", "import", "evidence", "accounting"),
|
|
195
|
+
nativeInstallSummary: {
|
|
196
|
+
count: arrayAt(pass, "stages", "native", "evidence", "installations").length,
|
|
197
|
+
lifecycle: at(pass, "stages", "native", "evidence", "safety", "lifecycle"),
|
|
198
|
+
liveDestinationCount: at(pass, "stages", "native", "evidence", "safety", "liveDestinationCount"),
|
|
199
|
+
},
|
|
200
|
+
eightRouteLedger: at(pass, "stages", "dogfood", "evidence", "ledger"),
|
|
201
|
+
eightRouteSummary: at(pass, "stages", "dogfood", "evidence", "summary"),
|
|
202
|
+
lifecycleSummary: {
|
|
203
|
+
disabledDrafts: at(pass, "stages", "lifecycle", "evidence", "disabledDrafts"),
|
|
204
|
+
operationCounts: at(pass, "stages", "lifecycle", "evidence", "operationCounts"),
|
|
205
|
+
},
|
|
206
|
+
safety: {
|
|
207
|
+
externalNetworkRequests: 0 as const, liveSecretsUsed: 0 as const,
|
|
208
|
+
productionActions: 0 as const, sourceMutations: 0 as const,
|
|
209
|
+
importedCodeExecuted: false as const, originalMarkupRendered: false as const,
|
|
210
|
+
runtimeLoaderInitialized: false as const, dataLayerTouched: false as const,
|
|
211
|
+
},
|
|
212
|
+
result: "pass" as const,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Trusted plain-JavaScript bootstrap for the frozen v84 native-install producer. */
|
|
2
|
+
if (process.argv.length !== 2) {
|
|
3
|
+
process.stderr.write("refused: fixed-input native-install evidence accepts no arguments\n");
|
|
4
|
+
process.exitCode = 64;
|
|
5
|
+
} else try {
|
|
6
|
+
const { sanitizeV84ProofEnvironment } = await import("./sanitize-v84-proof-environment.mjs");
|
|
7
|
+
sanitizeV84ProofEnvironment();
|
|
8
|
+
await import("tsx");
|
|
9
|
+
const { tsImport } = await import("tsx/esm/api");
|
|
10
|
+
const tooling = await tsImport("./initialize-v84-lifecycle-tooling.ts", import.meta.url);
|
|
11
|
+
if (tooling.V84_LIFECYCLE_TOOLING_READY !== true) throw new Error("tooling unavailable");
|
|
12
|
+
await import("./deny-v84-lifecycle-capabilities.mjs");
|
|
13
|
+
const producer = await tsImport("./install-v84-native-through-ws1.ts", import.meta.url);
|
|
14
|
+
process.stdout.write(`${JSON.stringify(await producer.buildFixedV84NativeInstallEvidence(), null, 2)}\n`);
|
|
15
|
+
} catch {
|
|
16
|
+
process.stderr.write("refused: fixed native-install evidence unavailable\n");
|
|
17
|
+
process.exitCode = 70;
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Capability-denied bootstrap for the fixed offline clone isolation proof. */
|
|
2
|
+
if (process.argv.length !== 2) {
|
|
3
|
+
process.stderr.write("refused: fixed-input clone-isolation command accepts no arguments\n");
|
|
4
|
+
process.exitCode = 64;
|
|
5
|
+
} else try {
|
|
6
|
+
const { sanitizeV84ProofEnvironment } = await import("./sanitize-v84-proof-environment.mjs");
|
|
7
|
+
sanitizeV84ProofEnvironment();
|
|
8
|
+
await import("tsx");
|
|
9
|
+
const { tsImport } = await import("tsx/esm/api");
|
|
10
|
+
const tooling = await tsImport("./initialize-v84-lifecycle-tooling.ts", import.meta.url);
|
|
11
|
+
if (tooling.V84_LIFECYCLE_TOOLING_READY !== true) throw new Error("tooling unavailable");
|
|
12
|
+
await import("./deny-v84-lifecycle-capabilities.mjs");
|
|
13
|
+
const proof = await tsImport("./prove-clone-isolation.ts", import.meta.url);
|
|
14
|
+
process.stdout.write(`${JSON.stringify(await proof.runOfflineCloneIsolationProof(), null, 2)}\n`);
|
|
15
|
+
} catch {
|
|
16
|
+
process.stderr.write("refused: fixed clone-isolation evidence unavailable\n");
|
|
17
|
+
process.exitCode = 70;
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Trusted plain-JavaScript bootstrap for the fixed v84 lifecycle proof. */
|
|
2
|
+
try {
|
|
3
|
+
const { sanitizeV84ProofEnvironment } = await import("./sanitize-v84-proof-environment.mjs");
|
|
4
|
+
sanitizeV84ProofEnvironment();
|
|
5
|
+
await import("tsx");
|
|
6
|
+
const { tsImport } = await import("tsx/esm/api");
|
|
7
|
+
const tooling = await tsImport("./initialize-v84-lifecycle-tooling.ts", import.meta.url);
|
|
8
|
+
if (tooling.V84_LIFECYCLE_TOOLING_READY !== true) throw new Error("tooling unavailable");
|
|
9
|
+
Object.defineProperty(globalThis, Symbol.for("tot.v84.lifecycle-producer-capability"), {
|
|
10
|
+
configurable: true,
|
|
11
|
+
value: "allow-exact-native-install-producer",
|
|
12
|
+
});
|
|
13
|
+
await import("./deny-v84-lifecycle-capabilities.mjs");
|
|
14
|
+
await tsImport("./validate-v84-clone-lifecycle.ts", import.meta.url);
|
|
15
|
+
} catch {
|
|
16
|
+
process.stderr.write("refused: fixed lifecycle evidence unavailable\n");
|
|
17
|
+
process.exitCode = 70;
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Capability-denied bootstrap for the fixed offline WS2 import proof. */
|
|
2
|
+
if (process.argv.length !== 2) {
|
|
3
|
+
process.stderr.write("refused: fixed-input WS2 import command accepts no arguments\n");
|
|
4
|
+
process.exitCode = 64;
|
|
5
|
+
} else try {
|
|
6
|
+
const { sanitizeV84ProofEnvironment } = await import("./sanitize-v84-proof-environment.mjs");
|
|
7
|
+
sanitizeV84ProofEnvironment();
|
|
8
|
+
await import("tsx");
|
|
9
|
+
const { tsImport } = await import("tsx/esm/api");
|
|
10
|
+
const tooling = await tsImport("./initialize-v84-lifecycle-tooling.ts", import.meta.url);
|
|
11
|
+
if (tooling.V84_LIFECYCLE_TOOLING_READY !== true) throw new Error("tooling unavailable");
|
|
12
|
+
await import("./deny-v84-lifecycle-capabilities.mjs");
|
|
13
|
+
await tsImport("./import-v84-through-ws2.ts", import.meta.url);
|
|
14
|
+
} catch {
|
|
15
|
+
process.stderr.write("refused: fixed WS2 import evidence unavailable\n");
|
|
16
|
+
process.exitCode = 70;
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Capability-denied bootstrap for the fixed v84 eight-route dogfood proof. */
|
|
2
|
+
try {
|
|
3
|
+
// No caller environment survives into the proof; live secrets cannot be read.
|
|
4
|
+
const { sanitizeV84ProofEnvironment } = await import("./sanitize-v84-proof-environment.mjs");
|
|
5
|
+
sanitizeV84ProofEnvironment();
|
|
6
|
+
await import("tsx");
|
|
7
|
+
const { tsImport } = await import("tsx/esm/api");
|
|
8
|
+
const tooling = await tsImport("./initialize-v84-lifecycle-tooling.ts", import.meta.url);
|
|
9
|
+
if (tooling.V84_LIFECYCLE_TOOLING_READY !== true) throw new Error("tooling unavailable");
|
|
10
|
+
await import("./deny-v84-dogfood-capabilities.mjs");
|
|
11
|
+
await tsImport("./dogfood-v84-nonportable-routes.ts", import.meta.url);
|
|
12
|
+
} catch {
|
|
13
|
+
process.stderr.write("refused: fixed nonportable-route dogfood unavailable\n");
|
|
14
|
+
process.exitCode = 70;
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Reduce the native process environment to the one fixed proof setting. */
|
|
2
|
+
export function sanitizeV84ProofEnvironment() {
|
|
3
|
+
const environment = process.env;
|
|
4
|
+
const inheritedKeys = Reflect.ownKeys(environment);
|
|
5
|
+
for (const key of inheritedKeys) {
|
|
6
|
+
if (typeof key !== "string" || !Reflect.deleteProperty(environment, key)) {
|
|
7
|
+
throw new Error("proof environment unavailable");
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
if (Reflect.ownKeys(environment).length !== 0) {
|
|
11
|
+
throw new Error("proof environment unavailable");
|
|
12
|
+
}
|
|
13
|
+
environment.TSX_DISABLE_CACHE = "1";
|
|
14
|
+
const descriptors = Object.getOwnPropertyDescriptors(environment);
|
|
15
|
+
const keys = Reflect.ownKeys(descriptors);
|
|
16
|
+
const descriptor = descriptors.TSX_DISABLE_CACHE;
|
|
17
|
+
if (keys.length !== 1 || keys[0] !== "TSX_DISABLE_CACHE" || descriptor === undefined ||
|
|
18
|
+
!("value" in descriptor) || descriptor.value !== "1") {
|
|
19
|
+
throw new Error("proof environment unavailable");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { dirname, resolve } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { resolveV84CleanCloneSourceGraph } from "./v84CleanCloneSourceGraph.js";
|
|
4
|
+
|
|
5
|
+
export const V84_CLEAN_CLONE_LAUNCHER_ENTRY =
|
|
6
|
+
"scripts/diag/rerun-v84-clean-clone.sh" as const;
|
|
7
|
+
export const V84_CLEAN_CLONE_BOOTSTRAP_ENTRY =
|
|
8
|
+
"scripts/diag/run-v84-clean-clone-attested.cjs" as const;
|
|
9
|
+
export const V84_CLEAN_CLONE_STANDALONE_SOURCE_ENTRY =
|
|
10
|
+
"apps/storefront/scripts/replay-v84-clean-clone-standalone.ts" as const;
|
|
11
|
+
export const V84_CLEAN_CLONE_BUILD_ENTRY =
|
|
12
|
+
"apps/storefront/scripts/build-v84-clean-clone-standalone.mjs" as const;
|
|
13
|
+
export const V84_CLEAN_CLONE_GRAPH_COUNT = 191;
|
|
14
|
+
export const V84_CLEAN_CLONE_GRAPH_SHA256 =
|
|
15
|
+
"e284ebf9bd5f0795bee4126c5b2e36cf7cbade05fcbcc9b716a35fa9800fa377" as const;
|
|
16
|
+
|
|
17
|
+
export interface V84CleanCloneGraphIdentity {
|
|
18
|
+
readonly paths: readonly string[];
|
|
19
|
+
readonly count: number;
|
|
20
|
+
readonly sha256: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resolvePinnedV84CleanCloneGraph(): V84CleanCloneGraphIdentity {
|
|
24
|
+
const storefrontDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
25
|
+
const repositoryRoot = resolve(storefrontDir, "../..");
|
|
26
|
+
return resolveV84CleanCloneSourceGraph(repositoryRoot, [
|
|
27
|
+
V84_CLEAN_CLONE_LAUNCHER_ENTRY,
|
|
28
|
+
V84_CLEAN_CLONE_BOOTSTRAP_ENTRY,
|
|
29
|
+
V84_CLEAN_CLONE_STANDALONE_SOURCE_ENTRY,
|
|
30
|
+
V84_CLEAN_CLONE_BUILD_ENTRY,
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function assertPinnedV84CleanCloneGraph(
|
|
35
|
+
resolveGraph: () => V84CleanCloneGraphIdentity = resolvePinnedV84CleanCloneGraph,
|
|
36
|
+
): V84CleanCloneGraphIdentity {
|
|
37
|
+
const graph = resolveGraph();
|
|
38
|
+
if (graph.count !== V84_CLEAN_CLONE_GRAPH_COUNT || graph.sha256 !== V84_CLEAN_CLONE_GRAPH_SHA256) {
|
|
39
|
+
throw new Error("The fixed clean-clone graph changed.");
|
|
40
|
+
}
|
|
41
|
+
return graph;
|
|
42
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { dirname, extname, relative, resolve, sep } from "node:path";
|
|
4
|
+
|
|
5
|
+
const TOOLCHAIN_FILES = [
|
|
6
|
+
"package.json",
|
|
7
|
+
"pnpm-lock.yaml",
|
|
8
|
+
"pnpm-workspace.yaml",
|
|
9
|
+
"apps/storefront/package.json",
|
|
10
|
+
"apps/storefront/tsconfig.json",
|
|
11
|
+
] as const;
|
|
12
|
+
const IMPORT_PATTERN = /(?:from\s+|import\s*(?:\(\s*)?|tsImport\s*\(\s*|require(?:\.resolve)?\s*\(\s*)["'`]([^"'`]+)["'`]/g;
|
|
13
|
+
const URL_PATTERN = /new\s+URL\s*\(\s*["'`]([^"'`]+)["'`]\s*,\s*import\.meta\.url\s*\)/g;
|
|
14
|
+
|
|
15
|
+
function sha256(value: string): string {
|
|
16
|
+
return createHash("sha256").update(value).digest("hex");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function canonicalSource(path: string, repositoryRoot: string): string {
|
|
20
|
+
const source = readFileSync(path, "utf8");
|
|
21
|
+
const relativePath = relative(repositoryRoot, path).split(sep).join("/");
|
|
22
|
+
if (relativePath === "apps/storefront/scripts/v84CleanCloneGraphPin.ts") {
|
|
23
|
+
const canonical = source.replace(
|
|
24
|
+
/(V84_CLEAN_CLONE_GRAPH_SHA256\s*=\s*")[a-f0-9]{64}("\s+as const)/,
|
|
25
|
+
"$1<self-pinned-graph-sha256>$2",
|
|
26
|
+
);
|
|
27
|
+
if (canonical === source) throw new Error("The clean-clone graph self-pin could not be canonicalized.");
|
|
28
|
+
return canonical;
|
|
29
|
+
}
|
|
30
|
+
if (relativePath === "scripts/diag/rerun-v84-clean-clone.sh") {
|
|
31
|
+
const canonical = source.replace(
|
|
32
|
+
/(expected_artifact_sha256=)[a-f0-9]{64}/,
|
|
33
|
+
"$1<self-pinned-replay-artifact-sha256>",
|
|
34
|
+
);
|
|
35
|
+
if (canonical === source) throw new Error("The clean-clone replay artifact pin could not be canonicalized.");
|
|
36
|
+
return canonical;
|
|
37
|
+
}
|
|
38
|
+
if (relativePath === "scripts/diag/run-v84-clean-clone-attested.cjs") {
|
|
39
|
+
const canonical = source.replace(
|
|
40
|
+
/(const expected = ")[a-f0-9]{64}(";)/,
|
|
41
|
+
"$1<self-pinned-execution-snapshot-sha256>$2",
|
|
42
|
+
);
|
|
43
|
+
if (canonical === source) throw new Error("The clean-clone bootstrap snapshot pin could not be canonicalized.");
|
|
44
|
+
return canonical;
|
|
45
|
+
}
|
|
46
|
+
return source;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function workspacePackages(repositoryRoot: string) {
|
|
50
|
+
const packages = new Map<string, { root: string; packageJson: string; manifest: Record<string, unknown> }>();
|
|
51
|
+
for (const parent of ["apps", "packages"]) {
|
|
52
|
+
const parentPath = resolve(repositoryRoot, parent);
|
|
53
|
+
for (const child of readdirSync(parentPath, { withFileTypes: true })) {
|
|
54
|
+
if (!child.isDirectory()) continue;
|
|
55
|
+
const root = resolve(parentPath, child.name);
|
|
56
|
+
const packageJson = resolve(root, "package.json");
|
|
57
|
+
if (!existsSync(packageJson)) continue;
|
|
58
|
+
const manifest = JSON.parse(readFileSync(packageJson, "utf8")) as Record<string, unknown>;
|
|
59
|
+
if (typeof manifest.name === "string") packages.set(manifest.name, { root, packageJson, manifest });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return packages;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function candidatePaths(target: string): string[] {
|
|
66
|
+
const extension = extname(target);
|
|
67
|
+
if (extension === ".js") return [target, `${target.slice(0, -3)}.ts`, `${target.slice(0, -3)}.mjs`];
|
|
68
|
+
if (extension) return [target];
|
|
69
|
+
return [target, `${target}.ts`, `${target}.mjs`, `${target}.js`, `${target}.json`, resolve(target, "index.ts")];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function exactFile(target: string): string {
|
|
73
|
+
const found = candidatePaths(target).find((path) => existsSync(path) && statSync(path).isFile());
|
|
74
|
+
if (!found) throw new Error("The clean-clone executable import graph could not be resolved.");
|
|
75
|
+
return found;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function exportTarget(exportsValue: unknown, key: string): string | null {
|
|
79
|
+
if (typeof exportsValue === "string" && key === ".") return exportsValue;
|
|
80
|
+
if (!exportsValue || typeof exportsValue !== "object" || Array.isArray(exportsValue)) return null;
|
|
81
|
+
const selected = (exportsValue as Record<string, unknown>)[key];
|
|
82
|
+
if (typeof selected === "string") return selected;
|
|
83
|
+
if (!selected || typeof selected !== "object" || Array.isArray(selected)) return null;
|
|
84
|
+
const conditions = selected as Record<string, unknown>;
|
|
85
|
+
for (const condition of ["import", "default", "types"]) {
|
|
86
|
+
if (typeof conditions[condition] === "string") return conditions[condition];
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function resolveSpecifier(
|
|
92
|
+
specifier: string,
|
|
93
|
+
importer: string,
|
|
94
|
+
repositoryRoot: string,
|
|
95
|
+
packages: ReturnType<typeof workspacePackages>,
|
|
96
|
+
): string[] {
|
|
97
|
+
const clean = specifier.split(/[?#]/, 1)[0]!;
|
|
98
|
+
if (clean.startsWith("node:") || /^[a-z]+:/i.test(clean)) return [];
|
|
99
|
+
if (clean.startsWith(".")) return [exactFile(resolve(dirname(importer), clean))];
|
|
100
|
+
if (clean.startsWith("@/")) return [exactFile(resolve(repositoryRoot, "apps/storefront/src", clean.slice(2)))];
|
|
101
|
+
const matched = [...packages.entries()]
|
|
102
|
+
.sort(([left], [right]) => right.length - left.length)
|
|
103
|
+
.find(([name]) => clean === name || clean.startsWith(`${name}/`));
|
|
104
|
+
if (!matched) return [];
|
|
105
|
+
const [name, workspace] = matched;
|
|
106
|
+
const subpath = clean === name ? "." : `.${clean.slice(name.length)}`;
|
|
107
|
+
const target = exportTarget(workspace.manifest.exports, subpath) ??
|
|
108
|
+
(subpath === "." && typeof workspace.manifest.main === "string" ? workspace.manifest.main : null);
|
|
109
|
+
if (!target) throw new Error("The clean-clone workspace barrel could not be resolved.");
|
|
110
|
+
return [workspace.packageJson, exactFile(resolve(workspace.root, target))];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function insideRepository(path: string, repositoryRoot: string): boolean {
|
|
114
|
+
const tail = relative(repositoryRoot, path);
|
|
115
|
+
return tail !== "" && tail !== ".." && !tail.startsWith(`..${sep}`) && !resolve(path).includes(`${sep}node_modules${sep}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function resolveV84CleanCloneSourceGraph(repositoryRoot: string, entries: readonly string[]) {
|
|
119
|
+
const packages = workspacePackages(repositoryRoot);
|
|
120
|
+
const seen = new Set<string>();
|
|
121
|
+
const pending = [
|
|
122
|
+
...TOOLCHAIN_FILES.map((path) => resolve(repositoryRoot, path)),
|
|
123
|
+
...entries.map((path) => resolve(repositoryRoot, path)),
|
|
124
|
+
];
|
|
125
|
+
while (pending.length > 0) {
|
|
126
|
+
const path = exactFile(pending.pop()!);
|
|
127
|
+
if (seen.has(path)) continue;
|
|
128
|
+
if (!insideRepository(path, repositoryRoot)) throw new Error("The clean-clone source graph escaped the repository.");
|
|
129
|
+
seen.add(path);
|
|
130
|
+
const source = readFileSync(path, "utf8");
|
|
131
|
+
const specifiers = [
|
|
132
|
+
...[...source.matchAll(IMPORT_PATTERN)].map((match) => match[1]!),
|
|
133
|
+
...[...source.matchAll(URL_PATTERN)].map((match) => match[1]!),
|
|
134
|
+
];
|
|
135
|
+
for (const specifier of specifiers) {
|
|
136
|
+
for (const resolved of resolveSpecifier(specifier, path, repositoryRoot, packages)) pending.push(resolved);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const paths = [...seen].sort();
|
|
140
|
+
const canonical = JSON.stringify(paths.map((path) => [
|
|
141
|
+
relative(repositoryRoot, path).split(sep).join("/"),
|
|
142
|
+
canonicalSource(path, repositoryRoot),
|
|
143
|
+
]));
|
|
144
|
+
return { paths, count: paths.length, sha256: sha256(canonical) };
|
|
145
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** Fixed-input lifecycle proof composed from the frozen offline native-install producer. */
|
|
3
|
+
import { readFixedV84NativeInstallEvidence } from "./fixed-v84-native-install-producer.js";
|
|
4
|
+
import { buildV84CloneLifecycleEvidence } from "../src/lib/apps/v84CloneLifecycleEvidence.js";
|
|
5
|
+
|
|
6
|
+
if (process.argv.length !== 2) {
|
|
7
|
+
process.stderr.write("refused: fixed-input lifecycle command accepts no arguments\n");
|
|
8
|
+
process.exit(64);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const nativeEvidence = readFixedV84NativeInstallEvidence();
|
|
13
|
+
const evidence = await buildV84CloneLifecycleEvidence(nativeEvidence);
|
|
14
|
+
process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`);
|
|
15
|
+
} catch {
|
|
16
|
+
process.stderr.write("refused: fixed lifecycle evidence unavailable\n");
|
|
17
|
+
process.exit(70);
|
|
18
|
+
}
|
|
@@ -47,7 +47,7 @@ const {
|
|
|
47
47
|
} = Astro.props;
|
|
48
48
|
|
|
49
49
|
// Render decision (placeholder / Cloudflare resizing / Shopify ?width=) lives in
|
|
50
|
-
// lib/imageAttrs.ts so it's unit-testable without rendering this component
|
|
50
|
+
// lib/imageAttrs.ts so it's unit-testable without rendering this component.
|
|
51
51
|
const { src: resolvedSrc, srcset } = resolveImage({ src, rehosted, width, height, seed, label });
|
|
52
52
|
|
|
53
53
|
const loadingAttr = loading ?? (priority ? "eager" : "lazy");
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* <Seo> — per-page title/meta, Open Graph, Twitter card, canonical, JSON-LD.
|
|
4
4
|
* (brief §8). Tenant-aware: OG image + site name come from the resolved tenant.
|
|
5
5
|
*/
|
|
6
|
+
import { articleSeoMetaTags, type ArticleMeta } from "@/lib/seo/meta.js";
|
|
7
|
+
import { withXDefault, type Alternate } from "@/lib/seo/alternates.js";
|
|
8
|
+
|
|
6
9
|
interface JsonLd {
|
|
7
10
|
[key: string]: unknown;
|
|
8
11
|
}
|
|
@@ -17,6 +20,25 @@ interface Props {
|
|
|
17
20
|
noindex?: boolean;
|
|
18
21
|
/** One or more JSON-LD graphs (Product, BreadcrumbList, Organization…). */
|
|
19
22
|
jsonLd?: JsonLd | JsonLd[];
|
|
23
|
+
/** Alternate RSS/Atom feeds this page advertises (e.g. a collection's feed). */
|
|
24
|
+
feeds?: { title: string; href: string }[];
|
|
25
|
+
// --- B1.6 article SEO hardening (all additive/optional) ---
|
|
26
|
+
/** Open Graph `article:*` meta; emitted only when `ogType === "article"`. */
|
|
27
|
+
article?: ArticleMeta;
|
|
28
|
+
/** og:image:alt — accessible description of the OG image. */
|
|
29
|
+
imageAlt?: string;
|
|
30
|
+
imageWidth?: number;
|
|
31
|
+
imageHeight?: number;
|
|
32
|
+
twitterSite?: string;
|
|
33
|
+
twitterCreator?: string;
|
|
34
|
+
/** Syndication: when set, REPLACES the derived self-canonical (rel=canonical
|
|
35
|
+
* + og:url) so search engines point at the original. */
|
|
36
|
+
canonicalOverride?: string;
|
|
37
|
+
/** I2 — per-variant `hreflang` alternates for a translated article (self +
|
|
38
|
+
* siblings). When present and non-empty, emits one `<link rel="alternate">`
|
|
39
|
+
* per entry PLUS an `x-default`. Absent/empty ⇒ no alternate links (a
|
|
40
|
+
* singleton post is unchanged). */
|
|
41
|
+
alternates?: Alternate[];
|
|
20
42
|
}
|
|
21
43
|
|
|
22
44
|
const {
|
|
@@ -27,10 +49,29 @@ const {
|
|
|
27
49
|
ogImage,
|
|
28
50
|
noindex = false,
|
|
29
51
|
jsonLd,
|
|
52
|
+
feeds = [],
|
|
53
|
+
article,
|
|
54
|
+
imageAlt,
|
|
55
|
+
imageWidth,
|
|
56
|
+
imageHeight,
|
|
57
|
+
twitterSite,
|
|
58
|
+
twitterCreator,
|
|
59
|
+
canonicalOverride,
|
|
60
|
+
alternates = [],
|
|
30
61
|
} = Astro.props;
|
|
31
62
|
|
|
32
63
|
const { tenant, canonicalBase } = Astro.locals;
|
|
33
|
-
const canonical =
|
|
64
|
+
const canonical =
|
|
65
|
+
canonicalOverride ?? new URL(path, canonicalBase + "/").toString();
|
|
66
|
+
const articleMeta = articleSeoMetaTags({
|
|
67
|
+
ogType,
|
|
68
|
+
article,
|
|
69
|
+
imageAlt,
|
|
70
|
+
imageWidth,
|
|
71
|
+
imageHeight,
|
|
72
|
+
twitterSite,
|
|
73
|
+
twitterCreator,
|
|
74
|
+
});
|
|
34
75
|
// Don't double-append the brand: merchant SEO titles (title_tag) often already
|
|
35
76
|
// end with the store name.
|
|
36
77
|
const fullTitle = title.includes(tenant.displayName)
|
|
@@ -41,6 +82,7 @@ const image = ogImage
|
|
|
41
82
|
: new URL(tenant.theme_tokens?.brand?.ogImage ?? "/brand/northwind-og.svg", canonicalBase + "/").toString();
|
|
42
83
|
|
|
43
84
|
const graphs = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
|
|
85
|
+
const alternateLinks = withXDefault(alternates);
|
|
44
86
|
---
|
|
45
87
|
|
|
46
88
|
<title>{fullTitle}</title>
|
|
@@ -48,6 +90,18 @@ const graphs = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
|
|
|
48
90
|
<link rel="canonical" href={canonical} />
|
|
49
91
|
{noindex && <meta name="robots" content="noindex,nofollow" />}
|
|
50
92
|
|
|
93
|
+
{
|
|
94
|
+
feeds.map((f) => (
|
|
95
|
+
<link rel="alternate" type="application/rss+xml" title={f.title} href={f.href} />
|
|
96
|
+
))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
{
|
|
100
|
+
alternateLinks.map((a) => (
|
|
101
|
+
<link rel="alternate" hreflang={a.hreflang} href={a.href} />
|
|
102
|
+
))
|
|
103
|
+
}
|
|
104
|
+
|
|
51
105
|
<meta property="og:type" content={ogType} />
|
|
52
106
|
<meta property="og:site_name" content={tenant.displayName} />
|
|
53
107
|
<meta property="og:title" content={fullTitle} />
|
|
@@ -60,6 +114,16 @@ const graphs = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
|
|
|
60
114
|
{description && <meta name="twitter:description" content={description} />}
|
|
61
115
|
<meta name="twitter:image" content={image} />
|
|
62
116
|
|
|
117
|
+
{
|
|
118
|
+
articleMeta.map((t) =>
|
|
119
|
+
t.property ? (
|
|
120
|
+
<meta property={t.property} content={t.content} />
|
|
121
|
+
) : (
|
|
122
|
+
<meta name={t.name} content={t.content} />
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
63
127
|
{
|
|
64
128
|
graphs.map((g) => (
|
|
65
129
|
<script
|