astroidjs 0.9.5 → 0.10.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/dist/astro/csp.d.ts +2 -8
- package/dist/astro/csp.js +2 -75
- package/dist/astro/index.d.ts +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/security/csp-origins.d.ts +16 -0
- package/dist/security/csp-origins.js +99 -0
- package/dist/worker/generate.js +5 -2
- package/package.json +5 -6
package/dist/astro/csp.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { AstroidConfig
|
|
1
|
+
import type { AstroidConfig } from "../config.js";
|
|
2
|
+
export { astroidCspOrigins } from "../security/csp-origins.js";
|
|
2
3
|
/** A `sha256-…` CSP hash, in the shape Astro's `security.csp.hashes` takes. */
|
|
3
4
|
export type CspHash = `${"sha256" | "sha384" | "sha512"}-${string}`;
|
|
4
5
|
/**
|
|
@@ -38,12 +39,6 @@ export interface AstroidSecurityConfig {
|
|
|
38
39
|
* hash on the next build.
|
|
39
40
|
*/
|
|
40
41
|
export declare function solidHydrationHash(): CspHash;
|
|
41
|
-
/**
|
|
42
|
-
* Every origin the project's enabled modules need, merged with the config's own
|
|
43
|
-
* `security.cspOrigins`. Exported so a site (or `astroid doctor`) can inspect
|
|
44
|
-
* what a config implies without rebuilding the whole policy.
|
|
45
|
-
*/
|
|
46
|
-
export declare function astroidCspOrigins(config: AstroidConfig): Required<CspOrigins>;
|
|
47
42
|
/**
|
|
48
43
|
* The `security` block for `astro.config.mjs` — Astro's half of the split.
|
|
49
44
|
*
|
|
@@ -61,4 +56,3 @@ export declare function astroidSecurity(config: AstroidConfig): AstroidSecurityC
|
|
|
61
56
|
export declare const ASTROID_VITE_BUILD: {
|
|
62
57
|
readonly assetsInlineLimit: 0;
|
|
63
58
|
};
|
|
64
|
-
export {};
|
package/dist/astro/csp.js
CHANGED
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
// imports.
|
|
28
28
|
import { createHash } from "node:crypto";
|
|
29
29
|
import { generateHydrationScript } from "solid-js/web";
|
|
30
|
-
import {
|
|
30
|
+
import { astroidCspOrigins } from "../security/csp-origins.js";
|
|
31
|
+
export { astroidCspOrigins } from "../security/csp-origins.js";
|
|
31
32
|
/**
|
|
32
33
|
* Hash of Solid's inline hydration bootstrap.
|
|
33
34
|
*
|
|
@@ -42,80 +43,6 @@ export function solidHydrationHash() {
|
|
|
42
43
|
const inner = generateHydrationScript().match(/<script[^>]*>([\s\S]*?)<\/script>/)?.[1] ?? "";
|
|
43
44
|
return `sha256-${createHash("sha256").update(inner).digest("base64")}`;
|
|
44
45
|
}
|
|
45
|
-
/** Origins a commerce provider's client-side SDK needs. Server-only providers
|
|
46
|
-
* (Fourthwall's storefront API) contribute nothing but their image host. */
|
|
47
|
-
const COMMERCE_ORIGINS = {
|
|
48
|
-
// Square Web Payments renders the card form in an iframe from the squarecdn
|
|
49
|
-
// hosts, tokenizes against pci-connect, and pulls its own fonts. Both the
|
|
50
|
-
// sandbox and production hosts are listed so ONE build serves either
|
|
51
|
-
// environment — which environment you're in is a runtime secret, not a
|
|
52
|
-
// build-time one.
|
|
53
|
-
square: {
|
|
54
|
-
script: ["https://sandbox.web.squarecdn.com", "https://web.squarecdn.com"],
|
|
55
|
-
frame: [
|
|
56
|
-
"https://sandbox.web.squarecdn.com",
|
|
57
|
-
"https://web.squarecdn.com",
|
|
58
|
-
"https://connect.squareupsandbox.com",
|
|
59
|
-
"https://connect.squareup.com",
|
|
60
|
-
],
|
|
61
|
-
connect: [
|
|
62
|
-
"https://pci-connect.squareupsandbox.com",
|
|
63
|
-
"https://pci-connect.squareup.com",
|
|
64
|
-
"https://sandbox.web.squarecdn.com",
|
|
65
|
-
"https://web.squarecdn.com",
|
|
66
|
-
],
|
|
67
|
-
font: [
|
|
68
|
-
"https://square-fonts-production-f.squarecdn.com",
|
|
69
|
-
"https://d1g145x70srn7h.cloudfront.net",
|
|
70
|
-
],
|
|
71
|
-
},
|
|
72
|
-
// Stripe.js and its Elements/Checkout iframes.
|
|
73
|
-
stripe: {
|
|
74
|
-
script: ["https://js.stripe.com"],
|
|
75
|
-
frame: ["https://js.stripe.com", "https://hooks.stripe.com"],
|
|
76
|
-
connect: ["https://api.stripe.com"],
|
|
77
|
-
},
|
|
78
|
-
// Fourthwall is read server-side; nothing runs in the browser.
|
|
79
|
-
fourthwall: {},
|
|
80
|
-
};
|
|
81
|
-
// Turnstile. Always allowed, not gated on the captcha being configured: the
|
|
82
|
-
// scaffold ships the widget dormant (see the dormant-until-provisioned
|
|
83
|
-
// convention) and it must not need a rebuild to switch on — CSP is baked at
|
|
84
|
-
// build time, the secret is a runtime value.
|
|
85
|
-
const TURNSTILE = {
|
|
86
|
-
script: ["https://challenges.cloudflare.com"],
|
|
87
|
-
frame: ["https://challenges.cloudflare.com"],
|
|
88
|
-
connect: ["https://challenges.cloudflare.com"],
|
|
89
|
-
};
|
|
90
|
-
// The map module. MapLibre spins its tile-decoding workers up from blob: URLs,
|
|
91
|
-
// so `worker-src blob:` is not optional — without it the map renders an empty
|
|
92
|
-
// canvas and the console fills with worker-construction errors.
|
|
93
|
-
//
|
|
94
|
-
// Nothing else is needed, and that's the whole argument for the self-hosted
|
|
95
|
-
// basemap: the PMTiles archive is served same-origin, so `connect-src` stays
|
|
96
|
-
// `'self'` with no tile host and no API key to allow.
|
|
97
|
-
const MAP = { worker: ["blob:"] };
|
|
98
|
-
const DIRECTIVE_KEYS = ["script", "frame", "connect", "font", "img", "worker"];
|
|
99
|
-
/** Merge origin lists, de-duplicated, order preserved. */
|
|
100
|
-
function mergeOrigins(...sets) {
|
|
101
|
-
const out = {};
|
|
102
|
-
for (const key of DIRECTIVE_KEYS) {
|
|
103
|
-
out[key] = [...new Set(sets.flatMap((set) => set[key] ?? []))];
|
|
104
|
-
}
|
|
105
|
-
return out;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Every origin the project's enabled modules need, merged with the config's own
|
|
109
|
-
* `security.cspOrigins`. Exported so a site (or `astroid doctor`) can inspect
|
|
110
|
-
* what a config implies without rebuilding the whole policy.
|
|
111
|
-
*/
|
|
112
|
-
export function astroidCspOrigins(config) {
|
|
113
|
-
return mergeOrigins(TURNSTILE, ...((config.modules ?? []).includes("map") ? [MAP] : []),
|
|
114
|
-
// EVERY provider in play, not "the" provider: a site can run Stripe for
|
|
115
|
-
// invoicing beside Fourthwall for the storefront, and a policy that allowed
|
|
116
|
-
// only one of them blocks the other's SDK at runtime.
|
|
117
|
-
...astroidCommerceProviders(config.commerce).map((p) => COMMERCE_ORIGINS[p] ?? {}), config.security?.cspOrigins ?? {});
|
|
118
|
-
}
|
|
119
46
|
/**
|
|
120
47
|
* Render one directive. The name is a literal from the union above, so the
|
|
121
48
|
* concatenation is a valid `CspDirective` by construction — which is what the
|
package/dist/astro/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ASTROID_VITE_BUILD, astroidCspOrigins, astroidSecurity, type AstroidSecurityConfig, type CspHash, solidHydrationHash, } from "./csp.js";
|
|
1
|
+
export { ASTROID_VITE_BUILD, astroidCspOrigins, astroidSecurity, type AstroidSecurityConfig, type CspDirective, type CspHash, solidHydrationHash, } from "./csp.js";
|
package/dist/config.d.ts
CHANGED
|
@@ -378,6 +378,8 @@ export interface SecurityConfig {
|
|
|
378
378
|
/** Per-directive origin lists contributed to the CSP. */
|
|
379
379
|
export interface CspOrigins {
|
|
380
380
|
script?: string[];
|
|
381
|
+
/** Rendered by the generated middleware (it owns `style-src`), not by Astro. */
|
|
382
|
+
style?: string[];
|
|
381
383
|
frame?: string[];
|
|
382
384
|
connect?: string[];
|
|
383
385
|
font?: string[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AstroidConfig, CspOrigins } from "../config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Every origin the project's enabled modules need, merged with the config's own
|
|
4
|
+
* `security.cspOrigins`. Exported so a site (or `astroid doctor`) can inspect
|
|
5
|
+
* what a config implies without rebuilding the whole policy.
|
|
6
|
+
*/
|
|
7
|
+
export declare function astroidCspOrigins(config: AstroidConfig): Required<CspOrigins>;
|
|
8
|
+
/**
|
|
9
|
+
* The `style-src` value the generated middleware rewrites every response to.
|
|
10
|
+
*
|
|
11
|
+
* `'unsafe-inline'` is required (Louise's data-driven `style=""` carriers and
|
|
12
|
+
* the editor's runtime `<style>`), which is why Astro can't own this directive:
|
|
13
|
+
* per spec a single hash here voids `'unsafe-inline'`. Module and config
|
|
14
|
+
* `style` origins ride along, e.g. the Square SDK's own stylesheet.
|
|
15
|
+
*/
|
|
16
|
+
export declare function astroidCspStyleSrc(config: AstroidConfig): string;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Copyright (c) 2026 BowenLabs. Astroid is MIT licensed.
|
|
2
|
+
//
|
|
3
|
+
// The CSP origins a config implies, as plain data.
|
|
4
|
+
//
|
|
5
|
+
// Split out of `astro/csp.ts` (build-time only: `node:crypto`, `solid-js/web`)
|
|
6
|
+
// so the worker generator can read it too: Astro's `security.csp` renders every
|
|
7
|
+
// directive except `style-src`, and the generated middleware renders that one.
|
|
8
|
+
// Both have to see the same origin set, or a module's stylesheet host lands in
|
|
9
|
+
// one half of the policy and not the other.
|
|
10
|
+
import { astroidCommerceProviders } from "../commerce/roles.js";
|
|
11
|
+
/** Origins a commerce provider's client-side SDK needs. Server-only providers
|
|
12
|
+
* (Fourthwall's storefront API) contribute nothing but their image host. */
|
|
13
|
+
const COMMERCE_ORIGINS = {
|
|
14
|
+
// Square Web Payments renders the card form in an iframe from the squarecdn
|
|
15
|
+
// hosts, tokenizes against pci-connect, and pulls its own fonts. Both the
|
|
16
|
+
// sandbox and production hosts are listed so ONE build serves either
|
|
17
|
+
// environment — which environment you're in is a runtime secret, not a
|
|
18
|
+
// build-time one.
|
|
19
|
+
square: {
|
|
20
|
+
script: ["https://sandbox.web.squarecdn.com", "https://web.squarecdn.com"],
|
|
21
|
+
frame: [
|
|
22
|
+
"https://sandbox.web.squarecdn.com",
|
|
23
|
+
"https://web.squarecdn.com",
|
|
24
|
+
"https://connect.squareupsandbox.com",
|
|
25
|
+
"https://connect.squareup.com",
|
|
26
|
+
],
|
|
27
|
+
connect: [
|
|
28
|
+
"https://pci-connect.squareupsandbox.com",
|
|
29
|
+
"https://pci-connect.squareup.com",
|
|
30
|
+
"https://sandbox.web.squarecdn.com",
|
|
31
|
+
"https://web.squarecdn.com",
|
|
32
|
+
],
|
|
33
|
+
// Web Payments SDK 1.85+ attaches its own `card-wrapper.css` to the HOST
|
|
34
|
+
// page (not just inside the iframe). Block it and `card.attach()` rejects,
|
|
35
|
+
// so the card form never mounts.
|
|
36
|
+
style: ["https://sandbox.web.squarecdn.com", "https://web.squarecdn.com"],
|
|
37
|
+
font: [
|
|
38
|
+
"https://square-fonts-production-f.squarecdn.com",
|
|
39
|
+
"https://d1g145x70srn7h.cloudfront.net",
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
// Stripe.js and its Elements/Checkout iframes.
|
|
43
|
+
stripe: {
|
|
44
|
+
script: ["https://js.stripe.com"],
|
|
45
|
+
frame: ["https://js.stripe.com", "https://hooks.stripe.com"],
|
|
46
|
+
connect: ["https://api.stripe.com"],
|
|
47
|
+
},
|
|
48
|
+
// Fourthwall is read server-side; nothing runs in the browser.
|
|
49
|
+
fourthwall: {},
|
|
50
|
+
};
|
|
51
|
+
// Turnstile. Always allowed, not gated on the captcha being configured: the
|
|
52
|
+
// scaffold ships the widget dormant (see the dormant-until-provisioned
|
|
53
|
+
// convention) and it must not need a rebuild to switch on — CSP is baked at
|
|
54
|
+
// build time, the secret is a runtime value.
|
|
55
|
+
const TURNSTILE = {
|
|
56
|
+
script: ["https://challenges.cloudflare.com"],
|
|
57
|
+
frame: ["https://challenges.cloudflare.com"],
|
|
58
|
+
connect: ["https://challenges.cloudflare.com"],
|
|
59
|
+
};
|
|
60
|
+
// The map module. MapLibre spins its tile-decoding workers up from blob: URLs,
|
|
61
|
+
// so `worker-src blob:` is not optional — without it the map renders an empty
|
|
62
|
+
// canvas and the console fills with worker-construction errors.
|
|
63
|
+
//
|
|
64
|
+
// Nothing else is needed, and that's the whole argument for the self-hosted
|
|
65
|
+
// basemap: the PMTiles archive is served same-origin, so `connect-src` stays
|
|
66
|
+
// `'self'` with no tile host and no API key to allow.
|
|
67
|
+
const MAP = { worker: ["blob:"] };
|
|
68
|
+
const DIRECTIVE_KEYS = ["script", "style", "frame", "connect", "font", "img", "worker"];
|
|
69
|
+
/** Merge origin lists, de-duplicated, order preserved. */
|
|
70
|
+
function mergeOrigins(...sets) {
|
|
71
|
+
const out = {};
|
|
72
|
+
for (const key of DIRECTIVE_KEYS) {
|
|
73
|
+
out[key] = [...new Set(sets.flatMap((set) => set[key] ?? []))];
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Every origin the project's enabled modules need, merged with the config's own
|
|
79
|
+
* `security.cspOrigins`. Exported so a site (or `astroid doctor`) can inspect
|
|
80
|
+
* what a config implies without rebuilding the whole policy.
|
|
81
|
+
*/
|
|
82
|
+
export function astroidCspOrigins(config) {
|
|
83
|
+
return mergeOrigins(TURNSTILE, ...((config.modules ?? []).includes("map") ? [MAP] : []),
|
|
84
|
+
// EVERY provider in play, not "the" provider: a site can run Stripe for
|
|
85
|
+
// invoicing beside Fourthwall for the storefront, and a policy that allowed
|
|
86
|
+
// only one of them blocks the other's SDK at runtime.
|
|
87
|
+
...astroidCommerceProviders(config.commerce).map((p) => COMMERCE_ORIGINS[p] ?? {}), config.security?.cspOrigins ?? {});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The `style-src` value the generated middleware rewrites every response to.
|
|
91
|
+
*
|
|
92
|
+
* `'unsafe-inline'` is required (Louise's data-driven `style=""` carriers and
|
|
93
|
+
* the editor's runtime `<style>`), which is why Astro can't own this directive:
|
|
94
|
+
* per spec a single hash here voids `'unsafe-inline'`. Module and config
|
|
95
|
+
* `style` origins ride along, e.g. the Square SDK's own stylesheet.
|
|
96
|
+
*/
|
|
97
|
+
export function astroidCspStyleSrc(config) {
|
|
98
|
+
return ["'self'", "'unsafe-inline'", ...astroidCspOrigins(config).style].join(" ");
|
|
99
|
+
}
|
package/dist/worker/generate.js
CHANGED
|
@@ -17,6 +17,7 @@ import { astroidPortal } from "../portal/config.js";
|
|
|
17
17
|
import { ASTROID_HEALTH_CRON, astroidCron, astroidUsesQueues } from "../queues/messages.js";
|
|
18
18
|
import { ASTROID_EDIT_SESSION_CLASS, ASTROID_REALTIME_BINDING, usesRealtime, } from "../realtime/scaffold.js";
|
|
19
19
|
import { capturesInquiries } from "../schema/framework.js";
|
|
20
|
+
import { astroidCspStyleSrc } from "../security/csp-origins.js";
|
|
20
21
|
import { ASTROID_REWRITE_EXCLUDE, ASTROID_TENANT_PREFIX } from "../tenancy/index.js";
|
|
21
22
|
import { astroidEditorRoutePlan } from "./routes.js";
|
|
22
23
|
// Astroid's default editable site_settings surface — the columns the Settings
|
|
@@ -470,8 +471,10 @@ export function generateAstroidWorker(config) {
|
|
|
470
471
|
export function generateAstroidMiddleware(config) {
|
|
471
472
|
// Louise's brand font is bundled + base64-inlined (no Google Fonts host to
|
|
472
473
|
// allow); createLouiseMiddleware auto-allows `data:` fonts in the CSP, so the
|
|
473
|
-
// inlined @font-face needs no manual `font-src` entry.
|
|
474
|
-
|
|
474
|
+
// inlined @font-face needs no manual `font-src` entry. Module + config `style`
|
|
475
|
+
// origins (the Square SDK's stylesheet) are baked in here; `astroid build`
|
|
476
|
+
// regenerates this file, so a config change lands on the next deploy.
|
|
477
|
+
const cspStyleSrc = astroidCspStyleSrc(config);
|
|
475
478
|
const portal = astroidPortal(config);
|
|
476
479
|
const tenancy = config.tenancy;
|
|
477
480
|
const rewritePrefix = tenancy?.rewritePrefix ?? ASTROID_TENANT_PREFIX;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astroidjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Astroid — an opinionated meta-framework over Louise Toolkit and Astro for building editable, multi-editor sites on Cloudflare Workers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"author": "BowenLabs",
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/bowenlabs/
|
|
17
|
+
"url": "git+https://github.com/bowenlabs/astroidjs.git",
|
|
18
18
|
"directory": "packages/astroid"
|
|
19
19
|
},
|
|
20
20
|
"bin": {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"access": "public"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"louise-toolkit": "0.
|
|
63
|
+
"louise-toolkit": "^0.28.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@types/node": "^24.13.3",
|
|
@@ -83,12 +83,11 @@
|
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
85
|
"engines": {
|
|
86
|
-
"node": ">=
|
|
86
|
+
"node": ">=26.0.0"
|
|
87
87
|
},
|
|
88
88
|
"scripts": {
|
|
89
89
|
"build": "tsgo -p tsconfig.build.json",
|
|
90
|
-
"
|
|
91
|
-
"test": "vp test",
|
|
90
|
+
"test": "vitest run",
|
|
92
91
|
"typecheck": "tsgo --noEmit"
|
|
93
92
|
}
|
|
94
93
|
}
|