@tokenoftrust/storefront-runner 1.3.4-rc.4 → 1.4.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 +15 -0
- package/apps/storefront/dev-plugins/dev-publish.mjs +55 -0
- package/apps/storefront/dev-plugins/tenant-hot-reload.mjs +86 -7
- package/apps/storefront/drizzle.config.apps.ts +13 -0
- package/apps/storefront/env.d.ts +10 -0
- package/apps/storefront/migrations/README.md +13 -7
- package/apps/storefront/migrations-apps/0000_fast_millenium_guard.sql +129 -0
- package/apps/storefront/migrations-apps/meta/0000_snapshot.json +843 -0
- package/apps/storefront/migrations-apps/meta/_journal.json +13 -0
- package/apps/storefront/package.json +13 -1
- package/apps/storefront/perf/README.md +64 -0
- package/apps/storefront/perf/assert-budgets.ts +159 -0
- package/apps/storefront/playwright.config.ts +23 -0
- package/apps/storefront/public/js/dashboard-apps.js +173 -0
- package/apps/storefront/public/shared/commerce-marketing.css +221 -0
- package/apps/storefront/src/components/CollectionCard.astro +1 -0
- package/apps/storefront/src/components/ProductCard.astro +1 -0
- package/apps/storefront/src/components/admin/AdminPublishTab.astro +1959 -0
- package/apps/storefront/src/components/apps/AppWidgetFrame.astro +30 -0
- package/apps/storefront/src/components/chrome/NavDropdown.astro +6 -3
- package/apps/storefront/src/components/chrome/SiteFooter.astro +10 -0
- package/apps/storefront/src/components/chrome/SiteHeader.astro +10 -0
- package/apps/storefront/src/components/commerce/RatingStars.astro +3 -2
- package/apps/storefront/src/components/content/Callout.astro +75 -0
- package/apps/storefront/src/components/content/NeedsReviewCallout.astro +66 -0
- package/apps/storefront/src/components/content/ProseSections.astro +121 -0
- package/apps/storefront/src/components/content/ProseToc.astro +34 -0
- package/apps/storefront/src/components/content/RichText.astro +44 -0
- package/apps/storefront/src/components/content/TrustStrip.astro +46 -0
- package/apps/storefront/src/components/home/Hero.astro +14 -0
- package/apps/storefront/src/components/islands/CheckoutComplianceGate.tsx +295 -0
- package/apps/storefront/src/components/islands/ImageGallery.tsx +42 -21
- package/apps/storefront/src/components/islands/VariantSelector.tsx +62 -12
- package/apps/storefront/src/components/plp/FacetSidebar.astro +2 -2
- package/apps/storefront/src/components/subscription/ManageSubscriptionEntry.astro +1 -0
- package/apps/storefront/src/config/compliance/rulesets.ts +79 -0
- package/apps/storefront/src/config/storeName.ts +34 -0
- package/apps/storefront/src/layouts/Layout.astro +97 -23
- package/apps/storefront/src/lib/analytics/budgets.json +69 -0
- package/apps/storefront/src/lib/analytics/lighthouseReport.ts +109 -0
- package/apps/storefront/src/lib/analytics/perfBudgets.ts +452 -0
- package/apps/storefront/src/lib/analytics/rumAlert.ts +179 -0
- package/apps/storefront/src/lib/analytics/webVitals.ts +269 -0
- package/apps/storefront/src/lib/apps/adminService.ts +106 -0
- package/apps/storefront/src/lib/apps/adminSession.ts +205 -0
- package/apps/storefront/src/lib/apps/apiAuth.ts +91 -0
- package/apps/storefront/src/lib/apps/apiRoute.ts +35 -0
- package/apps/storefront/src/lib/apps/catalogMapper.ts +39 -0
- package/apps/storefront/src/lib/apps/credentials.ts +153 -0
- package/apps/storefront/src/lib/apps/gatewayKeys.ts +156 -0
- package/apps/storefront/src/lib/apps/healthAggregate.ts +66 -0
- package/apps/storefront/src/lib/apps/orders/attributionService.ts +206 -0
- package/apps/storefront/src/lib/apps/orders/customerHash.ts +28 -0
- package/apps/storefront/src/lib/apps/orders/foxyOrderClient.ts +203 -0
- package/apps/storefront/src/lib/apps/orders/idempotency.ts +100 -0
- package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +117 -0
- package/apps/storefront/src/lib/apps/orders/orderMapper.ts +91 -0
- package/apps/storefront/src/lib/apps/orders/ordersStore.ts +181 -0
- package/apps/storefront/src/lib/apps/registryService.ts +579 -0
- package/apps/storefront/src/lib/apps/scopes.ts +79 -0
- package/apps/storefront/src/lib/apps/tokenIssuer.ts +121 -0
- package/apps/storefront/src/lib/apps/tokenVerifier.ts +148 -0
- package/apps/storefront/src/lib/apps/widgets/eligibility.ts +18 -0
- package/apps/storefront/src/lib/apps/widgets/frameProps.ts +52 -0
- package/apps/storefront/src/lib/apps/widgets/launchToken.ts +84 -0
- package/apps/storefront/src/lib/apps/widgets/placements.ts +57 -0
- package/apps/storefront/src/lib/apps/widgets/renderSlot.ts +111 -0
- package/apps/storefront/src/lib/auth/adminEntry.ts +119 -0
- package/apps/storefront/src/lib/auth/identityToken.ts +21 -2
- package/apps/storefront/src/lib/auth/loginGate.ts +102 -18
- package/apps/storefront/src/lib/auth/mcpClientAssertion.ts +215 -0
- package/apps/storefront/src/lib/auth/route.ts +16 -1
- package/apps/storefront/src/lib/auth/session.ts +8 -0
- package/apps/storefront/src/lib/auth/stepUpChallenge.ts +107 -0
- package/apps/storefront/src/lib/auth/totAccessClient.ts +208 -0
- package/apps/storefront/src/lib/blog/provider.ts +39 -0
- package/apps/storefront/src/lib/blog/types.ts +26 -0
- package/apps/storefront/src/lib/checkoutCommerce.ts +39 -1
- package/apps/storefront/src/lib/chrome/model.ts +11 -0
- package/apps/storefront/src/lib/compliance/enforcement.ts +95 -0
- package/apps/storefront/src/lib/content/callout.ts +78 -0
- package/apps/storefront/src/lib/content/index.ts +27 -0
- package/apps/storefront/src/lib/content/needsReview.ts +58 -0
- package/apps/storefront/src/lib/content/prose.ts +186 -0
- package/apps/storefront/src/lib/content/richtext.ts +76 -0
- package/apps/storefront/src/lib/content/trustStrip.ts +74 -0
- package/apps/storefront/src/lib/content-edit/client.ts +70 -14
- package/apps/storefront/src/lib/d1/catalog.ts +12 -0
- package/apps/storefront/src/lib/d1/schema-apps.ts +213 -0
- package/apps/storefront/src/lib/dev/apiBase.ts +8 -2
- package/apps/storefront/src/lib/dev/cliSignInCode.ts +65 -115
- package/apps/storefront/src/lib/dev/cockpitStore.ts +65 -0
- package/apps/storefront/src/lib/dev/previewStatus.ts +112 -0
- package/apps/storefront/src/lib/dev/rendezvousBroker.ts +241 -0
- package/apps/storefront/src/lib/dev/subjectReissue.ts +67 -0
- package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +10 -10
- package/apps/storefront/src/lib/env.ts +12 -0
- package/apps/storefront/src/lib/jsonld.ts +12 -17
- package/apps/storefront/src/lib/membership/eligibility.ts +37 -0
- package/apps/storefront/src/lib/monitoring/manifest.ts +302 -0
- package/apps/storefront/src/lib/privacy/emailHint.ts +13 -5
- package/apps/storefront/src/lib/publish/apex-readiness.ts +337 -0
- package/apps/storefront/src/lib/publish/dispatchHealth.ts +269 -0
- package/apps/storefront/src/lib/publish/domainState.ts +351 -0
- package/apps/storefront/src/lib/publish/shipWorkspace.ts +362 -0
- package/apps/storefront/src/lib/rawChrome.ts +34 -3
- package/apps/storefront/src/lib/storyblok/content-model.ts +34 -2
- package/apps/storefront/src/lib/storyblok/provider.ts +11 -4
- package/apps/storefront/src/lib/subscription/model.ts +114 -0
- package/apps/storefront/src/lib/tot/ToTClient.ts +3 -3
- package/apps/storefront/src/lib/tot/query.ts +32 -0
- package/apps/storefront/src/lib/webhooks/cloudflareQueueDispatcher.ts +82 -0
- package/apps/storefront/src/lib/webhooks/deliveryEngine.ts +245 -0
- package/apps/storefront/src/lib/webhooks/deliveryMapper.ts +34 -0
- package/apps/storefront/src/lib/webhooks/deliveryStore.ts +668 -0
- package/apps/storefront/src/lib/webhooks/dispatcher.ts +168 -0
- package/apps/storefront/src/lib/webhooks/emit.ts +167 -0
- package/apps/storefront/src/lib/webhooks/endpointGuard.ts +135 -0
- package/apps/storefront/src/lib/webhooks/events.ts +98 -0
- package/apps/storefront/src/lib/webhooks/getDispatcher.ts +49 -0
- package/apps/storefront/src/lib/webhooks/signing.ts +29 -0
- package/apps/storefront/src/lib/webhooks/webhookSigningKey.ts +146 -0
- package/apps/storefront/src/middleware/index.ts +28 -13
- package/apps/storefront/src/pages/404.astro +21 -9
- package/apps/storefront/src/pages/[...slug].astro +36 -2
- package/apps/storefront/src/pages/admin.astro +29 -3
- package/apps/storefront/src/pages/api/apps/admin/credentials/rotate.ts +60 -0
- package/apps/storefront/src/pages/api/apps/admin/health.ts +44 -0
- package/apps/storefront/src/pages/api/apps/admin/install.ts +100 -0
- package/apps/storefront/src/pages/api/apps/admin/list.ts +26 -0
- package/apps/storefront/src/pages/api/apps/admin/resume.ts +56 -0
- package/apps/storefront/src/pages/api/apps/admin/suspend.ts +57 -0
- package/apps/storefront/src/pages/api/apps/admin/uninstall.ts +74 -0
- package/apps/storefront/src/pages/api/apps/admin/update.ts +103 -0
- package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries/[deliveryId]/replay.ts +59 -0
- package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries.ts +51 -0
- package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +172 -0
- package/apps/storefront/src/pages/api/apps/oauth/token.ts +87 -0
- package/apps/storefront/src/pages/api/apps/v1/attribution.ts +142 -0
- package/apps/storefront/src/pages/api/apps/v1/catalog/products/[handle].ts +39 -0
- package/apps/storefront/src/pages/api/apps/v1/catalog/products.ts +49 -0
- package/apps/storefront/src/pages/api/apps/v1/health.ts +32 -0
- package/apps/storefront/src/pages/api/apps/v1/inventory.ts +59 -0
- package/apps/storefront/src/pages/api/apps/v1/orders/[id].ts +48 -0
- package/apps/storefront/src/pages/api/apps/v1/orders.ts +73 -0
- package/apps/storefront/src/pages/api/apps/v1/reports.ts +21 -0
- package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries/[deliveryId]/replay.ts +62 -0
- package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries.ts +47 -0
- package/apps/storefront/src/pages/api/auth/magic-exchange.ts +48 -1
- package/apps/storefront/src/pages/api/auth/step-up-send.ts +57 -0
- package/apps/storefront/src/pages/api/auth/step-up-verify.ts +129 -0
- package/apps/storefront/src/pages/api/auth/verify.ts +23 -0
- package/apps/storefront/src/pages/api/compliance/preflight.ts +206 -0
- package/apps/storefront/src/pages/api/rum/vitals.ts +54 -0
- package/apps/storefront/src/pages/api/test/dev-session.ts +133 -0
- package/apps/storefront/src/pages/auth/login.astro +197 -41
- package/apps/storefront/src/pages/auth/magic.astro +75 -43
- package/apps/storefront/src/pages/blog/[slug].astro +107 -0
- package/apps/storefront/src/pages/blog/index.astro +98 -0
- package/apps/storefront/src/pages/capabilities.astro +8 -0
- package/apps/storefront/src/pages/cockpit.astro +433 -69
- package/apps/storefront/src/pages/collections/[handle].astro +8 -0
- package/apps/storefront/src/pages/collections/index.astro +10 -2
- package/apps/storefront/src/pages/dashboard/[appDomain]/apps/index.astro +119 -0
- package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +5 -0
- package/apps/storefront/src/pages/index.astro +57 -0
- package/apps/storefront/src/pages/llms.txt.ts +31 -10
- package/apps/storefront/src/pages/products/[handle].astro +100 -9
- package/apps/storefront/src/pages/sitemap.xml.ts +21 -4
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +198 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +7 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +7 -0
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +7 -0
- package/apps/storefront/src/pages/style-guide/index.astro +10 -0
- package/apps/storefront/src/styles/fonts.css +54 -0
- package/apps/storefront/src/styles/global.css +22 -2
- package/apps/storefront/src/themes/schema.ts +3 -25
- package/apps/storefront/tsconfig.json +1 -1
- package/apps/storefront/vitest.config.ts +4 -1
- package/package.json +1 -1
- package/packages/public-runtime/src/candidate-index.ts +311 -0
- package/packages/public-runtime/src/checkout.ts +94 -2
- package/packages/public-runtime/src/compliance/evaluate.ts +265 -0
- package/packages/public-runtime/src/compliance/evidence-signals.ts +81 -0
- package/packages/public-runtime/src/compliance/index.ts +22 -0
- package/packages/public-runtime/src/compliance/pact-report.ts +94 -0
- package/packages/public-runtime/src/compliance/profile.ts +198 -0
- package/packages/public-runtime/src/compliance/ruleset.ts +117 -0
- package/packages/public-runtime/src/compliance/verification.ts +81 -0
- package/packages/public-runtime/src/csp.ts +27 -3
- package/packages/public-runtime/src/customization-reconcile.ts +35 -0
- package/packages/public-runtime/src/customization-runtime.ts +8 -0
- package/packages/public-runtime/src/customization-versioning.ts +17 -0
- package/packages/public-runtime/src/extension-contract.ts +2 -1
- package/packages/public-runtime/src/hash.ts +25 -0
- package/packages/public-runtime/src/index.ts +6 -0
- package/packages/public-runtime/src/membership.ts +353 -0
- package/packages/public-runtime/src/product.ts +24 -2
- package/packages/public-runtime/src/review-trust-proof.ts +194 -0
- package/packages/public-runtime/src/tenant-assets.ts +40 -5
- package/packages/public-runtime/src/tenant.ts +236 -0
- package/packages/public-runtime/src/widget-postmessage.ts +205 -0
- package/scripts/dev/publish.mjs +158 -0
- package/scripts/dev/transient-files.mjs +2 -1
- package/tenants/home/public/fonts/inter-latin-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-ext-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-ext-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/inter-latin-ext-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-ext-400-normal.woff2 +0 -0
- package/tenants/home/public/fonts/jetbrains-mono-latin-ext-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-700-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-800-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-500-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-600-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-700-normal.woff2 +0 -0
- package/tenants/home/public/fonts/plus-jakarta-sans-latin-ext-800-normal.woff2 +0 -0
- package/tenants/home/public/pages/storefront.css +23 -0
- package/apps/storefront/src/lib/dev/hostedCockpit.ts +0 -169
|
@@ -64,6 +64,21 @@ import { tenantHotReload } from "./dev-plugins/tenant-hot-reload.mjs";
|
|
|
64
64
|
// facets, search typeahead, mobile drawer) — near-zero JS everywhere else.
|
|
65
65
|
export default defineConfig({
|
|
66
66
|
output: "server",
|
|
67
|
+
// Prefetch (finding 5): every nav today is a cold MPA reload. Enable Astro's
|
|
68
|
+
// prefetch so key navigation + product-card links warm the next SSR response
|
|
69
|
+
// on intent. OPT-IN (prefetchAll:false) — only links carrying
|
|
70
|
+
// `data-astro-prefetch` prefetch (nav items, product/collection cards), so we
|
|
71
|
+
// don't blanket-fetch cart/auth/account/wishlist or over-fetch on load. The
|
|
72
|
+
// 'hover' default strategy fires on mouseenter/focus (intent-driven, cheap on
|
|
73
|
+
// bandwidth), degrading to tap on touch. Works on output:'server' with NO
|
|
74
|
+
// prerendered pages — prefetch just issues the same GET the click would.
|
|
75
|
+
// NOTE: this is prefetch WITHOUT View Transitions; no <ClientRouter> is added
|
|
76
|
+
// (see DECISIONS — it would need every once-run island/inline script rewired
|
|
77
|
+
// to astro:page-load and risks the CSP-nonce/age-gate paths).
|
|
78
|
+
prefetch: {
|
|
79
|
+
prefetchAll: false,
|
|
80
|
+
defaultStrategy: "hover",
|
|
81
|
+
},
|
|
67
82
|
// Externalize all CSS (no auto-inlined <style>) so a strict CSP needs no
|
|
68
83
|
// inline-style allowance for elements — every stylesheet is a 'self' <link>.
|
|
69
84
|
// Small first-paint tradeoff, offset by cross-page caching (see LIMITATIONS).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { handlePublish } from "../../../scripts/dev/publish.mjs";
|
|
3
|
+
|
|
4
|
+
// C5 · Publish in browser — server side. Dev-only (`apply: "serve"`), never
|
|
5
|
+
// reaches the production Worker. Maps POST /__tot/publish {path} onto the
|
|
6
|
+
// candidate_open flow in scripts/dev/publish.mjs — the local-loop counterpart
|
|
7
|
+
// to the hosted cockpit's /api/dev/publish.ts (unit s6), reusing the SAME
|
|
8
|
+
// per-actor deriveChangeId idempotency `tot submit` relies on so repeat
|
|
9
|
+
// publishes update ONE PR instead of piling up duplicates.
|
|
10
|
+
|
|
11
|
+
/** @param {any} req @returns {Promise<string>} */
|
|
12
|
+
function readBody(req) {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
let data = "";
|
|
15
|
+
req.on("data", (/** @type {any} */ c) => {
|
|
16
|
+
data += c;
|
|
17
|
+
if (data.length > 4 * 1024 * 1024) req.destroy();
|
|
18
|
+
});
|
|
19
|
+
req.on("end", () => resolve(data));
|
|
20
|
+
req.on("error", () => resolve(data));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function devPublish() {
|
|
25
|
+
/** @type {any} */
|
|
26
|
+
const plugin = {
|
|
27
|
+
name: "tot:dev-publish",
|
|
28
|
+
apply: "serve",
|
|
29
|
+
/** @param {any} server */
|
|
30
|
+
configureServer(server) {
|
|
31
|
+
server.middlewares.use(
|
|
32
|
+
async (/** @type {any} */ req, /** @type {any} */ res, /** @type {any} */ next) => {
|
|
33
|
+
if (req.method !== "POST" || !req.url || req.url.split("?")[0] !== "/__tot/publish") {
|
|
34
|
+
return next();
|
|
35
|
+
}
|
|
36
|
+
let body;
|
|
37
|
+
try {
|
|
38
|
+
body = JSON.parse((await readBody(req)) || "{}");
|
|
39
|
+
} catch {
|
|
40
|
+
res.statusCode = 400;
|
|
41
|
+
res.setHeader("content-type", "application/json");
|
|
42
|
+
res.end(JSON.stringify({ ok: false, status: "bad_json", message: "invalid JSON body" }));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const out = await handlePublish(process.env, body);
|
|
46
|
+
res.statusCode = out.status;
|
|
47
|
+
res.setHeader("content-type", "application/json");
|
|
48
|
+
res.setHeader("cache-control", "no-store");
|
|
49
|
+
res.end(JSON.stringify(out.json));
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
return plugin;
|
|
55
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { readdirSync, existsSync } from "node:fs";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
4
|
+
import { basename, dirname, join } from "node:path";
|
|
5
5
|
import { markSave, reportServerUp } from "./dev-loop-state.mjs";
|
|
6
|
+
import { isTransientWatchFile } from "../../../scripts/dev/transient-files.mjs";
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
6
8
|
|
|
7
9
|
// Repo-root tenants/ dir (colocated tenant layout) + the generated static dest
|
|
8
10
|
// the predev copy step mirrors public/ into. This module lives at
|
|
@@ -11,11 +13,40 @@ import { markSave, reportServerUp } from "./dev-loop-state.mjs";
|
|
|
11
13
|
const TENANTS_DIR = fileURLToPath(new URL("../../../tenants", import.meta.url)).replace(/\\/g, "/");
|
|
12
14
|
const PUBLIC_TENANTS_DEST = fileURLToPath(new URL("../public/tenants", import.meta.url));
|
|
13
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Load a TS module's exports for Node-side (plugin) use, reusing Vite's own
|
|
18
|
+
* transform pipeline instead of a plain `import` (which can't parse `.ts`) or
|
|
19
|
+
* `ssrLoadModule` (which requires the 'ssr' environment to be Node-runnable —
|
|
20
|
+
* it isn't here, since the Cloudflare adapter's ssr environment runs in
|
|
21
|
+
* workerd). `src/themes/schema.ts` and `reference.ts` only ever import types
|
|
22
|
+
* (fully erased by the transform), so the transformed output has zero runtime
|
|
23
|
+
* imports left to resolve — safe to eval directly via a data: URL import.
|
|
24
|
+
* @param {any} server @param {string} url
|
|
25
|
+
*/
|
|
26
|
+
async function loadTsModule(server, url) {
|
|
27
|
+
const result = await server.transformRequest(url);
|
|
28
|
+
if (!result) throw new Error(`transformRequest returned nothing for ${url}`);
|
|
29
|
+
// Vite's dev transform prepends module-graph bookkeeping imports (e.g. a
|
|
30
|
+
// preact-debug preamble, HMR deps) that only resolve inside Vite's own
|
|
31
|
+
// module graph, not a bare data: URL import. schema.ts/reference.ts only
|
|
32
|
+
// ever import types (fully erased already), so stripping every top-level
|
|
33
|
+
// `import ...;` line leaves the real, self-contained function/const
|
|
34
|
+
// exports intact.
|
|
35
|
+
const code = result.code.replace(/^import\s.*;\s*$/gm, "");
|
|
36
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(code, "utf8").toString("base64")}`;
|
|
37
|
+
return import(dataUrl);
|
|
38
|
+
}
|
|
39
|
+
|
|
14
40
|
/**
|
|
15
41
|
* Classify a watched absolute path as a tenant file: → { id, rest } where `rest`
|
|
16
42
|
* is tenant-relative posix ("content/home.html", "public/logo.png"), or null if
|
|
17
|
-
* the path isn't under a tenant
|
|
18
|
-
*
|
|
43
|
+
* the path isn't under a tenant OR is an editor/OS transient file (vim swap,
|
|
44
|
+
* emacs autosave, `.DS_Store`, a dotfile, …) — those are watcher noise, not real
|
|
45
|
+
* content, so neither reload logic nor the activity Monitor should ever see them
|
|
46
|
+
* (a vim `.home.html.swp` add/change/unlink was leaking into the developer's
|
|
47
|
+
* "Your activity" ledger before this check). Shared by handleHotUpdate (change)
|
|
48
|
+
* and the add/unlink watcher handlers so both agree on the content/-vs-public/
|
|
49
|
+
* split — and on what counts as noise.
|
|
19
50
|
* @param {string} file
|
|
20
51
|
* @returns {{ id: string, rest: string } | null}
|
|
21
52
|
*/
|
|
@@ -25,7 +56,9 @@ export function classifyTenantFile(file) {
|
|
|
25
56
|
const rel = f.slice(TENANTS_DIR.length + 1); // "<id>/<...>"
|
|
26
57
|
const slash = rel.indexOf("/");
|
|
27
58
|
if (slash < 0) return null;
|
|
28
|
-
|
|
59
|
+
const rest = rel.slice(slash + 1);
|
|
60
|
+
if (isTransientWatchFile(basename(rest))) return null;
|
|
61
|
+
return { id: rel.slice(0, slash), rest };
|
|
29
62
|
}
|
|
30
63
|
|
|
31
64
|
/** True for the raw content HTML that's read fresh from disk per request. @param {string} rest */
|
|
@@ -33,6 +66,22 @@ export function isContentHtml(rest) {
|
|
|
33
66
|
return rest.startsWith("content/") && rest.endsWith(".html");
|
|
34
67
|
}
|
|
35
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Strip the documentation keys (`_vendor`, `_note`, `$schema`, …) a tenant's
|
|
71
|
+
* theme.json may carry, mirroring src/themes/tenants/index.ts's stripMeta
|
|
72
|
+
* exactly — both must agree on what counts as a real token vs. a comment key.
|
|
73
|
+
* @param {Record<string, unknown>} parsed
|
|
74
|
+
*/
|
|
75
|
+
export function stripThemeMeta(parsed) {
|
|
76
|
+
/** @type {Record<string, unknown>} */
|
|
77
|
+
const out = {};
|
|
78
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
79
|
+
if (k.startsWith("_") || k.startsWith("$")) continue;
|
|
80
|
+
out[k] = v;
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
36
85
|
/**
|
|
37
86
|
* Is this tenant opted out of static-asset mirroring (R2-versioned)? Matches
|
|
38
87
|
* scripts/build/copy-tenant-assets.mjs's isVersioned EXACTLY (both the marker
|
|
@@ -120,9 +169,12 @@ export function seedKnown(root, known) {
|
|
|
120
169
|
// rawHtmlResponse in src/lib/rawMarketingHtml.ts.)
|
|
121
170
|
// - public/** — re-mirror the one changed asset into public/tenants/<id>/
|
|
122
171
|
// (skipping R2-versioned tenants, like copy-tenant-assets.mjs), then reload.
|
|
123
|
-
// content/*.json
|
|
124
|
-
// already invalidates + reloads them — left to default handling.
|
|
125
|
-
//
|
|
172
|
+
// content/*.json and other themes/*.json globs are ordinary glob imports, so
|
|
173
|
+
// Vite already invalidates + reloads them — left to default handling. A
|
|
174
|
+
// tenant's own theme.json (D1) is the one exception: instead of the default
|
|
175
|
+
// reload, handleHotUpdate below recomputes its CSS vars and patches them into
|
|
176
|
+
// the open page in place. Returning [] suppresses the pointless glob HMR that
|
|
177
|
+
// would otherwise fire for the raw files.
|
|
126
178
|
//
|
|
127
179
|
// RENAME/DELETE (C2): handleHotUpdate fires only on "change". Empirically, an
|
|
128
180
|
// add/unlink of a content/*.html file already triggers a correct Vite full-reload
|
|
@@ -231,6 +283,33 @@ export function tenantHotReload() {
|
|
|
231
283
|
return [];
|
|
232
284
|
}
|
|
233
285
|
|
|
286
|
+
// theme.json (D1): the only thing a save actually changes is the CSS
|
|
287
|
+
// custom-property values themeToCssVars() already serializes per request
|
|
288
|
+
// — recompute them the SAME way the SSR path does (middleware/index.ts)
|
|
289
|
+
// and patch them into the open page in place instead of reloading it.
|
|
290
|
+
// mergeTheme/themeToCssVars live in src/themes/schema.ts, a TS module
|
|
291
|
+
// only reachable through Vite's own transform pipeline — a plain Node
|
|
292
|
+
// `import` from this .mjs file can't load it, and `ssrLoadModule`
|
|
293
|
+
// requires the 'ssr' environment to be Node-runnable, which it isn't
|
|
294
|
+
// under the Cloudflare adapter (that environment runs in workerd). So
|
|
295
|
+
// loadTsModule() reuses the transform pipeline directly instead.
|
|
296
|
+
if (rest === "theme.json") {
|
|
297
|
+
try {
|
|
298
|
+
const raw = await readFile(ctx.file, "utf8");
|
|
299
|
+
const override = stripThemeMeta(JSON.parse(raw));
|
|
300
|
+
const { mergeTheme, themeToCssVars } = await loadTsModule(ctx.server, "/src/themes/schema.ts");
|
|
301
|
+
const { referenceTheme } = await loadTsModule(ctx.server, "/src/themes/reference.ts");
|
|
302
|
+
const css = themeToCssVars(mergeTheme(referenceTheme, override));
|
|
303
|
+
ctx.server.ws.send({ type: "custom", event: "tot:theme-vars", data: { css } });
|
|
304
|
+
return [];
|
|
305
|
+
} catch {
|
|
306
|
+
// Malformed theme.json mid-edit, or the module graph failed to
|
|
307
|
+
// load — degrade to the default full-reload rather than leaving
|
|
308
|
+
// the page on stale CSS vars or hanging silently.
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
234
313
|
return undefined;
|
|
235
314
|
},
|
|
236
315
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineConfig } from "drizzle-kit";
|
|
2
|
+
|
|
3
|
+
// Generate-only config for the STOREFRONT_APPS_DB lineage — sibling to
|
|
4
|
+
// drizzle.config.ts (catalog). Same dialect/driver; diffs schema-apps.ts into
|
|
5
|
+
// numbered SQL under migrations-apps/, which `wrangler d1 migrations apply
|
|
6
|
+
// STOREFRONT_APPS_DB` runs. Kept as a separate config (not a second `schema`
|
|
7
|
+
// entry on the catalog config) so each D1 gets its own independent migration
|
|
8
|
+
// lineage/journal — the whole point of splitting the database.
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
dialect: "sqlite",
|
|
11
|
+
schema: "./src/lib/d1/schema-apps.ts",
|
|
12
|
+
out: "./migrations-apps",
|
|
13
|
+
});
|
package/apps/storefront/env.d.ts
CHANGED
|
@@ -159,6 +159,16 @@ declare global {
|
|
|
159
159
|
};
|
|
160
160
|
/** Cloudflare runtime (env bindings) — provided by the adapter on Workers. */
|
|
161
161
|
runtime?: { env: CloudflareEnv };
|
|
162
|
+
/**
|
|
163
|
+
* Every private-app widget placement actually rendered for this request
|
|
164
|
+
* (PrivateApps epic, D5). The middleware seeds this to `[]` before
|
|
165
|
+
* `next()`; each page/layout that renders a widget slot (`renderSlot.ts`)
|
|
166
|
+
* pushes its resolved placements onto it as the page renders, so the
|
|
167
|
+
* middleware can read the full per-request set back out AFTER `next()`
|
|
168
|
+
* to extend the CSP's `frame-src` (`appWidgetCspAdditions`) with exactly
|
|
169
|
+
* the origins that ended up on the page — never more.
|
|
170
|
+
*/
|
|
171
|
+
activeWidgetPlacements?: { endpoint: string }[];
|
|
162
172
|
}
|
|
163
173
|
}
|
|
164
174
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
# D1 provision migrations (Drizzle Kit)
|
|
2
2
|
|
|
3
|
-
The catalog + customization D1 schema as numbered migrations, applied by
|
|
4
|
-
(the **provision** lifecycle phase — never `deploy`, never runtime). Generated
|
|
5
|
-
**Drizzle Kit** (ADR-0002), applied by `wrangler d1 migrations apply`.
|
|
3
|
+
The catalog + customization D1 (`CATALOG_DB`) schema as numbered migrations, applied by
|
|
4
|
+
`provision.sh` (the **provision** lifecycle phase — never `deploy`, never runtime). Generated
|
|
5
|
+
by **Drizzle Kit** (ADR-0002), applied by `wrangler d1 migrations apply`.
|
|
6
|
+
|
|
7
|
+
> The storefront-apps registry/webhooks/orders tables have their OWN D1
|
|
8
|
+
> (`STOREFRONT_APPS_DB`) + config (`drizzle.config.apps.ts`) + lineage
|
|
9
|
+
> (`../migrations-apps/`) — this directory holds ONLY catalog + customization.
|
|
6
10
|
|
|
7
11
|
## Source of truth
|
|
8
12
|
|
|
9
|
-
- **`src/lib/d1/schema.ts`** (Drizzle schema
|
|
10
|
-
*generation*. `drizzle-kit generate` diffs it into
|
|
11
|
-
(+ `meta/` journal) and owns the SQLite table-rebuild
|
|
13
|
+
- **`src/lib/d1/schema.ts`** (Drizzle schema, catalog + customization ONLY) is the
|
|
14
|
+
source of truth for migration *generation*. `drizzle-kit generate` diffs it into
|
|
15
|
+
numbered `migrations/*.sql` (+ `meta/` journal) and owns the SQLite table-rebuild
|
|
16
|
+
logic for `ALTER`s.
|
|
12
17
|
- **`products_fts`** (FTS5 virtual table) can't be modelled by Drizzle — it's a custom
|
|
13
18
|
migration (`0001_products_fts.sql`), hand-maintained.
|
|
14
19
|
- The raw-SQL read model + ETL still consume `CATALOG_D1_SCHEMA`/`CUSTOMIZATION_D1_SCHEMA`
|
|
@@ -51,4 +56,5 @@ wrangler d1 migrations apply CATALOG_DB --env <env> [--remote|--local]
|
|
|
51
56
|
```
|
|
52
57
|
|
|
53
58
|
> Catalog + customization tables share the **one** `CATALOG_DB` binding (one edge DB),
|
|
54
|
-
> per `src/lib/customization/d1Store.ts`.
|
|
59
|
+
> per `src/lib/customization/d1Store.ts`. The storefront-apps tables are a SEPARATE D1
|
|
60
|
+
> (`STOREFRONT_APPS_DB`) applied the same way, from `../migrations-apps/`.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
CREATE TABLE `app_attributions` (
|
|
2
|
+
`install_id` text NOT NULL,
|
|
3
|
+
`attribution_id` text NOT NULL,
|
|
4
|
+
`tenant_id` text NOT NULL,
|
|
5
|
+
`order_id` text NOT NULL,
|
|
6
|
+
`campaign` text,
|
|
7
|
+
`referral_code` text,
|
|
8
|
+
`commission_amount` real,
|
|
9
|
+
`commission_currency` text,
|
|
10
|
+
`customer_hash` text,
|
|
11
|
+
`recorded_at` text NOT NULL,
|
|
12
|
+
PRIMARY KEY(`install_id`, `attribution_id`)
|
|
13
|
+
);
|
|
14
|
+
--> statement-breakpoint
|
|
15
|
+
CREATE INDEX `idx_app_attributions_tenant_order` ON `app_attributions` (`tenant_id`,`order_id`);--> statement-breakpoint
|
|
16
|
+
CREATE TABLE `app_audit_log` (
|
|
17
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
18
|
+
`install_id` text NOT NULL,
|
|
19
|
+
`tenant_id` text NOT NULL,
|
|
20
|
+
`event` text NOT NULL,
|
|
21
|
+
`actor` text NOT NULL,
|
|
22
|
+
`trace_id` text,
|
|
23
|
+
`detail` text DEFAULT '{}' NOT NULL,
|
|
24
|
+
`at` text NOT NULL
|
|
25
|
+
);
|
|
26
|
+
--> statement-breakpoint
|
|
27
|
+
CREATE INDEX `idx_app_audit_install` ON `app_audit_log` (`install_id`);--> statement-breakpoint
|
|
28
|
+
CREATE TABLE `app_credentials` (
|
|
29
|
+
`install_id` text PRIMARY KEY NOT NULL,
|
|
30
|
+
`client_id` text NOT NULL,
|
|
31
|
+
`secret_hash` text NOT NULL,
|
|
32
|
+
`secret_created_at` text NOT NULL,
|
|
33
|
+
`rotated_at` text,
|
|
34
|
+
`jwks_kid` text NOT NULL
|
|
35
|
+
);
|
|
36
|
+
--> statement-breakpoint
|
|
37
|
+
CREATE UNIQUE INDEX `app_credentials_client_id_unique` ON `app_credentials` (`client_id`);--> statement-breakpoint
|
|
38
|
+
CREATE TABLE `app_installs` (
|
|
39
|
+
`install_id` text PRIMARY KEY NOT NULL,
|
|
40
|
+
`app_id` text NOT NULL,
|
|
41
|
+
`app_version` text NOT NULL,
|
|
42
|
+
`tenant_id` text NOT NULL,
|
|
43
|
+
`env` text NOT NULL,
|
|
44
|
+
`status` text DEFAULT 'active' NOT NULL,
|
|
45
|
+
`scopes` text DEFAULT '[]' NOT NULL,
|
|
46
|
+
`manifest` text NOT NULL,
|
|
47
|
+
`webhook_endpoint` text,
|
|
48
|
+
`widget_placements` text DEFAULT '[]' NOT NULL,
|
|
49
|
+
`install_actor` text NOT NULL,
|
|
50
|
+
`created_at` text NOT NULL,
|
|
51
|
+
`updated_at` text NOT NULL
|
|
52
|
+
);
|
|
53
|
+
--> statement-breakpoint
|
|
54
|
+
CREATE UNIQUE INDEX `uq_app_installs_app_tenant_env` ON `app_installs` (`app_id`,`tenant_id`,`env`);--> statement-breakpoint
|
|
55
|
+
CREATE INDEX `idx_app_installs_tenant` ON `app_installs` (`tenant_id`);--> statement-breakpoint
|
|
56
|
+
CREATE TABLE `idempotency_keys` (
|
|
57
|
+
`install_id` text NOT NULL,
|
|
58
|
+
`idempotency_key` text NOT NULL,
|
|
59
|
+
`body_hash` text NOT NULL,
|
|
60
|
+
`response_body` text NOT NULL,
|
|
61
|
+
`created_at` text NOT NULL,
|
|
62
|
+
PRIMARY KEY(`install_id`, `idempotency_key`)
|
|
63
|
+
);
|
|
64
|
+
--> statement-breakpoint
|
|
65
|
+
CREATE TABLE `orders` (
|
|
66
|
+
`tenant_id` text NOT NULL,
|
|
67
|
+
`external_order_id` text NOT NULL,
|
|
68
|
+
`env` text NOT NULL,
|
|
69
|
+
`status` text NOT NULL,
|
|
70
|
+
`currency` text NOT NULL,
|
|
71
|
+
`total` real DEFAULT 0 NOT NULL,
|
|
72
|
+
`subtotal` real,
|
|
73
|
+
`customer_hash` text,
|
|
74
|
+
`line_items` text DEFAULT '[]' NOT NULL,
|
|
75
|
+
`created_at` text NOT NULL,
|
|
76
|
+
`updated_at` text NOT NULL,
|
|
77
|
+
PRIMARY KEY(`tenant_id`, `external_order_id`)
|
|
78
|
+
);
|
|
79
|
+
--> statement-breakpoint
|
|
80
|
+
CREATE INDEX `idx_orders_tenant` ON `orders` (`tenant_id`);--> statement-breakpoint
|
|
81
|
+
CREATE TABLE `webhook_deliveries` (
|
|
82
|
+
`delivery_id` text PRIMARY KEY NOT NULL,
|
|
83
|
+
`event_id` text NOT NULL,
|
|
84
|
+
`install_id` text NOT NULL,
|
|
85
|
+
`tenant_id` text NOT NULL,
|
|
86
|
+
`topic` text NOT NULL,
|
|
87
|
+
`state` text DEFAULT 'pending' NOT NULL,
|
|
88
|
+
`attempts` integer DEFAULT 0 NOT NULL,
|
|
89
|
+
`last_status` integer,
|
|
90
|
+
`last_error_class` text,
|
|
91
|
+
`last_trace_id` text,
|
|
92
|
+
`next_attempt_at` text,
|
|
93
|
+
`created_at` text NOT NULL,
|
|
94
|
+
`updated_at` text NOT NULL
|
|
95
|
+
);
|
|
96
|
+
--> statement-breakpoint
|
|
97
|
+
CREATE INDEX `idx_webhook_deliveries_install` ON `webhook_deliveries` (`install_id`);--> statement-breakpoint
|
|
98
|
+
CREATE INDEX `idx_webhook_deliveries_due` ON `webhook_deliveries` (`state`,`next_attempt_at`);--> statement-breakpoint
|
|
99
|
+
CREATE TABLE `webhook_delivery_attempts` (
|
|
100
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
101
|
+
`delivery_id` text NOT NULL,
|
|
102
|
+
`attempt_no` integer NOT NULL,
|
|
103
|
+
`started_at` text NOT NULL,
|
|
104
|
+
`duration_ms` integer,
|
|
105
|
+
`http_status` integer,
|
|
106
|
+
`error_class` text,
|
|
107
|
+
`trace_id` text
|
|
108
|
+
);
|
|
109
|
+
--> statement-breakpoint
|
|
110
|
+
CREATE INDEX `idx_webhook_delivery_attempts_delivery` ON `webhook_delivery_attempts` (`delivery_id`);--> statement-breakpoint
|
|
111
|
+
CREATE TABLE `webhook_events` (
|
|
112
|
+
`id` text PRIMARY KEY NOT NULL,
|
|
113
|
+
`tenant_id` text NOT NULL,
|
|
114
|
+
`topic` text NOT NULL,
|
|
115
|
+
`dataschema_version` text NOT NULL,
|
|
116
|
+
`payload` text NOT NULL,
|
|
117
|
+
`created_at` text NOT NULL
|
|
118
|
+
);
|
|
119
|
+
--> statement-breakpoint
|
|
120
|
+
CREATE TABLE `webhook_install_health` (
|
|
121
|
+
`install_id` text PRIMARY KEY NOT NULL,
|
|
122
|
+
`last_success_at` text,
|
|
123
|
+
`failure_streak` integer DEFAULT 0 NOT NULL,
|
|
124
|
+
`dlq_count` integer DEFAULT 0 NOT NULL,
|
|
125
|
+
`last_status` integer,
|
|
126
|
+
`last_error_class` text,
|
|
127
|
+
`recent_trace_ids` text DEFAULT '[]' NOT NULL,
|
|
128
|
+
`updated_at` text NOT NULL
|
|
129
|
+
);
|