astroidjs 0.12.1 → 0.13.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/README.md +42 -42
- package/bin/astroid.mjs +25 -25
- package/dist/analytics/index.d.ts +3 -3
- package/dist/analytics/index.js +9 -9
- package/dist/astro/csp.d.ts +5 -5
- package/dist/astro/csp.js +6 -6
- package/dist/astro/index.js +1 -1
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +5 -5
- package/dist/commerce/adapters.d.ts +6 -6
- package/dist/commerce/adapters.js +9 -9
- package/dist/commerce/checkout-scaffold.d.ts +5 -5
- package/dist/commerce/checkout-scaffold.js +9 -9
- package/dist/commerce/checkout.d.ts +12 -12
- package/dist/commerce/checkout.js +7 -7
- package/dist/commerce/loader.d.ts +2 -2
- package/dist/commerce/loader.js +3 -3
- package/dist/commerce/mirror.d.ts +4 -4
- package/dist/commerce/mirror.js +9 -9
- package/dist/commerce/roles.d.ts +10 -10
- package/dist/commerce/roles.js +13 -13
- package/dist/commerce/secrets.d.ts +9 -9
- package/dist/commerce/secrets.js +9 -9
- package/dist/commerce/sync.d.ts +7 -7
- package/dist/commerce/sync.js +5 -5
- package/dist/components/sections.d.ts +9 -9
- package/dist/components/sections.js +12 -12
- package/dist/config.d.ts +62 -62
- package/dist/config.js +18 -18
- package/dist/email/inquiry.d.ts +2 -2
- package/dist/email/inquiry.js +1 -1
- package/dist/email/send.d.ts +4 -4
- package/dist/email/send.js +7 -7
- package/dist/email/templates.js +3 -3
- package/dist/email/theme.d.ts +1 -1
- package/dist/email/theme.js +4 -4
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -1
- package/dist/index.js +1 -1
- package/dist/map/pmtiles.d.ts +5 -5
- package/dist/map/pmtiles.js +5 -5
- package/dist/map/scaffold.d.ts +2 -2
- package/dist/map/scaffold.js +4 -4
- package/dist/map/style.d.ts +4 -4
- package/dist/map/style.js +1 -1
- package/dist/portal/config.d.ts +2 -2
- package/dist/portal/config.js +3 -3
- package/dist/portal/guard.d.ts +4 -4
- package/dist/portal/guard.js +4 -4
- package/dist/portal/nav.js +2 -2
- package/dist/portal/scaffold.d.ts +4 -4
- package/dist/portal/scaffold.js +6 -6
- package/dist/portal/session.d.ts +2 -2
- package/dist/portal/session.js +5 -5
- package/dist/portfolio/scaffold.d.ts +1 -1
- package/dist/portfolio/scaffold.js +4 -4
- package/dist/project/actions.d.ts +1 -1
- package/dist/project/actions.js +6 -6
- package/dist/project/generate.d.ts +4 -4
- package/dist/project/generate.js +15 -15
- package/dist/project/index.js +1 -1
- package/dist/project/scaffold.d.ts +2 -2
- package/dist/project/scaffold.js +11 -11
- package/dist/pwa/generate.d.ts +11 -11
- package/dist/pwa/generate.js +12 -12
- package/dist/queues/consumer.d.ts +3 -3
- package/dist/queues/consumer.js +2 -2
- package/dist/queues/messages.d.ts +4 -4
- package/dist/queues/messages.js +2 -2
- package/dist/queues/scaffold.d.ts +4 -4
- package/dist/queues/scaffold.js +8 -8
- package/dist/queues/webhook.d.ts +5 -5
- package/dist/queues/webhook.js +3 -3
- package/dist/realtime/scaffold.d.ts +4 -4
- package/dist/realtime/scaffold.js +8 -8
- package/dist/schema/collections.d.ts +6 -6
- package/dist/schema/collections.js +23 -23
- package/dist/schema/framework.d.ts +1 -1
- package/dist/schema/framework.js +2 -2
- package/dist/schema/generate.js +2 -2
- package/dist/schema/index.js +1 -1
- package/dist/secrets.d.ts +6 -6
- package/dist/secrets.js +6 -6
- package/dist/security/csp-origins.d.ts +1 -1
- package/dist/security/csp-origins.js +3 -3
- package/dist/security/rate-rules.d.ts +2 -2
- package/dist/security/rate-rules.js +8 -8
- package/dist/seo/resolve.d.ts +5 -5
- package/dist/seo/resolve.js +2 -2
- package/dist/seo/routes.d.ts +5 -5
- package/dist/seo/routes.js +3 -3
- package/dist/seo/structured-data.d.ts +6 -6
- package/dist/seo/structured-data.js +7 -7
- package/dist/status.d.ts +5 -5
- package/dist/status.js +7 -7
- package/dist/tenancy/index.d.ts +3 -3
- package/dist/tenancy/index.js +6 -6
- package/dist/worker/generate.d.ts +2 -2
- package/dist/worker/generate.js +19 -19
- package/dist/worker/index.js +1 -1
- package/dist/worker/routes.js +1 -1
- package/dist/workflow/advance.d.ts +3 -3
- package/dist/workflow/advance.js +6 -6
- package/dist/workflow/config.d.ts +4 -4
- package/dist/workflow/config.js +4 -4
- package/dist/workflow/generate.d.ts +2 -2
- package/dist/workflow/generate.js +4 -4
- package/package.json +3 -4
- package/src/components/Collection.tsx +5 -5
- package/src/components/Editable.astro +9 -9
- package/src/components/JustifiedGallery.astro +8 -8
- package/src/components/MediaSlot.astro +12 -12
- package/src/components/PortalShell.astro +4 -4
- package/src/components/RegisterSW.astro +3 -3
- package/src/components/Section.astro +8 -8
- package/src/components/Sections.astro +6 -6
- package/src/components/Seo.astro +3 -3
- package/src/components/StageBar.astro +3 -3
- package/src/components/StructuredData.astro +2 -2
- package/src/components/justify.ts +9 -9
- package/src/components/media-meta.ts +10 -10
- package/src/components/sections/AboutIntro.astro +1 -1
- package/src/components/sections/Contact.astro +1 -1
- package/src/components/sections/Cta.astro +1 -1
- package/src/components/sections/Faq.astro +1 -1
- package/src/components/sections/FeatureGrid.astro +2 -2
- package/src/components/sections/Hero.astro +1 -1
- package/src/components/sections/PricingTiers.astro +1 -1
- package/src/components/sections/ProductGrid.astro +1 -1
- package/src/components/sections/SplitImage.astro +1 -1
- package/src/components/sections/Steps.astro +1 -1
- package/src/components/sections/Testimonial.astro +1 -1
- package/src/components/sections.ts +17 -17
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { AstroidConfig } from "../config.js";
|
|
2
2
|
/** A generated file: a project-root-relative POSIX path + its full contents. */
|
|
3
3
|
export interface GeneratedFile {
|
|
4
|
-
/** Path relative to the project root, POSIX-separated (
|
|
4
|
+
/** Path relative to the project root, POSIX-separated (for example, `"src/worker.ts"`). */
|
|
5
5
|
path: string;
|
|
6
6
|
contents: string;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* The regenerated trio
|
|
9
|
+
* The regenerated trio—the files that are a pure function of the Astroid config
|
|
10
10
|
* and carry a "do not hand-edit" banner. `astroid generate` writes exactly these,
|
|
11
11
|
* and `astroid doctor` regenerates them in-memory to diff against disk. Scaffold-
|
|
12
12
|
* once files (wrangler.jsonc, astro.config, auth.ts) are NOT here by design.
|
|
@@ -22,7 +22,7 @@ export declare function generateAstroidProject(config: AstroidConfig): Generated
|
|
|
22
22
|
* names come from {@link commerceSecretNames}, the same declaration the runtime
|
|
23
23
|
* gate and the generated `env.d.ts` read.
|
|
24
24
|
*
|
|
25
|
-
* Empty string when the project enables no module that needs credentials
|
|
25
|
+
* Empty string when the project enables no module that needs credentials—the
|
|
26
26
|
* core secrets (session, Turnstile, mail) are already in the template file, with
|
|
27
27
|
* their own prose.
|
|
28
28
|
*/
|
|
@@ -31,7 +31,7 @@ export declare function generateAstroidSecretsEnv(config: AstroidConfig): string
|
|
|
31
31
|
* Generate a floor `wrangler.jsonc` from the config: the Worker name + editable
|
|
32
32
|
* bindings a baseline Louise site needs (D1, R2 media, the rate-limit + autosave
|
|
33
33
|
* KV, Cloudflare Images), custom-domain routes from `hosts`, and the `vars` the
|
|
34
|
-
* media route + editor read. Binding ids are placeholders
|
|
34
|
+
* media route + editor read. Binding ids are placeholders—real ids are filled by
|
|
35
35
|
* `wrangler … create` (or, later, `astroid deploy`); `astroid doctor` flags any
|
|
36
36
|
* still-unresolved placeholder.
|
|
37
37
|
*
|
package/dist/project/generate.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// Copyright (c) 2026 BowenLabs. Astroid is MIT licensed.
|
|
2
2
|
//
|
|
3
|
-
// Project generation
|
|
3
|
+
// Project generation—the config → files layer the `astroid` CLI writes.
|
|
4
4
|
//
|
|
5
5
|
// Two tiers of generated file, deliberately kept apart:
|
|
6
6
|
//
|
|
7
|
-
// 1. The REGENERATED trio (`generateAstroidProject`)
|
|
7
|
+
// 1. The REGENERATED trio (`generateAstroidProject`)—`src/schema.ts`,
|
|
8
8
|
// `src/worker.ts`, `src/middleware.ts`. Pure functions of the config, marked
|
|
9
9
|
// "do not hand-edit". `astroid generate` (and `dev`/`build`) rewrite these on
|
|
10
10
|
// every run, and `astroid doctor` diffs them to catch drift.
|
|
11
11
|
//
|
|
12
|
-
// 2. The SCAFFOLD-ONCE files (`generateAstroidWrangler`, …)
|
|
12
|
+
// 2. The SCAFFOLD-ONCE files (`generateAstroidWrangler`, …)—`wrangler.jsonc`
|
|
13
13
|
// and friends. `create-astroid` writes them once; the developer then owns
|
|
14
14
|
// them (fills real binding ids, secrets, account). `astroid generate` must
|
|
15
|
-
// NEVER clobber them, or it would wipe provisioned ids
|
|
15
|
+
// NEVER clobber them, or it would wipe provisioned ids—so they live in a
|
|
16
16
|
// separate function the regenerate path doesn't call.
|
|
17
17
|
import { ASTROID_VITALS_BINDING, astroidVitalsDataset } from "../analytics/index.js";
|
|
18
18
|
import { astroidCheckoutVars } from "../commerce/checkout-scaffold.js";
|
|
@@ -25,7 +25,7 @@ import { tenancyZone } from "../tenancy/index.js";
|
|
|
25
25
|
import { generateAstroidSchema } from "../schema/generate.js";
|
|
26
26
|
import { generateAstroidMiddleware, generateAstroidWorker } from "../worker/generate.js";
|
|
27
27
|
/**
|
|
28
|
-
* The regenerated trio
|
|
28
|
+
* The regenerated trio—the files that are a pure function of the Astroid config
|
|
29
29
|
* and carry a "do not hand-edit" banner. `astroid generate` writes exactly these,
|
|
30
30
|
* and `astroid doctor` regenerates them in-memory to diff against disk. Scaffold-
|
|
31
31
|
* once files (wrangler.jsonc, astro.config, auth.ts) are NOT here by design.
|
|
@@ -47,7 +47,7 @@ export function generateAstroidProject(config) {
|
|
|
47
47
|
* names come from {@link commerceSecretNames}, the same declaration the runtime
|
|
48
48
|
* gate and the generated `env.d.ts` read.
|
|
49
49
|
*
|
|
50
|
-
* Empty string when the project enables no module that needs credentials
|
|
50
|
+
* Empty string when the project enables no module that needs credentials—the
|
|
51
51
|
* core secrets (session, Turnstile, mail) are already in the template file, with
|
|
52
52
|
* their own prose.
|
|
53
53
|
*/
|
|
@@ -75,14 +75,14 @@ export function generateAstroidSecretsEnv(config) {
|
|
|
75
75
|
return lines.join("\n");
|
|
76
76
|
}
|
|
77
77
|
// Pinned compatibility date for the emitted Worker. A literal (Astroid's
|
|
78
|
-
// generators are pure
|
|
78
|
+
// generators are pure—no `Date.now()`), bumped deliberately when the runtime
|
|
79
79
|
// baseline moves; matches the reference site's wrangler.jsonc.
|
|
80
80
|
const COMPATIBILITY_DATE = "2026-06-20";
|
|
81
81
|
/**
|
|
82
82
|
* Generate a floor `wrangler.jsonc` from the config: the Worker name + editable
|
|
83
83
|
* bindings a baseline Louise site needs (D1, R2 media, the rate-limit + autosave
|
|
84
84
|
* KV, Cloudflare Images), custom-domain routes from `hosts`, and the `vars` the
|
|
85
|
-
* media route + editor read. Binding ids are placeholders
|
|
85
|
+
* media route + editor read. Binding ids are placeholders—real ids are filled by
|
|
86
86
|
* `wrangler … create` (or, later, `astroid deploy`); `astroid doctor` flags any
|
|
87
87
|
* still-unresolved placeholder.
|
|
88
88
|
*
|
|
@@ -120,7 +120,7 @@ export function generateAstroidWrangler(config) {
|
|
|
120
120
|
p(` { "pattern": ${JSON.stringify(host)}, "custom_domain": true },`);
|
|
121
121
|
}
|
|
122
122
|
if (tenancy) {
|
|
123
|
-
// A wildcard is a ZONE route, never a custom domain
|
|
123
|
+
// A wildcard is a ZONE route, never a custom domain—Cloudflare rejects
|
|
124
124
|
// `custom_domain: true` on a pattern containing `*`, which is precisely
|
|
125
125
|
// why `hosts` cannot express this.
|
|
126
126
|
p(" // Wildcard tenant hosts (`tenancy.hostPattern`). A zone route, NOT a");
|
|
@@ -137,7 +137,7 @@ export function generateAstroidWrangler(config) {
|
|
|
137
137
|
}
|
|
138
138
|
if (usesRealtime(config)) {
|
|
139
139
|
// The per-page live editing session (ADR 0002). Two halves, and BOTH are
|
|
140
|
-
// required
|
|
140
|
+
// required—a binding with no migration is a deploy error, and the class
|
|
141
141
|
// must also be exported from the worker entry (the generated src/worker.ts
|
|
142
142
|
// re-exports it) or wrangler can't resolve `class_name`.
|
|
143
143
|
p(" // Durable Object: the per-page live editing session (realtime module).");
|
|
@@ -154,7 +154,7 @@ export function generateAstroidWrangler(config) {
|
|
|
154
154
|
}
|
|
155
155
|
// Crons. ONE `scheduled` handler receives all of them and tells them apart by
|
|
156
156
|
// `controller.cron`, so this list and the handler's dispatch must agree
|
|
157
|
-
// exactly
|
|
157
|
+
// exactly—both come from `astroidCrons`, which is why it exists.
|
|
158
158
|
//
|
|
159
159
|
// Daily: the site-health scan (broken links, missing alt text, SEO gaps).
|
|
160
160
|
// Hourly (commerce only): the catalog re-sync safety net, so a missed or DLQ'd
|
|
@@ -217,8 +217,8 @@ export function generateAstroidWrangler(config) {
|
|
|
217
217
|
// Email Sending. NOT optional decoration: `src/env.d.ts` declares EMAIL as a
|
|
218
218
|
// required member, and Better Auth's magic-link path console-logs the link in
|
|
219
219
|
// dev but calls `env.EMAIL.send(...)` unconditionally in production. Without
|
|
220
|
-
// this binding that call is a TypeError on a binding that was never created
|
|
221
|
-
//
|
|
220
|
+
// this binding that call is a TypeError on a binding that was never created—so
|
|
221
|
+
// sign-in was impossible on every DEPLOYED site, while every local build
|
|
222
222
|
// and every CI scaffold passed. Nothing in this repo runs a deployed scaffold,
|
|
223
223
|
// which is why it survived.
|
|
224
224
|
p(" // Cloudflare Email Sending — magic-link sign-in + inquiry notifications.");
|
|
@@ -242,7 +242,7 @@ export function generateAstroidWrangler(config) {
|
|
|
242
242
|
p(" // undo — this feature was reverted twice for exactly that.");
|
|
243
243
|
p(' "ASTROID_EDGE_CACHE": "false",');
|
|
244
244
|
for (const v of astroidCheckoutVars(config)) {
|
|
245
|
-
// Public, not secret
|
|
245
|
+
// Public, not secret—the app id ships to the browser to mount the card
|
|
246
246
|
// field, and the environment is a choice. Keeping them out of the secret
|
|
247
247
|
// roster also keeps them out of the dormancy gate, which asks whether we can
|
|
248
248
|
// safely CALL Square, not whether a card field can render.
|
|
@@ -251,7 +251,7 @@ export function generateAstroidWrangler(config) {
|
|
|
251
251
|
p(" },");
|
|
252
252
|
// Secrets are NOT vars: they belong in .dev.vars locally and in `wrangler
|
|
253
253
|
// secret put` / Secrets Store when deployed. Listing the names here is
|
|
254
|
-
// deliberate
|
|
254
|
+
// deliberate—this is the file someone opens when provisioning, and the list
|
|
255
255
|
// is generated from the same declaration the runtime dormancy gate reads.
|
|
256
256
|
const secretNames = commerceSecretNames(config.commerce);
|
|
257
257
|
if (secretNames.length > 0) {
|
package/dist/project/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2026 BowenLabs. Astroid is MIT licensed.
|
|
2
2
|
//
|
|
3
|
-
// Project generation
|
|
3
|
+
// Project generation—config → the files the `astroid` CLI writes (the
|
|
4
4
|
// regenerated schema/worker/middleware trio + the scaffold-once wrangler.jsonc).
|
|
5
5
|
export * from "./generate.js";
|
|
6
6
|
export * from "./actions.js";
|
|
@@ -4,7 +4,7 @@ import type { AstroidConfig } from "../config.js";
|
|
|
4
4
|
*
|
|
5
5
|
* `apply` is the whole contract. `"skip"` (the default) leaves an existing file
|
|
6
6
|
* alone. `"append-once"` is for the files a project accumulates into rather than
|
|
7
|
-
* owns outright
|
|
7
|
+
* owns outright—`public/_headers` gets a stanza per module, and a second
|
|
8
8
|
* module must not erase the first one's.
|
|
9
9
|
*/
|
|
10
10
|
export interface ScaffoldFile {
|
|
@@ -23,7 +23,7 @@ export interface ScaffoldFile {
|
|
|
23
23
|
* Every scaffold-once file this config implies.
|
|
24
24
|
*
|
|
25
25
|
* Ordered by module so a `generate` that writes several prints them in a stable
|
|
26
|
-
* sequence. Returns `[]` for a plain marketing site with no modules
|
|
26
|
+
* sequence. Returns `[]` for a plain marketing site with no modules—the
|
|
27
27
|
* baseline floor is entirely the regenerated trio plus the static template.
|
|
28
28
|
*/
|
|
29
29
|
export declare function generateAstroidScaffoldFiles(config: AstroidConfig): ScaffoldFile[];
|
package/dist/project/scaffold.js
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
// src/worker.ts → import { handleQueueMessage } from "./queue.js"
|
|
10
10
|
// src/middleware.ts → import { resolvePortalUser } from "./portal-auth.js"
|
|
11
11
|
//
|
|
12
|
-
// The files behind those imports were written in exactly one
|
|
13
|
-
//
|
|
12
|
+
// The files behind those imports were written in exactly one
|
|
13
|
+
// place—`create-astroid`'s CLI—and nothing else could produce them. So turning a
|
|
14
14
|
// module on AFTER scaffold, by editing the one typed config the framework is
|
|
15
15
|
// built around, regenerated a trio importing files that did not exist. `astroid
|
|
16
16
|
// doctor` reported "healthy" and the project failed in Vite.
|
|
@@ -41,7 +41,7 @@ import { generateAstroidQueueSeam, generateAstroidWebhookRoutes } from "../queue
|
|
|
41
41
|
* Every scaffold-once file this config implies.
|
|
42
42
|
*
|
|
43
43
|
* Ordered by module so a `generate` that writes several prints them in a stable
|
|
44
|
-
* sequence. Returns `[]` for a plain marketing site with no modules
|
|
44
|
+
* sequence. Returns `[]` for a plain marketing site with no modules—the
|
|
45
45
|
* baseline floor is entirely the regenerated trio plus the static template.
|
|
46
46
|
*/
|
|
47
47
|
export function generateAstroidScaffoldFiles(config) {
|
|
@@ -56,7 +56,7 @@ export function generateAstroidScaffoldFiles(config) {
|
|
|
56
56
|
files.push({ path: "migrations/0003_catalog.sql", contents: catalogSql });
|
|
57
57
|
// --- the CWV beacon -------------------------------------------------------
|
|
58
58
|
// A static file under public/, so it is same-origin and covered by
|
|
59
|
-
// `script-src 'self'
|
|
59
|
+
// `script-src 'self'`—an inline script carrying generated content could not
|
|
60
60
|
// be hashed into the CSP and would be blocked.
|
|
61
61
|
const beacon = generateAstroidVitalsBeacon(config, cwvBeaconScript());
|
|
62
62
|
files.push({ path: beacon.path, contents: beacon.contents });
|
|
@@ -96,7 +96,7 @@ export function generateAstroidScaffoldFiles(config) {
|
|
|
96
96
|
// is why `astroid generate` must never rewrite them.
|
|
97
97
|
if (astroidUsesQueues(config)) {
|
|
98
98
|
files.push({ path: "src/queue.ts", contents: generateAstroidQueueSeam(config) });
|
|
99
|
-
// One receiver per provider
|
|
99
|
+
// One receiver per provider—a site can run two (invoicing + storefront).
|
|
100
100
|
for (const route of generateAstroidWebhookRoutes(config)) {
|
|
101
101
|
files.push({ path: route.path, contents: route.contents });
|
|
102
102
|
}
|
|
@@ -107,14 +107,14 @@ export function generateAstroidScaffoldFiles(config) {
|
|
|
107
107
|
if (gallery)
|
|
108
108
|
files.push({ path: "src/pages/work.astro", contents: gallery });
|
|
109
109
|
// --- pwa: the service worker, manifest, and its headers -------------------
|
|
110
|
-
// Static files under public/, not generated source
|
|
110
|
+
// Static files under public/, not generated source—a service worker is not
|
|
111
111
|
// bundled, and `_headers` is shared with whatever else writes to it.
|
|
112
112
|
const sw = generateServiceWorker(config);
|
|
113
113
|
if (sw) {
|
|
114
114
|
// `emitDir` puts them where the BROWSER will ask for them. A PWA on its own
|
|
115
115
|
// subdomain that rewrites to a path prefix (studio.example.com/ → /studio/)
|
|
116
|
-
// fetches /sw.js at its own origin root, which rewrites to /studio/sw.js
|
|
117
|
-
//
|
|
116
|
+
// fetches /sw.js at its own origin root, which rewrites to /studio/sw.js—so
|
|
117
|
+
// a worker emitted at the public root is a 404 nothing explains.
|
|
118
118
|
const pwaDir = resolvePwa(config).emitDir;
|
|
119
119
|
const publicBase = pwaDir ? `public/${pwaDir}` : "public";
|
|
120
120
|
files.push({ path: `${publicBase}/sw.js`, contents: sw });
|
|
@@ -125,7 +125,7 @@ export function generateAstroidScaffoldFiles(config) {
|
|
|
125
125
|
const headers = generatePwaHeaders(config);
|
|
126
126
|
if (headers) {
|
|
127
127
|
files.push({
|
|
128
|
-
// `_headers` stays at the public root wherever the worker lives
|
|
128
|
+
// `_headers` stays at the public root wherever the worker lives—it is
|
|
129
129
|
// one file for the whole site, and Cloudflare only reads it there.
|
|
130
130
|
path: "public/_headers",
|
|
131
131
|
contents: headers,
|
|
@@ -154,7 +154,7 @@ export function generateAstroidScaffoldFiles(config) {
|
|
|
154
154
|
files.push({ path: "src/edit-session.ts", contents: editSession });
|
|
155
155
|
// --- tenancy: what a subdomain maps to ------------------------------------
|
|
156
156
|
// Astroid owns the wildcard route and the middleware wiring; this file owns
|
|
157
|
-
// every decision
|
|
157
|
+
// every decision—the lookup, its caching, and what an unknown host means.
|
|
158
158
|
const tenancy = generateAstroidTenancy(config);
|
|
159
159
|
if (tenancy)
|
|
160
160
|
files.push({ path: "src/tenancy.ts", contents: tenancy });
|
|
@@ -167,7 +167,7 @@ export function generateAstroidScaffoldFiles(config) {
|
|
|
167
167
|
const route = generateAstroidPortalAuthRoute(config);
|
|
168
168
|
// Always non-null alongside portalAuth (same `astroidPortal` gate), but the
|
|
169
169
|
// types don't know that and a silent drop here is a portal that cannot
|
|
170
|
-
// authenticate
|
|
170
|
+
// authenticate—so assert it rather than `?.`-ing it away.
|
|
171
171
|
//
|
|
172
172
|
// The route file lives at the mount path, because Astro routing is
|
|
173
173
|
// file-path-based: a portal mounted at `/api/shop-auth` needs its catch-all
|
package/dist/pwa/generate.d.ts
CHANGED
|
@@ -21,38 +21,38 @@ export interface PwaConfig {
|
|
|
21
21
|
/** Extra paths to precache alongside the scope root. */
|
|
22
22
|
shell?: string[];
|
|
23
23
|
/**
|
|
24
|
-
* A prerendered page to serve when a navigation fails offline,
|
|
24
|
+
* A prerendered page to serve when a navigation fails offline, for example,
|
|
25
25
|
* `"/offline"`.
|
|
26
26
|
*
|
|
27
|
-
* Without it the fallback is the scope root
|
|
27
|
+
* Without it the fallback is the scope root—the *dynamic* app shell, which
|
|
28
28
|
* is exactly the wrong thing to precache when the app is auth-gated: that
|
|
29
29
|
* response carries `Cache-Control: no-store`, so either nothing is cached and
|
|
30
30
|
* the fallback is empty, or a signed-in shell is stored and later served to
|
|
31
31
|
* whoever opens the app next.
|
|
32
32
|
*
|
|
33
33
|
* Point it at a page with no session-specific markup. It is precached with the
|
|
34
|
-
* shell, so it must be prerendered
|
|
34
|
+
* shell, so it must be prerendered—a dynamic route here fails at exactly the
|
|
35
35
|
* moment it is needed.
|
|
36
36
|
*/
|
|
37
37
|
offlineFallback?: string;
|
|
38
38
|
/**
|
|
39
|
-
* Subdirectory under `public/` to emit `sw.js` and the manifest into,
|
|
39
|
+
* Subdirectory under `public/` to emit `sw.js` and the manifest into, for example,
|
|
40
40
|
* `"studio"`. Default: the public root.
|
|
41
41
|
*
|
|
42
|
-
* For a PWA served from its own subdomain that rewrites to a path prefix
|
|
43
|
-
*
|
|
42
|
+
* For a PWA served from its own subdomain that rewrites to a path prefix—`studio.example.com/`
|
|
43
|
+
* → `/studio/`—the browser fetches `/sw.js` at *its*
|
|
44
44
|
* origin root, which rewrites to `/studio/sw.js`. Emitting at the public root
|
|
45
45
|
* puts the file where nothing will ask for it.
|
|
46
46
|
*
|
|
47
47
|
* Set this to the same prefix the host rewrites to. With `scope` equal to the
|
|
48
|
-
* serving path, no `Service-Worker-Allowed` header is needed
|
|
48
|
+
* serving path, no `Service-Worker-Allowed` header is needed—a worker may
|
|
49
49
|
* always control its own directory and below.
|
|
50
50
|
*/
|
|
51
51
|
emitDir?: string;
|
|
52
52
|
}
|
|
53
53
|
/** True when this project switched the PWA on. */
|
|
54
54
|
export declare const usesPwa: (config: AstroidConfig) => boolean;
|
|
55
|
-
/** Resolved PWA settings
|
|
55
|
+
/** Resolved PWA settings—config over derivation over default. */
|
|
56
56
|
export declare function resolvePwa(config: AstroidConfig): Required<Omit<PwaConfig, "shell" | "offlineFallback" | "emitDir">> & {
|
|
57
57
|
shell: string[];
|
|
58
58
|
/** `null` when the app falls back to the scope root (see the config note). */
|
|
@@ -63,18 +63,18 @@ export declare function resolvePwa(config: AstroidConfig): Required<Omit<PwaConf
|
|
|
63
63
|
/**
|
|
64
64
|
* `public/manifest.webmanifest`.
|
|
65
65
|
*
|
|
66
|
-
* Icons are declared but NOT generated
|
|
66
|
+
* Icons are declared but NOT generated—a brand's icon is not something a
|
|
67
67
|
* scaffold can invent, and emitting placeholders would produce an installable
|
|
68
68
|
* app with a grey square for a face. The generated README step says to add them.
|
|
69
69
|
*/
|
|
70
70
|
export declare function generateWebManifest(config: AstroidConfig): string | null;
|
|
71
|
-
/** `public/sw.js`. Plain JS
|
|
71
|
+
/** `public/sw.js`. Plain JS—a service worker is not bundled. */
|
|
72
72
|
export declare function generateServiceWorker(config: AstroidConfig): string | null;
|
|
73
73
|
/**
|
|
74
74
|
* The `public/_headers` block the PWA needs.
|
|
75
75
|
*
|
|
76
76
|
* `Service-Worker-Allowed` is emitted ONLY when the scope is broader than the
|
|
77
|
-
* script's own location
|
|
77
|
+
* script's own location—which, with `sw.js` at the root, never is. Emitting it
|
|
78
78
|
* unconditionally (as the reference does) is harmless but misleading: it implies
|
|
79
79
|
* a requirement that isn't there, and someone later moving the script will trust
|
|
80
80
|
* a header that no longer says what they need.
|
package/dist/pwa/generate.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
// Copyright (c) 2026 BowenLabs. Astroid is MIT licensed.
|
|
2
2
|
//
|
|
3
|
-
// The PWA scaffold
|
|
3
|
+
// The PWA scaffold—a scoped service worker, a manifest, and the headers they
|
|
4
4
|
// need.
|
|
5
5
|
//
|
|
6
6
|
// The scoping is the whole design, not a detail. A Louise site is CMS-edited:
|
|
7
7
|
// an editor signs in, flips edit mode on, and edits the live page in place. A
|
|
8
8
|
// service worker that cached HTML across the whole origin would serve that
|
|
9
|
-
// editor a stale copy of the page they are trying to change
|
|
9
|
+
// editor a stale copy of the page they are trying to change—and the bug would
|
|
10
10
|
// present as "my edits don't save", which is about as far from the cause as a
|
|
11
11
|
// report can get.
|
|
12
12
|
//
|
|
13
13
|
// So the generated worker is scoped, and inside its scope it still refuses to
|
|
14
14
|
// touch anything dynamic:
|
|
15
15
|
//
|
|
16
|
-
// • `/api/*` never cached
|
|
17
|
-
// • editor routes never cached
|
|
18
|
-
// • edit-mode URLs never cached
|
|
16
|
+
// • `/api/*` never cached—checkout, auth, and every Louise write
|
|
17
|
+
// • editor routes never cached—the studio must always be live
|
|
18
|
+
// • edit-mode URLs never cached—`?louise` marks a request as an editing
|
|
19
19
|
// session, and caching one poisons it for everyone
|
|
20
20
|
//
|
|
21
21
|
// Everything else is the ordinary split: navigations network-first with a
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
// when their content does.
|
|
24
24
|
/** True when this project switched the PWA on. */
|
|
25
25
|
export const usesPwa = (config) => (config.modules ?? []).includes("pwa");
|
|
26
|
-
/** Resolved PWA settings
|
|
26
|
+
/** Resolved PWA settings—config over derivation over default. */
|
|
27
27
|
export function resolvePwa(config) {
|
|
28
28
|
const pwa = config.pwa ?? {};
|
|
29
29
|
// Normalized to a leading slash and no trailing one (except root), because
|
|
@@ -41,7 +41,7 @@ export function resolvePwa(config) {
|
|
|
41
41
|
themeColor: pwa.themeColor ?? config.theme.colors.brand,
|
|
42
42
|
offlineFallback: pwa.offlineFallback ?? null,
|
|
43
43
|
emitDir: (pwa.emitDir ?? "").replace(/^\/+|\/+$/g, ""),
|
|
44
|
-
// The offline page is precached with the shell
|
|
44
|
+
// The offline page is precached with the shell—a fallback fetched on
|
|
45
45
|
// demand is a fallback that isn't there when the network is.
|
|
46
46
|
shell: [
|
|
47
47
|
scope,
|
|
@@ -51,7 +51,7 @@ export function resolvePwa(config) {
|
|
|
51
51
|
],
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
/** URL prefix the emitted `sw.js` + manifest are served from
|
|
54
|
+
/** URL prefix the emitted `sw.js` + manifest are served from—`""` at the
|
|
55
55
|
* public root, `"/studio"` under an `emitDir`. */
|
|
56
56
|
function assetBase(emitDir) {
|
|
57
57
|
const dir = (emitDir ?? "").replace(/^\/+|\/+$/g, "");
|
|
@@ -60,7 +60,7 @@ function assetBase(emitDir) {
|
|
|
60
60
|
/**
|
|
61
61
|
* `public/manifest.webmanifest`.
|
|
62
62
|
*
|
|
63
|
-
* Icons are declared but NOT generated
|
|
63
|
+
* Icons are declared but NOT generated—a brand's icon is not something a
|
|
64
64
|
* scaffold can invent, and emitting placeholders would produce an installable
|
|
65
65
|
* app with a grey square for a face. The generated README step says to add them.
|
|
66
66
|
*/
|
|
@@ -100,7 +100,7 @@ export function generateWebManifest(config) {
|
|
|
100
100
|
],
|
|
101
101
|
}, null, 2)}\n`;
|
|
102
102
|
}
|
|
103
|
-
/** `public/sw.js`. Plain JS
|
|
103
|
+
/** `public/sw.js`. Plain JS—a service worker is not bundled. */
|
|
104
104
|
export function generateServiceWorker(config) {
|
|
105
105
|
if (!usesPwa(config))
|
|
106
106
|
return null;
|
|
@@ -230,7 +230,7 @@ export function generateServiceWorker(config) {
|
|
|
230
230
|
* The `public/_headers` block the PWA needs.
|
|
231
231
|
*
|
|
232
232
|
* `Service-Worker-Allowed` is emitted ONLY when the scope is broader than the
|
|
233
|
-
* script's own location
|
|
233
|
+
* script's own location—which, with `sw.js` at the root, never is. Emitting it
|
|
234
234
|
* unconditionally (as the reference does) is harmless but misleading: it implies
|
|
235
235
|
* a requirement that isn't there, and someone later moving the script will trust
|
|
236
236
|
* a header that no longer says what they need.
|
|
@@ -238,7 +238,7 @@ export function generateServiceWorker(config) {
|
|
|
238
238
|
export function generatePwaHeaders(config) {
|
|
239
239
|
if (!usesPwa(config))
|
|
240
240
|
return null;
|
|
241
|
-
// Paths must match where the files are actually emitted
|
|
241
|
+
// Paths must match where the files are actually emitted—a stanza for
|
|
242
242
|
// `/sw.js` while the worker lives at `/studio/sw.js` sets headers on nothing,
|
|
243
243
|
// and the no-cache rule is what stops a bad worker sticking around.
|
|
244
244
|
const base = assetBase(config.pwa?.emitDir);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type AstroidQueueMessage } from "./messages.js";
|
|
2
2
|
export interface QueueHandlerOptions {
|
|
3
3
|
/**
|
|
4
|
-
* Re-sync whatever the provider owns
|
|
4
|
+
* Re-sync whatever the provider owns—the catalog mirror, a cache. Called
|
|
5
5
|
* for a periodic refresh and for webhooks that touched the catalog.
|
|
6
6
|
*
|
|
7
7
|
* Receives the message that triggered it, so a site running more than one
|
|
8
8
|
* commerce provider can branch on `message.provider` rather than refreshing
|
|
9
|
-
* everything for everything. A zero-argument seam stays valid
|
|
9
|
+
* everything for everything. A zero-argument seam stays valid—the parameter
|
|
10
10
|
* is there to be ignored until it's needed.
|
|
11
11
|
*
|
|
12
12
|
* Throwing marks the message for retry, which is usually right: a failed
|
|
@@ -24,7 +24,7 @@ export interface QueueHandlerOptions {
|
|
|
24
24
|
* storefront and Square as its POS, at which point `refreshCatalog` means
|
|
25
25
|
* "re-pull Fourthwall" while Square emits `inventory.count.updated` on every
|
|
26
26
|
* single sale. Unscoped, a good Saturday becomes a sync storm against an
|
|
27
|
-
* unrelated provider's rate limit
|
|
27
|
+
* unrelated provider's rate limit—and the periodic refresh is unaffected, so
|
|
28
28
|
* the site looks fine until the day it's busy.
|
|
29
29
|
*/
|
|
30
30
|
catalogProvider?: string;
|
package/dist/queues/consumer.js
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
// acks as a no-op.
|
|
10
10
|
//
|
|
11
11
|
// That last part matters more than it looks. Order, payment, and subscription
|
|
12
|
-
// events are read live from the provider, so there is nothing local to
|
|
13
|
-
// but they still arrive, in volume. A consumer that treats every event as
|
|
12
|
+
// events are read live from the provider, so there is nothing local to
|
|
13
|
+
// update—but they still arrive, in volume. A consumer that treats every event as
|
|
14
14
|
// actionable turns a busy sales day into a catalog-refresh storm.
|
|
15
15
|
import { affectsCatalog } from "./messages.js";
|
|
16
16
|
/**
|
|
@@ -14,7 +14,7 @@ export declare const ASTROID_DEFAULT_CRON = "0 * * * *";
|
|
|
14
14
|
export declare function astroidCron(config: AstroidConfig): string | null;
|
|
15
15
|
/**
|
|
16
16
|
* Daily, at an off-peak-ish minute. The health scan crawls the site's own pages,
|
|
17
|
-
* so it is deliberately NOT on the hourly catalog cron
|
|
17
|
+
* so it is deliberately NOT on the hourly catalog cron—hourly would be a
|
|
18
18
|
* self-inflicted crawl 24× a day to recompute counts that move slowly.
|
|
19
19
|
*/
|
|
20
20
|
export declare const ASTROID_HEALTH_CRON = "17 4 * * *";
|
|
@@ -31,7 +31,7 @@ export declare const ASTROID_HEALTH_CRON = "17 4 * * *";
|
|
|
31
31
|
export declare function astroidCrons(config: AstroidConfig): string[];
|
|
32
32
|
/** Binding name for the project's queue producer. */
|
|
33
33
|
export declare const ASTROID_QUEUE_BINDING = "COMMERCE_QUEUE";
|
|
34
|
-
/** Queue names derived from the project key
|
|
34
|
+
/** Queue names derived from the project key—the main queue and its DLQ. */
|
|
35
35
|
export declare function astroidQueueNames(config: AstroidConfig): {
|
|
36
36
|
queue: string;
|
|
37
37
|
dlq: string;
|
|
@@ -44,9 +44,9 @@ export declare function astroidQueueNames(config: AstroidConfig): {
|
|
|
44
44
|
*/
|
|
45
45
|
export interface WebhookMessage {
|
|
46
46
|
kind: "webhook";
|
|
47
|
-
/** Which integration sent it
|
|
47
|
+
/** Which integration sent it—`"square"`, `"stripe"`, `"fourthwall"`. */
|
|
48
48
|
provider: string;
|
|
49
|
-
/** The provider's event type,
|
|
49
|
+
/** The provider's event type, for example, `"catalog.version.updated"`. */
|
|
50
50
|
type: string;
|
|
51
51
|
payload: unknown;
|
|
52
52
|
}
|
package/dist/queues/messages.js
CHANGED
|
@@ -25,7 +25,7 @@ export function astroidCron(config) {
|
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Daily, at an off-peak-ish minute. The health scan crawls the site's own pages,
|
|
28
|
-
* so it is deliberately NOT on the hourly catalog cron
|
|
28
|
+
* so it is deliberately NOT on the hourly catalog cron—hourly would be a
|
|
29
29
|
* self-inflicted crawl 24× a day to recompute counts that move slowly.
|
|
30
30
|
*/
|
|
31
31
|
export const ASTROID_HEALTH_CRON = "17 4 * * *";
|
|
@@ -52,7 +52,7 @@ export function astroidCrons(config) {
|
|
|
52
52
|
}
|
|
53
53
|
/** Binding name for the project's queue producer. */
|
|
54
54
|
export const ASTROID_QUEUE_BINDING = "COMMERCE_QUEUE";
|
|
55
|
-
/** Queue names derived from the project key
|
|
55
|
+
/** Queue names derived from the project key—the main queue and its DLQ. */
|
|
56
56
|
export function astroidQueueNames(config) {
|
|
57
57
|
return { queue: `${config.key}-commerce`, dlq: `${config.key}-commerce-dlq` };
|
|
58
58
|
}
|
|
@@ -11,7 +11,7 @@ import type { AstroidConfig, CommerceProvider } from "../config.js";
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function generateAstroidEnvBindings(config: AstroidConfig): string;
|
|
13
13
|
/**
|
|
14
|
-
* `src/queue.ts
|
|
14
|
+
* `src/queue.ts`—the consumer seam the generated worker imports.
|
|
15
15
|
*
|
|
16
16
|
* `astroidQueueHandler` already owns the dispatch every site wrote (periodic
|
|
17
17
|
* refresh, catalog-affecting webhook, no-op for everything else); what's left
|
|
@@ -20,14 +20,14 @@ export declare function generateAstroidEnvBindings(config: AstroidConfig): strin
|
|
|
20
20
|
*/
|
|
21
21
|
export declare function generateAstroidQueueSeam(config: AstroidConfig): string;
|
|
22
22
|
/**
|
|
23
|
-
* The provider webhook receiver
|
|
23
|
+
* The provider webhook receiver—`src/pages/api/webhooks/<provider>.ts`.
|
|
24
24
|
*
|
|
25
25
|
* Thin on purpose: `handleWebhook` owns the ordering (verify the raw body before
|
|
26
26
|
* parsing) and the status-code contract (which codes ask the provider to retry
|
|
27
27
|
* and which tell it to stop). What's here is the provider's own header and
|
|
28
28
|
* verifier, plus the secret read.
|
|
29
29
|
*
|
|
30
|
-
* Returns null when the project has no commerce provider
|
|
30
|
+
* Returns null when the project has no commerce provider—nothing to receive.
|
|
31
31
|
*/
|
|
32
32
|
export declare function generateAstroidWebhookRoute(config: AstroidConfig, forProvider?: CommerceProvider): string | null;
|
|
33
33
|
/**
|
|
@@ -35,7 +35,7 @@ export declare function generateAstroidWebhookRoute(config: AstroidConfig, forPr
|
|
|
35
35
|
*
|
|
36
36
|
* Plural because roles are: a site running Stripe for invoicing beside
|
|
37
37
|
* Fourthwall for the storefront receives from both, each with its own signing
|
|
38
|
-
* secret and header. One route per provider, not per role
|
|
38
|
+
* secret and header. One route per provider, not per role—a provider filling
|
|
39
39
|
* two roles still has one endpoint and one secret.
|
|
40
40
|
*/
|
|
41
41
|
export declare function generateAstroidWebhookRoutes(config: AstroidConfig): {
|
package/dist/queues/scaffold.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// The two SCAFFOLD-ONCE files the queue pipeline needs: the consumer seam
|
|
4
4
|
// (`src/queue.ts`) and the provider webhook receiver.
|
|
5
5
|
//
|
|
6
|
-
// Deliberately not part of the regenerated trio. Both exist to be edited
|
|
6
|
+
// Deliberately not part of the regenerated trio. Both exist to be edited—the
|
|
7
7
|
// consumer is where a project says what a catalog refresh actually does, and the
|
|
8
8
|
// webhook route is where it narrows which events it cares about. Regenerating
|
|
9
9
|
// over them would erase exactly the work they're for. The same boundary
|
|
@@ -15,7 +15,7 @@ import { ASTROID_QUEUE_BINDING } from "./messages.js";
|
|
|
15
15
|
/**
|
|
16
16
|
* Per-provider webhook facts: the header, the verifier, and how it's called.
|
|
17
17
|
*
|
|
18
|
-
* The signing-secret NAME is deliberately not here
|
|
18
|
+
* The signing-secret NAME is deliberately not here—it's one field of a
|
|
19
19
|
* provider's secret set, which `commerce/secrets.ts` owns so the wrangler
|
|
20
20
|
* generator, the status report, and this scaffold all read the same list.
|
|
21
21
|
*/
|
|
@@ -66,7 +66,7 @@ export function generateAstroidEnvBindings(config) {
|
|
|
66
66
|
// One secret SET per provider: a site running Stripe for invoicing and
|
|
67
67
|
// Fourthwall for the storefront talks to both, credentialed and signed
|
|
68
68
|
// independently. Every one is optional, because every one is allowed to be
|
|
69
|
-
// absent
|
|
69
|
+
// absent—that's what leaves the module dormant rather than broken.
|
|
70
70
|
...providers.flatMap((provider) => [
|
|
71
71
|
` /** ${provider} API credentials. Absent or still holding the`,
|
|
72
72
|
" * DUMMY_REPLACE_ME sentinel reads as unconfigured, which leaves commerce",
|
|
@@ -80,7 +80,7 @@ export function generateAstroidEnvBindings(config) {
|
|
|
80
80
|
].join("\n");
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
|
-
* `src/queue.ts
|
|
83
|
+
* `src/queue.ts`—the consumer seam the generated worker imports.
|
|
84
84
|
*
|
|
85
85
|
* `astroidQueueHandler` already owns the dispatch every site wrote (periodic
|
|
86
86
|
* refresh, catalog-affecting webhook, no-op for everything else); what's left
|
|
@@ -88,7 +88,7 @@ export function generateAstroidEnvBindings(config) {
|
|
|
88
88
|
* a generated constant.
|
|
89
89
|
*/
|
|
90
90
|
export function generateAstroidQueueSeam(config) {
|
|
91
|
-
// The STOREFRONT provider
|
|
91
|
+
// The STOREFRONT provider—it's the one with a catalog to re-sync. An
|
|
92
92
|
// invoicing-only provider has nothing for this hook to do.
|
|
93
93
|
const provider = astroidCommerceRoles(config.commerce).storefront;
|
|
94
94
|
const table = astroidCatalogMirror(config).table;
|
|
@@ -169,14 +169,14 @@ export function generateAstroidQueueSeam(config) {
|
|
|
169
169
|
.join("\n");
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
|
-
* The provider webhook receiver
|
|
172
|
+
* The provider webhook receiver—`src/pages/api/webhooks/<provider>.ts`.
|
|
173
173
|
*
|
|
174
174
|
* Thin on purpose: `handleWebhook` owns the ordering (verify the raw body before
|
|
175
175
|
* parsing) and the status-code contract (which codes ask the provider to retry
|
|
176
176
|
* and which tell it to stop). What's here is the provider's own header and
|
|
177
177
|
* verifier, plus the secret read.
|
|
178
178
|
*
|
|
179
|
-
* Returns null when the project has no commerce provider
|
|
179
|
+
* Returns null when the project has no commerce provider—nothing to receive.
|
|
180
180
|
*/
|
|
181
181
|
export function generateAstroidWebhookRoute(config, forProvider) {
|
|
182
182
|
const provider = forProvider ?? astroidCommerceProviders(config.commerce)[0];
|
|
@@ -222,7 +222,7 @@ export function generateAstroidWebhookRoute(config, forProvider) {
|
|
|
222
222
|
*
|
|
223
223
|
* Plural because roles are: a site running Stripe for invoicing beside
|
|
224
224
|
* Fourthwall for the storefront receives from both, each with its own signing
|
|
225
|
-
* secret and header. One route per provider, not per role
|
|
225
|
+
* secret and header. One route per provider, not per role—a provider filling
|
|
226
226
|
* two roles still has one endpoint and one secret.
|
|
227
227
|
*/
|
|
228
228
|
export function generateAstroidWebhookRoutes(config) {
|