@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
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Drizzle schema — the source of truth for `STOREFRONT_APPS_DB` *migration
|
|
3
|
-
* generation
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* D1, never the catalog.
|
|
3
|
+
* generation*. `schema.ts` covers the catalog + customization tables on
|
|
4
|
+
* `CATALOG_DB`; these tables are the storefront-apps registry/webhooks/orders
|
|
5
|
+
* spine and belong to a DEDICATED D1, never the catalog.
|
|
7
6
|
*
|
|
8
7
|
* `drizzle-kit generate --config drizzle.config.apps.ts` diffs this into
|
|
9
8
|
* numbered SQL under `migrations-apps/`, applied by `wrangler d1 migrations
|
|
@@ -11,8 +10,8 @@
|
|
|
11
10
|
*/
|
|
12
11
|
import { sqliteTable, text, integer, real, index, uniqueIndex, primaryKey } from "drizzle-orm/sqlite-core";
|
|
13
12
|
|
|
14
|
-
// --- Private Apps registry
|
|
15
|
-
// One install per (app, tenant, env). `installId` is the
|
|
13
|
+
// --- Private Apps registry --------------------------------------------------
|
|
14
|
+
// One install per (app, tenant, env). `installId` is the JWT `sub`.
|
|
16
15
|
// Append-only `app_audit_log` is never pruned by the service layer.
|
|
17
16
|
export const appInstalls = sqliteTable(
|
|
18
17
|
"app_installs",
|
|
@@ -28,6 +27,14 @@ export const appInstalls = sqliteTable(
|
|
|
28
27
|
webhookEndpoint: text("webhook_endpoint"),
|
|
29
28
|
widgetPlacements: text("widget_placements").notNull().default("[]"),
|
|
30
29
|
installActor: text("install_actor").notNull(),
|
|
30
|
+
// Nullable discriminator keeps the managed-analytics v1 lifecycle on the
|
|
31
|
+
// canonical install row instead of creating a second install authority.
|
|
32
|
+
managedKind: text("managed_kind"),
|
|
33
|
+
managedRevision: integer("managed_revision").notNull().default(0),
|
|
34
|
+
managedActiveRevisionId: text("managed_active_revision_id"),
|
|
35
|
+
// Validated non-live candidate only. Live effects remain in manifest and
|
|
36
|
+
// app_version_snapshots, the registry's established serving authorities.
|
|
37
|
+
managedCandidate: text("managed_candidate"),
|
|
31
38
|
createdAt: text("created_at").notNull(),
|
|
32
39
|
updatedAt: text("updated_at").notNull(),
|
|
33
40
|
},
|
|
@@ -71,14 +78,31 @@ export const appAuditLog = sqliteTable(
|
|
|
71
78
|
}),
|
|
72
79
|
);
|
|
73
80
|
|
|
74
|
-
//
|
|
81
|
+
// Inert reviewed migration suggestions. This is deliberately NOT an install,
|
|
82
|
+
// live effect, revision, or publish authority; conversion requires a separate
|
|
83
|
+
// canonical `app_installs` mutation and drafts can never be enabled.
|
|
84
|
+
export const integrationMigrationDrafts = sqliteTable(
|
|
85
|
+
"integration_migration_drafts",
|
|
86
|
+
{
|
|
87
|
+
draftId: text("draft_id").primaryKey(),
|
|
88
|
+
tenantId: text("tenant_id").notNull(),
|
|
89
|
+
revision: integer("revision").notNull(),
|
|
90
|
+
state: text("state").notNull().default("open"),
|
|
91
|
+
record: text("record").notNull(),
|
|
92
|
+
createdAt: text("created_at").notNull(),
|
|
93
|
+
updatedAt: text("updated_at").notNull(),
|
|
94
|
+
},
|
|
95
|
+
(t) => ({ idxIntegrationMigrationDraftsTenant: index("idx_integration_migration_drafts_tenant").on(t.tenantId, t.createdAt) }),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// --- Operational activity timeline ------------------------------------------
|
|
75
99
|
// The low-volume / high-value LIFECYCLE cohort of the actor×action telemetry
|
|
76
100
|
// spine (DECISIONS.md §8). Only actions whose catalog `spec.sinks` include
|
|
77
101
|
// "timeline" land here; the high-volume cohort goes to Cloudflare Analytics
|
|
78
102
|
// Engine (binding `ACTIVITY_ANALYTICS`), and EVERY action also goes to Workers
|
|
79
103
|
// Logs. Reuses the EXISTING STOREFRONT_APPS_DB (precedent: `app_audit_log`
|
|
80
104
|
// above) rather than a new binding — the cohort is small (~50k rows/month at
|
|
81
|
-
// 10× pilot) and the
|
|
105
|
+
// 10× pilot) and the timeline query UI needs point queries + joins + arbitrary
|
|
82
106
|
// retention that Analytics Engine cannot give.
|
|
83
107
|
//
|
|
84
108
|
// `id` is the emitter-minted event UUID and the PRIMARY KEY, so a retried/
|
|
@@ -116,7 +140,7 @@ export const activityEvents = sqliteTable(
|
|
|
116
140
|
ingestedAt: text("ingested_at").notNull(),
|
|
117
141
|
},
|
|
118
142
|
(t) => ({
|
|
119
|
-
// The
|
|
143
|
+
// The timeline query: a tenant's events newest-first.
|
|
120
144
|
idxActivityTenantAt: index("idx_activity_tenant_at").on(t.tenantId, t.at),
|
|
121
145
|
// Filter a tenant's timeline by action family (dashboards glob the prefix).
|
|
122
146
|
idxActivityTenantAction: index("idx_activity_tenant_action").on(t.tenantId, t.action),
|
|
@@ -125,7 +149,7 @@ export const activityEvents = sqliteTable(
|
|
|
125
149
|
}),
|
|
126
150
|
);
|
|
127
151
|
|
|
128
|
-
// --- Webhook event spine
|
|
152
|
+
// --- Webhook event spine ----------------------------------------------------
|
|
129
153
|
// Immutable event log. `id` is the semantic event id we mint — distinct from
|
|
130
154
|
// any per-delivery wire envelope id (see `webhookDeliveries.deliveryId` below).
|
|
131
155
|
export const webhookEvents = sqliteTable("webhook_events", {
|
|
@@ -195,10 +219,10 @@ export const webhookInstallHealth = sqliteTable("webhook_install_health", {
|
|
|
195
219
|
updatedAt: text("updated_at").notNull(),
|
|
196
220
|
});
|
|
197
221
|
|
|
198
|
-
// --- Order ingestion
|
|
222
|
+
// --- Order ingestion --------------------------------------------------------
|
|
199
223
|
// The read-model `ordersStore.ts` diffs incoming Foxy orders against (created
|
|
200
|
-
// → fulfilled transitions, for
|
|
201
|
-
// attribution route
|
|
224
|
+
// → fulfilled transitions, for event emission) and that the
|
|
225
|
+
// attribution route reads from for its cross-tenant ownership
|
|
202
226
|
// check. `(tenantId, externalOrderId)` is the composite PK — same "no
|
|
203
227
|
// synthetic id, the natural key IS the key" style as `customizationVersions`
|
|
204
228
|
// (schema.ts) — no SQL FK to `appAttributions.orderId` (repo convention — code-only).
|
|
@@ -225,7 +249,7 @@ export const orders = sqliteTable(
|
|
|
225
249
|
}),
|
|
226
250
|
);
|
|
227
251
|
|
|
228
|
-
//
|
|
252
|
+
// The idempotency ledger — keyed per
|
|
229
253
|
// `(installId, idempotencyKey)` so a retried write (e.g. attribution POST)
|
|
230
254
|
// replays the stored `responseBody` instead of re-applying the mutation.
|
|
231
255
|
// `bodyHash` (sha256 of the canonical request body) lets a caller re-sending
|
|
@@ -242,9 +266,38 @@ export const idempotencyKeys = sqliteTable(
|
|
|
242
266
|
(t) => ({ pk: primaryKey({ columns: [t.installId, t.idempotencyKey] }) }),
|
|
243
267
|
);
|
|
244
268
|
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
269
|
+
// --- Encrypted outbound social OAuth tokens ---------------------------------
|
|
270
|
+
// The ONLY retrievable secret store in this codebase: per-`(tenant, network)`
|
|
271
|
+
// OAuth access/refresh tokens we must REPLAY to X/LinkedIn, so — unlike the
|
|
272
|
+
// one-way-hashed `app_credentials` above — they are stored ENCRYPTED-AT-REST,
|
|
273
|
+
// not hashed. `ciphertext` is AES-GCM(base64) over the JSON token payload and
|
|
274
|
+
// `iv` its per-write 96-bit nonce (base64); the key-encryption-key (KEK) is a
|
|
275
|
+
// Worker env binding (`SOCIAL_TOKEN_KEK`), NEVER a column here — mirroring how
|
|
276
|
+
// every other real secret in this codebase is an env binding, not row data.
|
|
277
|
+
// Composite PK `(tenant_id, network)` is the natural key (same "the natural key
|
|
278
|
+
// IS the key" style as `orders`); a rotate is an INSERT OR REPLACE overwrite.
|
|
279
|
+
// `expires_at` is the token's own OAuth expiry (nullable — long-lived manual
|
|
280
|
+
// creds have none), distinct from the row's `updated_at` bookkeeping clock.
|
|
281
|
+
export const socialTokens = sqliteTable(
|
|
282
|
+
"social_tokens",
|
|
283
|
+
{
|
|
284
|
+
tenantId: text("tenant_id").notNull(),
|
|
285
|
+
network: text("network").notNull(),
|
|
286
|
+
ciphertext: text("ciphertext").notNull(),
|
|
287
|
+
iv: text("iv").notNull(),
|
|
288
|
+
expiresAt: text("expires_at"),
|
|
289
|
+
createdAt: text("created_at").notNull(),
|
|
290
|
+
updatedAt: text("updated_at").notNull(),
|
|
291
|
+
},
|
|
292
|
+
(t) => ({
|
|
293
|
+
pk: primaryKey({ columns: [t.tenantId, t.network] }),
|
|
294
|
+
idxSocialTokensTenant: index("idx_social_tokens_tenant").on(t.tenantId),
|
|
295
|
+
}),
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
// App-owned attribution/commission records (`attribution:write`). `orderId`
|
|
299
|
+
// references `orders.externalOrderId` in code
|
|
300
|
+
// only (no SQL FK, repo convention); the route enforces the cross-tenant
|
|
248
301
|
// ownership check the contract requires before ever writing a row here.
|
|
249
302
|
export const appAttributions = sqliteTable(
|
|
250
303
|
"app_attributions",
|
|
@@ -265,3 +318,305 @@ export const appAttributions = sqliteTable(
|
|
|
265
318
|
idxAppAttributionsTenantOrder: index("idx_app_attributions_tenant_order").on(t.tenantId, t.orderId),
|
|
266
319
|
}),
|
|
267
320
|
);
|
|
321
|
+
|
|
322
|
+
// --- Newsletter subscribers -------------------------------------------------
|
|
323
|
+
// First-party audience for the blog/newsletter digest, kept in OUR D1 (not a
|
|
324
|
+
// vendor list) so the per-tenant isolation + GDPR data-control invariants stay
|
|
325
|
+
// under our control.
|
|
326
|
+
// `tenantId` is the isolation boundary, written from the resolved host/session
|
|
327
|
+
// — NEVER a client body. Keyed on `(tenant_id, collection, email)` so a tenant
|
|
328
|
+
// with multiple collections (e.g. `blog` + `the-build`) runs independent lists.
|
|
329
|
+
// `token` is an opaque random used for both confirm + one-click unsubscribe
|
|
330
|
+
// links; `consentIpHash` is sha256(ip+salt) — never a raw IP (PII). Timestamps
|
|
331
|
+
// are ISO-8601 text. `status`: pending | confirmed | unsubscribed | bounced.
|
|
332
|
+
export const newsletterSubscribers = sqliteTable(
|
|
333
|
+
"newsletter_subscribers",
|
|
334
|
+
{
|
|
335
|
+
tenantId: text("tenant_id").notNull(),
|
|
336
|
+
collection: text("collection").notNull(),
|
|
337
|
+
email: text("email").notNull(),
|
|
338
|
+
status: text("status").notNull().default("pending"),
|
|
339
|
+
token: text("token").notNull(),
|
|
340
|
+
consentSource: text("consent_source"),
|
|
341
|
+
consentIpHash: text("consent_ip_hash"),
|
|
342
|
+
subscribedAt: text("subscribed_at").notNull(),
|
|
343
|
+
confirmedAt: text("confirmed_at"),
|
|
344
|
+
unsubscribedAt: text("unsubscribed_at"),
|
|
345
|
+
lastSentAt: text("last_sent_at"),
|
|
346
|
+
},
|
|
347
|
+
(t) => ({
|
|
348
|
+
pk: primaryKey({ columns: [t.tenantId, t.collection, t.email] }),
|
|
349
|
+
idxNewsletterTenantCollStatus: index("idx_newsletter_tenant_coll_status").on(
|
|
350
|
+
t.tenantId,
|
|
351
|
+
t.collection,
|
|
352
|
+
t.status,
|
|
353
|
+
),
|
|
354
|
+
}),
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
// Idempotent per-digest send log so a re-triggered digest can't double-send.
|
|
358
|
+
// Keyed on `(tenant_id, collection, digest_id)` (e.g. `the-build-2026-W34`);
|
|
359
|
+
// `postSlugs` is a JSON array of the slugs included in that digest.
|
|
360
|
+
export const newsletterSends = sqliteTable(
|
|
361
|
+
"newsletter_sends",
|
|
362
|
+
{
|
|
363
|
+
tenantId: text("tenant_id").notNull(),
|
|
364
|
+
collection: text("collection").notNull(),
|
|
365
|
+
digestId: text("digest_id").notNull(),
|
|
366
|
+
postSlugs: text("post_slugs").notNull().default("[]"),
|
|
367
|
+
recipientCount: integer("recipient_count").notNull().default(0),
|
|
368
|
+
sentAt: text("sent_at").notNull(),
|
|
369
|
+
},
|
|
370
|
+
(t) => ({ pk: primaryKey({ columns: [t.tenantId, t.collection, t.digestId] }) }),
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
// --- Canonical publish-candidate identity -----------------------------------
|
|
374
|
+
// ONE canonical candidate per `(tenant_id, repository, pr_number)` — the real
|
|
375
|
+
// forge PR. Retries/rebuilds are NOT new candidates; they are child `attempts`
|
|
376
|
+
// (below). This is the durable identity spine other units resolve against; the
|
|
377
|
+
// KV `ReviewEnvironment` (`cust:*`) and aggregate/release models (`rel:*`) are
|
|
378
|
+
// read projections that reference this row's `change_id`/`pr_number`.
|
|
379
|
+
//
|
|
380
|
+
// `id` is a SYNTHETIC surrogate (`cand_<uuid>`), deliberately DISTINCT from the
|
|
381
|
+
// canonical key so foreign keys (attempts) never depend on the mutable natural
|
|
382
|
+
// key. `change_id` is the REAL forge change id — the stable branch/build
|
|
383
|
+
// identity (`candidate/<change_id>`) — preserved, never derived from `id`.
|
|
384
|
+
// `tenant_id` is the isolation boundary, written from the resolved session,
|
|
385
|
+
// NEVER a client body. The UNIQUE `(tenant_id, repository, pr_number)` is what
|
|
386
|
+
// makes "one candidate per PR" a schema invariant (upsert-by-key, not
|
|
387
|
+
// insert-then-dedupe); the UNIQUE `(tenant_id, change_id)` keeps the branch/
|
|
388
|
+
// build identity unambiguous for resolve-by-changeId callers.
|
|
389
|
+
export const candidates = sqliteTable(
|
|
390
|
+
"candidates",
|
|
391
|
+
{
|
|
392
|
+
id: text("id").primaryKey(),
|
|
393
|
+
tenantId: text("tenant_id").notNull(),
|
|
394
|
+
// The `<tenant>-<tag>` forge repository the PR lives in.
|
|
395
|
+
repository: text("repository").notNull(),
|
|
396
|
+
// The forge PR number — the third leg of the canonical key.
|
|
397
|
+
prNumber: integer("pr_number").notNull(),
|
|
398
|
+
// The real forge change id — stable branch/build identity (`candidate/<change_id>`).
|
|
399
|
+
changeId: text("change_id").notNull(),
|
|
400
|
+
// Source branch, conventionally `candidate/<change_id>` (nullable convenience mirror).
|
|
401
|
+
branch: text("branch"),
|
|
402
|
+
title: text("title"),
|
|
403
|
+
author: text("author"),
|
|
404
|
+
// Canonical candidate lifecycle: open | preparing | ready | needs-attention | accepted | rejected | closed.
|
|
405
|
+
status: text("status").notNull().default("open"),
|
|
406
|
+
// The PR head/base shas as last reconciled (nullable until first read).
|
|
407
|
+
headSha: text("head_sha"),
|
|
408
|
+
baseSha: text("base_sha"),
|
|
409
|
+
createdAt: text("created_at").notNull(),
|
|
410
|
+
updatedAt: text("updated_at").notNull(),
|
|
411
|
+
},
|
|
412
|
+
(t) => ({
|
|
413
|
+
uqCandidatesCanonical: uniqueIndex("uq_candidates_tenant_repo_pr").on(
|
|
414
|
+
t.tenantId,
|
|
415
|
+
t.repository,
|
|
416
|
+
t.prNumber,
|
|
417
|
+
),
|
|
418
|
+
uqCandidatesChange: uniqueIndex("uq_candidates_tenant_change").on(t.tenantId, t.changeId),
|
|
419
|
+
idxCandidatesTenantStatus: index("idx_candidates_tenant_status").on(t.tenantId, t.status),
|
|
420
|
+
}),
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
// One `attempt` = one build/check/rebase EXECUTION of a candidate. Attempts are
|
|
424
|
+
// the child rows retries produce — they must NEVER queue as separate top-level
|
|
425
|
+
// candidate rows. `candidate_id` references `candidates.id` in code only (no SQL
|
|
426
|
+
// FK — repo convention, matches `webhook_deliveries.event_id` / `orders`).
|
|
427
|
+
// `tenant_id` is denormalized for tenant-scoped reads/isolation without a join.
|
|
428
|
+
// `attempt_number` is monotonic per candidate (1,2,3…) giving stable ordering;
|
|
429
|
+
// UNIQUE `(candidate_id, attempt_number)` makes a double-assigned number a loud
|
|
430
|
+
// failure rather than a silent duplicate. `kind`: build | check | rebase;
|
|
431
|
+
// `status`: pending | running | passed | failed | cancelled (mirrors
|
|
432
|
+
// `IntegrationRun`'s state vocabulary). `evidence` is a JSON EvidenceReport
|
|
433
|
+
// snapshot; `detail` a human-legible terminal-state message.
|
|
434
|
+
export const candidateAttempts = sqliteTable(
|
|
435
|
+
"candidate_attempts",
|
|
436
|
+
{
|
|
437
|
+
id: text("id").primaryKey(),
|
|
438
|
+
candidateId: text("candidate_id").notNull(),
|
|
439
|
+
tenantId: text("tenant_id").notNull(),
|
|
440
|
+
attemptNumber: integer("attempt_number").notNull(),
|
|
441
|
+
kind: text("kind").notNull(),
|
|
442
|
+
status: text("status").notNull().default("pending"),
|
|
443
|
+
// The candidate head sha this attempt executed against, or null if unknown.
|
|
444
|
+
headSha: text("head_sha"),
|
|
445
|
+
detail: text("detail"),
|
|
446
|
+
evidence: text("evidence"),
|
|
447
|
+
startedAt: text("started_at").notNull(),
|
|
448
|
+
// Null while pending/running; set on a terminal transition.
|
|
449
|
+
finishedAt: text("finished_at"),
|
|
450
|
+
},
|
|
451
|
+
(t) => ({
|
|
452
|
+
uqAttemptNumber: uniqueIndex("uq_candidate_attempts_candidate_number").on(
|
|
453
|
+
t.candidateId,
|
|
454
|
+
t.attemptNumber,
|
|
455
|
+
),
|
|
456
|
+
idxAttemptsCandidate: index("idx_candidate_attempts_candidate").on(t.candidateId),
|
|
457
|
+
idxAttemptsTenant: index("idx_candidate_attempts_tenant").on(t.tenantId),
|
|
458
|
+
}),
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
// One active submit per tenant/change. This serializes identity authorization,
|
|
462
|
+
// the Gitea mutation, and audit finalization so a verified callback cannot
|
|
463
|
+
// become stale between its forge read and its KV writes. `expires_at` is
|
|
464
|
+
// diagnostic only; recovery is explicit so a slow live submit cannot be
|
|
465
|
+
// time-fenced incorrectly.
|
|
466
|
+
export const candidateSubmitLeases = sqliteTable(
|
|
467
|
+
"candidate_submit_leases",
|
|
468
|
+
{
|
|
469
|
+
tenantId: text("tenant_id").notNull(),
|
|
470
|
+
changeId: text("change_id").notNull(),
|
|
471
|
+
authorizationId: text("authorization_id").notNull(),
|
|
472
|
+
status: text("status").notNull().default("active"),
|
|
473
|
+
acquiredAt: text("acquired_at").notNull(),
|
|
474
|
+
expiresAt: text("expires_at").notNull(),
|
|
475
|
+
},
|
|
476
|
+
(t) => ({
|
|
477
|
+
pk: primaryKey({ columns: [t.tenantId, t.changeId] }),
|
|
478
|
+
idxExpires: index("idx_candidate_submit_leases_expires").on(t.expiresAt),
|
|
479
|
+
}),
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
// --- Merchant consent configuration -----------------------------------------
|
|
483
|
+
// APPEND-ONLY revision history of a tenant's consent configuration (the
|
|
484
|
+
// ext-admin-03 surface that feeds the ext-policy-03 broker). Each save is a NEW
|
|
485
|
+
// immutable row — the current config is `MAX(revision)` per tenant — so the table
|
|
486
|
+
// IS the audit trail (actor + timestamp per revision, never mutated in place) and
|
|
487
|
+
// a revert is a forward-only new revision that copies a prior `config` and records
|
|
488
|
+
// `reverted_from`. `config` is the JSON `TenantConsentConfig` (never secret-bearing
|
|
489
|
+
// — consent config carries no secrets). `tenant_id` is the isolation boundary,
|
|
490
|
+
// written from the resolved session, never a client body. UNIQUE
|
|
491
|
+
// `(tenant_id, revision)` makes the monotonic revision a schema invariant.
|
|
492
|
+
export const consentConfigRevisions = sqliteTable(
|
|
493
|
+
"consent_config_revisions",
|
|
494
|
+
{
|
|
495
|
+
id: text("id").primaryKey(),
|
|
496
|
+
tenantId: text("tenant_id").notNull(),
|
|
497
|
+
// Monotonic per tenant (1, 2, 3…) — the latest revision is the current config.
|
|
498
|
+
revision: integer("revision").notNull(),
|
|
499
|
+
// The JSON-serialized validated `TenantConsentConfig`.
|
|
500
|
+
config: text("config").notNull(),
|
|
501
|
+
// Opaque actor id — never email/PII (matches `app_audit_log`).
|
|
502
|
+
actor: text("actor").notNull(),
|
|
503
|
+
// Human-legible note (e.g. the reason, or "revert to revision N").
|
|
504
|
+
note: text("note"),
|
|
505
|
+
// When this revision copies an earlier one, the source revision — else null.
|
|
506
|
+
revertedFrom: integer("reverted_from"),
|
|
507
|
+
createdAt: text("created_at").notNull(),
|
|
508
|
+
},
|
|
509
|
+
(t) => ({
|
|
510
|
+
uqConsentConfigTenantRevision: uniqueIndex("uq_consent_config_tenant_revision").on(
|
|
511
|
+
t.tenantId,
|
|
512
|
+
t.revision,
|
|
513
|
+
),
|
|
514
|
+
idxConsentConfigTenant: index("idx_consent_config_tenant").on(t.tenantId),
|
|
515
|
+
}),
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
// Demonstrated CMP demand — one row per `(tenant, adapter)` demand signal. The set
|
|
519
|
+
// of SELECTABLE CMP adapters is DERIVED from these rows (distinct-tenant count over
|
|
520
|
+
// a threshold), never a hardcoded catalog: the first CMP Storefront adapts is
|
|
521
|
+
// whichever real demand first proves (ADR 0014 P2 / 0025). UNIQUE
|
|
522
|
+
// `(tenant_id, adapter_id)` makes demand a per-tenant fact (a tenant re-asking does
|
|
523
|
+
// not inflate the count); the `adapter_id` index serves the per-adapter rollup.
|
|
524
|
+
export const consentCmpDemand = sqliteTable(
|
|
525
|
+
"consent_cmp_demand",
|
|
526
|
+
{
|
|
527
|
+
id: text("id").primaryKey(),
|
|
528
|
+
tenantId: text("tenant_id").notNull(),
|
|
529
|
+
adapterId: text("adapter_id").notNull(),
|
|
530
|
+
// Where the demand came from (a merchant request, a support ticket), for the record.
|
|
531
|
+
source: text("source"),
|
|
532
|
+
at: text("at").notNull(),
|
|
533
|
+
},
|
|
534
|
+
(t) => ({
|
|
535
|
+
uqConsentCmpDemandTenantAdapter: uniqueIndex("uq_consent_cmp_demand_tenant_adapter").on(
|
|
536
|
+
t.tenantId,
|
|
537
|
+
t.adapterId,
|
|
538
|
+
),
|
|
539
|
+
idxConsentCmpDemandAdapter: index("idx_consent_cmp_demand_adapter").on(t.adapterId),
|
|
540
|
+
}),
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
// --- Commerce conversion attribution (ext-commerce-04) -----------------------
|
|
544
|
+
// The single-use ledger for the signed checkout-correlation token's `jti`
|
|
545
|
+
// (`packages/public-runtime/src/integration/correlation-token.ts`). The order join
|
|
546
|
+
// consumes a token EXACTLY once: a replay of a consumed `jti` is refused. `jti` is
|
|
547
|
+
// the natural key (the token's own 96-bit nonce); `expires_at` is the token's Unix-
|
|
548
|
+
// seconds `exp` so a consumed row can be pruned once the token is already `expired`
|
|
549
|
+
// (a past-`exp` token is rejected before the guard is even reached). Carries no PII
|
|
550
|
+
// and no secret — the `jti` is an opaque nonce, never the token or the signing key.
|
|
551
|
+
export const correlationReplay = sqliteTable("correlation_replay", {
|
|
552
|
+
jti: text("jti").primaryKey(),
|
|
553
|
+
expiresAt: integer("expires_at").notNull(),
|
|
554
|
+
consumedAt: text("consumed_at").notNull(),
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
// --- Retained managed-app version facets (ext-apps-02) -----------------------
|
|
558
|
+
// APPEND-ONLY retention of every activated managed-app VERSION's COMPLETE
|
|
559
|
+
// restorable facet set, and the atomic-rollback spine over it. One row per
|
|
560
|
+
// activation of an install; the CURRENT active version is `MAX(seq)` per install
|
|
561
|
+
// (same "the latest row is current" model as `consent_config_revisions`). The
|
|
562
|
+
// whole restorable facet set (code ref/digest, entry module, public config,
|
|
563
|
+
// contributions, granted scopes, consent declaration, CSP origins) is one JSON
|
|
564
|
+
// blob in `facets` — so retaining a version and rolling one back are each a
|
|
565
|
+
// SINGLE-ROW insert: the restore is atomic by construction (you get the whole
|
|
566
|
+
// prior facet set or nothing — never a partial/mixed activation). A rollback is
|
|
567
|
+
// forward-only: it appends a NEW activation copying a retained version's facets
|
|
568
|
+
// and records `restored_from_seq`, so history is never rewritten and the rollback
|
|
569
|
+
// is itself an audited row. `tenant_id` is the isolation boundary, denormalized
|
|
570
|
+
// for tenant-scoped reads (no SQL FK — repo convention). `facets` carries no
|
|
571
|
+
// secret material (proved by the ext-kernel-01 secret scan before insert). UNIQUE
|
|
572
|
+
// `(install_id, seq)` makes the monotonic sequence a schema invariant.
|
|
573
|
+
export const appVersionSnapshots = sqliteTable(
|
|
574
|
+
"app_version_snapshots",
|
|
575
|
+
{
|
|
576
|
+
id: text("id").primaryKey(),
|
|
577
|
+
installId: text("install_id").notNull(),
|
|
578
|
+
tenantId: text("tenant_id").notNull(),
|
|
579
|
+
// Monotonic per install (1, 2, 3…); the largest is the active version.
|
|
580
|
+
seq: integer("seq").notNull(),
|
|
581
|
+
// The app package version this activation serves (mirror of facets.appVersion).
|
|
582
|
+
appVersion: text("app_version").notNull(),
|
|
583
|
+
// The complete restorable facet set as one JSON blob (AppVersionFacets).
|
|
584
|
+
facets: text("facets").notNull(),
|
|
585
|
+
// Opaque actor id — never email/PII (matches `app_audit_log`).
|
|
586
|
+
actor: text("actor").notNull(),
|
|
587
|
+
// Human-legible note (e.g. the reason, or "rollback to version N").
|
|
588
|
+
note: text("note"),
|
|
589
|
+
// When this activation restores an earlier one, its source `seq` — else null.
|
|
590
|
+
restoredFromSeq: integer("restored_from_seq"),
|
|
591
|
+
createdAt: text("created_at").notNull(),
|
|
592
|
+
},
|
|
593
|
+
(t) => ({
|
|
594
|
+
uqAppVersionSnapshotsInstallSeq: uniqueIndex("uq_app_version_snapshots_install_seq").on(
|
|
595
|
+
t.installId,
|
|
596
|
+
t.seq,
|
|
597
|
+
),
|
|
598
|
+
idxAppVersionSnapshotsInstall: index("idx_app_version_snapshots_install").on(t.installId),
|
|
599
|
+
}),
|
|
600
|
+
);
|
|
601
|
+
|
|
602
|
+
// The per-`(tenant, external_order_id)` attribution ledger. An order's attribution is
|
|
603
|
+
// decided ONCE (on its first `order.created`/`order.fulfilled` conversion) and reused
|
|
604
|
+
// for every later lifecycle conversion, so the correlation `jti` is consumed once per
|
|
605
|
+
// order — not once per lifecycle event — and a duplicate/replayed/out-of-order webhook
|
|
606
|
+
// reproduces the same outcome. `attributed` is 0/1; when attributed, `correlation_id`
|
|
607
|
+
// + `correlation_expires_at` hold the shared thread; when not, `reason` records why
|
|
608
|
+
// (missing/expired/context_mismatch/replay/…). Never customer identity — only the
|
|
609
|
+
// opaque correlation handle. `(tenant_id, external_order_id)` is the natural key.
|
|
610
|
+
export const orderAttribution = sqliteTable(
|
|
611
|
+
"order_attribution",
|
|
612
|
+
{
|
|
613
|
+
tenantId: text("tenant_id").notNull(),
|
|
614
|
+
externalOrderId: text("external_order_id").notNull(),
|
|
615
|
+
attributed: integer("attributed").notNull().default(0),
|
|
616
|
+
correlationId: text("correlation_id"),
|
|
617
|
+
correlationExpiresAt: text("correlation_expires_at"),
|
|
618
|
+
reason: text("reason"),
|
|
619
|
+
recordedAt: text("recorded_at").notNull(),
|
|
620
|
+
},
|
|
621
|
+
(t) => ({ pk: primaryKey({ columns: [t.tenantId, t.externalOrderId] }) }),
|
|
622
|
+
);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Opaque, SESSION-KV-backed credential that lets a developer's LOCAL dev-loop
|
|
3
3
|
* process authenticate POST /api/dev/activity on the hosted Worker — the
|
|
4
|
-
* local→hosted activity bridge
|
|
5
|
-
* 2026-07-14-hosted-dev-activity-bridge-and-stepper).
|
|
4
|
+
* local→hosted activity bridge.
|
|
6
5
|
*
|
|
7
6
|
* Minted alongside the existing cli-signin-code paste
|
|
8
7
|
* (apps/storefront/src/lib/dev/cliSignInCode.ts) and cached by the CLI in
|
|
@@ -30,8 +29,7 @@ export interface ActivityIngestClaims {
|
|
|
30
29
|
* sign-in code was issued (see api/dev/cli-signin-code.ts). It rides in the
|
|
31
30
|
* claims so every runtime/activity write the local loop makes with this token
|
|
32
31
|
* is stampable with the same id — support looks a live session up by it.
|
|
33
|
-
* Optional
|
|
34
|
-
* carry no trace); every freshly-minted token sets it.
|
|
32
|
+
* Optional: a token without it carries no trace; every freshly-minted token sets it.
|
|
35
33
|
*/
|
|
36
34
|
traceId?: string;
|
|
37
35
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Per-vendor "recent activity" feed for the hosted /dev panel — a small ring
|
|
3
3
|
* buffer of file-save events reported by a developer's LOCAL dev loop (see
|
|
4
|
-
* activityIngestToken.ts for the write-path auth). File-level only
|
|
5
|
-
*
|
|
6
|
-
* handoff 2026-07-14-hosted-dev-activity-bridge-and-stepper).
|
|
4
|
+
* activityIngestToken.ts for the write-path auth). File-level only: no
|
|
5
|
+
* per-line diff, no separate published-history tier.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
export type ActivityEventKind = "change" | "add" | "unlink" | "up";
|
|
@@ -62,8 +61,7 @@ export async function clearActivity(kv: KVNamespace, appDomain: string): Promise
|
|
|
62
61
|
|
|
63
62
|
/**
|
|
64
63
|
* Business-readable translation of a reported file path + event, for the
|
|
65
|
-
* activity log. File-level only — no per-line diff enrichment
|
|
66
|
-
* 2026-07-14: "we can show that in step 2").
|
|
64
|
+
* activity log. File-level only — no per-line diff enrichment.
|
|
67
65
|
*/
|
|
68
66
|
export function describeActivity(file: string | undefined, event: ActivityEventKind): string {
|
|
69
67
|
if (event === "up") return "Your store is running locally";
|
|
@@ -3,12 +3,9 @@
|
|
|
3
3
|
* click-to-source). Local `astro dev` serves these off dev-server-only plugins at
|
|
4
4
|
* `/__tot/*` (dev-plugins/dev-file-browser.mjs, dev-write.mjs, dev-diff.mjs, ...) —
|
|
5
5
|
* paths that don't exist in the deployed Cloudflare Worker. The hosted Worker instead
|
|
6
|
-
* serves the SAME shape off `/api/dev/*` Astro API routes
|
|
6
|
+
* serves the SAME shape off `/api/dev/*` Astro API routes
|
|
7
7
|
* (cp-tree, cp-file, cp-write, cp-diff, cp-locate). One dev.astro UI, one resolver.
|
|
8
8
|
*
|
|
9
|
-
* See decision `architecture-environment-aware-cockpit`
|
|
10
|
-
* (workstream tot-lime-cloud-dev-cockpit).
|
|
11
|
-
*
|
|
12
9
|
* `basePath` is the request's tenant prefix ("" host-routed, "/<tenant>" path-routed).
|
|
13
10
|
* The HOSTED routes are tenant-scoped through the middleware's host/path resolution, so
|
|
14
11
|
* a `/<tenant>/cockpit` render must call `/<tenant>/api/dev/*` for `locals.tenant` to be
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Stuck? Ask" recovery affordance. A quiet FAB that opens a scoped Q&A
|
|
3
|
+
* for "why isn't the loop working" — NOT general AI editing. Static answers
|
|
4
|
+
* ship as markup; the two stateful answers (is it running? / save-vs-reload)
|
|
5
|
+
* update from the shared tot:loop-state signal + window.__totLoop (monitor.ts
|
|
6
|
+
* — no second poll). "Reconnect preview" reloads the page, re-establishing
|
|
7
|
+
* the HMR connection and re-reading loop state (recovers a stale client); a
|
|
8
|
+
* fully-down server is handled by the answer text (run tot start). Imported
|
|
9
|
+
* from a processed `<script>` in cockpit.astro (ADR 0013), rendered only when
|
|
10
|
+
* isLocalDevLoop.
|
|
11
|
+
*/
|
|
12
|
+
export function initAsk(): void {
|
|
13
|
+
const fab = document.getElementById("askFab");
|
|
14
|
+
const panel = document.getElementById("askPanel");
|
|
15
|
+
if (!fab || !panel) return;
|
|
16
|
+
const ansRunning = document.getElementById("ans-running");
|
|
17
|
+
const ansChange = document.getElementById("ans-change");
|
|
18
|
+
const restart = document.getElementById("restartBtn");
|
|
19
|
+
|
|
20
|
+
fab.addEventListener("click", (e) => { e.stopPropagation(); panel.classList.toggle("open"); });
|
|
21
|
+
document.addEventListener("click", (e) => {
|
|
22
|
+
if (!panel.contains(e.target as Node) && e.target !== fab && !fab.contains(e.target as Node)) panel.classList.remove("open");
|
|
23
|
+
});
|
|
24
|
+
if (restart) restart.addEventListener("click", () => { location.reload(); });
|
|
25
|
+
|
|
26
|
+
function rel(ts: number | string): string {
|
|
27
|
+
const d = Math.max(0, Math.round((Date.now() - Number(ts)) / 1000));
|
|
28
|
+
return d < 2 ? "just now" : d < 60 ? d + "s ago" : Math.floor(d / 60) + "m ago";
|
|
29
|
+
}
|
|
30
|
+
function update(s: any) {
|
|
31
|
+
if (!s) return;
|
|
32
|
+
if (ansRunning) {
|
|
33
|
+
ansRunning.textContent = (s.offline || !s.server)
|
|
34
|
+
? "Your dev server isn't reachable right now — run tot start in your terminal, then reload this page."
|
|
35
|
+
: "Yes — your server is running" + (s.port ? " on port " + s.port : "") + ". This page is connected to it.";
|
|
36
|
+
}
|
|
37
|
+
if (ansChange) {
|
|
38
|
+
if (!s.lastSaveAt) {
|
|
39
|
+
ansChange.textContent = "No saves seen yet. Edit a watched file (like content/home.html) and save — it'll show up here.";
|
|
40
|
+
} else if ((s.lastReloadAt || 0) >= s.lastSaveAt) {
|
|
41
|
+
ansChange.textContent = "Working: your last save (" + rel(s.lastSaveAt) + ") triggered a reload (" + rel(s.lastReloadAt) + "). If the page didn't visibly change, make sure you edited the file the page renders from.";
|
|
42
|
+
} else {
|
|
43
|
+
ansChange.textContent = "Your save (" + rel(s.lastSaveAt) + ") hasn't been reflected by a reload yet — the preview may be stale. Try Reconnect preview below.";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
window.addEventListener("tot:loop-state", (e: any) => { update(e.detail); });
|
|
48
|
+
if (window.__totLoop) update(window.__totLoop);
|
|
49
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C8 · Click-to-source capstone — the cockpit side. Runs the live-preview
|
|
3
|
+
* iframe (mini + full-screen dialog) and LISTENS for the framed picker's
|
|
4
|
+
* tot:locate postMessage. The picker (ai-widget-client.js, auto-injected into
|
|
5
|
+
* the same-origin preview) resolves a click to {path,line,col} via
|
|
6
|
+
* /__tot/locate, then — because it is framed — postMessages the result here
|
|
7
|
+
* instead of showing its own toast. We verify event.origin === our origin,
|
|
8
|
+
* then hand off to files.ts's window.__totOpenFileAt to open the source +
|
|
9
|
+
* drop the caret. Only content-region hits ever arrive (chrome/refused
|
|
10
|
+
* clicks stay silent in the frame), per decision
|
|
11
|
+
* click-to-source-anchors-at-content-region. Imported from a processed
|
|
12
|
+
* `<script>` in cockpit.astro (ADR 0013), rendered only when isLocalDevLoop.
|
|
13
|
+
* isDev and the hosted app domain are read from `document.body.dataset`.
|
|
14
|
+
*/
|
|
15
|
+
export function initClickToSource(): void {
|
|
16
|
+
const isDev = document.body.dataset.cockpitIsDev === "true";
|
|
17
|
+
const hostedAppDomain = document.body.dataset.cockpitAppDomain || "";
|
|
18
|
+
const dlg: any = document.getElementById("previewDialog");
|
|
19
|
+
const expandBtn = document.getElementById("previewExpand");
|
|
20
|
+
const closeBtn = document.getElementById("previewClose");
|
|
21
|
+
const dlgFrame: any = document.getElementById("previewDialogFrame");
|
|
22
|
+
const miniFrame: any = document.getElementById("previewFrame");
|
|
23
|
+
const urlEl = document.getElementById("previewUrl");
|
|
24
|
+
|
|
25
|
+
if (miniFrame) {
|
|
26
|
+
if (isDev) {
|
|
27
|
+
// Point the preview at the DEV tenant (TOT_DEV_TENANT), read from the server
|
|
28
|
+
// via /__tot/dev-loop-status — NOT the SSR appDomain (workerd can't see
|
|
29
|
+
// TOT_DEV_*). Same-origin, so the auto-injected picker can postMessage back.
|
|
30
|
+
fetch("/__tot/dev-loop-status")
|
|
31
|
+
.then((r) => r.json())
|
|
32
|
+
.then((s) => {
|
|
33
|
+
const tenant = s && s.tenant;
|
|
34
|
+
if (!tenant) return;
|
|
35
|
+
const src = "/" + tenant + "/";
|
|
36
|
+
miniFrame.src = src;
|
|
37
|
+
if (urlEl) urlEl.textContent = "localhost preview · " + tenant;
|
|
38
|
+
})
|
|
39
|
+
.catch(() => { /* dev server unreachable — preview stays blank */ });
|
|
40
|
+
} else if (hostedAppDomain) {
|
|
41
|
+
// Hosted: the SSR-resolved tenant IS the signed-in developer's own store
|
|
42
|
+
// (cp-env's capability gate already scoped it) — same-origin, so a cp-write
|
|
43
|
+
// save + this reload shows the developer's own draft overlay via the
|
|
44
|
+
// middleware's tot_dev_draft cookie check.
|
|
45
|
+
miniFrame.src = "/" + hostedAppDomain + "/";
|
|
46
|
+
if (urlEl) urlEl.textContent = "your store · " + hostedAppDomain;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (expandBtn && dlg) {
|
|
51
|
+
expandBtn.addEventListener("click", () => {
|
|
52
|
+
if (dlgFrame && !dlgFrame.getAttribute("src") && miniFrame) dlgFrame.src = miniFrame.getAttribute("src") || miniFrame.src;
|
|
53
|
+
if (typeof dlg.showModal === "function") dlg.showModal(); else dlg.setAttribute("open", "");
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (closeBtn && dlg) closeBtn.addEventListener("click", () => { dlg.close ? dlg.close() : dlg.removeAttribute("open"); });
|
|
57
|
+
if (dlg) dlg.addEventListener("click", (e: MouseEvent) => { if (e.target === dlg) { dlg.close ? dlg.close() : dlg.removeAttribute("open"); } });
|
|
58
|
+
|
|
59
|
+
// The one privileged inbound message: a source location from OUR OWN origin's
|
|
60
|
+
// framed preview. Reject any other origin, shape, or type outright.
|
|
61
|
+
window.addEventListener("message", (e) => {
|
|
62
|
+
if (e.origin !== window.location.origin) return;
|
|
63
|
+
const d: any = e.data;
|
|
64
|
+
if (!d || d.type !== "tot:locate" || typeof d.path !== "string") return;
|
|
65
|
+
if (typeof (window as any).__totOpenFileAt === "function") {
|
|
66
|
+
const opened = (window as any).__totOpenFileAt(d.path, d.line, d.col);
|
|
67
|
+
// If the preview was expanded full-screen, close it so the editor + caret are visible.
|
|
68
|
+
if (opened && dlg && dlg.open) { dlg.close ? dlg.close() : dlg.removeAttribute("open"); }
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|