@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,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The merchant Review-and-Release VIEW MODEL and its pure builder.
|
|
3
|
+
*
|
|
4
|
+
* `buildReviewReleaseViewModel` consumes the SAME `GET /api/changes` payload the
|
|
5
|
+
* admin publish surface already fetches (see `src/pages/api/changes/index.ts`) plus
|
|
6
|
+
* a small server-resolved context, and produces a fully-serializable, UI-agnostic
|
|
7
|
+
* shape a component can render directly — every string already interpolated, every
|
|
8
|
+
* decision already made. This is the props contract the downstream
|
|
9
|
+
* `review-release-workspace` unit builds its two-decision UI against; the
|
|
10
|
+
* `ChangeCardView` / `NextReleaseView` shapes ARE the props for its future
|
|
11
|
+
* change-row and release-status components.
|
|
12
|
+
*
|
|
13
|
+
* The builder is pure (no DOM, no I/O, deterministic), so it runs equally on the
|
|
14
|
+
* server (to embed the model) or the client (to re-derive it on each poll), and is
|
|
15
|
+
* exhaustively unit-testable.
|
|
16
|
+
*/
|
|
17
|
+
import {
|
|
18
|
+
CHANGE_STATE_COPY,
|
|
19
|
+
RELEASE_STATE_COPY,
|
|
20
|
+
ADD_TO_NEXT_RELEASE_LABEL,
|
|
21
|
+
PUBLISH_NOW_LABEL,
|
|
22
|
+
VIEW_LIVE_STORE_LABEL,
|
|
23
|
+
PUBLISH_CONFIRM_COPY,
|
|
24
|
+
WHATS_IN_RELEASE_HEADING,
|
|
25
|
+
whatsInReleaseFallback,
|
|
26
|
+
} from "./copy.js";
|
|
27
|
+
import { resolveChangeState, type ChangeStateFacts } from "./changeState.js";
|
|
28
|
+
import { resolveReleaseState, type ReleaseStateFacts } from "./releaseState.js";
|
|
29
|
+
import {
|
|
30
|
+
resolveMerchantPermissions,
|
|
31
|
+
type MerchantPermissions,
|
|
32
|
+
} from "./permissions.js";
|
|
33
|
+
import type {
|
|
34
|
+
InternalAggregateState,
|
|
35
|
+
InternalChangeStatus,
|
|
36
|
+
MerchantChangeActionId,
|
|
37
|
+
MerchantChangeStateId,
|
|
38
|
+
MerchantReleaseActionId,
|
|
39
|
+
MerchantReleaseStateId,
|
|
40
|
+
} from "./types.js";
|
|
41
|
+
|
|
42
|
+
// ── Input: the subset of GET /api/changes this model reads ───────────────────────
|
|
43
|
+
// Intentionally a focused structural subset (not the full wire type) so the seam is
|
|
44
|
+
// explicit and the builder never couples to fields it doesn't consume.
|
|
45
|
+
|
|
46
|
+
/** One evidence check on a change row. */
|
|
47
|
+
export interface ChangesPayloadEvidenceCheck {
|
|
48
|
+
status: "pass" | "fail" | string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** One change row from `payload.changes` (a built candidate or a synthetic not-built PR). */
|
|
52
|
+
export interface ChangesPayloadChange {
|
|
53
|
+
changeId: string | null;
|
|
54
|
+
prNumber?: number | null;
|
|
55
|
+
status: InternalChangeStatus | string;
|
|
56
|
+
built?: boolean;
|
|
57
|
+
mergeable?: boolean;
|
|
58
|
+
liveStateConfirmed?: boolean;
|
|
59
|
+
updatedAt?: string | null;
|
|
60
|
+
evidence?: { promotable?: boolean; checks?: ChangesPayloadEvidenceCheck[] } | null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** One staged PR from `payload.aggregate.includedPrs` (carries the human title). */
|
|
64
|
+
export interface ChangesPayloadIncludedPr {
|
|
65
|
+
changeId?: string | null;
|
|
66
|
+
prNumber?: number | null;
|
|
67
|
+
title?: string | null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The aggregate card projection. */
|
|
71
|
+
export interface ChangesPayloadAggregate {
|
|
72
|
+
queueState?: InternalAggregateState | string;
|
|
73
|
+
aggregateSha?: string | null;
|
|
74
|
+
includedPrs?: ChangesPayloadIncludedPr[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The ship-plan projection (ok-plan carries the paywall verdict; a refusal does not). */
|
|
78
|
+
export interface ChangesPayloadPlan {
|
|
79
|
+
ok?: boolean;
|
|
80
|
+
paywall?: { allowed?: boolean } | null;
|
|
81
|
+
alreadyShipped?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The live-version pointer. */
|
|
85
|
+
export interface ChangesPayloadCurrent {
|
|
86
|
+
versionId?: string | null;
|
|
87
|
+
createdAt?: string | null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The `/api/changes` fields the merchant model consumes. */
|
|
91
|
+
export interface ChangesPayload {
|
|
92
|
+
changes?: ChangesPayloadChange[];
|
|
93
|
+
aggregate?: ChangesPayloadAggregate | null;
|
|
94
|
+
plan?: ChangesPayloadPlan | null;
|
|
95
|
+
current?: ChangesPayloadCurrent | null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Server-resolved context the model can't derive from the payload alone. */
|
|
99
|
+
export interface ReviewReleaseContext {
|
|
100
|
+
/** Owner/admin/ship-on-behalf — mirrors the server ship gate. */
|
|
101
|
+
canShip: boolean;
|
|
102
|
+
/** This is an internal test store (publishing to a live storefront is blocked). */
|
|
103
|
+
internalTestStore?: boolean;
|
|
104
|
+
/** The store's display name, for the publish-confirm copy. */
|
|
105
|
+
storeName?: string;
|
|
106
|
+
/** A publish POST is in flight right now (client-owned transient). */
|
|
107
|
+
shipInFlight?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* After how long in "Preparing" the reassuring slow sub-line appears (contract
|
|
110
|
+
* §9.5 leaves the value to this layer; default 2 min). Compared against a
|
|
111
|
+
* change's `updatedAt`.
|
|
112
|
+
*/
|
|
113
|
+
preparingSlowThresholdMs?: number;
|
|
114
|
+
/** Injectable clock for deterministic slow-threshold tests. */
|
|
115
|
+
now?: () => number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── Output: the view model ───────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
/** A change's one merchant action, fully labelled. */
|
|
121
|
+
export interface MerchantChangeAction {
|
|
122
|
+
id: MerchantChangeActionId;
|
|
123
|
+
label: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** One change, ready to render. `label`/`subline` are final (interpolated) copy. */
|
|
127
|
+
export interface ChangeCardView {
|
|
128
|
+
changeId: string | null;
|
|
129
|
+
prNumber: number | null;
|
|
130
|
+
/** Human title when known (from the staged summary), else null → the UI falls back to the id. */
|
|
131
|
+
title: string | null;
|
|
132
|
+
state: MerchantChangeStateId;
|
|
133
|
+
label: string;
|
|
134
|
+
subline: string;
|
|
135
|
+
/** The primary action this state carries, or null. `needs-attention` carries none —
|
|
136
|
+
* its subline already states the developer was notified automatically. */
|
|
137
|
+
action: MerchantChangeAction | null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** The next release's one merchant action, fully labelled. */
|
|
141
|
+
export interface MerchantReleaseAction {
|
|
142
|
+
id: MerchantReleaseActionId;
|
|
143
|
+
label: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** The publish confirmation dialog copy, interpolated. */
|
|
147
|
+
export interface PublishConfirmView {
|
|
148
|
+
heading: string;
|
|
149
|
+
body: string;
|
|
150
|
+
confirm: string;
|
|
151
|
+
cancel: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** The next release, ready to render. */
|
|
155
|
+
export interface NextReleaseView {
|
|
156
|
+
state: MerchantReleaseStateId;
|
|
157
|
+
heading: string;
|
|
158
|
+
body: string;
|
|
159
|
+
/** Count of staged changes (the `{n}` in the copy). */
|
|
160
|
+
changeCount: number;
|
|
161
|
+
/** "What's in this release" — a plain list of change titles (Ready to publish). */
|
|
162
|
+
contents: { heading: string; items: string[]; fallback: string };
|
|
163
|
+
/** The primary action (publish-now / view-live-store), or null. */
|
|
164
|
+
action: MerchantReleaseAction | null;
|
|
165
|
+
/** The publish confirmation copy (present iff `action` is publish-now). */
|
|
166
|
+
confirm: PublishConfirmView | null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** The whole merchant Review-and-Release surface as data. */
|
|
170
|
+
export interface ReviewReleaseViewModel {
|
|
171
|
+
changes: ChangeCardView[];
|
|
172
|
+
nextRelease: NextReleaseView;
|
|
173
|
+
permissions: MerchantPermissions;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const DEFAULT_SLOW_MS = 120_000;
|
|
177
|
+
|
|
178
|
+
// ── Builder ──────────────────────────────────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
export function buildReviewReleaseViewModel(
|
|
181
|
+
payload: ChangesPayload,
|
|
182
|
+
context: ReviewReleaseContext,
|
|
183
|
+
): ReviewReleaseViewModel {
|
|
184
|
+
const aggregate = payload.aggregate ?? {};
|
|
185
|
+
const includedPrs = aggregate.includedPrs ?? [];
|
|
186
|
+
const plan = payload.plan ?? null;
|
|
187
|
+
const current = payload.current ?? null;
|
|
188
|
+
|
|
189
|
+
const titleByChange = indexTitles(includedPrs);
|
|
190
|
+
const stagedKeys = stagedIdentitySet(includedPrs);
|
|
191
|
+
const now = context.now ?? Date.now;
|
|
192
|
+
const slowMs = context.preparingSlowThresholdMs ?? DEFAULT_SLOW_MS;
|
|
193
|
+
|
|
194
|
+
const changes = (payload.changes ?? []).map((c) =>
|
|
195
|
+
buildChangeCard(c, { titleByChange, stagedKeys, now, slowMs }),
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const planOk = plan?.ok === true;
|
|
199
|
+
const paywalled = planOk && plan?.paywall?.allowed === false;
|
|
200
|
+
const alreadyShipped = plan?.alreadyShipped === true;
|
|
201
|
+
|
|
202
|
+
const nextRelease = buildNextRelease({
|
|
203
|
+
queueState: (aggregate.queueState as InternalAggregateState) ?? "empty",
|
|
204
|
+
aggregateSha: aggregate.aggregateSha ?? null,
|
|
205
|
+
includedPrs,
|
|
206
|
+
planOk,
|
|
207
|
+
alreadyShipped,
|
|
208
|
+
shipInFlight: context.shipInFlight === true,
|
|
209
|
+
liveVersionId: current?.versionId ?? null,
|
|
210
|
+
liveCreatedAt: current?.createdAt ?? null,
|
|
211
|
+
canPublish: context.canShip && !paywalled && !context.internalTestStore,
|
|
212
|
+
storeName: context.storeName,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const permissions = resolveMerchantPermissions({
|
|
216
|
+
canShip: context.canShip,
|
|
217
|
+
paywalled,
|
|
218
|
+
internalTestStore: context.internalTestStore === true,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return { changes, nextRelease, permissions };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ── Change card ──────────────────────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
interface ChangeBuildDeps {
|
|
227
|
+
titleByChange: (change: ChangesPayloadChange) => string | null;
|
|
228
|
+
stagedKeys: Set<string>;
|
|
229
|
+
now: () => number;
|
|
230
|
+
slowMs: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function buildChangeCard(c: ChangesPayloadChange, deps: ChangeBuildDeps): ChangeCardView {
|
|
234
|
+
const inNextRelease = isStaged(c, deps.stagedKeys);
|
|
235
|
+
const checks = c.evidence?.checks ?? [];
|
|
236
|
+
const facts: ChangeStateFacts = {
|
|
237
|
+
status: normalizeStatus(c.status),
|
|
238
|
+
promotable: c.evidence?.promotable === true,
|
|
239
|
+
// A not-built row has no settled mergeability; treat absent as not-mergeable
|
|
240
|
+
// (it isn't ready-to-add), which the precedence handles as "preparing".
|
|
241
|
+
mergeable: c.mergeable === true,
|
|
242
|
+
hasFailingChecks: checks.some((k) => k.status === "fail"),
|
|
243
|
+
liveStateConfirmed: c.liveStateConfirmed !== false,
|
|
244
|
+
inNextRelease,
|
|
245
|
+
// Merged/closed changes are filtered out of the open queue upstream, so a row
|
|
246
|
+
// in `payload.changes` is never `published`; a "Recently published" history is
|
|
247
|
+
// a separate source the workspace unit may add (contract §9.7).
|
|
248
|
+
published: false,
|
|
249
|
+
};
|
|
250
|
+
const state = resolveChangeState(facts);
|
|
251
|
+
const copy = CHANGE_STATE_COPY[state];
|
|
252
|
+
|
|
253
|
+
const subline =
|
|
254
|
+
state === "preparing" && isSlow(c.updatedAt, deps.now(), deps.slowMs) && copy.sublineSlow
|
|
255
|
+
? copy.sublineSlow
|
|
256
|
+
: copy.subline;
|
|
257
|
+
|
|
258
|
+
const action: MerchantChangeAction | null =
|
|
259
|
+
state === "ready-to-add"
|
|
260
|
+
? { id: "add-to-next-release", label: ADD_TO_NEXT_RELEASE_LABEL }
|
|
261
|
+
: null;
|
|
262
|
+
// `needs-attention` carries no merchant action at all — its subline already
|
|
263
|
+
// states the developer was notified (automatic, via the real backend handoff),
|
|
264
|
+
// so a "Notify developer" button would be a fake no-op duplicating that claim.
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
changeId: c.changeId ?? null,
|
|
268
|
+
prNumber: c.prNumber ?? null,
|
|
269
|
+
title: deps.titleByChange(c),
|
|
270
|
+
state,
|
|
271
|
+
label: copy.label,
|
|
272
|
+
subline,
|
|
273
|
+
action,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function isSlow(updatedAt: string | null | undefined, nowMs: number, slowMs: number): boolean {
|
|
278
|
+
if (!updatedAt) return false;
|
|
279
|
+
const t = new Date(updatedAt).getTime();
|
|
280
|
+
if (!Number.isFinite(t)) return false;
|
|
281
|
+
return nowMs - t >= slowMs;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ── Next release ─────────────────────────────────────────────────────────────────
|
|
285
|
+
|
|
286
|
+
interface NextReleaseInput {
|
|
287
|
+
queueState: InternalAggregateState;
|
|
288
|
+
aggregateSha: string | null;
|
|
289
|
+
includedPrs: ChangesPayloadIncludedPr[];
|
|
290
|
+
planOk: boolean;
|
|
291
|
+
alreadyShipped: boolean;
|
|
292
|
+
shipInFlight: boolean;
|
|
293
|
+
liveVersionId: string | null;
|
|
294
|
+
liveCreatedAt: string | null;
|
|
295
|
+
canPublish: boolean;
|
|
296
|
+
storeName?: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function buildNextRelease(input: NextReleaseInput): NextReleaseView {
|
|
300
|
+
const changeCount = input.includedPrs.length;
|
|
301
|
+
const matchesLive = Boolean(
|
|
302
|
+
input.aggregateSha && input.liveVersionId && input.aggregateSha === input.liveVersionId,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
const facts: ReleaseStateFacts = {
|
|
306
|
+
queueState: input.queueState,
|
|
307
|
+
// An already-shipped plan is a live/no-op, not a fresh "ready to publish".
|
|
308
|
+
planOk: input.planOk && !input.alreadyShipped,
|
|
309
|
+
shipInFlight: input.shipInFlight,
|
|
310
|
+
matchesLive,
|
|
311
|
+
hasStaged: changeCount > 0,
|
|
312
|
+
};
|
|
313
|
+
const state = resolveReleaseState(facts);
|
|
314
|
+
const copy = RELEASE_STATE_COPY[state];
|
|
315
|
+
|
|
316
|
+
const heading = copy.heading;
|
|
317
|
+
const body = interpolate(copy.body, {
|
|
318
|
+
n: String(changeCount),
|
|
319
|
+
date: formatReleaseDate(input.liveCreatedAt),
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const items = input.includedPrs
|
|
323
|
+
.map((p) => (p.title ?? "").trim())
|
|
324
|
+
.filter((t) => t.length > 0);
|
|
325
|
+
|
|
326
|
+
let action: MerchantReleaseAction | null = null;
|
|
327
|
+
let confirm: PublishConfirmView | null = null;
|
|
328
|
+
if (state === "ready-to-publish" && input.canPublish) {
|
|
329
|
+
action = { id: "publish-now", label: PUBLISH_NOW_LABEL };
|
|
330
|
+
confirm = {
|
|
331
|
+
heading: PUBLISH_CONFIRM_COPY.heading,
|
|
332
|
+
body: interpolate(PUBLISH_CONFIRM_COPY.body, {
|
|
333
|
+
n: String(changeCount),
|
|
334
|
+
store: input.storeName?.trim() || "your store",
|
|
335
|
+
}),
|
|
336
|
+
confirm: PUBLISH_CONFIRM_COPY.confirm,
|
|
337
|
+
cancel: PUBLISH_CONFIRM_COPY.cancel,
|
|
338
|
+
};
|
|
339
|
+
} else if (state === "live") {
|
|
340
|
+
action = { id: "view-live-store", label: VIEW_LIVE_STORE_LABEL };
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
state,
|
|
345
|
+
heading,
|
|
346
|
+
body,
|
|
347
|
+
changeCount,
|
|
348
|
+
contents: {
|
|
349
|
+
heading: WHATS_IN_RELEASE_HEADING,
|
|
350
|
+
items,
|
|
351
|
+
fallback: whatsInReleaseFallback(changeCount),
|
|
352
|
+
},
|
|
353
|
+
action,
|
|
354
|
+
confirm,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// ── Small pure helpers ───────────────────────────────────────────────────────────
|
|
359
|
+
|
|
360
|
+
const KNOWN_STATUSES: ReadonlySet<string> = new Set<InternalChangeStatus>([
|
|
361
|
+
"queued",
|
|
362
|
+
"reconciling",
|
|
363
|
+
"ready",
|
|
364
|
+
"blocked",
|
|
365
|
+
"not-built",
|
|
366
|
+
"building",
|
|
367
|
+
"accepted",
|
|
368
|
+
"merged",
|
|
369
|
+
"closed",
|
|
370
|
+
]);
|
|
371
|
+
|
|
372
|
+
/** Coerce an unknown wire status to the closed vocabulary; unknowns read as "preparing". */
|
|
373
|
+
function normalizeStatus(status: string): InternalChangeStatus {
|
|
374
|
+
return (KNOWN_STATUSES.has(status) ? status : "queued") as InternalChangeStatus;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** Stable identity key for staged-membership matching (prefer changeId, else PR). */
|
|
378
|
+
function identityKey(changeId?: string | null, prNumber?: number | null): string | null {
|
|
379
|
+
if (changeId) return "c:" + changeId;
|
|
380
|
+
if (typeof prNumber === "number") return "p:" + prNumber;
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function stagedIdentitySet(includedPrs: ChangesPayloadIncludedPr[]): Set<string> {
|
|
385
|
+
const set = new Set<string>();
|
|
386
|
+
for (const p of includedPrs) {
|
|
387
|
+
const byChange = identityKey(p.changeId, null);
|
|
388
|
+
const byPr = identityKey(null, p.prNumber);
|
|
389
|
+
if (byChange) set.add(byChange);
|
|
390
|
+
if (byPr) set.add(byPr);
|
|
391
|
+
}
|
|
392
|
+
return set;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function isStaged(c: ChangesPayloadChange, staged: Set<string>): boolean {
|
|
396
|
+
const byChange = identityKey(c.changeId, null);
|
|
397
|
+
const byPr = identityKey(null, c.prNumber);
|
|
398
|
+
return Boolean((byChange && staged.has(byChange)) || (byPr && staged.has(byPr)));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function indexTitles(
|
|
402
|
+
includedPrs: ChangesPayloadIncludedPr[],
|
|
403
|
+
): (change: ChangesPayloadChange) => string | null {
|
|
404
|
+
const byChange = new Map<string, string>();
|
|
405
|
+
const byPr = new Map<number, string>();
|
|
406
|
+
for (const p of includedPrs) {
|
|
407
|
+
const title = (p.title ?? "").trim();
|
|
408
|
+
if (!title) continue;
|
|
409
|
+
if (p.changeId) byChange.set(p.changeId, title);
|
|
410
|
+
if (typeof p.prNumber === "number") byPr.set(p.prNumber, title);
|
|
411
|
+
}
|
|
412
|
+
return (change) => {
|
|
413
|
+
if (change.changeId && byChange.has(change.changeId)) return byChange.get(change.changeId)!;
|
|
414
|
+
if (typeof change.prNumber === "number" && byPr.has(change.prNumber)) {
|
|
415
|
+
return byPr.get(change.prNumber)!;
|
|
416
|
+
}
|
|
417
|
+
return null;
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** Substitute `{token}` occurrences; unknown tokens are left intact. */
|
|
422
|
+
function interpolate(template: string, values: Record<string, string>): string {
|
|
423
|
+
return template.replace(/\{(\w+)\}/g, (m: string, key: string) =>
|
|
424
|
+
key in values ? values[key]! : m,
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const MONTHS = [
|
|
429
|
+
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
430
|
+
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
|
431
|
+
];
|
|
432
|
+
|
|
433
|
+
/** Deterministic UTC "Mon D, YYYY" for the `{date}` token; empty when unknown. */
|
|
434
|
+
export function formatReleaseDate(iso: string | null | undefined): string {
|
|
435
|
+
if (!iso) return "";
|
|
436
|
+
const d = new Date(iso);
|
|
437
|
+
const t = d.getTime();
|
|
438
|
+
if (!Number.isFinite(t)) return "";
|
|
439
|
+
return `${MONTHS[d.getUTCMonth()]} ${d.getUTCDate()}, ${d.getUTCFullYear()}`;
|
|
440
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The merchant's two actions, as pure functions over an injected `fetch`.
|
|
3
|
+
*
|
|
4
|
+
* These translate the internal endpoint contracts (`POST /api/changes/accept` =
|
|
5
|
+
* accept-to-preview, `POST /api/changes/ship` = go-live) into the merchant's
|
|
6
|
+
* two-decision vocabulary, collapsing every internal failure onto a state that
|
|
7
|
+
* requires NOTHING of the merchant (contract §7 "error philosophy"): an integrate
|
|
8
|
+
* conflict resolves to the change's `needs-attention`; a publish that refuses
|
|
9
|
+
* (paywall) stays put with the reason; a publish that fails after the flip resolves
|
|
10
|
+
* to the release's auto-retry `needs-attention`. There is deliberately NO retry /
|
|
11
|
+
* rebuild / resolve result — the surface offers no such control.
|
|
12
|
+
*
|
|
13
|
+
* Injected `fetch` keeps them node-testable (the storefront test env is `node`).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The minimal fetch surface these actions use (satisfied by the global `fetch`). */
|
|
17
|
+
export type FetchLike = (
|
|
18
|
+
input: string,
|
|
19
|
+
init?: { method?: string; headers?: Record<string, string>; body?: string },
|
|
20
|
+
) => Promise<{ ok: boolean; status: number; json: () => Promise<unknown> }>;
|
|
21
|
+
|
|
22
|
+
// ── Add to next release ──────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
export interface AddDeps {
|
|
25
|
+
fetch: FetchLike;
|
|
26
|
+
/** basePath-aware `POST /api/changes/accept` URL. */
|
|
27
|
+
endpoint: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Which change to add — its canonical id when known, else its PR number. */
|
|
31
|
+
export interface AddRef {
|
|
32
|
+
changeId: string | null;
|
|
33
|
+
prNumber: number | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type AddResult =
|
|
37
|
+
/** The change was queued into the next release (now "In next release"). */
|
|
38
|
+
| { kind: "added" }
|
|
39
|
+
/** The change couldn't go in as-is (conflict/blocked) — now "Needs attention". */
|
|
40
|
+
| { kind: "needs-attention" }
|
|
41
|
+
/** A transport/unexpected failure — the surface re-reads; no retry control. */
|
|
42
|
+
| { kind: "error"; message: string };
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Add a ready change to the next release (accept-to-preview). The endpoint returns
|
|
46
|
+
* the honest integrate outcome (`{ ok, queueState, reason, statusMessage }`, never a
|
|
47
|
+
* bare `merged: true`): `ok` ⇒ staged; a completed-but-not-ok enqueue (conflict) ⇒
|
|
48
|
+
* needs-attention. A non-2xx or thrown transport error ⇒ `error` (the surface simply
|
|
49
|
+
* re-reads state — it never shows a retry button).
|
|
50
|
+
*/
|
|
51
|
+
export async function addChangeToRelease(deps: AddDeps, ref: AddRef): Promise<AddResult> {
|
|
52
|
+
const body: Record<string, unknown> = {};
|
|
53
|
+
if (ref.changeId) body.changeId = ref.changeId;
|
|
54
|
+
else if (typeof ref.prNumber === "number") body.prNumber = ref.prNumber;
|
|
55
|
+
else return { kind: "error", message: "No change reference to add." };
|
|
56
|
+
|
|
57
|
+
let res: Awaited<ReturnType<FetchLike>>;
|
|
58
|
+
try {
|
|
59
|
+
res = await deps.fetch(deps.endpoint, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: { "content-type": "application/json" },
|
|
62
|
+
body: JSON.stringify(body),
|
|
63
|
+
});
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return { kind: "error", message: (err as Error).message };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!res.ok) {
|
|
69
|
+
const payload = await safeJson(res);
|
|
70
|
+
return { kind: "error", message: readError(payload) ?? `Request failed (${res.status}).` };
|
|
71
|
+
}
|
|
72
|
+
const payload = (await safeJson(res)) as { ok?: unknown } | null;
|
|
73
|
+
// A completed enqueue that did not go green is a conflict/blocked candidate — it is
|
|
74
|
+
// handed to a developer, so the change becomes "Needs attention" (no merchant retry).
|
|
75
|
+
return payload && payload.ok === true ? { kind: "added" } : { kind: "needs-attention" };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Publish now ──────────────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
export interface PublishDeps {
|
|
81
|
+
fetch: FetchLike;
|
|
82
|
+
/** basePath-aware `POST /api/changes/ship` URL. */
|
|
83
|
+
endpoint: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type PublishResult =
|
|
87
|
+
/** The release went live. */
|
|
88
|
+
| { kind: "published" }
|
|
89
|
+
/** Refused at the paywall — stays Ready to publish; show the upgrade prompt. */
|
|
90
|
+
| { kind: "paywall"; message: string }
|
|
91
|
+
/** A pre-flip refusal that isn't merchant-actionable (moved/not green) — still preparing. */
|
|
92
|
+
| { kind: "not-ready" }
|
|
93
|
+
/** The flip failed after starting — Needs attention, retried automatically. */
|
|
94
|
+
| { kind: "publish-failed" }
|
|
95
|
+
/** A transport/unexpected failure — the surface re-reads; no retry control. */
|
|
96
|
+
| { kind: "error"; message: string };
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Publish the next release live. Sends the human go-live gate (`confirmGoLive: true`)
|
|
100
|
+
* — the confirm dialog IS that gate. The exact-digest pin, reviewed-digest token, and
|
|
101
|
+
* included-PR manifest stay server-side (the merchant confirmed a plain-language
|
|
102
|
+
* dialog, not a digest). Maps the orchestrator's honest terminal state onto the
|
|
103
|
+
* merchant vocabulary:
|
|
104
|
+
* - `shipped` → published
|
|
105
|
+
* - refused `paywall` → paywall (stays Ready to publish w/ upgrade)
|
|
106
|
+
* - refused (other, pre-flip) → not-ready (release re-reads as Preparing)
|
|
107
|
+
* - `promote_failed`/`record_failed`→ publish-failed (Needs attention, auto-retry)
|
|
108
|
+
*/
|
|
109
|
+
export async function publishNextRelease(deps: PublishDeps): Promise<PublishResult> {
|
|
110
|
+
let res: Awaited<ReturnType<FetchLike>>;
|
|
111
|
+
try {
|
|
112
|
+
res = await deps.fetch(deps.endpoint, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: { "content-type": "application/json" },
|
|
115
|
+
body: JSON.stringify({ confirmGoLive: true }),
|
|
116
|
+
});
|
|
117
|
+
} catch (err) {
|
|
118
|
+
return { kind: "error", message: (err as Error).message };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const payload = (await safeJson(res)) as
|
|
122
|
+
| { ok?: unknown; state?: unknown; reason?: unknown; message?: unknown }
|
|
123
|
+
| null;
|
|
124
|
+
|
|
125
|
+
if (payload && payload.ok === true) return { kind: "published" };
|
|
126
|
+
|
|
127
|
+
const state = typeof payload?.state === "string" ? payload.state : "";
|
|
128
|
+
const reason = typeof payload?.reason === "string" ? payload.reason : "";
|
|
129
|
+
const message = typeof payload?.message === "string" ? payload.message : "";
|
|
130
|
+
|
|
131
|
+
if (state === "refused") {
|
|
132
|
+
if (reason === "paywall") return { kind: "paywall", message: message || "Publishing is part of the paid plan." };
|
|
133
|
+
// not_green / no_passed_run / sha_mismatch / digest_mismatch / artifact_missing /
|
|
134
|
+
// bundle_unstaged / golive_unconfirmed: the release moved out from under the plan.
|
|
135
|
+
// Not merchant-actionable — it re-reads as Preparing and settles automatically.
|
|
136
|
+
return { kind: "not-ready" };
|
|
137
|
+
}
|
|
138
|
+
if (state === "promote_failed" || state === "record_failed") {
|
|
139
|
+
return { kind: "publish-failed" };
|
|
140
|
+
}
|
|
141
|
+
// No recognizable terminal state (e.g. a bare error body / non-2xx) — transport-ish.
|
|
142
|
+
return { kind: "error", message: message || readError(payload) || `Publish failed (${res.status}).` };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ── helpers ──────────────────────────────────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
async function safeJson(res: { json: () => Promise<unknown> }): Promise<unknown> {
|
|
148
|
+
try {
|
|
149
|
+
return await res.json();
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function readError(payload: unknown): string | null {
|
|
156
|
+
if (payload && typeof payload === "object" && "error" in payload) {
|
|
157
|
+
const e = (payload as { error?: unknown }).error;
|
|
158
|
+
if (typeof e === "string") return e;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|