@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
|
@@ -17,12 +17,24 @@
|
|
|
17
17
|
import type {
|
|
18
18
|
EditorialPage,
|
|
19
19
|
HomeContent,
|
|
20
|
-
SiteChrome,
|
|
21
20
|
} from "./content-model.js";
|
|
21
|
+
import type { ChromeConfig } from "../chrome/model.js";
|
|
22
22
|
import type { CustomizationEnv, KvGet, TenantConfig } from "@tot/public-runtime";
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
contentArtifactPath,
|
|
25
|
+
listPublishedArtifactPaths,
|
|
26
|
+
readPublishedArtifact,
|
|
27
|
+
} from "@tot/public-runtime";
|
|
24
28
|
import { renderRawChrome } from "../rawChrome.js";
|
|
25
29
|
import { parseChromeConfig } from "../chrome/parseConfig.js";
|
|
30
|
+
import { parseChromeAssignments } from "../chrome/model.js";
|
|
31
|
+
|
|
32
|
+
/** Safe, always-valid fallback when neither the tenant's own chrome.json nor
|
|
33
|
+
* the default scope's validates — the storefront must always render. */
|
|
34
|
+
const EMPTY_CHROME_CONFIG: ChromeConfig = {
|
|
35
|
+
header: { variant: "primary", brand: { label: "" }, nav: [] },
|
|
36
|
+
footer: { variant: "default", columns: [] },
|
|
37
|
+
};
|
|
26
38
|
|
|
27
39
|
export interface ContentProvider {
|
|
28
40
|
getHome(): Promise<HomeContent>;
|
|
@@ -48,11 +60,21 @@ export interface ContentProvider {
|
|
|
48
60
|
* spliced in (see lib/rawMarketingHtml.ts). Lets raw pages stop duplicating
|
|
49
61
|
* chrome: chrome lives once here, pages become fragments. File:
|
|
50
62
|
* `content/<tenant>/chrome.html`. Tenant-owned (no cross-tenant fallback).
|
|
63
|
+
*
|
|
64
|
+
* `currentPath`, when given, is the tenant-relative request path (e.g. "/"
|
|
65
|
+
* or "/collections/all") in the same unprefixed form the chrome config's
|
|
66
|
+
* own nav `href`s are authored in — drives `aria-current="page"` on the
|
|
67
|
+
* matching primary-nav link when the wrapper is rendered from chrome.json
|
|
68
|
+
* (rawChrome.ts). Omitted ⇒ no item is marked current.
|
|
51
69
|
*/
|
|
52
|
-
getChromeHtml(): Promise<string | null>;
|
|
53
|
-
getChrome(): Promise<
|
|
70
|
+
getChromeHtml(currentPath?: string): Promise<string | null>;
|
|
71
|
+
getChrome(): Promise<ChromeConfig>;
|
|
54
72
|
getPage(slug: string): Promise<EditorialPage | null>;
|
|
55
73
|
listPages(): Promise<EditorialPage[]>;
|
|
74
|
+
/** Raw tenant-content artifact, relative to `content/`. */
|
|
75
|
+
readArtifact(relative: string): Promise<string | null>;
|
|
76
|
+
/** Artifact paths relative to `content/`; null means use a legacy fallback. */
|
|
77
|
+
listArtifactPaths(prefix?: string): Promise<string[] | null>;
|
|
56
78
|
}
|
|
57
79
|
|
|
58
80
|
// ---------------------------------------------------------------------------
|
|
@@ -67,9 +89,16 @@ export interface ContentProvider {
|
|
|
67
89
|
const homeGlobs = import.meta.glob<HomeContent>("../../../../../tenants/*/content/home.json", {
|
|
68
90
|
import: "default",
|
|
69
91
|
});
|
|
70
|
-
const chromeGlobs = import.meta.glob<
|
|
92
|
+
const chromeGlobs = import.meta.glob<unknown>("../../../../../tenants/*/content/chrome.json", {
|
|
71
93
|
import: "default",
|
|
72
94
|
});
|
|
95
|
+
// Per-page header/footer variant overrides for the raw-HTML chrome path (see
|
|
96
|
+
// lib/chrome/assignments.ts). Tenant-owned, no cross-tenant fallback — same
|
|
97
|
+
// convention as chromeGlobs above.
|
|
98
|
+
const chromeAssignmentGlobs = import.meta.glob<unknown>(
|
|
99
|
+
"../../../../../tenants/*/content/chrome-assignments.json",
|
|
100
|
+
{ import: "default" },
|
|
101
|
+
);
|
|
73
102
|
const pageGlobs = import.meta.glob<EditorialPage>("../../../../../tenants/*/content/pages/*.json", {
|
|
74
103
|
import: "default",
|
|
75
104
|
});
|
|
@@ -91,6 +120,10 @@ const chromeHtmlGlobs = import.meta.glob<string>("../../../../../tenants/*/conte
|
|
|
91
120
|
query: "?raw",
|
|
92
121
|
import: "default",
|
|
93
122
|
});
|
|
123
|
+
const artifactGlobs = import.meta.glob<string>("../../../../../tenants/*/content/**/*", {
|
|
124
|
+
query: "?raw",
|
|
125
|
+
import: "default",
|
|
126
|
+
});
|
|
94
127
|
|
|
95
128
|
const DEFAULT_SCOPE = "home";
|
|
96
129
|
|
|
@@ -196,18 +229,22 @@ export class LocalContentProvider implements ContentProvider {
|
|
|
196
229
|
.sort((a, b) => a.localeCompare(b));
|
|
197
230
|
}
|
|
198
231
|
|
|
199
|
-
async getChromeHtml(): Promise<string | null> {
|
|
232
|
+
async getChromeHtml(currentPath?: string): Promise<string | null> {
|
|
200
233
|
// (1) A hand-authored chrome.html wins — keeps a not-yet-adopted tenant's chrome
|
|
201
234
|
// byte-identical (dev: fresh from disk so an edit previews on save).
|
|
202
235
|
const dev = await readRawDevFile(this.scope, "chrome.html");
|
|
203
236
|
if (dev !== null) return dev;
|
|
204
237
|
const loader = pickContent(chromeHtmlGlobs, this.scope);
|
|
205
238
|
if (loader) return loader();
|
|
206
|
-
// (2) No chrome.html: render the CANONICAL shared chrome
|
|
207
|
-
// tenant's chrome.json — but only when it
|
|
208
|
-
//
|
|
239
|
+
// (2) No chrome.html: render the CANONICAL shared chrome from the
|
|
240
|
+
// tenant's chrome.json — but only when it validates whole against the
|
|
241
|
+
// consolidated ChromeConfig schema (lib/chrome/parseConfig.ts). Tenant-
|
|
242
|
+
// owned only, like the raw HTML above (no cross-tenant fallback).
|
|
209
243
|
const config = await this.loadChromeConfig();
|
|
210
|
-
|
|
244
|
+
if (!config) return null;
|
|
245
|
+
// Per-page variant override — a page not listed in chrome-assignments.json
|
|
246
|
+
// keeps chrome.json's default variant. renderRawChrome resolves it.
|
|
247
|
+
return renderRawChrome(config, currentPath, await this.loadChromeAssignments());
|
|
211
248
|
}
|
|
212
249
|
|
|
213
250
|
/** The tenant's parsed raw-chrome config (chrome.json), or null if not adopted. */
|
|
@@ -225,31 +262,33 @@ export class LocalContentProvider implements ContentProvider {
|
|
|
225
262
|
return loader ? parseChromeConfig(await loader()) : null;
|
|
226
263
|
}
|
|
227
264
|
|
|
228
|
-
|
|
265
|
+
/** The tenant's parsed page-assignment manifest (chrome-assignments.json),
|
|
266
|
+
* or null if absent/invalid — same dev-hot-reload + tenant-owned-only
|
|
267
|
+
* discipline as loadChromeConfig. */
|
|
268
|
+
private async loadChromeAssignments(): Promise<ReturnType<typeof parseChromeAssignments>> {
|
|
269
|
+
const devRaw = await readRawDevFile(this.scope, "chrome-assignments.json");
|
|
270
|
+
if (devRaw !== null) {
|
|
271
|
+
try {
|
|
272
|
+
return parseChromeAssignments(JSON.parse(devRaw));
|
|
273
|
+
} catch {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const loader = pickContent(chromeAssignmentGlobs, this.scope);
|
|
278
|
+
return loader ? parseChromeAssignments(await loader()) : null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async getChrome(): Promise<ChromeConfig> {
|
|
282
|
+
// The full config is validated as ONE document now (header/footer are
|
|
283
|
+
// both required) — there is no more partial-field merge across scopes; a
|
|
284
|
+
// tenant's own chrome.json either validates whole, or the default scope's
|
|
285
|
+
// does, or the storefront falls back to an empty-but-valid config.
|
|
286
|
+
const own = await this.loadChromeConfig();
|
|
287
|
+
if (own) return own;
|
|
288
|
+
if (this.scope === DEFAULT_SCOPE) return EMPTY_CHROME_CONFIG;
|
|
229
289
|
const defL = pickContent(chromeGlobs, DEFAULT_SCOPE);
|
|
230
|
-
const def
|
|
231
|
-
|
|
232
|
-
: { nav: [], footer: { columns: [], social: [] } };
|
|
233
|
-
const ownL = pickContent(chromeGlobs, this.scope);
|
|
234
|
-
if (!ownL) return def;
|
|
235
|
-
const c = await ownL();
|
|
236
|
-
if (this.scope === DEFAULT_SCOPE) return c;
|
|
237
|
-
// Per-field fallback fills only STRUCTURAL scaffolding (nav/footer) so a
|
|
238
|
-
// partially-adopted tenant still renders. Promotional/identity/legal fields
|
|
239
|
-
// (announcement, headerCtas, disclaimers) are tenant-OWNED and never inherit
|
|
240
|
-
// from the default scope — otherwise e.g. a marketing tenant would show the
|
|
241
|
-
// default store's shipping banner or nicotine disclaimers.
|
|
242
|
-
return {
|
|
243
|
-
nav: c.nav?.length ? c.nav : def.nav,
|
|
244
|
-
footer:
|
|
245
|
-
c.footer && (c.footer.columns?.length || c.footer.social?.length)
|
|
246
|
-
? c.footer
|
|
247
|
-
: def.footer,
|
|
248
|
-
headerCtas: c.headerCtas,
|
|
249
|
-
announcement: c.announcement,
|
|
250
|
-
disclaimer: c.disclaimer,
|
|
251
|
-
disclaimers: c.disclaimers,
|
|
252
|
-
};
|
|
290
|
+
const def = defL ? parseChromeConfig(await defL()) : null;
|
|
291
|
+
return def ?? EMPTY_CHROME_CONFIG;
|
|
253
292
|
}
|
|
254
293
|
|
|
255
294
|
async getPage(slug: string): Promise<EditorialPage | null> {
|
|
@@ -264,6 +303,24 @@ export class LocalContentProvider implements ContentProvider {
|
|
|
264
303
|
const loaders = pickPages(this.scope);
|
|
265
304
|
return Promise.all(loaders.map((l) => l()));
|
|
266
305
|
}
|
|
306
|
+
|
|
307
|
+
async readArtifact(relative: string): Promise<string | null> {
|
|
308
|
+
const normalized = relative.replace(/^\/+/, "");
|
|
309
|
+
const marker = `/tenants/${this.scope}/content/${normalized}`;
|
|
310
|
+
const key = Object.keys(artifactGlobs).find((candidate) => candidate.endsWith(marker));
|
|
311
|
+
return key ? artifactGlobs[key]!() : null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async listArtifactPaths(prefix = ""): Promise<string[]> {
|
|
315
|
+
const marker = `/tenants/${this.scope}/content/`;
|
|
316
|
+
return Object.keys(artifactGlobs)
|
|
317
|
+
.flatMap((key) => {
|
|
318
|
+
const at = key.indexOf(marker);
|
|
319
|
+
return at < 0 ? [] : [key.slice(at + marker.length)];
|
|
320
|
+
})
|
|
321
|
+
.filter((path) => path.startsWith(prefix))
|
|
322
|
+
.sort((a, b) => a.localeCompare(b));
|
|
323
|
+
}
|
|
267
324
|
}
|
|
268
325
|
|
|
269
326
|
// ---------------------------------------------------------------------------
|
|
@@ -405,26 +462,24 @@ export class StoryblokContentProvider implements ContentProvider {
|
|
|
405
462
|
return this.fallback.listPageHtmlSlugs();
|
|
406
463
|
}
|
|
407
464
|
|
|
408
|
-
getChromeHtml(): Promise<string | null> {
|
|
465
|
+
getChromeHtml(currentPath?: string): Promise<string | null> {
|
|
409
466
|
// The chrome wrapper lives in tenant content files, not Storyblok — delegate.
|
|
410
|
-
return this.fallback.getChromeHtml();
|
|
467
|
+
return this.fallback.getChromeHtml(currentPath);
|
|
411
468
|
}
|
|
412
469
|
|
|
413
|
-
async getChrome(): Promise<
|
|
414
|
-
// Editorial chrome (nav/footer
|
|
415
|
-
//
|
|
416
|
-
//
|
|
470
|
+
async getChrome(): Promise<ChromeConfig> {
|
|
471
|
+
// Editorial chrome (nav/footer) is authored in Storyblok; brand/variant
|
|
472
|
+
// and everything else stay MIGRATION-sourced (the local chrome.json), so
|
|
473
|
+
// overlay only nav + footer from Storyblok when present.
|
|
417
474
|
const local = await this.fallback.getChrome();
|
|
418
475
|
try {
|
|
419
476
|
const story = await fetchStory(this.token, "chrome");
|
|
420
477
|
const c = story?.content;
|
|
421
478
|
if (c && Array.isArray(c.nav)) {
|
|
422
479
|
return {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
disclaimer: local.disclaimer,
|
|
427
|
-
disclaimers: local.disclaimers,
|
|
480
|
+
...local,
|
|
481
|
+
header: { ...local.header, nav: c.nav },
|
|
482
|
+
footer: c.footer ? { ...local.footer, ...c.footer } : local.footer,
|
|
428
483
|
};
|
|
429
484
|
}
|
|
430
485
|
} catch {
|
|
@@ -461,6 +516,14 @@ export class StoryblokContentProvider implements ContentProvider {
|
|
|
461
516
|
}
|
|
462
517
|
return this.fallback.listPages();
|
|
463
518
|
}
|
|
519
|
+
|
|
520
|
+
readArtifact(relative: string): Promise<string | null> {
|
|
521
|
+
return this.fallback.readArtifact(relative);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
listArtifactPaths(prefix?: string): Promise<string[] | null> {
|
|
525
|
+
return this.fallback.listArtifactPaths(prefix);
|
|
526
|
+
}
|
|
464
527
|
}
|
|
465
528
|
|
|
466
529
|
// ---------------------------------------------------------------------------
|
|
@@ -468,7 +531,8 @@ export class StoryblokContentProvider implements ContentProvider {
|
|
|
468
531
|
// resolved environment (store->app wiring). For each content artifact it checks
|
|
469
532
|
// the customization store ({live,test} pointer -> versioned JSON); if present it
|
|
470
533
|
// serves that, otherwise it delegates to the base provider (Storyblok/local).
|
|
471
|
-
//
|
|
534
|
+
// Enumeration also follows the selected immutable manifest, so sitemap/blog/page
|
|
535
|
+
// indexes do not need a build-time tenant checkout.
|
|
472
536
|
// ---------------------------------------------------------------------------
|
|
473
537
|
|
|
474
538
|
export interface ContentCustomization {
|
|
@@ -517,34 +581,72 @@ export class PublishedContentProvider implements ContentProvider {
|
|
|
517
581
|
return (await this.publishedRaw(rel)) ?? this.base.getPageHtml(slug);
|
|
518
582
|
}
|
|
519
583
|
listPageHtmlSlugs(): Promise<string[]> {
|
|
520
|
-
return this.
|
|
584
|
+
return this.listArtifactPaths("pages-html/").then((paths) =>
|
|
585
|
+
paths === null
|
|
586
|
+
? this.base.listPageHtmlSlugs()
|
|
587
|
+
: paths
|
|
588
|
+
.filter((path) => path.endsWith(".html"))
|
|
589
|
+
.map((path) => path.slice("pages-html/".length, -".html".length)),
|
|
590
|
+
);
|
|
521
591
|
}
|
|
522
|
-
async getChromeHtml(): Promise<string | null> {
|
|
592
|
+
async getChromeHtml(currentPath?: string): Promise<string | null> {
|
|
523
593
|
// A published raw chrome.html override (parallels the home.html/pages-html
|
|
524
594
|
// publish path) wins, so a vendor edit previews / goes live with no rebuild.
|
|
525
595
|
const publishedHtml = await this.publishedRaw("chrome.html");
|
|
526
596
|
if (publishedHtml) return publishedHtml;
|
|
527
|
-
// Else, if the PUBLISHED chrome.json opts into shared chrome
|
|
597
|
+
// Else, if the PUBLISHED chrome.json opts into shared chrome, render
|
|
528
598
|
// the canonical wrapper from it — so a config edit previews without a rebuild.
|
|
529
599
|
const config = parseChromeConfig(await this.published<unknown>("chrome.json"));
|
|
530
|
-
if (config)
|
|
600
|
+
if (config) {
|
|
601
|
+
// Per-page variant override, resolved against the PUBLISHED assignment
|
|
602
|
+
// manifest (mirrors chrome.json itself — each source resolves fully
|
|
603
|
+
// within itself, no mixing published/base artifacts).
|
|
604
|
+
const assignments = parseChromeAssignments(await this.published<unknown>("chrome-assignments.json"));
|
|
605
|
+
return renderRawChrome(config, currentPath, assignments);
|
|
606
|
+
}
|
|
531
607
|
// Otherwise fall back to the base chain (bundled chrome.html or config render).
|
|
532
|
-
return this.base.getChromeHtml();
|
|
608
|
+
return this.base.getChromeHtml(currentPath);
|
|
533
609
|
}
|
|
534
|
-
async getChrome(): Promise<
|
|
535
|
-
|
|
610
|
+
async getChrome(): Promise<ChromeConfig> {
|
|
611
|
+
// Runs through the SAME fail-closed schema validator as getChromeHtml's
|
|
612
|
+
// chrome.json branch (lib/chrome/parseConfig.ts) — a published artifact is
|
|
613
|
+
// no longer trusted blind (was: JSON.parse + a raw cast to SiteChrome).
|
|
614
|
+
const config = parseChromeConfig(await this.published<unknown>("chrome.json"));
|
|
615
|
+
return config ?? this.base.getChrome();
|
|
536
616
|
}
|
|
537
617
|
async getPage(slug: string): Promise<EditorialPage | null> {
|
|
538
618
|
return (await this.published<EditorialPage>(`pages/${slug}.json`)) ?? this.base.getPage(slug);
|
|
539
619
|
}
|
|
540
|
-
listPages(): Promise<EditorialPage[]> {
|
|
541
|
-
|
|
620
|
+
async listPages(): Promise<EditorialPage[]> {
|
|
621
|
+
const paths = await this.listArtifactPaths("pages/");
|
|
622
|
+
if (paths === null) return this.base.listPages();
|
|
623
|
+
const pages = await Promise.all(
|
|
624
|
+
paths
|
|
625
|
+
.filter((path) => path.endsWith(".json"))
|
|
626
|
+
.map(async (path) => this.published<EditorialPage>(path)),
|
|
627
|
+
);
|
|
628
|
+
return pages.filter((page): page is EditorialPage => page !== null);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
readArtifact(relative: string): Promise<string | null> {
|
|
632
|
+
return this.publishedRaw(relative);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
async listArtifactPaths(prefix = ""): Promise<string[] | null> {
|
|
636
|
+
const root = contentArtifactPath(this.tenantId, "");
|
|
637
|
+
const paths = await listPublishedArtifactPaths(
|
|
638
|
+
this.cust.get,
|
|
639
|
+
this.tenantId,
|
|
640
|
+
this.cust.env,
|
|
641
|
+
`${root}${prefix}`,
|
|
642
|
+
);
|
|
643
|
+
return paths?.map((path) => path.slice(root.length)) ?? null;
|
|
542
644
|
}
|
|
543
645
|
}
|
|
544
646
|
|
|
545
647
|
// ---------------------------------------------------------------------------
|
|
546
|
-
// DevDraftContentProvider — the per-developer DRAFT overlay
|
|
547
|
-
//
|
|
648
|
+
// DevDraftContentProvider — the per-developer DRAFT overlay. Wraps the
|
|
649
|
+
// resolved provider chain and serves a
|
|
548
650
|
// draft artifact (written by /api/content-edit/ai-edit into TENANT_CACHE under
|
|
549
651
|
// `dev-draft:<tenantId>:<draftId>:<path>`) when one exists, else delegates.
|
|
550
652
|
// The middleware constructs this ONLY for a request whose signed tot_dev_draft
|
|
@@ -581,10 +683,10 @@ export class DevDraftContentProvider implements ContentProvider {
|
|
|
581
683
|
listPageHtmlSlugs(): Promise<string[]> {
|
|
582
684
|
return this.base.listPageHtmlSlugs();
|
|
583
685
|
}
|
|
584
|
-
getChromeHtml(): Promise<string | null> {
|
|
585
|
-
return this.base.getChromeHtml();
|
|
686
|
+
getChromeHtml(currentPath?: string): Promise<string | null> {
|
|
687
|
+
return this.base.getChromeHtml(currentPath);
|
|
586
688
|
}
|
|
587
|
-
getChrome(): Promise<
|
|
689
|
+
getChrome(): Promise<ChromeConfig> {
|
|
588
690
|
return this.base.getChrome();
|
|
589
691
|
}
|
|
590
692
|
getPage(slug: string): Promise<EditorialPage | null> {
|
|
@@ -593,6 +695,12 @@ export class DevDraftContentProvider implements ContentProvider {
|
|
|
593
695
|
listPages(): Promise<EditorialPage[]> {
|
|
594
696
|
return this.base.listPages();
|
|
595
697
|
}
|
|
698
|
+
readArtifact(relative: string): Promise<string | null> {
|
|
699
|
+
return this.base.readArtifact(relative);
|
|
700
|
+
}
|
|
701
|
+
listArtifactPaths(prefix?: string): Promise<string[] | null> {
|
|
702
|
+
return this.base.listArtifactPaths(prefix);
|
|
703
|
+
}
|
|
596
704
|
}
|
|
597
705
|
|
|
598
706
|
const PLACEHOLDER_TOKEN_RE = /PLACEHOLDER|^$/i;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Because a savings headline (a "%", a "$" amount) is a claim, {@link
|
|
10
10
|
* SubscriptionFigure} is treated as ILLUSTRATIVE by default — same discipline
|
|
11
|
-
* as the membership tier figures
|
|
11
|
+
* as the membership tier figures:
|
|
12
12
|
* unless a figure explicitly asserts `real: true`, the widget marks it as an
|
|
13
13
|
* example so it is never presented as a live offer.
|
|
14
14
|
*/
|
|
@@ -44,8 +44,8 @@ export interface SubscriptionFigure {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* The account-management actions a subscriber can take on an Autopilot order
|
|
48
|
-
*
|
|
47
|
+
* The account-management actions a subscriber can take on an Autopilot order.
|
|
48
|
+
* The storefront never EXECUTES these — each is a handoff into the
|
|
49
49
|
* tenant's product-owned manage-subscription portal (see {@link
|
|
50
50
|
* SubscriptionManagePortal}); this enum just gives the entry points stable,
|
|
51
51
|
* typed identities so the copy, ordering, and analytics hooks are consistent.
|
|
@@ -151,7 +151,7 @@ function defaultActionHref(action: SubscriptionManageAction, baseHref: string):
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
|
-
* Build the manage-subscription entry points for a tenant's portal — the
|
|
154
|
+
* Build the manage-subscription entry points for a tenant's portal — the
|
|
155
155
|
* skip / pause / cancel / reschedule / quantity (+ resume / swap / address)
|
|
156
156
|
* handoffs. Each entry is a plain link into `portal.baseHref`; the storefront
|
|
157
157
|
* hands off, the provider executes.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Thin wrapper binding the generic blog engine to the "the-build" collection.
|
|
2
|
+
// The engine (src/lib/blog/collection.ts) is the single implementation; this
|
|
3
|
+
// module only fixes the collection id so existing/downstream callers can import
|
|
4
|
+
// collection-bound helpers.
|
|
5
|
+
import { getPost, listPosts, resolveRedirect, type Collection } from "../blog/collection.js";
|
|
6
|
+
import type { BlogPost, BlogPostSummary } from "../blog/types.js";
|
|
7
|
+
import type { ContentProvider } from "../storyblok/provider.js";
|
|
8
|
+
|
|
9
|
+
export const THE_BUILD: Collection = { id: "the-build", base: "/the-build" };
|
|
10
|
+
|
|
11
|
+
export function listBuildPosts(
|
|
12
|
+
tenantId: string,
|
|
13
|
+
opts?: { includeUnpublished?: boolean; now?: string; content?: ContentProvider },
|
|
14
|
+
): Promise<BlogPostSummary[]> {
|
|
15
|
+
return listPosts(tenantId, THE_BUILD.id, opts);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getBuildPost(
|
|
19
|
+
tenantId: string,
|
|
20
|
+
slug: string,
|
|
21
|
+
opts?: { includeUnpublished?: boolean; now?: string; content?: ContentProvider },
|
|
22
|
+
): Promise<BlogPost | null> {
|
|
23
|
+
return getPost(tenantId, THE_BUILD.id, slug, opts);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function resolveBuildRedirect(
|
|
27
|
+
tenantId: string,
|
|
28
|
+
slug: string,
|
|
29
|
+
content?: ContentProvider,
|
|
30
|
+
): Promise<string | null> {
|
|
31
|
+
return resolveRedirect(tenantId, THE_BUILD.id, slug, content);
|
|
32
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Estimated reading time for a post's rendered HTML (B1.5). Pure + Node-free
|
|
2
|
+
// (parse5 is Workers-safe), so it's unit-testable and usable on any render path.
|
|
3
|
+
import { parseFragment } from "parse5";
|
|
4
|
+
|
|
5
|
+
/** Minimal structural view of a parse5 node (duck-typed, as scripts/dev/locate.mjs does). */
|
|
6
|
+
interface P5Node {
|
|
7
|
+
nodeName: string;
|
|
8
|
+
tagName?: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
childNodes?: P5Node[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const WORDS_PER_MINUTE = 225;
|
|
14
|
+
|
|
15
|
+
function collectText(node: P5Node, out: string[]): void {
|
|
16
|
+
if (node.nodeName === "#text") {
|
|
17
|
+
if (node.value) out.push(node.value);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Non-visible/text-irrelevant subtrees never count toward reading time.
|
|
21
|
+
if (node.tagName === "script" || node.tagName === "style") return;
|
|
22
|
+
for (const child of node.childNodes ?? []) collectText(child, out);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Reading time in whole minutes: visible word count / 225 wpm, rounded up, min 1.
|
|
27
|
+
* Ignores markup, script, and style content.
|
|
28
|
+
*/
|
|
29
|
+
export function readingTime(html: string): number {
|
|
30
|
+
const frag = parseFragment(html ?? "") as unknown as P5Node;
|
|
31
|
+
const parts: string[] = [];
|
|
32
|
+
collectText(frag, parts);
|
|
33
|
+
const words = parts.join(" ").trim().split(/\s+/).filter(Boolean);
|
|
34
|
+
return Math.max(1, Math.ceil(words.length / WORDS_PER_MINUTE));
|
|
35
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Table of contents for a post's rendered HTML (B1.5): parse h2/h3 headings and
|
|
2
|
+
// derive stable anchor ids. Pure + Node-free (parse5 is Workers-safe).
|
|
3
|
+
//
|
|
4
|
+
// `toc()` and `htmlWithHeadingIds()` derive ids from the SAME deterministic pass
|
|
5
|
+
// (`annotate`), so a render path can feed `htmlWithHeadingIds(post.contentHtml)`
|
|
6
|
+
// to `set:html` and `toc(post.contentHtml)` to the aside and the anchors line up.
|
|
7
|
+
import { parseFragment, serialize } from "parse5";
|
|
8
|
+
import { slugifyHeading } from "../content/prose.js";
|
|
9
|
+
|
|
10
|
+
/** Minimal structural view of a parse5 node (duck-typed, as scripts/dev/locate.mjs does). */
|
|
11
|
+
interface P5Node {
|
|
12
|
+
nodeName: string;
|
|
13
|
+
tagName?: string;
|
|
14
|
+
value?: string;
|
|
15
|
+
attrs?: { name: string; value: string }[];
|
|
16
|
+
childNodes?: P5Node[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TocEntry {
|
|
20
|
+
id: string;
|
|
21
|
+
text: string;
|
|
22
|
+
level: 2 | 3;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function textOf(node: P5Node): string {
|
|
26
|
+
if (node.nodeName === "#text") return node.value ?? "";
|
|
27
|
+
return (node.childNodes ?? []).map(textOf).join("");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getId(node: P5Node): string | undefined {
|
|
31
|
+
return node.attrs?.find((a) => a.name === "id")?.value?.trim() || undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function* headings(node: P5Node): Generator<P5Node> {
|
|
35
|
+
for (const child of node.childNodes ?? []) {
|
|
36
|
+
if (child.tagName === "h2" || child.tagName === "h3") yield child;
|
|
37
|
+
yield* headings(child);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface AnnotatedHeading {
|
|
42
|
+
node: P5Node;
|
|
43
|
+
id: string;
|
|
44
|
+
text: string;
|
|
45
|
+
level: 2 | 3;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Walk headings in document order, assigning each a unique anchor id: an
|
|
50
|
+
* author-supplied `id` is kept as-is; otherwise the slugified text, de-duped
|
|
51
|
+
* with a numeric suffix on collision. Empty headings are skipped.
|
|
52
|
+
*/
|
|
53
|
+
function* annotate(root: P5Node): Generator<AnnotatedHeading> {
|
|
54
|
+
const seen = new Map<string, number>();
|
|
55
|
+
for (const node of headings(root)) {
|
|
56
|
+
const text = textOf(node).replace(/\s+/g, " ").trim();
|
|
57
|
+
if (!text) continue;
|
|
58
|
+
const level: 2 | 3 = node.tagName === "h2" ? 2 : 3;
|
|
59
|
+
const explicit = getId(node);
|
|
60
|
+
let id: string;
|
|
61
|
+
if (explicit) {
|
|
62
|
+
id = explicit;
|
|
63
|
+
seen.set(id, (seen.get(id) ?? 0) + 1);
|
|
64
|
+
} else {
|
|
65
|
+
const base = slugifyHeading(text) || "section";
|
|
66
|
+
const n = seen.get(base) ?? 0;
|
|
67
|
+
seen.set(base, n + 1);
|
|
68
|
+
id = n === 0 ? base : `${base}-${n + 1}`;
|
|
69
|
+
}
|
|
70
|
+
yield { node, id, text, level };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** TOC entries (one per h2/h3) with stable anchor ids, in document order. */
|
|
75
|
+
export function toc(html: string): TocEntry[] {
|
|
76
|
+
const frag = parseFragment(html ?? "") as unknown as P5Node;
|
|
77
|
+
return [...annotate(frag)].map(({ id, text, level }) => ({ id, text, level }));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The same HTML with anchor ids added to any h2/h3 that lacks one (author ids
|
|
82
|
+
* untouched). Returns the input unchanged when every heading already has an id,
|
|
83
|
+
* so posts without generated anchors are byte-for-byte preserved.
|
|
84
|
+
*/
|
|
85
|
+
export function htmlWithHeadingIds(html: string): string {
|
|
86
|
+
const frag = parseFragment(html ?? "") as unknown as P5Node;
|
|
87
|
+
let changed = false;
|
|
88
|
+
for (const { node, id } of annotate(frag)) {
|
|
89
|
+
if (!getId(node)) {
|
|
90
|
+
node.attrs = [...(node.attrs ?? []), { name: "id", value: id }];
|
|
91
|
+
changed = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return changed ? serialize(frag as never) : (html ?? "");
|
|
95
|
+
}
|
|
@@ -166,7 +166,7 @@ export async function createToTClient(
|
|
|
166
166
|
tenant: TenantConfig,
|
|
167
167
|
d1?: D1Like,
|
|
168
168
|
): Promise<ToTClient> {
|
|
169
|
-
// Edge read replica
|
|
169
|
+
// Edge read replica: when a D1 binding is wired,
|
|
170
170
|
// serve reads from it (FTS5 search + SQL facets). Otherwise the bundled fixture
|
|
171
171
|
// snapshot renders the site offline. The tot20 HTTP catalog API has been retired,
|
|
172
172
|
// so the read path is fully edge-native.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* D1-backed ToTClient — the edge read-replica path
|
|
2
|
+
* D1-backed ToTClient — the edge read-replica path.
|
|
3
3
|
*
|
|
4
4
|
* Implements the same ToTClient interface as Fixture/Http, but every read is a D1
|
|
5
5
|
* query (FTS5 search, SQL faceted listing, row-blob retrieval) instead of an
|
|
@@ -56,7 +56,7 @@ export class D1ToTClient implements ToTClient {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
async getReviews(_handle: string): Promise<Review[]> {
|
|
59
|
-
//
|
|
59
|
+
// Reviews are display-via-metafields; the D1 catalog carries none.
|
|
60
60
|
return [];
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The ToTClient interface — the storefront's single product-truth contract.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Lives in its own module so the concrete backends (FixtureToTClient here,
|
|
5
5
|
* D1ToTClient in d1Client.ts) can both `implements ToTClient` without a circular
|
|
6
6
|
* module edge: d1Client imports only this contract, while ToTClient.ts imports
|
|
7
|
-
* D1ToTClient for its factory. ToTClient.ts re-exports this type
|
|
8
|
-
* `import type { ToTClient } from "./ToTClient"` call sites are unchanged.
|
|
7
|
+
* D1ToTClient for its factory. ToTClient.ts re-exports this type.
|
|
9
8
|
*/
|
|
10
9
|
import type {
|
|
11
10
|
CatalogCollection,
|
|
@@ -25,6 +24,6 @@ export interface ToTClient {
|
|
|
25
24
|
getFeatured(limit?: number): Promise<CatalogProduct[]>;
|
|
26
25
|
/** Full active catalog — used to build the per-tenant search index. */
|
|
27
26
|
getAllActiveProducts(): Promise<CatalogProduct[]>;
|
|
28
|
-
/** Full review content for a product
|
|
27
|
+
/** Full review content for a product. */
|
|
29
28
|
getReviews(handle: string): Promise<Review[]>;
|
|
30
29
|
}
|