@tokenoftrust/storefront-runner 1.4.2-rc.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/storefront/astro.config.mjs +3 -3
- package/apps/storefront/dev-plugins/tenant-hot-reload.mjs +8 -3
- package/apps/storefront/env.d.ts +54 -5
- package/apps/storefront/integrations/materialize-guard.mjs +12 -14
- package/apps/storefront/migrations-apps/0004_deep_morph.sql +36 -0
- package/apps/storefront/migrations-apps/0005_common_mystique.sql +23 -0
- package/apps/storefront/migrations-apps/0006_broad_microchip.sql +16 -0
- package/apps/storefront/migrations-apps/0007_brave_outlaw_kid.sql +15 -0
- package/apps/storefront/migrations-apps/0008_blue_dazzler.sql +11 -0
- package/apps/storefront/migrations-apps/0009_bored_shinobi_shaw.sql +15 -0
- package/apps/storefront/migrations-apps/0010_ws4_verified_provider_measurement.sql +35 -0
- package/apps/storefront/migrations-apps/meta/0004_snapshot.json +1474 -0
- package/apps/storefront/migrations-apps/meta/0005_snapshot.json +1617 -0
- package/apps/storefront/migrations-apps/meta/0006_snapshot.json +1716 -0
- package/apps/storefront/migrations-apps/meta/0007_snapshot.json +1812 -0
- package/apps/storefront/migrations-apps/meta/0008_snapshot.json +1881 -0
- package/apps/storefront/migrations-apps/meta/0009_snapshot.json +1979 -0
- package/apps/storefront/migrations-apps/meta/_journal.json +42 -0
- package/apps/storefront/public/apps/tot.demo.analytics/0.1.0/entry.js +42 -0
- package/apps/storefront/public/platform/amplitude-http/v1/entry.mjs +19 -0
- package/apps/storefront/public/platform/google-measurement/v1/entry.mjs +19 -0
- package/apps/storefront/public/shared/commerce-chrome.css +20 -2
- package/apps/storefront/scripts/build-v84-clean-clone-standalone.mjs +68 -0
- package/apps/storefront/scripts/deny-v84-clean-clone-standalone-capabilities.mjs +111 -0
- package/apps/storefront/scripts/deny-v84-dogfood-capabilities.mjs +2 -0
- package/apps/storefront/scripts/deny-v84-lifecycle-capabilities.mjs +247 -0
- package/apps/storefront/scripts/dogfood-v84-nonportable-routes.ts +73 -0
- package/apps/storefront/scripts/fixed-v84-native-install-producer.ts +79 -0
- package/apps/storefront/scripts/generated/v84-clean-clone-replay.bundle.mjs +10982 -0
- package/apps/storefront/scripts/import-v84-through-ws2.ts +38 -0
- package/apps/storefront/scripts/initialize-v84-lifecycle-tooling-dependency.ts +2 -0
- package/apps/storefront/scripts/initialize-v84-lifecycle-tooling.ts +4 -0
- package/apps/storefront/scripts/install-v84-native-through-ws1.ts +185 -0
- package/apps/storefront/scripts/prove-clone-isolation.ts +506 -0
- package/apps/storefront/scripts/replay-v84-clean-clone-pass.ts +148 -0
- package/apps/storefront/scripts/replay-v84-clean-clone-standalone.ts +35 -0
- package/apps/storefront/scripts/replay-v84-clean-clone.ts +214 -0
- package/apps/storefront/scripts/run-fixed-v84-native-install-producer.mjs +18 -0
- package/apps/storefront/scripts/run-v84-clone-isolation-proof.mjs +18 -0
- package/apps/storefront/scripts/run-v84-clone-lifecycle-proof.mjs +18 -0
- package/apps/storefront/scripts/run-v84-import-through-ws2-proof.mjs +17 -0
- package/apps/storefront/scripts/run-v84-nonportable-route-dogfood.mjs +15 -0
- package/apps/storefront/scripts/sanitize-v84-proof-environment.mjs +21 -0
- package/apps/storefront/scripts/v84CleanCloneGraphPin.ts +42 -0
- package/apps/storefront/scripts/v84CleanCloneSourceGraph.ts +145 -0
- package/apps/storefront/scripts/validate-v84-clone-lifecycle.ts +18 -0
- package/apps/storefront/src/components/Img.astro +1 -1
- package/apps/storefront/src/components/admin/AdminBlogTab.astro +19 -16
- package/apps/storefront/src/components/admin/AdminIntegrationsTab.astro +105 -0
- package/apps/storefront/src/components/admin/AdminPublishTab.astro +1057 -412
- package/apps/storefront/src/components/admin/AdminSettingsTab.astro +2 -2
- package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +5 -5
- package/apps/storefront/src/components/chrome/NavDropdown.astro +12 -0
- package/apps/storefront/src/components/chrome/SiteFooter.astro +7 -2
- package/apps/storefront/src/components/chrome/SiteHeader.astro +46 -10
- package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +1 -1
- package/apps/storefront/src/components/compliance/ComplianceNotice.astro +1 -2
- package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +1 -2
- package/apps/storefront/src/components/compliance/PactActNotice.astro +1 -1
- package/apps/storefront/src/components/compliance/Prop65Warning.astro +1 -2
- package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +2 -3
- package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +2 -2
- package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +2 -3
- package/apps/storefront/src/components/content/TrustStrip.astro +4 -4
- package/apps/storefront/src/components/islands/MobileNav.tsx +26 -1
- package/apps/storefront/src/components/islands/VariantSelector.tsx +27 -2
- package/apps/storefront/src/components/islands/useCheckoutHandoffCorrelation.ts +75 -0
- package/apps/storefront/src/components/membership/IllustrativeLabel.astro +1 -2
- package/apps/storefront/src/components/membership/TierCards.astro +2 -2
- package/apps/storefront/src/components/membership/TierComparisonTable.astro +2 -2
- package/apps/storefront/src/components/subscription/SavingsExplainer.astro +2 -2
- package/apps/storefront/src/config/adminTenantLookup.ts +35 -0
- package/apps/storefront/src/config/devTenantSeed.ts +9 -9
- package/apps/storefront/src/config/resolver.ts +18 -10
- package/apps/storefront/src/layouts/Layout.astro +100 -20
- package/apps/storefront/src/lib/activity/candidateSubmitLease.ts +87 -0
- package/apps/storefront/src/lib/activity/changeActorAttribution.ts +86 -6
- package/apps/storefront/src/lib/activity/deployVersion.ts +1 -1
- package/apps/storefront/src/lib/admin/adminShell.ts +2 -0
- package/apps/storefront/src/lib/admin/envelope.ts +1 -2
- package/apps/storefront/src/lib/apps/adminService.ts +10 -0
- package/apps/storefront/src/lib/apps/adminSession.ts +1 -1
- package/apps/storefront/src/lib/apps/appVersionStore.ts +281 -0
- package/apps/storefront/src/lib/apps/consentConfigStore.ts +228 -0
- package/apps/storefront/src/lib/apps/gtmMigrationInstall.ts +447 -0
- package/apps/storefront/src/lib/apps/gtmMigrationReport.ts +367 -0
- package/apps/storefront/src/lib/apps/gtmMigrationTab.ts +315 -0
- package/apps/storefront/src/lib/apps/integrationLifecycle.ts +614 -0
- package/apps/storefront/src/lib/apps/integrationLifecycleController.ts +125 -0
- package/apps/storefront/src/lib/apps/integrationReadModel.ts +563 -0
- package/apps/storefront/src/lib/apps/integrationsTab.ts +547 -0
- package/apps/storefront/src/lib/apps/integrationsView.ts +106 -0
- package/apps/storefront/src/lib/apps/managedAnalyticsService.ts +599 -0
- package/apps/storefront/src/lib/apps/orders/orderConversionD1.ts +150 -0
- package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +8 -0
- package/apps/storefront/src/lib/apps/orders/ordersStore.ts +1 -1
- package/apps/storefront/src/lib/apps/orders/verifiedProviderMeasurement.ts +117 -0
- package/apps/storefront/src/lib/apps/registryService.ts +264 -10
- package/apps/storefront/src/lib/apps/tenantIntegrationMaterialization.ts +170 -0
- package/apps/storefront/src/lib/apps/v84CleanCloneReplayContext.ts +16 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleCacheEvidence.ts +105 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleEvidence.ts +177 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleMaterialization.ts +251 -0
- package/apps/storefront/src/lib/apps/v84CloneLifecycleSemantics.ts +241 -0
- package/apps/storefront/src/lib/apps/v84CloneMigrationEvidence.ts +211 -0
- package/apps/storefront/src/lib/apps/v84CloneNativeInstallEvidence.ts +409 -0
- package/apps/storefront/src/lib/apps/v84NonportableCodeCoaching.ts +368 -0
- package/apps/storefront/src/lib/apps/v84NonportableRouteContract.ts +188 -0
- package/apps/storefront/src/lib/apps/v84NonportableRouteDogfood.ts +291 -0
- package/apps/storefront/src/lib/apps/ws1ManagedAnalyticsClient.ts +95 -0
- package/apps/storefront/src/lib/auth/adminApiGuard.ts +66 -0
- package/apps/storefront/src/lib/auth/adminEntry.ts +2 -2
- package/apps/storefront/src/lib/auth/adminLanding.ts +88 -0
- package/apps/storefront/src/lib/blog/collection.ts +114 -17
- package/apps/storefront/src/lib/blog/markdown.ts +1 -1
- package/apps/storefront/src/lib/blog/provider.ts +76 -9
- package/apps/storefront/src/lib/blog/types.ts +9 -9
- package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome-assignments.example.json +6 -0
- package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome.example.json +79 -0
- package/apps/storefront/src/lib/chrome/model.ts +48 -253
- package/apps/storefront/src/lib/chrome/navCurrent.ts +29 -0
- package/apps/storefront/src/lib/chrome/parseConfig.ts +18 -32
- package/apps/storefront/src/lib/chrome/variant.ts +39 -0
- package/apps/storefront/src/lib/commerce/checkoutHandoffCorrelation.ts +105 -0
- package/apps/storefront/src/lib/compliance/tamper-sentinel-boot.ts +152 -0
- package/apps/storefront/src/lib/compliance/tamper-sentinel.ts +327 -0
- package/apps/storefront/src/lib/content/index.ts +5 -5
- package/apps/storefront/src/lib/content-edit/applyDiff.ts +1 -1
- package/apps/storefront/src/lib/content-edit/route.ts +1 -1
- package/apps/storefront/src/lib/d1/catalog.ts +12 -0
- package/apps/storefront/src/lib/d1/schema-apps.ts +276 -0
- package/apps/storefront/src/lib/dev/cockpit/ask.ts +49 -0
- package/apps/storefront/src/lib/dev/cockpit/clickToSource.ts +71 -0
- package/apps/storefront/src/lib/dev/cockpit/copyCommand.ts +227 -0
- package/apps/storefront/src/lib/dev/cockpit/files.ts +249 -0
- package/apps/storefront/src/lib/dev/cockpit/hostedActivity.ts +500 -0
- package/apps/storefront/src/lib/dev/cockpit/infoPopover.ts +12 -0
- package/apps/storefront/src/lib/dev/cockpit/mcpCopy.ts +34 -0
- package/apps/storefront/src/lib/dev/cockpit/monitor.ts +107 -0
- package/apps/storefront/src/lib/dev/cockpit/stepper.ts +116 -0
- package/apps/storefront/src/lib/dev/cockpit/themeToggle.ts +23 -0
- package/apps/storefront/src/lib/dev/runtimeStore.ts +1 -1
- package/apps/storefront/src/lib/edgeCache.ts +18 -6
- package/apps/storefront/src/lib/email/candidateConflictEmail.ts +80 -0
- package/apps/storefront/src/lib/integration/browserEnvironment.ts +137 -0
- package/apps/storefront/src/lib/integration/managedInstallDeclarations.ts +72 -0
- package/apps/storefront/src/lib/integration/nonceStamp.ts +49 -0
- package/apps/storefront/src/lib/integration/tenantDeclarations.ts +116 -0
- package/apps/storefront/src/lib/membership/eligibility.ts +1 -1
- package/apps/storefront/src/lib/membership/model.ts +1 -2
- package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +2 -2
- package/apps/storefront/src/lib/newsletter/consent.ts +2 -2
- package/apps/storefront/src/lib/newsletter/send.ts +3 -3
- package/apps/storefront/src/lib/previewReload.ts +57 -1
- package/apps/storefront/src/lib/publish/adminPublishTab.ts +1775 -669
- package/apps/storefront/src/lib/publish/buildStream.ts +269 -0
- package/apps/storefront/src/lib/publish/collapsePersistence.ts +72 -0
- package/apps/storefront/src/lib/publish/lifecycleState.ts +369 -0
- package/apps/storefront/src/lib/publish/liveReleaseSummary.ts +29 -0
- package/apps/storefront/src/lib/publish/mergeDoctorOnFailure.ts +78 -0
- package/apps/storefront/src/lib/publish/mergeHealthBanner.ts +62 -0
- package/apps/storefront/src/lib/publish/mergeRowFindings.ts +124 -0
- package/apps/storefront/src/lib/publish/mergeSupportEscalation.ts +75 -0
- package/apps/storefront/src/lib/publish/publish-guard.ts +88 -0
- package/apps/storefront/src/lib/publish/publishFormat.ts +165 -0
- package/apps/storefront/src/lib/publish/publishHero.ts +177 -0
- package/apps/storefront/src/lib/publish/reviewRelease/changeState.ts +66 -0
- package/apps/storefront/src/lib/publish/reviewRelease/copy.ts +141 -0
- package/apps/storefront/src/lib/publish/reviewRelease/index.ts +41 -0
- package/apps/storefront/src/lib/publish/reviewRelease/permissions.ts +47 -0
- package/apps/storefront/src/lib/publish/reviewRelease/releaseState.ts +42 -0
- package/apps/storefront/src/lib/publish/reviewRelease/types.ts +59 -0
- package/apps/storefront/src/lib/publish/reviewRelease/viewModel.ts +440 -0
- package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/actions.ts +161 -0
- package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/controller.ts +325 -0
- package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/render.ts +241 -0
- package/apps/storefront/src/lib/publish/shipWorkspace.ts +22 -3
- package/apps/storefront/src/lib/publish/sseRoute.ts +119 -0
- package/apps/storefront/src/lib/publish/streamLogConsole.ts +142 -0
- package/apps/storefront/src/lib/publish/versionNumber.ts +52 -0
- package/apps/storefront/src/lib/rawChrome.ts +125 -47
- package/apps/storefront/src/lib/rawMarketingHtml.ts +74 -3
- package/apps/storefront/src/lib/seo/alternates.ts +1 -1
- package/apps/storefront/src/lib/social/notify.ts +4 -4
- package/apps/storefront/src/lib/storyblok/content-model.ts +7 -33
- package/apps/storefront/src/lib/storyblok/provider.ts +203 -69
- package/apps/storefront/src/lib/subscription/model.ts +4 -4
- package/apps/storefront/src/lib/the-build/provider.ts +9 -4
- package/apps/storefront/src/middleware/index.ts +273 -51
- package/apps/storefront/src/pages/[...slug].astro +9 -4
- package/apps/storefront/src/pages/admin/review-release.astro +265 -0
- package/apps/storefront/src/pages/admin/select.astro +96 -0
- package/apps/storefront/src/pages/admin.astro +16 -2
- package/apps/storefront/src/pages/api/activity.ts +8 -8
- package/apps/storefront/src/pages/api/admin/activity-alerts.ts +5 -20
- package/apps/storefront/src/pages/api/admin/orders/[id].ts +7 -2
- package/apps/storefront/src/pages/api/admin/orders.ts +8 -2
- package/apps/storefront/src/pages/api/apps/admin/gtm-migration-install.ts +174 -0
- package/apps/storefront/src/pages/api/apps/admin/gtm-migration.ts +96 -0
- package/apps/storefront/src/pages/api/apps/admin/integration-lifecycle.ts +118 -0
- package/apps/storefront/src/pages/api/apps/admin/integrations.ts +89 -0
- package/apps/storefront/src/pages/api/apps/admin/platform-adapters.ts +85 -0
- package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +74 -2
- package/apps/storefront/src/pages/api/commerce/checkout-handoff.ts +77 -0
- package/apps/storefront/src/pages/api/compliance/tamper.ts +88 -0
- package/apps/storefront/src/pages/api/integrations/v1/[operation].ts +108 -0
- package/apps/storefront/src/pages/api/rum/vitals.ts +1 -2
- package/apps/storefront/src/pages/blog/[slug].astro +5 -5
- package/apps/storefront/src/pages/blog/author/[author].astro +3 -3
- package/apps/storefront/src/pages/blog/category/[category].astro +2 -2
- package/apps/storefront/src/pages/blog/index.astro +2 -2
- package/apps/storefront/src/pages/blog/tag/[tag].astro +2 -2
- package/apps/storefront/src/pages/cockpit.astro +61 -1362
- package/apps/storefront/src/pages/index.astro +10 -5
- package/apps/storefront/src/pages/llms.txt.ts +1 -1
- package/apps/storefront/src/pages/products/[handle].astro +7 -6
- package/apps/storefront/src/pages/sitemap.xml.ts +2 -2
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +42 -31
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +8 -3
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +6 -2
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +6 -2
- package/apps/storefront/src/pages/style-guide/index.astro +19 -5
- package/apps/storefront/src/pages/tenants/[id]/[...path].ts +38 -2
- package/apps/storefront/src/pages/the-build/[slug].astro +4 -4
- package/apps/storefront/src/pages/the-build/index.astro +2 -2
- package/apps/storefront/src/pages/the-build/rss.xml.ts +2 -2
- package/apps/storefront/src/styles/admin.css +27 -1
- package/apps/storefront/src/themes/tenants/index.ts +19 -7
- package/apps/storefront/tsconfig.json +1 -1
- package/package.json +1 -1
- package/packages/public-runtime/package.json +2 -1
- package/packages/public-runtime/schemas/managed-analytics/v1/adapter-definition.schema.json +427 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/create-integration-install-request.schema.json +161 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/create-migration-draft-request.schema.json +157 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/delete-integration-install-request.schema.json +84 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/delete-migration-draft-request.schema.json +84 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/error-envelope.schema.json +180 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-adapter-definition-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-install-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-revision-request.schema.json +79 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/get-migration-draft-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/integration-install.schema.json +167 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/integration-revision.schema.json +208 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/list-adapter-definitions-request.schema.json +53 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-installs-request.schema.json +53 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-revisions-request.schema.json +82 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/migration-draft.schema.json +218 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/mutation-request.schema.json +52 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/mutation-success-envelope.schema.json +49 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/read-request.schema.json +20 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/read-success-envelope.schema.json +45 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/revise-integration-install-request.schema.json +156 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/set-integration-install-status-request.schema.json +92 -0
- package/packages/public-runtime/schemas/managed-analytics/v1/update-migration-draft-request.schema.json +184 -0
- package/packages/public-runtime/scripts/generate-managed-analytics-api-v1-schemas.mjs +13 -0
- package/packages/public-runtime/src/activity/catalog.ts +41 -37
- package/packages/public-runtime/src/activity/event.ts +6 -6
- package/packages/public-runtime/src/activity/index.ts +2 -2
- package/packages/public-runtime/src/activity/redaction.ts +4 -4
- package/packages/public-runtime/src/candidate-index.ts +42 -8
- package/packages/public-runtime/src/checkout-orders.ts +2 -2
- package/packages/public-runtime/src/checkout-style-publish.ts +2 -2
- package/packages/public-runtime/src/checkout-style.ts +7 -7
- package/packages/public-runtime/src/checkout.ts +3 -3
- package/packages/public-runtime/src/chrome.ts +777 -0
- package/packages/public-runtime/src/compliance-obligations.ts +310 -0
- package/packages/public-runtime/src/csp.ts +99 -0
- package/packages/public-runtime/src/customization-runtime.ts +32 -1
- package/packages/public-runtime/src/destination-webhook/contract.ts +353 -0
- package/packages/public-runtime/src/embed-catalog.d.mts +9 -0
- package/packages/public-runtime/src/embed-catalog.mjs +40 -0
- package/packages/public-runtime/src/evidence.ts +288 -0
- package/packages/public-runtime/src/gtm-migration/bounds.ts +138 -0
- package/packages/public-runtime/src/gtm-migration/disposition-rules.ts +361 -0
- package/packages/public-runtime/src/gtm-migration/dispositions.ts +181 -0
- package/packages/public-runtime/src/gtm-migration/draft-generator.ts +400 -0
- package/packages/public-runtime/src/gtm-migration/graph.ts +468 -0
- package/packages/public-runtime/src/gtm-migration/index.ts +95 -0
- package/packages/public-runtime/src/gtm-migration/parse.ts +410 -0
- package/packages/public-runtime/src/gtm-migration/references.ts +266 -0
- package/packages/public-runtime/src/gtm-migration/types.ts +86 -0
- package/packages/public-runtime/src/index.ts +16 -1
- package/packages/public-runtime/src/integration/assurance-decision.ts +259 -0
- package/packages/public-runtime/src/integration/assurance.ts +228 -0
- package/packages/public-runtime/src/integration/candidate-evidence.ts +377 -0
- package/packages/public-runtime/src/integration/commerce-broker.ts +497 -0
- package/packages/public-runtime/src/integration/consent-broker.ts +337 -0
- package/packages/public-runtime/src/integration/consent-cmp-demand.ts +115 -0
- package/packages/public-runtime/src/integration/consent-config.ts +260 -0
- package/packages/public-runtime/src/integration/consent-preview.ts +125 -0
- package/packages/public-runtime/src/integration/correlation-token.ts +444 -0
- package/packages/public-runtime/src/integration/csp-compiler.ts +267 -0
- package/packages/public-runtime/src/integration/csp.ts +105 -0
- package/packages/public-runtime/src/integration/digest.ts +43 -0
- package/packages/public-runtime/src/integration/environment.ts +228 -0
- package/packages/public-runtime/src/integration/events-catalog.ts +186 -0
- package/packages/public-runtime/src/integration/events.ts +701 -0
- package/packages/public-runtime/src/integration/g2-action-boundary.ts +106 -0
- package/packages/public-runtime/src/integration/index.ts +90 -0
- package/packages/public-runtime/src/integration/interim-bridge.ts +138 -0
- package/packages/public-runtime/src/integration/lifecycle-boot.ts +317 -0
- package/packages/public-runtime/src/integration/lifecycle-runtime.ts +393 -0
- package/packages/public-runtime/src/integration/lifecycle.ts +94 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.d.mts +2 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.mjs +10 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1.schemas.ts +382 -0
- package/packages/public-runtime/src/integration/managed-analytics-api-v1.ts +684 -0
- package/packages/public-runtime/src/integration/managed-analytics-bridge.ts +383 -0
- package/packages/public-runtime/src/integration/managed-analytics-value-safety.ts +14 -0
- package/packages/public-runtime/src/integration/managed-analytics.ts +277 -0
- package/packages/public-runtime/src/integration/manifest.ts +470 -0
- package/packages/public-runtime/src/integration/native-amplitude.ts +362 -0
- package/packages/public-runtime/src/integration/native-ga4.ts +352 -0
- package/packages/public-runtime/src/integration/observability.ts +451 -0
- package/packages/public-runtime/src/integration/order-conversion.ts +0 -0
- package/packages/public-runtime/src/integration/phases.ts +182 -0
- package/packages/public-runtime/src/integration/plan.ts +112 -0
- package/packages/public-runtime/src/integration/platform-adapter-runtime.ts +146 -0
- package/packages/public-runtime/src/integration/platform-adapters.ts +671 -0
- package/packages/public-runtime/src/integration/promotion-gate.ts +451 -0
- package/packages/public-runtime/src/integration/provider-checkout-extension.ts +425 -0
- package/packages/public-runtime/src/integration/receipt-measurement.ts +370 -0
- package/packages/public-runtime/src/integration/regulated-parent-cert.ts +311 -0
- package/packages/public-runtime/src/integration/render-phases.ts +267 -0
- package/packages/public-runtime/src/integration/resolve.ts +465 -0
- package/packages/public-runtime/src/integration/result.ts +239 -0
- package/packages/public-runtime/src/integration/secrets.ts +92 -0
- package/packages/public-runtime/src/integration/tamper-evidence.ts +205 -0
- package/packages/public-runtime/src/integration/tamper-recovery.ts +127 -0
- package/packages/public-runtime/src/integration/version.ts +92 -0
- package/packages/public-runtime/src/integration-capabilities.ts +520 -0
- package/packages/public-runtime/src/membership.ts +2 -2
- package/packages/public-runtime/src/raw-html-policy.ts +2 -4
- package/packages/public-runtime/src/regulated-commerce/broker/consent-dedupe.ts +144 -0
- package/packages/public-runtime/src/regulated-commerce/correlation/contract.ts +177 -0
- package/packages/public-runtime/src/regulated-commerce/diagnostics/local-dispatch.ts +24 -0
- package/packages/public-runtime/src/regulated-commerce/diagnostics/read-model.ts +69 -0
- package/packages/public-runtime/src/regulated-commerce/dispatch/core.ts +134 -0
- package/packages/public-runtime/src/regulated-commerce/events/contract.ts +113 -0
- package/packages/public-runtime/src/regulated-commerce/ledger/core.ts +81 -0
- package/packages/public-runtime/src/regulated-commerce/mappings/ga4-ads.ts +87 -0
- package/packages/public-runtime/src/regulated-commerce/provider-order/bridge.ts +52 -0
- package/packages/public-runtime/src/regulated-commerce/purchase-truth/contract.ts +252 -0
- package/packages/public-runtime/src/regulated-commerce/sources/accepted-browser-operation.ts +67 -0
- package/packages/public-runtime/src/regulated-commerce/testing/fake-destination.ts +93 -0
- package/packages/public-runtime/src/static-bundle.ts +5 -5
- package/packages/public-runtime/src/tenant-assets.ts +143 -4
- package/packages/public-runtime/src/tenant.ts +136 -9
- package/packages/public-runtime/tests/fixtures/integration/browser-environment.example.json +8 -0
- package/packages/public-runtime/tests/fixtures/integration/commerce-event.example.json +44 -0
- package/packages/public-runtime/tests/fixtures/integration/commerce-order-event.example.json +44 -0
- package/packages/public-runtime/tests/fixtures/integration/compliance-assurance-record.example.json +50 -0
- package/packages/public-runtime/tests/fixtures/integration/integration-manifest-v2.example.json +120 -0
- package/packages/public-runtime/tests/fixtures/integration/managed-analytics-v1/fake-adapter-catalog.json +35 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-action-registry.example.json +11 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/README.md +22 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/entry.js +30 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/manifest.json +75 -0
- package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/public-config.json +3 -0
- package/packages/public-runtime/tests/fixtures/regulated-commerce/fake-destinations.ts +38 -0
- package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.provenance.json +29 -0
- package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.redacted.json +3397 -0
- package/scripts/build/copy-tenant-assets.mjs +12 -5
- package/scripts/dev/ai-edit.mjs +2 -1
- package/scripts/dev/file-browser.mjs +2 -2
- package/scripts/dev/file-writer.mjs +2 -2
- package/scripts/dev/integration-guardrails.mjs +498 -0
- package/scripts/dev/safe-path.mjs +2 -2
- package/scripts/dev/tenant-source-root.mjs +3 -2
- package/scripts/tot-dev.mjs +5 -4
|
@@ -57,8 +57,13 @@ if (rawHtml && rawHtmlPolicy(tenant).allowed) {
|
|
|
57
57
|
// Shared chrome: if the tenant ships a chrome.html wrapper AND this home is a
|
|
58
58
|
// body-only fragment, rawHtmlResponse splices it in; a full document serves
|
|
59
59
|
// verbatim (backward-compatible).
|
|
60
|
-
const chromeWrapper = await content.getChromeHtml();
|
|
61
|
-
return rawHtmlResponse(rawHtml, {
|
|
60
|
+
const chromeWrapper = await content.getChromeHtml("/");
|
|
61
|
+
return rawHtmlResponse(rawHtml, {
|
|
62
|
+
nonce: Astro.locals.cspNonce,
|
|
63
|
+
basePath,
|
|
64
|
+
chromeWrapper,
|
|
65
|
+
plan: Astro.locals.integrationPlan,
|
|
66
|
+
});
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
const home = await content.getHome();
|
|
@@ -143,9 +148,9 @@ for (const block of marketing ? [] : home.blocks) {
|
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
|
|
146
|
-
// Private-app widgets
|
|
151
|
+
// Private-app widgets — home.section slot. Commerce-home only; marketing-
|
|
147
152
|
// tenant homes (raw HTML, above, and the marketing-block home) are out of
|
|
148
|
-
// scope
|
|
153
|
+
// scope (deferred). No dark-mode preference infra exists yet — "light"
|
|
149
154
|
// is the only theme hint until that lands.
|
|
150
155
|
const homeSectionWidgets = marketing
|
|
151
156
|
? []
|
|
@@ -326,7 +331,7 @@ const homeSectionWidgets = marketing
|
|
|
326
331
|
return null;
|
|
327
332
|
})
|
|
328
333
|
}
|
|
329
|
-
{/* Private-app widgets (
|
|
334
|
+
{/* Private-app widgets (home.section) — sandboxed per install. */}
|
|
330
335
|
{homeSectionWidgets.map((w) => (
|
|
331
336
|
<Section>
|
|
332
337
|
<AppWidgetFrame
|
|
@@ -34,7 +34,7 @@ export async function GET(context: APIContext): Promise<Response> {
|
|
|
34
34
|
content.listPages(),
|
|
35
35
|
tot.getFeatured(12),
|
|
36
36
|
content.getHome().catch(() => null),
|
|
37
|
-
listBlogPosts(tenant.tenant_id),
|
|
37
|
+
listBlogPosts(tenant.tenant_id, content),
|
|
38
38
|
]);
|
|
39
39
|
// Empty synthesized collections (no active members) never make the guide —
|
|
40
40
|
// an LLM shouldn't be pointed at a URL that resolves to zero products.
|
|
@@ -60,7 +60,7 @@ if (!product || product.status === "archived") {
|
|
|
60
60
|
}
|
|
61
61
|
const isDraft = product.status !== "active";
|
|
62
62
|
|
|
63
|
-
// Private-app widgets
|
|
63
|
+
// Private-app widgets — product.aside slot, one iframe per live install.
|
|
64
64
|
// No dark-mode preference is resolved anywhere in the storefront yet; "light"
|
|
65
65
|
// is the only theme hint until that infra exists.
|
|
66
66
|
const productAsideWidgets = await renderWidgetSlot(
|
|
@@ -111,7 +111,7 @@ const mf = (ns: string, key: string) =>
|
|
|
111
111
|
product.metafields.find((m) => m.namespace === ns && m.key === key)?.value;
|
|
112
112
|
|
|
113
113
|
// Reviews — REAL aggregate from the store's reviews app, mirrored to metafields.
|
|
114
|
-
// readReviewAggregate is the single, real-or-absent reader
|
|
114
|
+
// readReviewAggregate is the single, real-or-absent reader: it parses both
|
|
115
115
|
// the bare and JSON-blob rating forms and the real count key, and returns {0,0}
|
|
116
116
|
// unless BOTH numbers are real positives — so no fabricated rating can render.
|
|
117
117
|
const { average: reviewAvg, count: reviewCount } = readReviewAggregate(product);
|
|
@@ -181,7 +181,7 @@ const available = isAvailable(product);
|
|
|
181
181
|
// side so the island can render a signed, tamper-proof form. In `signed` mode a
|
|
182
182
|
// missing secret means we render NO cart (never a tamperable form); the
|
|
183
183
|
// `unsigned-demo` mode needs no secret. Drafts still get a cart (preview links).
|
|
184
|
-
// Membership + Autopilot mechanics
|
|
184
|
+
// Membership + Autopilot mechanics. Member pricing renders only once a
|
|
185
185
|
// real eligibility signal flows through resolveMemberContext (Phase 2); Phase 1
|
|
186
186
|
// is anonymous. Autopilot (subscription options) is hidden when the tenant has
|
|
187
187
|
// set commerce.autopilot.enabled = false (hide-at-launch).
|
|
@@ -198,7 +198,7 @@ const pricing: {
|
|
|
198
198
|
? { membershipRule, stacking: membershipProgram?.stacking ?? DEFAULT_STACKING_POLICY }
|
|
199
199
|
: undefined;
|
|
200
200
|
const autopilotEnabled = isAutopilotEnabled(tenant.commerce?.autopilot);
|
|
201
|
-
// Server-side pricing context
|
|
201
|
+
// Server-side pricing context. The SIGNED price is the member-adjusted
|
|
202
202
|
// effective price for THIS request's resolved eligibility — never the list price,
|
|
203
203
|
// and never re-derived client-side. Phase 1 resolves anonymous, so this yields the
|
|
204
204
|
// list/subscription price; a Phase-2 member request signs their member price.
|
|
@@ -366,8 +366,9 @@ const jsonLd = [productJsonLd, breadcrumbLd(crumbs, canonicalBase)];
|
|
|
366
366
|
productTitle={product.title}
|
|
367
367
|
checkoutCart={checkoutCart}
|
|
368
368
|
pricing={pricing}
|
|
369
|
+
handoffUrl={withBase(basePath, "/api/commerce/checkout-handoff")}
|
|
369
370
|
/>
|
|
370
|
-
{/* Regulated-tenant checkout ENFORCEMENT gate
|
|
371
|
+
{/* Regulated-tenant checkout ENFORCEMENT gate. Intercepts the
|
|
371
372
|
managed-cart handoff to clear age + ship-to compliance server-side
|
|
372
373
|
before the external checkout. Only mounts when a store is wired AND
|
|
373
374
|
the tenant is regulated. */}
|
|
@@ -392,7 +393,7 @@ const jsonLd = [productJsonLd, breadcrumbLd(crumbs, canonicalBase)];
|
|
|
392
393
|
</button>
|
|
393
394
|
</div>
|
|
394
395
|
|
|
395
|
-
{/* Private-app widgets (
|
|
396
|
+
{/* Private-app widgets (product.aside) — sandboxed per install. */}
|
|
396
397
|
{productAsideWidgets.map((w) => (
|
|
397
398
|
<div class="mt-7">
|
|
398
399
|
<AppWidgetFrame
|
|
@@ -67,7 +67,7 @@ export async function GET(context: APIContext): Promise<Response> {
|
|
|
67
67
|
urls.push({ loc: `${base}/${page.slug}` });
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const blogPosts = await listBlogPosts(tenant.tenant_id);
|
|
70
|
+
const blogPosts = await listBlogPosts(tenant.tenant_id, content);
|
|
71
71
|
if (blogPosts.length > 0) {
|
|
72
72
|
urls.push({ loc: `${base}/blog/` });
|
|
73
73
|
for (const post of blogPosts) {
|
|
@@ -85,7 +85,7 @@ export async function GET(context: APIContext): Promise<Response> {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const buildPosts = await listBuildPosts(tenant.tenant_id);
|
|
88
|
+
const buildPosts = await listBuildPosts(tenant.tenant_id, { content });
|
|
89
89
|
if (buildPosts.length > 0) {
|
|
90
90
|
urls.push({ loc: `${base}/the-build/` });
|
|
91
91
|
for (const post of buildPosts) {
|
|
@@ -20,6 +20,7 @@ export const prerender = false;
|
|
|
20
20
|
// utilities + reference theme-token fallbacks so the (token-styled) components
|
|
21
21
|
// render here without the app Layout. The `.sg-commerce` wrapper pins the
|
|
22
22
|
// reference palette so they look coherent regardless of the marketing theme CSS.
|
|
23
|
+
import { tenantDirSegment } from "@tot/public-runtime";
|
|
23
24
|
import "@/styles/global.css";
|
|
24
25
|
import PriceDisplay from "@/components/commerce/PriceDisplay.astro";
|
|
25
26
|
import RatingStars from "@/components/commerce/RatingStars.astro";
|
|
@@ -88,26 +89,27 @@ const cspNonce = Astro.locals.cspNonce;
|
|
|
88
89
|
|
|
89
90
|
// --- Sample chrome data (preview-only; no live tenant content) ----------------
|
|
90
91
|
const sampleNav: ChromeNavItem[] = [
|
|
91
|
-
{ label: "New", href: "#", flag: true, badge: "NEW" },
|
|
92
|
+
{ id: "nav-new", label: "New", href: "#", flag: true, badge: "NEW" },
|
|
92
93
|
{
|
|
94
|
+
id: "nav-shop",
|
|
93
95
|
label: "Shop",
|
|
94
96
|
href: "#",
|
|
95
97
|
columns: [
|
|
96
|
-
{ title: "Category", links: [{ label: "Disposables", href: "#" }, { label: "E-Liquid", href: "#" }, { label: "Devices", href: "#" }] },
|
|
97
|
-
{ title: "Featured", links: [{ label: "Best Sellers", href: "#" }, { label: "On Sale", href: "#", badge: "%" }] },
|
|
98
|
-
{ title: "Brands", links: [{ label: "Northwind", href: "#" }, { label: "Summit Co.", href: "#" }] },
|
|
98
|
+
{ title: "Category", links: [{ id: "nav-shop-disposables", label: "Disposables", href: "#" }, { id: "nav-shop-eliquid", label: "E-Liquid", href: "#" }, { id: "nav-shop-devices", label: "Devices", href: "#" }] },
|
|
99
|
+
{ title: "Featured", links: [{ id: "nav-shop-bestsellers", label: "Best Sellers", href: "#" }, { id: "nav-shop-onsale", label: "On Sale", href: "#", badge: "%" }] },
|
|
100
|
+
{ title: "Brands", links: [{ id: "nav-shop-northwind", label: "Northwind", href: "#" }, { id: "nav-shop-summit", label: "Summit Co.", href: "#" }] },
|
|
99
101
|
],
|
|
100
102
|
},
|
|
101
|
-
{ label: "Coils & Parts", href: "#", children: [{ label: "Coils", href: "#" }, { label: "Pods", href: "#" }, { label: "Batteries", href: "#" }] },
|
|
102
|
-
{ label: "On Sale", href: "#" },
|
|
103
|
+
{ id: "nav-coils", label: "Coils & Parts", href: "#", children: [{ id: "nav-coils-coils", label: "Coils", href: "#" }, { id: "nav-coils-pods", label: "Pods", href: "#" }, { id: "nav-coils-batteries", label: "Batteries", href: "#" }] },
|
|
104
|
+
{ id: "nav-sale", label: "On Sale", href: "#" },
|
|
103
105
|
];
|
|
104
106
|
const sampleSocial = [
|
|
105
107
|
{ label: "X", href: "#", iconPath: "M18.9 2H22l-7.1 8.1L23 22h-6.6l-5-6.6L5.7 22H2.6l7.6-8.7L1.5 2h6.8l4.5 6 5.1-6z" },
|
|
106
108
|
];
|
|
107
109
|
const sampleFooterCols = [
|
|
108
|
-
{ title: "Shop", links: [{ label: "Disposables", href: "#" }, { label: "E-Liquid", href: "#" }, { label: "Devices", href: "#" }] },
|
|
109
|
-
{ title: "Support", links: [{ label: "Contact", href: "#" }, { label: "Shipping", href: "#" }, { label: "Returns", href: "#" }] },
|
|
110
|
-
{ title: "Company", links: [{ label: "About", href: "#" }, { label: "Blog", href: "#" }] },
|
|
110
|
+
{ title: "Shop", links: [{ id: "ftr-shop-disposables", label: "Disposables", href: "#" }, { id: "ftr-shop-eliquid", label: "E-Liquid", href: "#" }, { id: "ftr-shop-devices", label: "Devices", href: "#" }] },
|
|
111
|
+
{ title: "Support", links: [{ id: "ftr-support-contact", label: "Contact", href: "#" }, { id: "ftr-support-shipping", label: "Shipping", href: "#" }, { id: "ftr-support-returns", label: "Returns", href: "#" }] },
|
|
112
|
+
{ title: "Company", links: [{ id: "ftr-company-about", label: "About", href: "#" }, { id: "ftr-company-blog", label: "Blog", href: "#" }] },
|
|
111
113
|
];
|
|
112
114
|
// BrandGrid samples: text-wordmark tiles and logo-image tiles (Img renders
|
|
113
115
|
// deterministic placeholders offline so the image code path is exercised
|
|
@@ -125,7 +127,7 @@ const sampleBrandsLogo: Brand[] = [
|
|
|
125
127
|
{ label: "Pod King", href: "#", logoSrc: "#", logoWidth: 200, logoHeight: 100 },
|
|
126
128
|
{ label: "Flavor Beast", href: "#", logoSrc: "#", logoWidth: 200, logoHeight: 100 },
|
|
127
129
|
];
|
|
128
|
-
// Review/UGC samples
|
|
130
|
+
// Review/UGC samples: illustrative fixture reviews
|
|
129
131
|
// ONLY, for previewing ReviewSummary/ReviewList token styling in isolation —
|
|
130
132
|
// never sourced from or rendered on a live product page (see
|
|
131
133
|
// docs/architecture/review-markup-policy.md; real callers pass tot.getReviews()
|
|
@@ -135,7 +137,7 @@ const sampleReviews: Review[] = [
|
|
|
135
137
|
{ author: "Priya K.", rating: 4, body: "Good overall, battery life could be a bit longer.", date: "2026-05-18", verifiedBuyer: true },
|
|
136
138
|
{ author: "T. Nguyen", rating: 3, title: "Decent, not amazing", body: "Does the job but nothing stands out versus similar devices.", date: "2026-04-30" },
|
|
137
139
|
];
|
|
138
|
-
// Blog/article samples
|
|
140
|
+
// Blog/article samples: featured-image cards (Img renders deterministic
|
|
139
141
|
// placeholders offline so the image path is exercised) + one image-less card
|
|
140
142
|
// (token-tinted placeholder band). Meta is illustrative example copy only.
|
|
141
143
|
const sampleArticles: Article[] = [
|
|
@@ -236,7 +238,7 @@ const sampleComparisonRows: ComparisonRow[] = [
|
|
|
236
238
|
{ label: "Cancel anytime", cells: [null, true, true] },
|
|
237
239
|
];
|
|
238
240
|
|
|
239
|
-
// --- Sample structured content
|
|
241
|
+
// --- Sample structured content — the DATA a policy page is driven by,
|
|
240
242
|
// replacing a hand-authored HTML/CSS fragment. Exercises headings (TOC),
|
|
241
243
|
// rich-text links, lists, a definition glossary, tone callouts, a contact
|
|
242
244
|
// block, and a needs-review flag (reviewer-only). ---------------------------
|
|
@@ -293,13 +295,13 @@ const sampleProseSections: ProseSection[] = [
|
|
|
293
295
|
},
|
|
294
296
|
];
|
|
295
297
|
|
|
296
|
-
// Trust strip
|
|
298
|
+
// Trust strip: mixes real claims + a real rating with
|
|
297
299
|
// fabrication vectors that MUST be dropped — the guide proves real-or-absent.
|
|
298
300
|
const sampleTrustStrip: TrustStripItem[] = [
|
|
299
301
|
{ kind: "claim", label: "Ships from USA" },
|
|
300
302
|
{ kind: "claim", label: "Lab-tested" },
|
|
301
303
|
{ kind: "rating", average: 4.9, count: 369, label: "avg rating" },
|
|
302
|
-
{ kind: "claim", label: "Based on 369 reviews" }, // fabricated → dropped
|
|
304
|
+
{ kind: "claim", label: "Based on 369 reviews" }, // fabricated → dropped
|
|
303
305
|
{ kind: "rating", average: 5, count: 0 }, // half-populated → dropped
|
|
304
306
|
];
|
|
305
307
|
|
|
@@ -458,10 +460,13 @@ const sampleMarketingBlocks: MarketingBlock[] = [
|
|
|
458
460
|
// Colocated repo-root layout: from src/pages/style-guide/[tenant]/ the repo
|
|
459
461
|
// root is six levels up.
|
|
460
462
|
const themeModules = import.meta.glob<Record<string, any>>(
|
|
461
|
-
|
|
463
|
+
[
|
|
464
|
+
"../../../../../../tenants/*/content/themes/*.json",
|
|
465
|
+
"../../../../../../tenants/e2e/*/content/themes/*.json",
|
|
466
|
+
],
|
|
462
467
|
{ eager: true, import: "default" },
|
|
463
468
|
);
|
|
464
|
-
const seg =
|
|
469
|
+
const seg = `${tenantDirSegment(tenant ?? "")}content/themes/`;
|
|
465
470
|
const t = Object.entries(themeModules)
|
|
466
471
|
.filter(([path]) => path.includes(seg))
|
|
467
472
|
.map(([, mod]) => mod)
|
|
@@ -469,17 +474,23 @@ const t = Object.entries(themeModules)
|
|
|
469
474
|
|
|
470
475
|
if (!t) return new Response(null, { status: 404 });
|
|
471
476
|
|
|
472
|
-
// Has this tenant adopted the canonical shared chrome
|
|
473
|
-
// longer ships its own mkt.css (retired at integration
|
|
477
|
+
// Has this tenant adopted the canonical shared chrome? If so it no
|
|
478
|
+
// longer ships its own mkt.css (retired at integration) — link the
|
|
474
479
|
// platform /shared/commerce-chrome.css instead so the marketing-component
|
|
475
480
|
// samples below still render in-brand.
|
|
476
481
|
const chromeModules = import.meta.glob<Record<string, any>>(
|
|
477
|
-
|
|
482
|
+
[
|
|
483
|
+
"../../../../../../tenants/*/content/chrome.json",
|
|
484
|
+
"../../../../../../tenants/e2e/*/content/chrome.json",
|
|
485
|
+
],
|
|
478
486
|
{ eager: true, import: "default" },
|
|
479
487
|
);
|
|
480
|
-
const chromeSeg =
|
|
488
|
+
const chromeSeg = `${tenantDirSegment(tenant ?? "")}content/chrome.json`;
|
|
481
489
|
const chromeConfig = Object.entries(chromeModules).find(([path]) => path.includes(chromeSeg))?.[1];
|
|
482
|
-
|
|
490
|
+
// Adoption is now "does chrome.json carry the consolidated header/footer
|
|
491
|
+
// shape" (lib/chrome/model.ts ChromeConfig) — the old `sharedChrome: true`
|
|
492
|
+
// opt-in flag is retired; a successfully-shaped config IS the adopted signal.
|
|
493
|
+
const usesSharedChrome = !!chromeConfig?.header && !!chromeConfig?.footer;
|
|
483
494
|
|
|
484
495
|
const tk = t.tokens ?? {};
|
|
485
496
|
const storyboard = t.storyboard ?? null;
|
|
@@ -492,7 +503,7 @@ const REFERENCE_COMPONENT_VARS: Record<string, string> = {
|
|
|
492
503
|
"--color-muted": "#5c6663", "--color-primary": "#1f3a34", "--color-primary-contrast": "#f4f1ea",
|
|
493
504
|
"--color-accent": "#b5612f", "--color-border": "#dcd6c9", "--color-success": "#3f6b4f",
|
|
494
505
|
"--color-sale": "#9e3b2e",
|
|
495
|
-
//
|
|
506
|
+
// Semantic + quality-bar interaction tokens — reference (Northwind)
|
|
496
507
|
// values so the text/icon-token samples render concretely and re-skin when a
|
|
497
508
|
// descriptor overrides them via preview.componentVars.
|
|
498
509
|
"--color-warning": "#8a5717", "--color-error": "#a22014", "--color-info": "#2c5b73",
|
|
@@ -610,7 +621,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
610
621
|
.sg-commerce .sg-h { color: var(--color-primary); }
|
|
611
622
|
.sg-commerce .sg-block { border-top-color: var(--color-border); }
|
|
612
623
|
|
|
613
|
-
/* Semantic text & icon token samples (v1.1
|
|
624
|
+
/* Semantic text & icon token samples (v1.1). Each swatch reads
|
|
614
625
|
ONE contract token so the guide proves text/icon roles resolve + re-skin
|
|
615
626
|
from tokens alone — never a hard-coded color. */
|
|
616
627
|
.sg-tok-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
|
|
@@ -952,7 +963,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
952
963
|
</div>
|
|
953
964
|
</section>
|
|
954
965
|
|
|
955
|
-
{/* ── Semantic text & icon tokens (v1.1
|
|
966
|
+
{/* ── Semantic text & icon tokens (v1.1) ──────────────────────────────
|
|
956
967
|
The quality-bar coverage sample: every text role, icon tint, and
|
|
957
968
|
interaction state renders from a NAMED contract token — nothing here
|
|
958
969
|
hard-codes a color or borrows `accent`. Swap the theme (or a
|
|
@@ -1138,7 +1149,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1138
1149
|
<section class="sg-block">
|
|
1139
1150
|
<p class="sg-h">Chrome — UtilityNav</p>
|
|
1140
1151
|
<UtilityNav
|
|
1141
|
-
links={[{ label: "News", href: "#" }, { label: "About", href: "#" }, { label: "Contact", href: "#" }]}
|
|
1152
|
+
links={[{ id: "util-news", label: "News", href: "#" }, { id: "util-about", label: "About", href: "#" }, { id: "util-contact", label: "Contact", href: "#" }]}
|
|
1142
1153
|
locale="English"
|
|
1143
1154
|
currency="United States (USD $)"
|
|
1144
1155
|
social={sampleSocial}
|
|
@@ -1283,8 +1294,8 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1283
1294
|
— no pricing/checkout/subscription mechanics. Figures are ILLUSTRATIVE
|
|
1284
1295
|
by default: unless a tier asserts real:true the widget renders a
|
|
1285
1296
|
first-class "Illustrative figures" affordance (badge + "e.g." + note)
|
|
1286
|
-
so an example number is never shown as a live offer
|
|
1287
|
-
|
|
1297
|
+
so an example number is never shown as a live offer. Fed sample
|
|
1298
|
+
tiers here; a tenant
|
|
1288
1299
|
supplies its own on a membership page. */}
|
|
1289
1300
|
<section class="sg-block">
|
|
1290
1301
|
<p class="sg-h">Membership tiers — <code>components/membership/</code></p>
|
|
@@ -1307,13 +1318,13 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1307
1318
|
/>
|
|
1308
1319
|
</section>
|
|
1309
1320
|
|
|
1310
|
-
{/* ── Structured content widgets (components/content
|
|
1321
|
+
{/* ── Structured content widgets (components/content/) ───────
|
|
1311
1322
|
The DATA-driven promotion of repeated raw-page patterns. A tenant
|
|
1312
1323
|
authors a policy/about/compliance page as structured `sections`
|
|
1313
1324
|
(JSON) instead of copying an HTML/CSS fragment; these components
|
|
1314
1325
|
render it with the a11y (headings, <dl>, <address>, roles, tap
|
|
1315
|
-
targets) baked in and every color from
|
|
1316
|
-
|
|
1326
|
+
targets) baked in and every color from tokens. The trust strip is
|
|
1327
|
+
guarded — real-or-absent, fabricated proof dropped. */}
|
|
1317
1328
|
<section class="sg-block">
|
|
1318
1329
|
<p class="sg-h">Structured content — <code>components/content/</code></p>
|
|
1319
1330
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Data-driven framework widgets (F4): a policy page rendered from structured <code>sections</code> with no HTML/CSS to copy. Accessibility lives in the components; tenant content is pure data.</p>
|
|
@@ -1374,7 +1385,7 @@ const componentVarsInline = Object.entries(componentVars)
|
|
|
1374
1385
|
{/* ── Interactive islands (components/islands/) ─────────────────────
|
|
1375
1386
|
Client-hydrated Preact islands. Each is tenant-agnostic and reads
|
|
1376
1387
|
only fixture/localStorage data here — no live catalog, cart, or ToT
|
|
1377
|
-
calls
|
|
1388
|
+
calls. */}
|
|
1378
1389
|
<section class="sg-block">
|
|
1379
1390
|
<p class="sg-h">Islands — <code>components/islands/</code></p>
|
|
1380
1391
|
<p class="lede" style="font-size:.95rem;color:var(--color-muted)">Client-hydrated Preact islands exercised with fixture data — no live catalog, cart, or ToT calls.</p>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
3
|
* Preview/dev-only SHARED RAW-CHROME STYLE GUIDE —
|
|
4
|
-
* `/_style-guide/<tenant>/chrome/<theme-id
|
|
4
|
+
* `/_style-guide/<tenant>/chrome/<theme-id>/`.
|
|
5
5
|
*
|
|
6
6
|
* Renders the platform-shipped raw chrome set — the `/shared/commerce-chrome.css`
|
|
7
7
|
* class vocabulary (announcement + utility bar, header + search + actions, primary
|
|
@@ -30,11 +30,16 @@ const cspNonce = Astro.locals.cspNonce;
|
|
|
30
30
|
|
|
31
31
|
// Tenant-local theme descriptors. From src/pages/style-guide/[tenant]/chrome/ the
|
|
32
32
|
// repo root is seven levels up.
|
|
33
|
+
import { tenantDirSegment } from "@tot/public-runtime";
|
|
34
|
+
|
|
33
35
|
const themeModules = import.meta.glob<Record<string, any>>(
|
|
34
|
-
|
|
36
|
+
[
|
|
37
|
+
"../../../../../../../tenants/*/content/themes/*.json",
|
|
38
|
+
"../../../../../../../tenants/e2e/*/content/themes/*.json",
|
|
39
|
+
],
|
|
35
40
|
{ eager: true, import: "default" },
|
|
36
41
|
);
|
|
37
|
-
const seg =
|
|
42
|
+
const seg = `${tenantDirSegment(tenant ?? "")}content/themes/`;
|
|
38
43
|
const t = Object.entries(themeModules)
|
|
39
44
|
.filter(([path]) => path.includes(seg))
|
|
40
45
|
.map(([, mod]) => mod)
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
export const prerender = false;
|
|
19
19
|
|
|
20
|
+
import { tenantDirSegment } from "@tot/public-runtime";
|
|
20
21
|
import "@/styles/global.css";
|
|
21
22
|
import type { MarkdownInstance } from "astro";
|
|
22
23
|
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
@@ -27,10 +28,13 @@ const cspNonce = Astro.locals.cspNonce;
|
|
|
27
28
|
// Tenant-local theme descriptors. From src/pages/style-guide/[tenant]/guide/ the
|
|
28
29
|
// repo root is seven levels up (same depth as the chrome guide).
|
|
29
30
|
const themeModules = import.meta.glob<Record<string, any>>(
|
|
30
|
-
|
|
31
|
+
[
|
|
32
|
+
"../../../../../../../tenants/*/content/themes/*.json",
|
|
33
|
+
"../../../../../../../tenants/e2e/*/content/themes/*.json",
|
|
34
|
+
],
|
|
31
35
|
{ eager: true, import: "default" },
|
|
32
36
|
);
|
|
33
|
-
const seg =
|
|
37
|
+
const seg = `${tenantDirSegment(tenant ?? "")}content/themes/`;
|
|
34
38
|
const t = Object.entries(themeModules)
|
|
35
39
|
.filter(([path]) => path.includes(seg))
|
|
36
40
|
.map(([, mod]) => mod)
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
export const prerender = false;
|
|
18
18
|
|
|
19
|
+
import { tenantDirSegment } from "@tot/public-runtime";
|
|
19
20
|
import StyleGuideNav from "@/components/style-guide/StyleGuideNav.astro";
|
|
20
21
|
|
|
21
22
|
const { tenant } = Astro.params;
|
|
@@ -24,10 +25,13 @@ const cspNonce = Astro.locals.cspNonce;
|
|
|
24
25
|
// Tenant-local theme descriptors. Colocated repo-root layout: from
|
|
25
26
|
// src/pages/style-guide/[tenant]/ the repo root is six levels up.
|
|
26
27
|
const themeModules = import.meta.glob<Record<string, any>>(
|
|
27
|
-
|
|
28
|
+
[
|
|
29
|
+
"../../../../../../tenants/*/content/themes/*.json",
|
|
30
|
+
"../../../../../../tenants/e2e/*/content/themes/*.json",
|
|
31
|
+
],
|
|
28
32
|
{ eager: true, import: "default" },
|
|
29
33
|
);
|
|
30
|
-
const seg =
|
|
34
|
+
const seg = `${tenantDirSegment(tenant ?? "")}content/themes/`;
|
|
31
35
|
const themes = Object.entries(themeModules)
|
|
32
36
|
.filter(([path]) => path.includes(seg))
|
|
33
37
|
.map(([, mod]) => mod);
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Preview/dev-only STYLE-GUIDE ROOT INDEX — `/_style-guide/`.
|
|
4
4
|
*
|
|
5
|
-
* Lists
|
|
6
|
-
* discoverable from one place.
|
|
5
|
+
* Lists every REAL tenant and each of its theme guides, so all clients' guides
|
|
6
|
+
* are discoverable from one place. Platform test tenants (the `.e2e.test` class,
|
|
7
|
+
* colocated under tenants/e2e/) are NOT listed — a generalized listing shows
|
|
8
|
+
* clients, not fixtures. `?includeTestTenants=1` opts them back in for someone
|
|
9
|
+
* who came here to look at one. Review surface only: noindex, never in the
|
|
7
10
|
* sitemap, never part of production marketing publishing. Tenant-agnostic —
|
|
8
11
|
* theme data is tenant-local (tenants/<tenant>/content/themes/*.json).
|
|
9
12
|
*
|
|
@@ -17,25 +20,33 @@
|
|
|
17
20
|
*/
|
|
18
21
|
export const prerender = false;
|
|
19
22
|
|
|
23
|
+
import { listedTenantIds } from "@tot/public-runtime";
|
|
24
|
+
|
|
20
25
|
const cspNonce = Astro.locals.cspNonce;
|
|
26
|
+
const includeTestTenants = Astro.url.searchParams.get("includeTestTenants") === "1";
|
|
21
27
|
|
|
22
28
|
// All tenant-local theme descriptors, grouped by tenant. Colocated repo-root
|
|
23
29
|
// layout: from src/pages/style-guide/ the repo root is five levels up.
|
|
24
30
|
const themeModules = import.meta.glob<Record<string, any>>(
|
|
25
|
-
|
|
31
|
+
[
|
|
32
|
+
"../../../../../tenants/*/content/themes/*.json",
|
|
33
|
+
"../../../../../tenants/e2e/*/content/themes/*.json",
|
|
34
|
+
],
|
|
26
35
|
{ eager: true, import: "default" },
|
|
27
36
|
);
|
|
28
37
|
|
|
29
38
|
const ROLE_ORDER: Record<string, number> = { current: 0, candidate: 1, legacy: 2 };
|
|
30
39
|
const byTenant = new Map<string, any[]>();
|
|
31
40
|
for (const [path, mod] of Object.entries(themeModules)) {
|
|
32
|
-
const m = /\/tenants\/([^/]+)\/content\/themes\//.exec(path);
|
|
41
|
+
const m = /\/tenants\/(?:e2e\/)?([^/]+)\/content\/themes\//.exec(path);
|
|
33
42
|
const tenant = m?.[1];
|
|
34
43
|
if (!tenant) continue;
|
|
35
44
|
if (!byTenant.has(tenant)) byTenant.set(tenant, []);
|
|
36
45
|
byTenant.get(tenant)!.push(mod);
|
|
37
46
|
}
|
|
47
|
+
const listedIds = new Set(listedTenantIds([...byTenant.keys()], { includeTestTenants }));
|
|
38
48
|
const tenants = [...byTenant.entries()]
|
|
49
|
+
.filter(([tenant]) => listedIds.has(tenant))
|
|
39
50
|
.map(([tenant, themes]) => ({
|
|
40
51
|
tenant,
|
|
41
52
|
themes: themes.sort((a, b) => (ROLE_ORDER[a.role] ?? 9) - (ROLE_ORDER[b.role] ?? 9)),
|
|
@@ -77,7 +88,10 @@ const tenants = [...byTenant.entries()]
|
|
|
77
88
|
<div class="wrap">
|
|
78
89
|
<span class="flag">Preview · dev only · noindex</span>
|
|
79
90
|
<h1>Client style guides</h1>
|
|
80
|
-
<p class="sub">Every tenant and its theme guides. Open a guide to preview the standard components and page sections re-skinned under that theme. Nothing here re-skins a live site.</p>
|
|
91
|
+
<p class="sub">Every client tenant and its theme guides. Open a guide to preview the standard components and page sections re-skinned under that theme. Nothing here re-skins a live site.</p>
|
|
92
|
+
<p class="sub">{includeTestTenants
|
|
93
|
+
? <span>Showing platform test tenants too — <a href="/_style-guide/">hide them</a>.</span>
|
|
94
|
+
: <span>Platform test tenants are hidden — <a href="/_style-guide/?includeTestTenants=1">show them</a>.</span>}</p>
|
|
81
95
|
|
|
82
96
|
{tenants.map(({ tenant, themes }) => (
|
|
83
97
|
<section class="tenant">
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* GET /tenants/<id>/<path> — serve a tenant's versioned static asset from R2.
|
|
3
3
|
*
|
|
4
4
|
* The version-scoped replacement for the build-time `copy-tenant-assets.mjs`
|
|
5
|
-
* baking
|
|
5
|
+
* baking. Resolves the tenant's active
|
|
6
6
|
* channel→snapshot versionId from the `cust:assets-pointer:<id>` KV record and
|
|
7
7
|
* streams `tenants/<id>/<versionId>/<rel>` from the TENANT_ASSETS R2 bucket with
|
|
8
8
|
* the right content-type + a revalidating cache header + a versionId ETag.
|
|
@@ -17,12 +17,36 @@
|
|
|
17
17
|
import type { APIContext } from "astro";
|
|
18
18
|
import {
|
|
19
19
|
serveTenantAsset,
|
|
20
|
+
verifyPreviewToken,
|
|
20
21
|
type R2BucketLike,
|
|
21
22
|
} from "@tot/public-runtime";
|
|
22
|
-
import { readR2, readKv } from "@/lib/env";
|
|
23
|
+
import { readR2, readKv, readEnv } from "@/lib/env";
|
|
23
24
|
|
|
24
25
|
export const prerender = false;
|
|
25
26
|
|
|
27
|
+
/** A versionId is a content sha — restrict to a safe R2 key segment (no traversal). */
|
|
28
|
+
const SAFE_VERSION_ID = /^[A-Za-z0-9._-]{1,128}$/;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a CANDIDATE-preview version override for this asset request, or null.
|
|
32
|
+
* A candidate/revision page sets `tot_preview_version` (its versionId) + the
|
|
33
|
+
* `tot_preview` capability token; when the token verifies for THIS tenant, we serve
|
|
34
|
+
* that exact snapshot (`tenants/<id>/<versionId>/…`) instead of the channel pointer,
|
|
35
|
+
* so a candidate's NEW assets — unreachable via the never-flipped channel — resolve.
|
|
36
|
+
* Token-gated + tenant-matched so it can never serve another tenant's snapshot.
|
|
37
|
+
*/
|
|
38
|
+
async function resolvePreviewVersion(context: APIContext, urlTenant: string): Promise<string | null> {
|
|
39
|
+
const versionId = context.cookies.get("tot_preview_version")?.value ?? null;
|
|
40
|
+
const token = context.cookies.get("tot_preview")?.value ?? null;
|
|
41
|
+
if (!versionId || !token || !urlTenant) return null;
|
|
42
|
+
if (!SAFE_VERSION_ID.test(versionId) || versionId.includes("..")) return null;
|
|
43
|
+
const secret = (await readEnv("CUSTOMIZATION_PREVIEW_SECRET")) ?? null;
|
|
44
|
+
if (!secret) return null;
|
|
45
|
+
const verified = await verifyPreviewToken(secret, token, Math.floor(Date.now() / 1000));
|
|
46
|
+
if (!verified.ok || verified.claims.tenantId !== urlTenant) return null;
|
|
47
|
+
return versionId;
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
export async function GET(context: APIContext): Promise<Response> {
|
|
27
51
|
const [bucket, kv] = await Promise.all([
|
|
28
52
|
readR2("TENANT_ASSETS"),
|
|
@@ -36,17 +60,29 @@ export async function GET(context: APIContext): Promise<Response> {
|
|
|
36
60
|
});
|
|
37
61
|
}
|
|
38
62
|
|
|
63
|
+
const previewVersionId = await resolvePreviewVersion(context, context.params.id ?? "");
|
|
64
|
+
|
|
39
65
|
const res = await serveTenantAsset(
|
|
40
66
|
{
|
|
41
67
|
// Runtime binding structurally satisfies the shared-runtime R2 seam.
|
|
42
68
|
bucket: bucket as unknown as R2BucketLike,
|
|
43
69
|
kvGet: (key) => kv.get(key),
|
|
44
70
|
channel: context.locals.customizationEnv ?? "live",
|
|
71
|
+
...(previewVersionId ? { versionId: previewVersionId } : {}),
|
|
45
72
|
ifNoneMatch: context.request.headers.get("if-none-match"),
|
|
46
73
|
},
|
|
47
74
|
new URL(context.request.url).pathname,
|
|
48
75
|
);
|
|
49
76
|
|
|
77
|
+
// A candidate-preview asset must NEVER be edge/CDN-cached under its tokenless URL
|
|
78
|
+
// (that would poison the public asset with candidate bytes, and Vary doesn't cover
|
|
79
|
+
// the auth cookie). Force no-store for the preview-version path; the normal
|
|
80
|
+
// channel-served asset keeps its revalidating cache header.
|
|
81
|
+
if (res && previewVersionId) {
|
|
82
|
+
res.headers.set("cache-control", "no-store");
|
|
83
|
+
res.headers.set("x-robots-tag", "noindex, nofollow");
|
|
84
|
+
}
|
|
85
|
+
|
|
50
86
|
return (
|
|
51
87
|
res ??
|
|
52
88
|
new Response("Not found", {
|
|
@@ -11,11 +11,11 @@ import { getTranslations } from "@/lib/blog/collection.js";
|
|
|
11
11
|
import { buildAlternates } from "@/lib/seo/alternates.js";
|
|
12
12
|
import { breadcrumbLd } from "@/lib/jsonld.js";
|
|
13
13
|
|
|
14
|
-
const { tenant, canonicalBase, basePath } = Astro.locals;
|
|
14
|
+
const { tenant, canonicalBase, basePath, content } = Astro.locals;
|
|
15
15
|
const slug = Astro.params.slug ?? "";
|
|
16
|
-
const post = await getBuildPost(tenant.tenant_id, slug);
|
|
16
|
+
const post = await getBuildPost(tenant.tenant_id, slug, { content });
|
|
17
17
|
if (!post) {
|
|
18
|
-
const redirect = await resolveBuildRedirect(tenant.tenant_id, slug);
|
|
18
|
+
const redirect = await resolveBuildRedirect(tenant.tenant_id, slug, content);
|
|
19
19
|
if (redirect) return Astro.redirect(`${basePath}/the-build/${redirect}/`, 301);
|
|
20
20
|
return new Response(null, { status: 404 });
|
|
21
21
|
}
|
|
@@ -45,7 +45,7 @@ const buildHref = `${basePath}/the-build/`;
|
|
|
45
45
|
// the live-visible variant set (self + siblings); `buildAlternates` yields [] for
|
|
46
46
|
// a singleton, so a non-translated post gets no alternates and no `lang` override
|
|
47
47
|
// (byte-identical to today).
|
|
48
|
-
const translations = await getTranslations(tenant.tenant_id, THE_BUILD.id, post.slug);
|
|
48
|
+
const translations = await getTranslations(tenant.tenant_id, THE_BUILD.id, post.slug, { content });
|
|
49
49
|
const alternates = buildAlternates(translations, (s) =>
|
|
50
50
|
new URL(`/the-build/${s}/`, canonicalBase + "/").toString(),
|
|
51
51
|
);
|
|
@@ -8,8 +8,8 @@ import Layout from "@/layouts/Layout.astro";
|
|
|
8
8
|
import PostAccessBadge from "@/components/blog/PostAccessBadge.astro";
|
|
9
9
|
import { listBuildPosts } from "@/lib/the-build/provider.js";
|
|
10
10
|
|
|
11
|
-
const { tenant, basePath, canonicalBase } = Astro.locals;
|
|
12
|
-
const posts = await listBuildPosts(tenant.tenant_id);
|
|
11
|
+
const { tenant, basePath, canonicalBase, content } = Astro.locals;
|
|
12
|
+
const posts = await listBuildPosts(tenant.tenant_id, { content });
|
|
13
13
|
if (posts.length === 0) return new Response(null, { status: 404 });
|
|
14
14
|
|
|
15
15
|
const href = (path: string) => `${basePath}${path}` || "/";
|
|
@@ -11,8 +11,8 @@ import { listBuildPosts, THE_BUILD } from "@/lib/the-build/provider.js";
|
|
|
11
11
|
import { renderRssFeed } from "@/lib/blog/rss.js";
|
|
12
12
|
|
|
13
13
|
export async function GET(context: APIContext): Promise<Response> {
|
|
14
|
-
const { tenant, canonicalBase } = context.locals;
|
|
15
|
-
const posts = await listBuildPosts(tenant.tenant_id);
|
|
14
|
+
const { tenant, canonicalBase, content } = context.locals;
|
|
15
|
+
const posts = await listBuildPosts(tenant.tenant_id, { content });
|
|
16
16
|
if (posts.length === 0) return new Response(null, { status: 404 });
|
|
17
17
|
|
|
18
18
|
const body = renderRssFeed({
|