@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,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/apps/admin/platform-adapters — the first-class native adapter
|
|
3
|
+
* surface (ext-admin-04). Two actions over the pure, edge-safe adapter core
|
|
4
|
+
* ({@link platformAdapterCatalog} / {@link buildPlatformAdapterDeclaration}):
|
|
5
|
+
*
|
|
6
|
+
* - `catalog` — the first-class adapter cards (consent purposes + performance
|
|
7
|
+
* budget + CSP origins + per-stage destination behavior), so a merchant sees the
|
|
8
|
+
* material effects before configuring anything.
|
|
9
|
+
* - `build` — turn a merchant's public destination ids (per environment) into a
|
|
10
|
+
* tenant-scoped declaration + resolved effective plan + read-model card, or
|
|
11
|
+
* refuse. Fail-closed: an unknown adapter, a missing/invalid live id, or a
|
|
12
|
+
* non-live stage that reuses the live id blocks with violations.
|
|
13
|
+
*
|
|
14
|
+
* Auth mirrors the other `/api/apps/admin/*` routes: the tenant is `auth.tenantId`
|
|
15
|
+
* from the resolved operator session — NEVER the request body — so a build is only
|
|
16
|
+
* ever scoped to the caller's own tenant. The build environment is derived server-side
|
|
17
|
+
* as a `candidate` stage, so the browser can never forge a live-stage declaration.
|
|
18
|
+
* Configuring is a manage action ({@link requireManageRole}). The route does NOT
|
|
19
|
+
* persist — staging/publishing a produced candidate is ext-admin-07's lifecycle.
|
|
20
|
+
*/
|
|
21
|
+
import type { APIContext } from "astro";
|
|
22
|
+
import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
|
|
23
|
+
import { json, requireManageRole } from "@/lib/apps/adminService.js";
|
|
24
|
+
import {
|
|
25
|
+
platformAdapterCatalog,
|
|
26
|
+
buildPlatformAdapterDeclaration,
|
|
27
|
+
resolveBrowserEnvironment,
|
|
28
|
+
INTEGRATION_SITE_SURFACES,
|
|
29
|
+
type IntegrationSiteSurface,
|
|
30
|
+
} from "@tot/public-runtime";
|
|
31
|
+
|
|
32
|
+
export const prerender = false;
|
|
33
|
+
|
|
34
|
+
export async function POST(context: APIContext): Promise<Response> {
|
|
35
|
+
const url = new URL(context.request.url);
|
|
36
|
+
const requestedTenant = url.searchParams.get("tenant");
|
|
37
|
+
const auth = await resolveOperatorSession(context, requestedTenant);
|
|
38
|
+
if (!auth.ok) return json({ error: auth.message }, auth.status);
|
|
39
|
+
const roleDenied = requireManageRole(auth);
|
|
40
|
+
if (roleDenied) return roleDenied;
|
|
41
|
+
|
|
42
|
+
let body: unknown;
|
|
43
|
+
try {
|
|
44
|
+
body = await context.request.json();
|
|
45
|
+
} catch {
|
|
46
|
+
return json({ error: "request body must be JSON" }, 400);
|
|
47
|
+
}
|
|
48
|
+
if (typeof body !== "object" || body === null) {
|
|
49
|
+
return json({ error: "request body must be a JSON object" }, 400);
|
|
50
|
+
}
|
|
51
|
+
const action = (body as { action?: unknown }).action;
|
|
52
|
+
|
|
53
|
+
if (action === "catalog") {
|
|
54
|
+
return json({ catalog: platformAdapterCatalog() });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (action === "build") {
|
|
58
|
+
const fields = (body as { fields?: unknown }).fields;
|
|
59
|
+
const base = typeof fields === "object" && fields !== null ? (fields as Record<string, unknown>) : {};
|
|
60
|
+
const surfaceParam = (base["siteSurface"] as IntegrationSiteSurface | undefined) ?? "storefront";
|
|
61
|
+
const siteSurface = INTEGRATION_SITE_SURFACES.includes(surfaceParam) ? surfaceParam : "storefront";
|
|
62
|
+
// A build always targets a candidate; the environment is server-derived, so a
|
|
63
|
+
// browser can never forge a live-stage declaration.
|
|
64
|
+
const environment = resolveBrowserEnvironment({
|
|
65
|
+
siteSurface,
|
|
66
|
+
canonicalHost: url.host,
|
|
67
|
+
revision: typeof base["revision"] === "string" ? (base["revision"] as string) : "adapter-candidate",
|
|
68
|
+
dev: false,
|
|
69
|
+
localHost: false,
|
|
70
|
+
candidate: true,
|
|
71
|
+
previewHost: false,
|
|
72
|
+
customizationEnv: "test",
|
|
73
|
+
});
|
|
74
|
+
const result = buildPlatformAdapterDeclaration({
|
|
75
|
+
adapterId: base["adapterId"],
|
|
76
|
+
ids: base["ids"],
|
|
77
|
+
tenantPublicId: auth.tenantId,
|
|
78
|
+
environment,
|
|
79
|
+
});
|
|
80
|
+
const status = result.ok ? 200 : result.reason === "unknown-adapter" ? 404 : 422;
|
|
81
|
+
return json({ result }, status);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return json({ error: 'action must be "catalog" or "build"' }, 400);
|
|
85
|
+
}
|
|
@@ -23,18 +23,29 @@ import {
|
|
|
23
23
|
receiveForwardedOrder,
|
|
24
24
|
type OrderForwardInput,
|
|
25
25
|
} from "@/lib/apps/orders/orderForwardReceiver.js";
|
|
26
|
+
import { joinForwardedOrderConversion } from "@/lib/apps/orders/orderConversionD1.js";
|
|
27
|
+
import { D1VerifiedProviderMeasurementStore } from "@/lib/apps/orders/verifiedProviderMeasurement.js";
|
|
26
28
|
import type { OrderLineItem, OrderStatus } from "@/lib/apps/orders/ordersStore.js";
|
|
27
29
|
import { recordActivity } from "@/lib/activity/recordActivity";
|
|
28
30
|
|
|
29
31
|
export const prerender = false;
|
|
30
32
|
|
|
31
33
|
const SIGNATURE_HEADER = "x-order-forward-signature";
|
|
32
|
-
const ORDER_STATUSES: readonly OrderStatus[] = ["created", "fulfilled", "cancelled"];
|
|
34
|
+
const ORDER_STATUSES: readonly OrderStatus[] = ["created", "fulfilled", "refunded", "cancelled"];
|
|
33
35
|
|
|
34
36
|
function json(body: unknown, status: number): Response {
|
|
35
37
|
return new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
/** Coarse, non-PII conversion-join diagnostic (never the order id or correlation token). */
|
|
41
|
+
function logConversionDiag(fields: Record<string, unknown>): void {
|
|
42
|
+
try {
|
|
43
|
+
console.warn("[diag:order-conversion]", JSON.stringify(fields));
|
|
44
|
+
} catch {
|
|
45
|
+
/* diagnostics must never break the caller */
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
// --- HMAC verification -----------------------------------------------------
|
|
39
50
|
// Same shape as `@tot/private-controlplane`'s `verifyGiteaSignature` (hex
|
|
40
51
|
// HMAC-SHA256 over the raw body, verified via `crypto.subtle.verify` so a
|
|
@@ -85,6 +96,10 @@ interface OrderForwardBody {
|
|
|
85
96
|
lineItems?: unknown;
|
|
86
97
|
rawCustomerId?: unknown;
|
|
87
98
|
createdAt?: unknown;
|
|
99
|
+
providerFields?: unknown;
|
|
100
|
+
providerEventId?: unknown;
|
|
101
|
+
occurredAt?: unknown;
|
|
102
|
+
amountMinor?: unknown;
|
|
88
103
|
}
|
|
89
104
|
|
|
90
105
|
function parseLineItems(value: unknown): OrderLineItem[] | string {
|
|
@@ -128,7 +143,16 @@ function parseOrderForwardInput(body: OrderForwardBody): OrderForwardInput | str
|
|
|
128
143
|
return "rawCustomerId must be a string";
|
|
129
144
|
}
|
|
130
145
|
if (body.createdAt !== undefined && typeof body.createdAt !== "string") return "createdAt must be a string";
|
|
146
|
+
if (
|
|
147
|
+
body.providerFields !== undefined &&
|
|
148
|
+
(typeof body.providerFields !== "object" || body.providerFields === null || Array.isArray(body.providerFields))
|
|
149
|
+
) {
|
|
150
|
+
return "providerFields must be an object";
|
|
151
|
+
}
|
|
131
152
|
|
|
153
|
+
if (body.providerEventId !== undefined && (typeof body.providerEventId !== "string" || !body.providerEventId.trim())) return "providerEventId must be a non-empty string";
|
|
154
|
+
if (body.occurredAt !== undefined && typeof body.occurredAt !== "string") return "occurredAt must be a string";
|
|
155
|
+
if (body.amountMinor !== undefined && (typeof body.amountMinor !== "number" || !Number.isSafeInteger(body.amountMinor) || body.amountMinor < 0)) return "amountMinor must be a non-negative safe integer";
|
|
132
156
|
return {
|
|
133
157
|
tenantId: body.tenantId,
|
|
134
158
|
externalOrderId: body.externalOrderId,
|
|
@@ -140,6 +164,10 @@ function parseOrderForwardInput(body: OrderForwardBody): OrderForwardInput | str
|
|
|
140
164
|
lineItems,
|
|
141
165
|
rawCustomerId: body.rawCustomerId as string | undefined,
|
|
142
166
|
createdAt: body.createdAt as string | undefined,
|
|
167
|
+
providerEventId: body.providerEventId as string | undefined,
|
|
168
|
+
occurredAt: body.occurredAt as string | undefined,
|
|
169
|
+
amountMinor: body.amountMinor as number | undefined,
|
|
170
|
+
providerFields: body.providerFields as Record<string, unknown> | undefined,
|
|
143
171
|
};
|
|
144
172
|
}
|
|
145
173
|
|
|
@@ -168,7 +196,51 @@ export async function POST(context: APIContext): Promise<Response> {
|
|
|
168
196
|
const d1 = await readD1("STOREFRONT_APPS_DB");
|
|
169
197
|
if (!d1) return json({ error: "orders store not configured" }, 503);
|
|
170
198
|
|
|
171
|
-
const
|
|
199
|
+
const db = fromD1(d1);
|
|
200
|
+
const result = await receiveForwardedOrder(db, input);
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
// This local-only outbox runs only after raw-body HMAC verification and the
|
|
204
|
+
// trusted order receiver. Its failure is fail-soft: commerce still ACKs.
|
|
205
|
+
try {
|
|
206
|
+
const measurement = await new D1VerifiedProviderMeasurementStore(db).record(input);
|
|
207
|
+
if (measurement.outcome === "recorded") {
|
|
208
|
+
logConversionDiag({ tenantId: input.tenantId, env: input.env, regulatedMeasurement: "recorded" });
|
|
209
|
+
}
|
|
210
|
+
} catch (cause) {
|
|
211
|
+
logConversionDiag({
|
|
212
|
+
tenantId: input.tenantId,
|
|
213
|
+
env: input.env,
|
|
214
|
+
regulatedMeasurement: "outbox-unavailable",
|
|
215
|
+
error: cause instanceof Error ? cause.name : "unknown",
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Join the verified order to its browser handoff correlation and produce the
|
|
220
|
+
// authoritative server conversion event(s) — ext-commerce-05 destinations fan
|
|
221
|
+
// these out. The join owns idempotency + single-use replay defense; a failure
|
|
222
|
+
// here must never fail the order ACK, so it is fail-soft (logged, swallowed).
|
|
223
|
+
try {
|
|
224
|
+
const conversion = await joinForwardedOrderConversion(db, input, result);
|
|
225
|
+
if (conversion.events.length > 0) {
|
|
226
|
+
// Coarse, non-PII diagnostic: attribution outcome + conversion count only —
|
|
227
|
+
// never the order id, correlation token, or any customer field.
|
|
228
|
+
logConversionDiag({
|
|
229
|
+
tenantId: input.tenantId,
|
|
230
|
+
env: input.env,
|
|
231
|
+
conversions: conversion.events.length,
|
|
232
|
+
attributed: conversion.attribution.attributed,
|
|
233
|
+
reason: conversion.attribution.attributed ? undefined : conversion.attribution.reason,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
} catch (cause) {
|
|
237
|
+
logConversionDiag({
|
|
238
|
+
tenantId: input.tenantId,
|
|
239
|
+
env: input.env,
|
|
240
|
+
error: cause instanceof Error ? cause.name : "unknown",
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
172
244
|
// D11: HIGH-VOLUME machine action (the tot-foxycart forwarder, HMAC-authed) → analytics
|
|
173
245
|
// only, never timelined. Coarse dimensions only; customer/order ids never stored.
|
|
174
246
|
recordActivity({
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E1.1 — public reaction endpoint. POST a reaction for the post addressed by the
|
|
3
|
+
* route (`/api/blog/<collection>/<slug>/react`); returns the post's full reaction
|
|
4
|
+
* tallies as JSON. Anonymous, no identity — the reader is never authenticated.
|
|
5
|
+
*
|
|
6
|
+
* Discipline (mirrors the other public POSTs, `newsletter.ts` / `rum/vitals.ts`):
|
|
7
|
+
* - Tenant is resolved from `locals.tenant`, NEVER the request body.
|
|
8
|
+
* - A soft per-IP KV rate limit stops trivial scripted inflation; over-cap
|
|
9
|
+
* returns the current tallies (429) without counting — abuse blast-radius is
|
|
10
|
+
* ~0 (a counter), so the cap is lenient.
|
|
11
|
+
* - Never 500. Every path returns a clean JSON response; `recordReaction` is
|
|
12
|
+
* itself best-effort and never throws.
|
|
13
|
+
*/
|
|
14
|
+
import type { APIRoute } from "astro";
|
|
15
|
+
import { readKv } from "@/lib/env";
|
|
16
|
+
import {
|
|
17
|
+
getReactionCounts,
|
|
18
|
+
isReaction,
|
|
19
|
+
recordReaction,
|
|
20
|
+
type Reaction,
|
|
21
|
+
} from "@/lib/blog/reactions";
|
|
22
|
+
import { checkRateLimit } from "@/lib/rate/kvWindow";
|
|
23
|
+
|
|
24
|
+
export const prerender = false;
|
|
25
|
+
|
|
26
|
+
const RATE_WINDOW_SECONDS = 60;
|
|
27
|
+
const RATE_MAX_PER_WINDOW = 10;
|
|
28
|
+
|
|
29
|
+
function json(body: unknown, status = 200): Response {
|
|
30
|
+
return new Response(JSON.stringify(body), {
|
|
31
|
+
status,
|
|
32
|
+
headers: { "content-type": "application/json; charset=utf-8" },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Best-effort client IP for rate-limit keying — Cloudflare's header, else XFF. */
|
|
37
|
+
function clientIp(request: Request): string {
|
|
38
|
+
const cf = request.headers.get("cf-connecting-ip");
|
|
39
|
+
if (cf) return cf;
|
|
40
|
+
const xff = request.headers.get("x-forwarded-for");
|
|
41
|
+
if (xff) return xff.split(",")[0]!.trim();
|
|
42
|
+
return "unknown";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Pull the reaction from a JSON or form-encoded body. */
|
|
46
|
+
async function readReaction(request: Request): Promise<string | null> {
|
|
47
|
+
try {
|
|
48
|
+
const type = request.headers.get("content-type") ?? "";
|
|
49
|
+
if (type.includes("application/json")) {
|
|
50
|
+
const body = (await request.json()) as { reaction?: unknown };
|
|
51
|
+
return typeof body.reaction === "string" ? body.reaction : null;
|
|
52
|
+
}
|
|
53
|
+
const form = await request.formData();
|
|
54
|
+
const value = form.get("reaction");
|
|
55
|
+
return typeof value === "string" ? value : null;
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const POST: APIRoute = async (context) => {
|
|
62
|
+
const tenantId = context.locals?.tenant?.tenant_id;
|
|
63
|
+
const collection = context.params.collection;
|
|
64
|
+
const slug = context.params.slug;
|
|
65
|
+
if (!tenantId || !collection || !slug) {
|
|
66
|
+
return json({ ok: false, error: "not_found", counts: {} as Record<Reaction, number> }, 404);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const reaction = await readReaction(context.request);
|
|
70
|
+
const kv = await readKv("TENANT_CACHE");
|
|
71
|
+
|
|
72
|
+
if (!isReaction(reaction)) {
|
|
73
|
+
return json(
|
|
74
|
+
{
|
|
75
|
+
ok: false,
|
|
76
|
+
error: "invalid_reaction",
|
|
77
|
+
counts: await getReactionCounts(kv, tenantId, collection, slug),
|
|
78
|
+
},
|
|
79
|
+
400,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const { allowed } = await checkRateLimit(kv, `react:${tenantId}:${clientIp(context.request)}`, {
|
|
84
|
+
windowSeconds: RATE_WINDOW_SECONDS,
|
|
85
|
+
maxRequests: RATE_MAX_PER_WINDOW,
|
|
86
|
+
});
|
|
87
|
+
if (!allowed) {
|
|
88
|
+
return json(
|
|
89
|
+
{
|
|
90
|
+
ok: false,
|
|
91
|
+
error: "rate_limited",
|
|
92
|
+
counts: await getReactionCounts(kv, tenantId, collection, slug),
|
|
93
|
+
},
|
|
94
|
+
429,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Best-effort: no-ops for a non-live post; never throws. When there is no KV
|
|
99
|
+
// binding (local dev) the increment can't persist, but we still return the
|
|
100
|
+
// (all-zero) tallies so the client has a consistent shape.
|
|
101
|
+
if (kv) await recordReaction(kv, tenantId, collection, slug, reaction);
|
|
102
|
+
|
|
103
|
+
return json({ ok: true, counts: await getReactionCounts(kv, tenantId, collection, slug) });
|
|
104
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/commerce/checkout-handoff — the checkout-correlation MINT seam
|
|
3
|
+
* (ext-commerce-10).
|
|
4
|
+
*
|
|
5
|
+
* The shopper's analytics consent is a CLIENT-side decision (CMP / native banner),
|
|
6
|
+
* but the correlation token is minted under the SERVER-only signing secret. So at the
|
|
7
|
+
* handoff the client posts its LIVE consent snapshot and the server mints the token,
|
|
8
|
+
* returning ONLY the opaque passthrough cart field to attach to the managed-cart form.
|
|
9
|
+
* The signing secret never leaves the server; the token carries no PII and no secret.
|
|
10
|
+
*
|
|
11
|
+
* Server-owned by construction:
|
|
12
|
+
* - The tenant and the {@link IntegrationEnvironment} stage come from `context.locals`
|
|
13
|
+
* (the renderer-owned `BrowserEnvironment`), NEVER from the request body — a client
|
|
14
|
+
* cannot mint a cross-tenant or cross-stage token.
|
|
15
|
+
* - The consent snapshot is parsed FAIL-CLOSED (`parseConsentSnapshot`): an absent,
|
|
16
|
+
* forged, or tampered snapshot collapses to default-deny → unattributed.
|
|
17
|
+
* - No store on this tenant, consent withheld, or no signing key → an explicit
|
|
18
|
+
* unattributed response; the handoff proceeds, checkout is never blocked.
|
|
19
|
+
*/
|
|
20
|
+
import type { APIContext } from "astro";
|
|
21
|
+
import { parseConsentSnapshot, defaultConsentSnapshot } from "@tot/public-runtime";
|
|
22
|
+
import { resolveCheckoutHandoffCorrelation } from "@/lib/commerce/checkoutHandoffCorrelation";
|
|
23
|
+
|
|
24
|
+
export const prerender = false;
|
|
25
|
+
|
|
26
|
+
function json(body: unknown, status = 200): Response {
|
|
27
|
+
return new Response(JSON.stringify(body), {
|
|
28
|
+
status,
|
|
29
|
+
headers: {
|
|
30
|
+
"content-type": "application/json; charset=utf-8",
|
|
31
|
+
"cache-control": "no-store",
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface HandoffBody {
|
|
37
|
+
/** The shopper's serialized consent snapshot (the `__TOT_INTEGRATION_CONSENT__` global). */
|
|
38
|
+
consent?: unknown;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function POST(context: APIContext): Promise<Response> {
|
|
42
|
+
const { tenant, browserEnvironment, commerce } = context.locals;
|
|
43
|
+
|
|
44
|
+
// No managed checkout on this tenant → nothing to attribute.
|
|
45
|
+
if (!commerce) {
|
|
46
|
+
return json({ attributed: false, reason: "no-store" });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let body: HandoffBody;
|
|
50
|
+
try {
|
|
51
|
+
body = (await context.request.json()) as HandoffBody;
|
|
52
|
+
} catch {
|
|
53
|
+
body = {};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Fail-closed: an absent/forged/tampered snapshot is default-deny (essential only).
|
|
57
|
+
const consent = parseConsentSnapshot(body.consent) ?? defaultConsentSnapshot();
|
|
58
|
+
|
|
59
|
+
const result = await resolveCheckoutHandoffCorrelation({
|
|
60
|
+
tenant: tenant.tenant_id,
|
|
61
|
+
// Env-consistency: the request's own resolved stage, never a client value.
|
|
62
|
+
environment: browserEnvironment.environment,
|
|
63
|
+
consent,
|
|
64
|
+
// Opaque per-handoff logical id the order join threads back to.
|
|
65
|
+
eventId: crypto.randomUUID(),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (result.attributed) {
|
|
69
|
+
// Return ONLY the opaque passthrough field; the signing secret never leaves here.
|
|
70
|
+
return json({ attributed: true, cartField: result.cartField });
|
|
71
|
+
}
|
|
72
|
+
return json({ attributed: false, reason: result.reason });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function GET(): Promise<Response> {
|
|
76
|
+
return json({ error: "method_not_allowed" }, 405);
|
|
77
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/compliance/tamper — the server receiver for protected-surface tamper
|
|
3
|
+
* beacons (D-R7, `integration-protected-tamper-recovery`).
|
|
4
|
+
*
|
|
5
|
+
* The browser sentinel restores safe state IN the document and posts a
|
|
6
|
+
* `TamperEvidenceBeacon` here. This route validates it fail-closed, records the
|
|
7
|
+
* durable evidence + operator alert, and — when the beacon is attributable to a
|
|
8
|
+
* single active install — SUSPENDS that install. It is a DETECTIVE control: the
|
|
9
|
+
* suspension is after-the-fact recovery, never prevention.
|
|
10
|
+
*
|
|
11
|
+
* TENANT SCOPE is server-owned: the install lookup and suspend are ALWAYS keyed on
|
|
12
|
+
* `locals.tenant` (middleware-resolved from the request host), never on the
|
|
13
|
+
* body-supplied `tenant` — a page cannot ask to suspend another tenant's app. The
|
|
14
|
+
* beacon body carries no secret (the contract rejects one), and the response is a
|
|
15
|
+
* write-path ack the emitter ignores, so a failed post never breaks the page.
|
|
16
|
+
*/
|
|
17
|
+
import type { APIContext } from "astro";
|
|
18
|
+
import { getRegistryService, json } from "@/lib/apps/adminService.js";
|
|
19
|
+
import type { AppInstall } from "@/lib/apps/registryService.js";
|
|
20
|
+
import { RegistryError } from "@/lib/apps/registryService.js";
|
|
21
|
+
import { planTamperRecovery, type AttributableInstall } from "@tot/public-runtime";
|
|
22
|
+
|
|
23
|
+
export const prerender = false;
|
|
24
|
+
|
|
25
|
+
const SYSTEM_ACTOR = "system:tamper-sentinel";
|
|
26
|
+
|
|
27
|
+
function toAttributable(install: AppInstall): AttributableInstall {
|
|
28
|
+
return {
|
|
29
|
+
installId: install.installId,
|
|
30
|
+
appId: install.appId,
|
|
31
|
+
appVersion: install.appVersion,
|
|
32
|
+
status: install.status,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function POST(context: APIContext): Promise<Response> {
|
|
37
|
+
const tenantId = context.locals.tenant?.tenant_id;
|
|
38
|
+
// No resolved tenant ⇒ nothing third-party could be scoped to; accept-and-drop so
|
|
39
|
+
// the emitter never errors or retries.
|
|
40
|
+
if (!tenantId) return json({ ok: true, accepted: false }, 202);
|
|
41
|
+
|
|
42
|
+
let body: unknown;
|
|
43
|
+
try {
|
|
44
|
+
body = await context.request.json();
|
|
45
|
+
} catch {
|
|
46
|
+
return json({ ok: false, error: "invalid JSON body" }, 400);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Resolve the tenant's installs (empty when the registry binding isn't configured
|
|
50
|
+
// in this runtime — the beacon is still validated + recorded, just not actioned).
|
|
51
|
+
const registry = await getRegistryService();
|
|
52
|
+
const installs: AttributableInstall[] =
|
|
53
|
+
registry instanceof Response
|
|
54
|
+
? []
|
|
55
|
+
: (await registry.listByTenant(tenantId)).map(toAttributable);
|
|
56
|
+
|
|
57
|
+
const plan = planTamperRecovery(body, installs, {
|
|
58
|
+
recordId: crypto.randomUUID(),
|
|
59
|
+
receivedAt: new Date().toISOString(),
|
|
60
|
+
});
|
|
61
|
+
if (!plan.ok) return json({ ok: false, error: "invalid tamper beacon" }, 400);
|
|
62
|
+
|
|
63
|
+
const { record, suspend } = plan.plan;
|
|
64
|
+
// Durable, secret-free evidence line for operations. The beacon itself is the record.
|
|
65
|
+
// eslint-disable-next-line no-console
|
|
66
|
+
console.warn(
|
|
67
|
+
`[tamper] tenant=${tenantId} record=${record.recordId} surface=${record.beacon.surface} kind=${record.beacon.kind} recovered=${record.beacon.recovered} app=${record.beacon.attribution?.appId ?? "unattributable"}`,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
let suspended = false;
|
|
71
|
+
if (suspend && !(registry instanceof Response)) {
|
|
72
|
+
try {
|
|
73
|
+
await registry.suspend(suspend.installId, SYSTEM_ACTOR);
|
|
74
|
+
suspended = true;
|
|
75
|
+
} catch (err) {
|
|
76
|
+
// An already-suspended/uninstalled install (invalid_state) is a benign
|
|
77
|
+
// no-op under rapid re-mutation; anything else is swallowed so the write
|
|
78
|
+
// path never errors the emitter. The audit row from a successful suspend is
|
|
79
|
+
// the durable trail.
|
|
80
|
+
if (!(err instanceof RegistryError)) {
|
|
81
|
+
// eslint-disable-next-line no-console
|
|
82
|
+
console.error(`[tamper] suspend failed for ${suspend.installId}`, err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return json({ ok: true, accepted: true, recovered: record.beacon.recovered, suspended }, 202);
|
|
88
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** Published managed analytics v1 RPC transport: basePath + client method name. */
|
|
2
|
+
import type { APIContext } from "astro";
|
|
3
|
+
import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
|
|
4
|
+
import { getManagedAnalyticsService, json, requireManageRole } from "@/lib/apps/adminService.js";
|
|
5
|
+
import {
|
|
6
|
+
validateCreateIntegrationInstallRequest, validateCreateMigrationDraftRequest,
|
|
7
|
+
validateDeleteIntegrationInstallRequest, validateDeleteMigrationDraftRequest,
|
|
8
|
+
validateGetAdapterDefinitionRequest, validateGetIntegrationInstallRequest,
|
|
9
|
+
validateGetIntegrationRevisionRequest, validateGetMigrationDraftRequest,
|
|
10
|
+
validateListAdapterDefinitionsRequest, validateListIntegrationInstallsRequest,
|
|
11
|
+
validateListIntegrationRevisionsRequest, validateReviseIntegrationInstallRequest,
|
|
12
|
+
validateSetIntegrationInstallStatusRequest, validateUpdateMigrationDraftRequest,
|
|
13
|
+
type CreateIntegrationInstallRequest, type CreateMigrationDraftRequest,
|
|
14
|
+
type DeleteIntegrationInstallRequest, type DeleteMigrationDraftRequest,
|
|
15
|
+
type GetAdapterDefinitionRequest, type GetIntegrationInstallRequest,
|
|
16
|
+
type GetIntegrationRevisionRequest, type GetMigrationDraftRequest,
|
|
17
|
+
type ListAdapterDefinitionsRequest, type ListIntegrationInstallsRequest,
|
|
18
|
+
type ListIntegrationRevisionsRequest, type ReviseIntegrationInstallRequest,
|
|
19
|
+
type SetIntegrationInstallStatusRequest, type UpdateMigrationDraftRequest,
|
|
20
|
+
} from "@tot/public-runtime";
|
|
21
|
+
import { MANAGED_ANALYTICS_READ_OPERATIONS, managedAnalyticsOpaqueId, sanitizeManagedAnalyticsOutbound, type ManagedAnalyticsOperation } from "@/lib/apps/managedAnalyticsService.js";
|
|
22
|
+
|
|
23
|
+
export const prerender = false;
|
|
24
|
+
type Validator = (input: unknown) => { ok: true; value: unknown } | { ok: false; violations: Array<{ path: string; code: string; message: string }> };
|
|
25
|
+
|
|
26
|
+
// Null-prototype + own-property lookup: `constructor`/prototype names can never
|
|
27
|
+
// enter dispatch, even if a runtime supplies them as a dynamic path segment.
|
|
28
|
+
const VALIDATORS: Readonly<Record<string, Validator>> = Object.assign(Object.create(null) as Record<string, Validator>, {
|
|
29
|
+
listAdapterDefinitions: validateListAdapterDefinitionsRequest,
|
|
30
|
+
getAdapterDefinition: validateGetAdapterDefinitionRequest,
|
|
31
|
+
listIntegrationInstalls: validateListIntegrationInstallsRequest,
|
|
32
|
+
getIntegrationInstall: validateGetIntegrationInstallRequest,
|
|
33
|
+
listIntegrationRevisions: validateListIntegrationRevisionsRequest,
|
|
34
|
+
getIntegrationRevision: validateGetIntegrationRevisionRequest,
|
|
35
|
+
getMigrationDraft: validateGetMigrationDraftRequest,
|
|
36
|
+
createMigrationDraft: validateCreateMigrationDraftRequest,
|
|
37
|
+
updateMigrationDraft: validateUpdateMigrationDraftRequest,
|
|
38
|
+
deleteMigrationDraft: validateDeleteMigrationDraftRequest,
|
|
39
|
+
createIntegrationInstall: validateCreateIntegrationInstallRequest,
|
|
40
|
+
reviseIntegrationInstall: validateReviseIntegrationInstallRequest,
|
|
41
|
+
setIntegrationInstallStatus: validateSetIntegrationInstallStatusRequest,
|
|
42
|
+
deleteIntegrationInstall: validateDeleteIntegrationInstallRequest,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const STATUS: Record<string, number> = {
|
|
46
|
+
invalid_request: 400, unauthorized: 401, forbidden: 403, not_found: 404,
|
|
47
|
+
validation_failed: 422, unsupported_version: 400, stale_revision: 409,
|
|
48
|
+
idempotency_conflict: 409, adapter_deprecated: 409, conflict: 409,
|
|
49
|
+
internal_error: 500,
|
|
50
|
+
};
|
|
51
|
+
function response(body: unknown): Response {
|
|
52
|
+
const code = body && typeof body === "object" && "error" in body
|
|
53
|
+
? (body as { error?: { code?: string } }).error?.code : undefined;
|
|
54
|
+
return json(body, code ? STATUS[code] ?? 500 : 200);
|
|
55
|
+
}
|
|
56
|
+
function routeError(code: string, message: string, details?: Array<{ path: string; code: string; message: string }>): Response {
|
|
57
|
+
return response({ apiVersion: "v1", requestId: managedAnalyticsOpaqueId("req"), error: { code, message, ...(details?.length ? { details } : {}) } });
|
|
58
|
+
}
|
|
59
|
+
function operationResponse(operation: ManagedAnalyticsOperation, body: unknown): Response {
|
|
60
|
+
const safe = sanitizeManagedAnalyticsOutbound(operation, body);
|
|
61
|
+
return safe === null ? routeError("internal_error", "The integration service could not complete the request.") : response(safe);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function POST(context: APIContext): Promise<Response> {
|
|
65
|
+
try {
|
|
66
|
+
const operation = context.params.operation;
|
|
67
|
+
if (!operation || !Object.prototype.hasOwnProperty.call(VALIDATORS, operation)) {
|
|
68
|
+
return routeError("invalid_request", "Unknown managed analytics v1 operation.");
|
|
69
|
+
}
|
|
70
|
+
const op = operation as ManagedAnalyticsOperation;
|
|
71
|
+
const url = new URL(context.request.url);
|
|
72
|
+
const auth = await resolveOperatorSession(context, url.searchParams.get("tenant"));
|
|
73
|
+
if (!auth.ok) return routeError(auth.status === 401 ? "unauthorized" : "forbidden", "The request is not authorized.");
|
|
74
|
+
if (!MANAGED_ANALYTICS_READ_OPERATIONS.has(op) && requireManageRole(auth)) {
|
|
75
|
+
return routeError("forbidden", "The request is not authorized.");
|
|
76
|
+
}
|
|
77
|
+
let raw: unknown;
|
|
78
|
+
try { raw = await context.request.json(); }
|
|
79
|
+
catch { return routeError("invalid_request", "The request body must be valid JSON."); }
|
|
80
|
+
const parsed = VALIDATORS[operation]!(raw);
|
|
81
|
+
if (!parsed.ok) {
|
|
82
|
+
const unsupportedVersion = parsed.violations.some(({ path, code }) => path === "apiVersion" && code === "unsupported_value");
|
|
83
|
+
return routeError(unsupportedVersion ? "unsupported_version" : "invalid_request", unsupportedVersion ? "The API version is not supported." : "The request failed validation.", parsed.violations);
|
|
84
|
+
}
|
|
85
|
+
const service = await getManagedAnalyticsService();
|
|
86
|
+
if (service instanceof Response) return routeError("internal_error", "The integration service is unavailable.");
|
|
87
|
+
const ctx = { tenantId: auth.tenantId, actor: auth.actor };
|
|
88
|
+
const request = parsed.value;
|
|
89
|
+
switch (op) {
|
|
90
|
+
case "listAdapterDefinitions": return operationResponse(op, service.listAdapterDefinitions(request as ListAdapterDefinitionsRequest));
|
|
91
|
+
case "getAdapterDefinition": return operationResponse(op, service.getAdapterDefinition((request as GetAdapterDefinitionRequest).query.adapterId));
|
|
92
|
+
case "listIntegrationInstalls": return operationResponse(op, await service.listIntegrationInstalls(ctx, request as ListIntegrationInstallsRequest));
|
|
93
|
+
case "getIntegrationInstall": return operationResponse(op, await service.getIntegrationInstall(ctx, (request as GetIntegrationInstallRequest).query.installId));
|
|
94
|
+
case "listIntegrationRevisions": { const value = request as ListIntegrationRevisionsRequest; return operationResponse(op, await service.listIntegrationRevisions(ctx, value.query.installId, value.query)); }
|
|
95
|
+
case "getIntegrationRevision": { const value = request as GetIntegrationRevisionRequest; return operationResponse(op, await service.getIntegrationRevision(ctx, value.query.installId, value.query.revisionId)); }
|
|
96
|
+
case "getMigrationDraft": return operationResponse(op, await service.getMigrationDraft(ctx, (request as GetMigrationDraftRequest).query.draftId));
|
|
97
|
+
case "createMigrationDraft": return operationResponse(op, await service.createMigrationDraft(ctx, request as CreateMigrationDraftRequest));
|
|
98
|
+
case "updateMigrationDraft": return operationResponse(op, await service.updateMigrationDraft(ctx, request as UpdateMigrationDraftRequest));
|
|
99
|
+
case "deleteMigrationDraft": return operationResponse(op, await service.deleteMigrationDraft(ctx, request as DeleteMigrationDraftRequest));
|
|
100
|
+
case "createIntegrationInstall": return operationResponse(op, await service.createIntegrationInstall(ctx, request as CreateIntegrationInstallRequest));
|
|
101
|
+
case "reviseIntegrationInstall": return operationResponse(op, await service.reviseIntegrationInstall(ctx, request as ReviseIntegrationInstallRequest));
|
|
102
|
+
case "setIntegrationInstallStatus": return operationResponse(op, await service.setIntegrationInstallStatus(ctx, request as SetIntegrationInstallStatusRequest));
|
|
103
|
+
case "deleteIntegrationInstall": return operationResponse(op, await service.deleteIntegrationInstall(ctx, request as DeleteIntegrationInstallRequest));
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
return routeError("internal_error", "The integration service could not complete the request.");
|
|
107
|
+
}
|
|
108
|
+
}
|