@demiurgejs/core 0.2.0-beta.2 → 0.2.0-beta.4
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 +13 -11
- package/bin/demiurge.mjs +30 -12
- package/dist/adapter/testing.js.map +1 -1
- package/dist/browser/file-router.d.ts +388 -5
- package/dist/browser/file-router.d.ts.map +1 -1
- package/dist/browser/focus.d.ts +20 -0
- package/dist/browser/focus.d.ts.map +1 -0
- package/dist/browser/index.d.ts +7 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/mutation-action.d.ts +81 -0
- package/dist/browser/mutation-action.d.ts.map +1 -0
- package/dist/chunks/document-shell-CpJnFtSC.js +36 -0
- package/dist/chunks/document-shell-CpJnFtSC.js.map +1 -0
- package/dist/chunks/env-startup-DOBYWlZD.js +257 -0
- package/dist/chunks/env-startup-DOBYWlZD.js.map +1 -0
- package/dist/chunks/{image-codec-BGTx_t5K.js → image-codec-BmzWnH6W.js} +2 -2
- package/dist/chunks/{image-codec-BGTx_t5K.js.map → image-codec-BmzWnH6W.js.map} +1 -1
- package/dist/chunks/{images-B9MqcjSA.js → images-BQ80950B.js} +99 -91
- package/dist/chunks/images-BQ80950B.js.map +1 -0
- package/dist/chunks/index-BVk9zWbe.js +832 -0
- package/dist/chunks/index-BVk9zWbe.js.map +1 -0
- package/dist/chunks/manifest-vO6c0G0W.js +19 -0
- package/dist/chunks/manifest-vO6c0G0W.js.map +1 -0
- package/dist/chunks/plugin-BQgMiHxa.js +1827 -0
- package/dist/chunks/plugin-BQgMiHxa.js.map +1 -0
- package/dist/chunks/session-store-ChModVcq.js +92 -0
- package/dist/chunks/session-store-ChModVcq.js.map +1 -0
- package/dist/chunks/static-files-ehaD1kE7.js +51 -0
- package/dist/chunks/static-files-ehaD1kE7.js.map +1 -0
- package/dist/chunks/{streaming-BQ1bykDo.js → streaming-BEbPN7Uk.js} +163 -163
- package/dist/chunks/streaming-BEbPN7Uk.js.map +1 -0
- package/dist/chunks/testing-DueXbMo4.js +4167 -0
- package/dist/chunks/testing-DueXbMo4.js.map +1 -0
- package/dist/chunks/vite-DO70kZA6.js +259 -0
- package/dist/chunks/vite-DO70kZA6.js.map +1 -0
- package/dist/cli.d.ts +17 -25
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +159 -124
- package/dist/cli.js.map +1 -1
- package/dist/config/define.d.ts +3 -0
- package/dist/config/define.d.ts.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +78 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load.d.ts +12 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/types.d.ts +64 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/validate.d.ts +9 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/vite.d.ts +12 -0
- package/dist/config/vite.d.ts.map +1 -0
- package/dist/data/cache.d.ts +10 -0
- package/dist/data/cache.d.ts.map +1 -1
- package/dist/data/idempotency.d.ts.map +1 -1
- package/dist/data/index.d.ts +3 -1
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/testing.d.ts.map +1 -1
- package/dist/data/testing.js +94 -72
- package/dist/data/testing.js.map +1 -1
- package/dist/data/tiered.d.ts +7 -0
- package/dist/data/tiered.d.ts.map +1 -0
- package/dist/deployment/testing.d.ts +25 -0
- package/dist/deployment/testing.d.ts.map +1 -0
- package/dist/deployment/testing.js +171 -0
- package/dist/deployment/testing.js.map +1 -0
- package/dist/document/deferred-scripts.d.ts.map +1 -1
- package/dist/document/hydration.d.ts +9 -0
- package/dist/document/hydration.d.ts.map +1 -1
- package/dist/document/index.d.ts +5 -2
- package/dist/document/index.d.ts.map +1 -1
- package/dist/document/metadata.d.ts +8 -0
- package/dist/document/metadata.d.ts.map +1 -1
- package/dist/document/navigation.d.ts +28 -0
- package/dist/document/navigation.d.ts.map +1 -0
- package/dist/document/render.d.ts +3 -1
- package/dist/document/render.d.ts.map +1 -1
- package/dist/document/seo.d.ts.map +1 -1
- package/dist/document/trusted-types.d.ts +10 -0
- package/dist/document/trusted-types.d.ts.map +1 -0
- package/dist/edge/assets.d.ts.map +1 -1
- package/dist/edge/index.js +55 -73
- package/dist/edge/index.js.map +1 -1
- package/dist/index.d.ts +15 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2078 -573
- package/dist/index.js.map +1 -1
- package/dist/internal/testing.js +11 -11
- package/dist/kv/index.d.ts +4 -0
- package/dist/kv/index.d.ts.map +1 -1
- package/dist/kv/index.js +180 -60
- package/dist/kv/index.js.map +1 -1
- package/dist/kv/rate-limit-store.d.ts +8 -0
- package/dist/kv/rate-limit-store.d.ts.map +1 -0
- package/dist/kv/session-store.d.ts +20 -0
- package/dist/kv/session-store.d.ts.map +1 -0
- package/dist/kv/store.d.ts.map +1 -1
- package/dist/manifest.d.ts +10 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/node/http.d.ts.map +1 -1
- package/dist/node/image.d.ts.map +1 -1
- package/dist/node/index.d.ts +3 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +251 -178
- package/dist/node/index.js.map +1 -1
- package/dist/node/serve.d.ts +47 -0
- package/dist/node/serve.d.ts.map +1 -0
- package/dist/node/static.d.ts.map +1 -1
- package/dist/node/streaming.d.ts.map +1 -1
- package/dist/platform/fonts.d.ts.map +1 -1
- package/dist/platform/image-url.d.ts.map +1 -1
- package/dist/platform/images.d.ts.map +1 -1
- package/dist/platform/index.d.ts +5 -1
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/observability.d.ts +2 -1
- package/dist/platform/observability.d.ts.map +1 -1
- package/dist/platform/url.d.ts +19 -0
- package/dist/platform/url.d.ts.map +1 -0
- package/dist/platform/web-vitals-client.d.ts +32 -0
- package/dist/platform/web-vitals-client.d.ts.map +1 -0
- package/dist/platform/web-vitals.d.ts +78 -0
- package/dist/platform/web-vitals.d.ts.map +1 -0
- package/dist/redis/index.d.ts +4 -0
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +209 -54
- package/dist/redis/index.js.map +1 -1
- package/dist/redis/rate-limit-store.d.ts +8 -0
- package/dist/redis/rate-limit-store.d.ts.map +1 -0
- package/dist/redis/session-store.d.ts +9 -0
- package/dist/redis/session-store.d.ts.map +1 -0
- package/dist/redis/store.d.ts.map +1 -1
- package/dist/route/index.d.ts +2 -2
- package/dist/route/index.d.ts.map +1 -1
- package/dist/route/middleware.d.ts.map +1 -1
- package/dist/route/mutation.d.ts +97 -0
- package/dist/route/mutation.d.ts.map +1 -0
- package/dist/route/response.d.ts.map +1 -1
- package/dist/route/types.d.ts +6 -1
- package/dist/route/types.d.ts.map +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/manifest.d.ts +9 -0
- package/dist/router/manifest.d.ts.map +1 -1
- package/dist/router/navigation-data.d.ts +9 -1
- package/dist/router/navigation-data.d.ts.map +1 -1
- package/dist/routing/generate.d.ts +3 -0
- package/dist/routing/generate.d.ts.map +1 -1
- package/dist/routing/index.d.ts +3 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/locale.d.ts +43 -0
- package/dist/routing/locale.d.ts.map +1 -0
- package/dist/routing/types.d.ts +12 -0
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/security/cookie-session.d.ts +43 -0
- package/dist/security/cookie-session.d.ts.map +1 -0
- package/dist/security/cookies.d.ts +26 -0
- package/dist/security/cookies.d.ts.map +1 -0
- package/dist/security/csrf.d.ts +1 -1
- package/dist/security/csrf.d.ts.map +1 -1
- package/dist/security/env-startup.d.ts +15 -0
- package/dist/security/env-startup.d.ts.map +1 -0
- package/dist/security/env.d.ts +25 -6
- package/dist/security/env.d.ts.map +1 -1
- package/dist/security/fetch-metadata.d.ts +29 -0
- package/dist/security/fetch-metadata.d.ts.map +1 -0
- package/dist/security/index.d.ts +14 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/policy.d.ts.map +1 -1
- package/dist/security/rate-limit.d.ts +6 -3
- package/dist/security/rate-limit.d.ts.map +1 -1
- package/dist/security/report.d.ts.map +1 -1
- package/dist/security/request.d.ts.map +1 -1
- package/dist/security/session-manager.d.ts +32 -0
- package/dist/security/session-manager.d.ts.map +1 -0
- package/dist/security/session-store.d.ts +51 -0
- package/dist/security/session-store.d.ts.map +1 -0
- package/dist/security/testing.d.ts +10 -0
- package/dist/security/testing.d.ts.map +1 -0
- package/dist/security/testing.js +145 -0
- package/dist/security/testing.js.map +1 -0
- package/dist/security/types.d.ts +73 -3
- package/dist/security/types.d.ts.map +1 -1
- package/dist/server/document-shell.d.ts.map +1 -1
- package/dist/server/errors.d.ts +1 -0
- package/dist/server/errors.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/not-found.d.ts +1 -0
- package/dist/server/not-found.d.ts.map +1 -1
- package/dist/server/render-tree.d.ts.map +1 -1
- package/dist/server/request-handler.d.ts +10 -2
- package/dist/server/request-handler.d.ts.map +1 -1
- package/dist/server/request-metadata.d.ts +1 -0
- package/dist/server/request-metadata.d.ts.map +1 -1
- package/dist/server/ssr.d.ts +2 -0
- package/dist/server/ssr.d.ts.map +1 -1
- package/dist/static/index.d.ts +2 -0
- package/dist/static/index.d.ts.map +1 -1
- package/dist/static/index.js +380 -363
- package/dist/static/index.js.map +1 -1
- package/dist/static/preview.d.ts.map +1 -1
- package/dist/static/vercel.d.ts +11 -2
- package/dist/static/vercel.d.ts.map +1 -1
- package/dist/static-files.d.ts +12 -0
- package/dist/static-files.d.ts.map +1 -1
- package/dist/type-guards.d.ts +19 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/vite/env-boundary.d.ts +14 -0
- package/dist/vite/env-boundary.d.ts.map +1 -0
- package/dist/vite/index.d.ts +8 -3
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +22 -1196
- package/dist/vite/index.js.map +1 -1
- package/dist/vite/plugin.d.ts +8 -1
- package/dist/vite/plugin.d.ts.map +1 -1
- package/dist/vite/policy-verification.d.ts.map +1 -1
- package/dist/vite/route-audit.d.ts +50 -0
- package/dist/vite/route-audit.d.ts.map +1 -0
- package/package.json +19 -6
- package/dist/chunks/document-shell-D1xo6cEA.js +0 -35
- package/dist/chunks/document-shell-D1xo6cEA.js.map +0 -1
- package/dist/chunks/images-B9MqcjSA.js.map +0 -1
- package/dist/chunks/request-metadata-D5NrT8ks.js +0 -642
- package/dist/chunks/request-metadata-D5NrT8ks.js.map +0 -1
- package/dist/chunks/static-files-DUjHw-4H.js +0 -11
- package/dist/chunks/static-files-DUjHw-4H.js.map +0 -1
- package/dist/chunks/streaming-BQ1bykDo.js.map +0 -1
- package/dist/chunks/testing-B_iMFYz_.js +0 -3321
- package/dist/chunks/testing-B_iMFYz_.js.map +0 -1
- package/dist/route/action.d.ts +0 -33
- package/dist/route/action.d.ts.map +0 -1
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import { p as
|
|
2
|
-
|
|
1
|
+
import { p as P } from "./index-BVk9zWbe.js";
|
|
2
|
+
function j(t) {
|
|
3
|
+
return t.split("?")[0].split("#")[0];
|
|
4
|
+
}
|
|
5
|
+
function v(t) {
|
|
6
|
+
const e = j(t).split("/").at(-1);
|
|
7
|
+
return e.includes(".") ? e.split(".").at(-1).toLowerCase() : "";
|
|
8
|
+
}
|
|
9
|
+
const u = "/_demiurge/font", k = {
|
|
3
10
|
otf: "otf",
|
|
4
11
|
ttf: "ttf",
|
|
5
12
|
woff: "woff",
|
|
6
13
|
woff2: "woff2"
|
|
7
|
-
},
|
|
14
|
+
}, x = {
|
|
8
15
|
otf: "opentype",
|
|
9
16
|
ttf: "truetype",
|
|
10
17
|
woff: "woff",
|
|
11
18
|
woff2: "woff2"
|
|
12
|
-
},
|
|
19
|
+
}, E = {
|
|
13
20
|
otf: "font/otf",
|
|
14
21
|
ttf: "font/ttf",
|
|
15
22
|
woff: "font/woff",
|
|
16
23
|
woff2: "font/woff2"
|
|
17
|
-
},
|
|
24
|
+
}, G = {
|
|
18
25
|
// A Google font needs the file URL that the Google stylesheet points at.
|
|
19
26
|
// The framework reads no third-party stylesheet, because that request is
|
|
20
27
|
// the privacy cost self-hosting removes.
|
|
@@ -57,58 +64,58 @@ const u = "/_demiurge/font", j = {
|
|
|
57
64
|
};
|
|
58
65
|
}
|
|
59
66
|
};
|
|
60
|
-
function
|
|
67
|
+
function B(t) {
|
|
61
68
|
return [...t];
|
|
62
69
|
}
|
|
63
|
-
function
|
|
70
|
+
function N(t) {
|
|
64
71
|
const e = p(t.family), r = p(String(t.weight));
|
|
65
72
|
return `${e}-${r}-${t.style}.${m(t.src)}`;
|
|
66
73
|
}
|
|
67
|
-
function
|
|
68
|
-
return t.selfHost ? `${e}/${
|
|
74
|
+
function I(t, e = u) {
|
|
75
|
+
return t.selfHost ? `${e}/${N(t)}` : t.src;
|
|
69
76
|
}
|
|
70
|
-
function
|
|
77
|
+
function F(t = u) {
|
|
71
78
|
return `${t}/fonts.css`;
|
|
72
79
|
}
|
|
73
|
-
function
|
|
74
|
-
return
|
|
80
|
+
function R(t) {
|
|
81
|
+
return E[m(t)];
|
|
75
82
|
}
|
|
76
83
|
function m(t) {
|
|
77
|
-
const e =
|
|
78
|
-
if (!
|
|
84
|
+
const e = k[v(t)];
|
|
85
|
+
if (!e)
|
|
79
86
|
throw new Error(
|
|
80
87
|
`Font source ${JSON.stringify(t)} has no known font extension.`
|
|
81
88
|
);
|
|
82
|
-
return
|
|
89
|
+
return e;
|
|
83
90
|
}
|
|
84
|
-
function
|
|
91
|
+
function X(t, e = u) {
|
|
85
92
|
return t.length === 0 ? [] : [
|
|
86
93
|
{
|
|
87
|
-
href:
|
|
94
|
+
href: F(e),
|
|
88
95
|
kind: "link",
|
|
89
96
|
rel: "stylesheet"
|
|
90
97
|
},
|
|
91
|
-
...
|
|
98
|
+
...L(t, e)
|
|
92
99
|
];
|
|
93
100
|
}
|
|
94
|
-
function
|
|
101
|
+
function L(t, e = u) {
|
|
95
102
|
return t.map(
|
|
96
|
-
(r) =>
|
|
103
|
+
(r) => P(I(r, e), {
|
|
97
104
|
as: "font",
|
|
98
105
|
// A font request runs in CORS mode even on the same origin. A preload
|
|
99
106
|
// without this attribute fetches the file twice.
|
|
100
107
|
crossOrigin: "anonymous",
|
|
101
|
-
type:
|
|
108
|
+
type: R(r.src)
|
|
102
109
|
})
|
|
103
110
|
);
|
|
104
111
|
}
|
|
105
|
-
function
|
|
112
|
+
function Y(t, e = u) {
|
|
106
113
|
return t.map((r) => {
|
|
107
|
-
const n =
|
|
114
|
+
const n = I(r, e);
|
|
108
115
|
return [
|
|
109
116
|
"@font-face {",
|
|
110
117
|
` font-family: "${$(r.family)}";`,
|
|
111
|
-
` src: url("${$(n)}") format("${
|
|
118
|
+
` src: url("${$(n)}") format("${x[m(r.src)]}");`,
|
|
112
119
|
` font-style: ${r.style};`,
|
|
113
120
|
` font-weight: ${r.weight};`,
|
|
114
121
|
` font-display: ${r.display};`,
|
|
@@ -118,7 +125,7 @@ function B(t, e = u) {
|
|
|
118
125
|
}).join(`
|
|
119
126
|
`);
|
|
120
127
|
}
|
|
121
|
-
function
|
|
128
|
+
function Z(t) {
|
|
122
129
|
const e = /* @__PURE__ */ new Set();
|
|
123
130
|
for (const r of t)
|
|
124
131
|
r.selfHost || e.add(new URL(r.src).origin);
|
|
@@ -136,80 +143,80 @@ function p(t) {
|
|
|
136
143
|
function $(t) {
|
|
137
144
|
return t.replace(/[\\"]/g, "\\$&");
|
|
138
145
|
}
|
|
139
|
-
const
|
|
146
|
+
const z = "/_demiurge/image", O = {
|
|
140
147
|
avif: "avif",
|
|
141
148
|
jpeg: "jpg",
|
|
142
149
|
png: "png",
|
|
143
150
|
webp: "webp"
|
|
144
|
-
},
|
|
151
|
+
}, S = {
|
|
145
152
|
avif: "avif",
|
|
146
153
|
jpeg: "jpeg",
|
|
147
154
|
jpg: "jpeg",
|
|
148
155
|
png: "png",
|
|
149
156
|
webp: "webp"
|
|
150
|
-
},
|
|
151
|
-
function
|
|
157
|
+
}, U = /^(.+)\.w(\d{1,5})(?:\.q(\d{1,3}))?\.([a-z0-9]+)$/;
|
|
158
|
+
function T(t, e) {
|
|
152
159
|
const r = new URLSearchParams({
|
|
153
160
|
src: t.src,
|
|
154
161
|
w: String(t.width)
|
|
155
162
|
});
|
|
156
163
|
return t.quality !== void 0 && r.set("q", String(t.quality)), t.format !== "auto" && r.set("f", t.format), `${e}?${r.toString()}`;
|
|
157
164
|
}
|
|
158
|
-
function
|
|
165
|
+
function W(t, e) {
|
|
159
166
|
if (t.sourceKind === "remote")
|
|
160
167
|
throw new Error(
|
|
161
168
|
`Image source ${JSON.stringify(t.src)} is remote. A static image loader can only emit a local image.`
|
|
162
169
|
);
|
|
163
170
|
const r = t.quality === void 0 ? "" : `.q${t.quality}`;
|
|
164
|
-
return `${e}${t.src}.w${t.width}${r}.${
|
|
171
|
+
return `${e}${t.src}.w${t.width}${r}.${V(t)}`;
|
|
165
172
|
}
|
|
166
|
-
function
|
|
173
|
+
function tt(t, e) {
|
|
167
174
|
if (!t.startsWith(`${e}/`))
|
|
168
175
|
return;
|
|
169
|
-
const r =
|
|
176
|
+
const r = U.exec(t.slice(e.length));
|
|
170
177
|
if (!r)
|
|
171
178
|
return;
|
|
172
|
-
const [, n, a, s,
|
|
173
|
-
if (!(!i || !
|
|
179
|
+
const [, n, a, s, f] = r, i = S[f], l = Number(a), o = s === void 0 ? void 0 : Number(s);
|
|
180
|
+
if (!(!i || !b(n) || l <= 0 || o !== void 0 && (o < 1 || o > 100)))
|
|
174
181
|
return { format: i, quality: o, sourceKind: "local", src: n, width: l };
|
|
175
182
|
}
|
|
176
|
-
function
|
|
183
|
+
function V(t) {
|
|
177
184
|
if (t.format !== "auto")
|
|
178
|
-
return
|
|
179
|
-
const e =
|
|
185
|
+
return O[t.format];
|
|
186
|
+
const e = b(t.src);
|
|
180
187
|
if (!e)
|
|
181
188
|
throw new Error(
|
|
182
189
|
`Image source ${JSON.stringify(t.src)} has no known image extension. Declare an explicit format.`
|
|
183
190
|
);
|
|
184
191
|
return e === "jpeg" ? "jpg" : e;
|
|
185
192
|
}
|
|
186
|
-
function
|
|
187
|
-
const e = t
|
|
188
|
-
return
|
|
193
|
+
function b(t) {
|
|
194
|
+
const e = v(t);
|
|
195
|
+
return e in S ? e : void 0;
|
|
189
196
|
}
|
|
190
|
-
function
|
|
197
|
+
function et(t, e) {
|
|
191
198
|
const r = new RegExp(
|
|
192
|
-
`${
|
|
199
|
+
`${A(e)}/[^"'\\s,)<>]+`,
|
|
193
200
|
"g"
|
|
194
201
|
);
|
|
195
202
|
return [...new Set(t.match(r) ?? [])];
|
|
196
203
|
}
|
|
197
|
-
function
|
|
204
|
+
function A(t) {
|
|
198
205
|
return t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
199
206
|
}
|
|
200
|
-
function
|
|
207
|
+
function rt(t) {
|
|
201
208
|
return t;
|
|
202
209
|
}
|
|
203
|
-
function
|
|
210
|
+
function nt(t, e = {}) {
|
|
204
211
|
return h(t, e) !== null;
|
|
205
212
|
}
|
|
206
|
-
function
|
|
213
|
+
function at(t, e = {}) {
|
|
207
214
|
const r = h(t.src, e);
|
|
208
215
|
if (!r)
|
|
209
216
|
throw new Error(`Image source "${t.src}" is not allowed by the image policy.`);
|
|
210
|
-
g("width", t.width), g("height", t.height),
|
|
211
|
-
const n = t.format ?? "auto", a = e.loader ?? "optimizer", s = e.optimizerPath ??
|
|
212
|
-
const
|
|
217
|
+
g("width", t.width), g("height", t.height), M(t.quality);
|
|
218
|
+
const n = t.format ?? "auto", a = e.loader ?? "optimizer", s = e.optimizerPath ?? z, i = Q(t.width, t.widths).map((o) => {
|
|
219
|
+
const q = Math.round(t.height / t.width * o), w = {
|
|
213
220
|
format: n,
|
|
214
221
|
quality: t.quality,
|
|
215
222
|
sourceKind: r.kind,
|
|
@@ -218,8 +225,8 @@ function rt(t, e = {}) {
|
|
|
218
225
|
};
|
|
219
226
|
return {
|
|
220
227
|
format: n,
|
|
221
|
-
height:
|
|
222
|
-
src: a === "static" ?
|
|
228
|
+
height: q,
|
|
229
|
+
src: a === "static" ? W(w, s) : T(w, s),
|
|
223
230
|
width: o
|
|
224
231
|
};
|
|
225
232
|
}), l = i[0];
|
|
@@ -246,64 +253,64 @@ function h(t, e) {
|
|
|
246
253
|
} catch {
|
|
247
254
|
return null;
|
|
248
255
|
}
|
|
249
|
-
return r.protocol !== "https:" && r.protocol !== "http:" ? null :
|
|
256
|
+
return r.protocol !== "https:" && r.protocol !== "http:" ? null : H(r, e.remote ?? []) ? { kind: "remote", src: r.toString() } : null;
|
|
250
257
|
}
|
|
251
|
-
function
|
|
258
|
+
function H(t, e) {
|
|
252
259
|
return e.some(
|
|
253
|
-
(r) => typeof r == "string" ?
|
|
260
|
+
(r) => typeof r == "string" ? J(t, r) : K(t, r)
|
|
254
261
|
);
|
|
255
262
|
}
|
|
256
|
-
function
|
|
263
|
+
function J(t, e) {
|
|
257
264
|
try {
|
|
258
265
|
return t.origin === new URL(e).origin;
|
|
259
266
|
} catch {
|
|
260
267
|
return !1;
|
|
261
268
|
}
|
|
262
269
|
}
|
|
263
|
-
function
|
|
264
|
-
return e.protocol && t.protocol !== e.protocol || t.hostname !== e.hostname || e.port !== void 0 && t.port !== e.port ? !1 : e.pathname ?
|
|
270
|
+
function K(t, e) {
|
|
271
|
+
return e.protocol && t.protocol !== e.protocol || t.hostname !== e.hostname || e.port !== void 0 && t.port !== e.port ? !1 : e.pathname ? C(t.pathname, e.pathname) : !0;
|
|
265
272
|
}
|
|
266
|
-
function
|
|
273
|
+
function C(t, e) {
|
|
267
274
|
return e.endsWith("*") ? t.startsWith(e.slice(0, -1)) : t === e;
|
|
268
275
|
}
|
|
269
276
|
function g(t, e) {
|
|
270
277
|
if (!Number.isInteger(e) || e <= 0)
|
|
271
278
|
throw new Error(`Image ${t} must be a positive integer.`);
|
|
272
279
|
}
|
|
273
|
-
function
|
|
280
|
+
function M(t) {
|
|
274
281
|
if (t !== void 0 && (!Number.isInteger(t) || t < 1 || t > 100))
|
|
275
282
|
throw new Error("Image quality must be an integer between 1 and 100.");
|
|
276
283
|
}
|
|
277
|
-
function
|
|
284
|
+
function Q(t, e) {
|
|
278
285
|
const r = e ?? [t, t * 2], n = [...new Set(r)];
|
|
279
286
|
for (const a of n)
|
|
280
287
|
g("width", a);
|
|
281
288
|
return n.sort((a, s) => a - s);
|
|
282
289
|
}
|
|
283
|
-
const
|
|
290
|
+
const D = /* @__PURE__ */ new Set([
|
|
284
291
|
"avif",
|
|
285
292
|
"jpeg",
|
|
286
293
|
"png",
|
|
287
294
|
"webp"
|
|
288
295
|
]);
|
|
289
|
-
function
|
|
296
|
+
function ot(t, e = {}) {
|
|
290
297
|
const r = t.searchParams.get("src");
|
|
291
298
|
if (!r)
|
|
292
|
-
return
|
|
299
|
+
return c(400, "The image request must declare a src parameter.");
|
|
293
300
|
const n = h(r, e);
|
|
294
301
|
if (!n)
|
|
295
|
-
return
|
|
302
|
+
return c(403, "The image policy does not allow this image source.");
|
|
296
303
|
const a = Number(t.searchParams.get("w"));
|
|
297
304
|
if (!Number.isInteger(a) || a <= 0)
|
|
298
|
-
return
|
|
299
|
-
const s = t.searchParams.get("q"),
|
|
300
|
-
if (
|
|
301
|
-
return
|
|
305
|
+
return c(400, "The image width must be a positive integer.");
|
|
306
|
+
const s = t.searchParams.get("q"), f = s === null ? void 0 : Number(s);
|
|
307
|
+
if (f !== void 0 && (!Number.isInteger(f) || f < 1 || f > 100))
|
|
308
|
+
return c(400, "The image quality must be an integer from 1 through 100.");
|
|
302
309
|
const i = t.searchParams.get("f");
|
|
303
|
-
return i !== null && !
|
|
310
|
+
return i !== null && !D.has(i) ? c(400, "The image format is not supported.") : {
|
|
304
311
|
descriptor: {
|
|
305
312
|
format: i ?? "auto",
|
|
306
|
-
quality:
|
|
313
|
+
quality: f,
|
|
307
314
|
sourceKind: n.kind,
|
|
308
315
|
src: n.src,
|
|
309
316
|
width: a
|
|
@@ -311,29 +318,30 @@ function nt(t, e = {}) {
|
|
|
311
318
|
ok: !0
|
|
312
319
|
};
|
|
313
320
|
}
|
|
314
|
-
function
|
|
321
|
+
function c(t, e) {
|
|
315
322
|
return { ok: !1, rejection: { reason: e, status: t } };
|
|
316
323
|
}
|
|
317
324
|
export {
|
|
318
|
-
|
|
319
|
-
|
|
325
|
+
R as a,
|
|
326
|
+
F as b,
|
|
320
327
|
m as c,
|
|
321
328
|
u as d,
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
329
|
+
z as e,
|
|
330
|
+
N as f,
|
|
331
|
+
et as g,
|
|
332
|
+
nt as h,
|
|
333
|
+
b as i,
|
|
334
|
+
ot as j,
|
|
335
|
+
at as k,
|
|
336
|
+
B as l,
|
|
337
|
+
rt as m,
|
|
338
|
+
G as n,
|
|
339
|
+
I as o,
|
|
340
|
+
tt as p,
|
|
341
|
+
X as q,
|
|
342
|
+
Y as r,
|
|
343
|
+
L as s,
|
|
344
|
+
Z as t,
|
|
345
|
+
j as u
|
|
338
346
|
};
|
|
339
|
-
//# sourceMappingURL=images-
|
|
347
|
+
//# sourceMappingURL=images-BQ80950B.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images-BQ80950B.js","sources":["../../src/platform/url.ts","../../src/platform/fonts.ts","../../src/platform/image-url.ts","../../src/platform/images.ts"],"sourcesContent":["/**\n * Drops the query string and the fragment from a URL or path, leaving the\n * path portion. Both are cut at the first occurrence, so a `?` inside a\n * fragment and a `#` inside a query are handled the way a browser handles\n * them: the earlier delimiter wins.\n */\nexport function urlPath(url: string) {\n return url.split(\"?\")[0]!.split(\"#\")[0]!;\n}\n\n/**\n * Resolves the file extension of a URL or path, lower-cased and without the\n * leading dot. The query string and the fragment are ignored, and only the\n * last path segment is considered, so a dot in a directory name never leaks\n * into the answer.\n *\n * A name with no dot and a name ending in a dot both answer the empty\n * string, which no caller's extension table names, so an unparseable name is\n * reported as unknown rather than mistaken for a format.\n */\nexport function urlExtension(url: string) {\n const name = urlPath(url).split(\"/\").at(-1)!;\n\n return name.includes(\".\") ? name.split(\".\").at(-1)!.toLowerCase() : \"\";\n}\n","import { preload } from \"../document/links\";\nimport { urlExtension } from \"./url\";\nimport type { LinkTag } from \"../document\";\n\nexport type FontStyle = \"normal\" | \"italic\" | \"oblique\";\n\nexport type FontFormat = \"otf\" | \"ttf\" | \"woff\" | \"woff2\";\n\nexport type FontDefinition = {\n display: \"auto\" | \"block\" | \"fallback\" | \"optional\" | \"swap\";\n family: string;\n kind: \"font\";\n // A self-hosted font is published from the application origin, so `'self'`\n // covers it. A font left on a third-party host stays a `font-src` entry and\n // a privacy question, and `fontSources` makes that cost visible.\n selfHost: boolean;\n source: \"google\" | \"local\";\n src: string;\n style: FontStyle;\n weight: number | `${number} ${number}`;\n};\n\nexport type LocalFontOptions = {\n display?: FontDefinition[\"display\"];\n name: string;\n src: string;\n style?: FontStyle;\n weight?: FontDefinition[\"weight\"];\n};\n\nexport type GoogleFontOptions = {\n display?: FontDefinition[\"display\"];\n family: string;\n selfHost?: boolean;\n src: string;\n style?: FontStyle;\n weight?: FontDefinition[\"weight\"];\n};\n\nexport type FontContribution = readonly FontDefinition[];\n\n// The framework publishes every self-hosted font under one path. The build\n// writes the files, and the Node handler serves the same URLs at request time.\nexport const defaultFontPath = \"/_demiurge/font\";\n\nconst fontFormats: Record<string, FontFormat> = {\n otf: \"otf\",\n ttf: \"ttf\",\n woff: \"woff\",\n woff2: \"woff2\",\n};\n\nconst fontFaceFormats: Record<FontFormat, string> = {\n otf: \"opentype\",\n ttf: \"truetype\",\n woff: \"woff\",\n woff2: \"woff2\",\n};\n\nconst fontMediaTypes: Record<FontFormat, string> = {\n otf: \"font/otf\",\n ttf: \"font/ttf\",\n woff: \"font/woff\",\n woff2: \"font/woff2\",\n};\n\nexport const font = {\n // A Google font needs the file URL that the Google stylesheet points at.\n // The framework reads no third-party stylesheet, because that request is\n // the privacy cost self-hosting removes.\n google(options: GoogleFontOptions): FontDefinition {\n const src = options.src.trim();\n\n if (!isRemoteSource(src)) {\n throw new Error(\n `Google font ${JSON.stringify(options.family)} needs an https font file URL as its source.`,\n );\n }\n\n assertKnownFormat(src);\n\n return {\n display: options.display ?? \"swap\",\n family: options.family,\n kind: \"font\",\n selfHost: options.selfHost ?? true,\n source: \"google\",\n src,\n style: options.style ?? \"normal\",\n weight: options.weight ?? 400,\n };\n },\n // A local font names a file in the project. The build reads that file and\n // publishes it, so the file does not have to sit in the public directory.\n local(options: LocalFontOptions): FontDefinition {\n const src = options.src.trim();\n\n if (!src) {\n throw new Error(\"Local font source must not be empty.\");\n }\n\n if (isRemoteSource(src)) {\n throw new Error(\n `Local font ${JSON.stringify(options.name)} must name a project file rather than a URL.`,\n );\n }\n\n assertKnownFormat(src);\n\n return {\n display: options.display ?? \"swap\",\n family: options.name,\n kind: \"font\",\n selfHost: true,\n source: \"local\",\n src,\n style: options.style ?? \"normal\",\n weight: options.weight ?? 400,\n };\n },\n};\n\nexport function defineFonts(fonts: FontContribution): FontContribution {\n return [...fonts];\n}\n\n// The published file name derives from the declaration alone. The renderer\n// and the build therefore agree on every URL without sharing any state.\nexport function fontAssetFileName(definition: FontDefinition) {\n const family = slug(definition.family);\n const weight = slug(String(definition.weight));\n\n return `${family}-${weight}-${definition.style}.${fontFormat(definition.src)}`;\n}\n\nexport function fontAssetUrl(\n definition: FontDefinition,\n basePath: string = defaultFontPath,\n) {\n return definition.selfHost\n ? `${basePath}/${fontAssetFileName(definition)}`\n : definition.src;\n}\n\nexport function fontStylesheetUrl(basePath: string = defaultFontPath) {\n return `${basePath}/fonts.css`;\n}\n\nexport function fontMediaType(file: string) {\n return fontMediaTypes[fontFormat(file)];\n}\n\nexport function fontFormat(file: string): FontFormat {\n const format = fontFormats[urlExtension(file)];\n\n if (!format) {\n throw new Error(\n `Font source ${JSON.stringify(file)} has no known font extension.`,\n );\n }\n\n return format;\n}\n\n// The stylesheet and the preload links are the whole document contribution.\n// An application spreads them into `links` in its root layout.\nexport function fontLinks(\n fonts: FontContribution,\n basePath: string = defaultFontPath,\n): LinkTag[] {\n if (fonts.length === 0) {\n return [];\n }\n\n return [\n {\n href: fontStylesheetUrl(basePath),\n kind: \"link\" as const,\n rel: \"stylesheet\",\n },\n ...fontPreloadLinks(fonts, basePath),\n ];\n}\n\nexport function fontPreloadLinks(\n fonts: FontContribution,\n basePath: string = defaultFontPath,\n): LinkTag[] {\n return fonts.map((definition) =>\n preload(fontAssetUrl(definition, basePath), {\n as: \"font\",\n // A font request runs in CORS mode even on the same origin. A preload\n // without this attribute fetches the file twice.\n crossOrigin: \"anonymous\",\n type: fontMediaType(definition.src),\n })\n );\n}\n\nexport function renderFontFaceCss(\n fonts: FontContribution,\n basePath: string = defaultFontPath,\n) {\n return fonts\n .map((definition) => {\n const url = fontAssetUrl(definition, basePath);\n\n return [\n \"@font-face {\",\n ` font-family: \"${escapeCss(definition.family)}\";`,\n ` src: url(\"${escapeCss(url)}\") format(\"${\n fontFaceFormats[fontFormat(definition.src)]\n }\");`,\n ` font-style: ${definition.style};`,\n ` font-weight: ${definition.weight};`,\n ` font-display: ${definition.display};`,\n \"}\",\n ].join(\"\\n\");\n })\n .join(\"\\n\");\n}\n\n// A self-hosted font set collapses to `'self'`, which every framework preset\n// already declares. A third-party host has to be named here instead.\nexport function fontSources(fonts: FontContribution): string[] {\n const origins = new Set<string>();\n\n for (const definition of fonts) {\n if (!definition.selfHost) {\n origins.add(new URL(definition.src).origin);\n }\n }\n\n return [\"'self'\", ...[...origins].sort()];\n}\n\nfunction isRemoteSource(src: string) {\n return /^https?:\\/\\//i.test(src);\n}\n\nfunction assertKnownFormat(src: string) {\n fontFormat(src);\n}\n\nfunction slug(value: string) {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\") || \"font\";\n}\n\nfunction escapeCss(value: string) {\n return value.replace(/[\\\\\"]/g, \"\\\\$&\");\n}\n","import type { ImageFormat } from \"./images\";\nimport { urlExtension } from \"./url\";\n\nexport type ImageSourceKind = \"local\" | \"remote\";\n\n// The descriptor is the complete input of one variant. The build pipeline and\n// the runtime optimizer both derive a file name and an encoded body from it.\nexport type ImageVariantDescriptor = {\n format: ImageFormat;\n quality?: number;\n sourceKind: ImageSourceKind;\n src: string;\n width: number;\n};\n\nexport const defaultImageOptimizerPath = \"/_demiurge/image\";\n\nconst formatExtensions: Record<Exclude<ImageFormat, \"auto\">, string> = {\n avif: \"avif\",\n jpeg: \"jpg\",\n png: \"png\",\n webp: \"webp\",\n};\n\nconst extensionFormats: Record<string, Exclude<ImageFormat, \"auto\">> = {\n avif: \"avif\",\n jpeg: \"jpeg\",\n jpg: \"jpeg\",\n png: \"png\",\n webp: \"webp\",\n};\n\nconst variantNamePattern = /^(.+)\\.w(\\d{1,5})(?:\\.q(\\d{1,3}))?\\.([a-z0-9]+)$/;\n\nexport function createImageOptimizerUrl(\n descriptor: ImageVariantDescriptor,\n optimizerPath: string,\n) {\n const params = new URLSearchParams({\n src: descriptor.src,\n w: String(descriptor.width),\n });\n\n if (descriptor.quality !== undefined) {\n params.set(\"q\", String(descriptor.quality));\n }\n\n if (descriptor.format !== \"auto\") {\n params.set(\"f\", descriptor.format);\n }\n\n return `${optimizerPath}?${params.toString()}`;\n}\n\n// A static build has no optimizer process, so the variant path must describe\n// the complete transform. The build reads the path back and emits the file,\n// and no shared state has to cross the build and render boundary.\nexport function createImageVariantPath(\n descriptor: ImageVariantDescriptor,\n optimizerPath: string,\n) {\n if (descriptor.sourceKind === \"remote\") {\n throw new Error(\n `Image source ${JSON.stringify(descriptor.src)} is remote. A static image loader can only emit a local image.`,\n );\n }\n\n const quality = descriptor.quality === undefined\n ? \"\"\n : `.q${descriptor.quality}`;\n\n return `${optimizerPath}${descriptor.src}.w${descriptor.width}${quality}.${\n resolveVariantExtension(descriptor)\n }`;\n}\n\nexport function parseImageVariantPath(\n pathname: string,\n optimizerPath: string,\n): ImageVariantDescriptor | undefined {\n if (!pathname.startsWith(`${optimizerPath}/`)) {\n return undefined;\n }\n\n const match = variantNamePattern.exec(pathname.slice(optimizerPath.length));\n\n if (!match) {\n return undefined;\n }\n\n const [, src, rawWidth, rawQuality, extension] = match;\n const format = extensionFormats[extension!];\n const width = Number(rawWidth);\n const quality = rawQuality === undefined ? undefined : Number(rawQuality);\n\n if (\n !format ||\n !imageSourceExtension(src!) ||\n width <= 0 ||\n (quality !== undefined && (quality < 1 || quality > 100))\n ) {\n return undefined;\n }\n\n return { format, quality, sourceKind: \"local\", src: src!, width };\n}\n\nexport function resolveVariantExtension(descriptor: ImageVariantDescriptor) {\n if (descriptor.format !== \"auto\") {\n return formatExtensions[descriptor.format];\n }\n\n const extension = imageSourceExtension(descriptor.src);\n\n if (!extension) {\n throw new Error(\n `Image source ${JSON.stringify(descriptor.src)} has no known image extension. Declare an explicit format.`,\n );\n }\n\n return extension === \"jpeg\" ? \"jpg\" : extension;\n}\n\nexport function imageSourceExtension(src: string) {\n const extension = urlExtension(src);\n\n return extension in extensionFormats ? extension : undefined;\n}\n\n// The build and the development server both find variants by reading the\n// documents that the application rendered. A variant that no document\n// references is a variant that nothing can request.\nexport function collectImageVariantPaths(html: string, optimizerPath: string) {\n const pattern = new RegExp(\n `${escapeRegExp(optimizerPath)}/[^\"'\\\\s,)<>]+`,\n \"g\",\n );\n\n return [...new Set(html.match(pattern) ?? [])];\n}\n\nfunction escapeRegExp(value: string) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","import {\n createImageOptimizerUrl,\n createImageVariantPath,\n defaultImageOptimizerPath,\n type ImageVariantDescriptor,\n} from \"./image-url\";\n\n// `optimizer` points every variant at a request-time endpoint. `static`\n// points every variant at a file that the static build emits.\nexport type ImageLoader = \"optimizer\" | \"static\";\n\nexport type ImageFormat = \"auto\" | \"avif\" | \"webp\" | \"jpeg\" | \"png\";\n\nexport type RemoteImagePattern = {\n hostname: string;\n pathname?: string;\n port?: string;\n protocol?: \"http:\" | \"https:\";\n};\n\nexport type ImagePolicy = {\n loader?: ImageLoader;\n local?: boolean;\n optimizerPath?: string;\n remote?: readonly (string | RemoteImagePattern)[];\n};\n\nexport type ImageTransformOptions = {\n alt: string;\n format?: ImageFormat;\n height: number;\n priority?: boolean;\n quality?: number;\n sizes?: string;\n src: string;\n width: number;\n widths?: readonly number[];\n};\n\nexport type ImageVariant = {\n format: ImageFormat;\n height: number;\n src: string;\n width: number;\n};\n\nexport type ImageTransformPlan = {\n alt: string;\n decoding: \"async\";\n fetchPriority?: \"high\";\n height: number;\n loading: \"eager\" | \"lazy\";\n sizes?: string;\n source: {\n kind: \"local\" | \"remote\";\n src: string;\n };\n src: string;\n srcSet: string;\n variants: ImageVariant[];\n width: number;\n};\n\nexport function defineImages(policy: ImagePolicy): ImagePolicy {\n return policy;\n}\n\nexport function isAllowedImageSource(src: string, policy: ImagePolicy = {}) {\n return classifyImageSource(src, policy) !== null;\n}\n\nexport function planImageTransform(\n options: ImageTransformOptions,\n policy: ImagePolicy = {},\n): ImageTransformPlan {\n const source = classifyImageSource(options.src, policy);\n\n if (!source) {\n throw new Error(`Image source \"${options.src}\" is not allowed by the image policy.`);\n }\n\n validateImageDimension(\"width\", options.width);\n validateImageDimension(\"height\", options.height);\n validateImageQuality(options.quality);\n\n const format = options.format ?? \"auto\";\n const loader = policy.loader ?? \"optimizer\";\n const optimizerPath = policy.optimizerPath ?? defaultImageOptimizerPath;\n const widths = normalizeVariantWidths(options.width, options.widths);\n const variants = widths.map((width) => {\n const height = Math.round((options.height / options.width) * width);\n const descriptor: ImageVariantDescriptor = {\n format,\n quality: options.quality,\n sourceKind: source.kind,\n src: source.kind === \"remote\" ? source.src : options.src,\n width,\n };\n\n return {\n format,\n height,\n src: loader === \"static\"\n ? createImageVariantPath(descriptor, optimizerPath)\n : createImageOptimizerUrl(descriptor, optimizerPath),\n width,\n };\n });\n const primaryVariant = variants[0];\n\n return {\n alt: options.alt,\n decoding: \"async\",\n fetchPriority: options.priority ? \"high\" : undefined,\n height: options.height,\n loading: options.priority ? \"eager\" : \"lazy\",\n sizes: options.sizes,\n source,\n src: primaryVariant.src,\n srcSet: variants\n .map((variant) => `${variant.src} ${variant.width}w`)\n .join(\", \"),\n variants,\n width: options.width,\n };\n}\n\nfunction classifyImageSource(\n src: string,\n policy: ImagePolicy,\n): ImageTransformPlan[\"source\"] | null {\n if (src.startsWith(\"/\") && !src.startsWith(\"//\")) {\n return policy.local === false ? null : { kind: \"local\", src };\n }\n\n let url: URL;\n\n try {\n url = new URL(src);\n } catch {\n return null;\n }\n\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n return null;\n }\n\n return isAllowedRemoteImage(url, policy.remote ?? [])\n ? { kind: \"remote\", src: url.toString() }\n : null;\n}\n\nfunction isAllowedRemoteImage(\n url: URL,\n remotes: readonly (string | RemoteImagePattern)[],\n) {\n return remotes.some((remote) =>\n typeof remote === \"string\"\n ? matchesRemoteOrigin(url, remote)\n : matchesRemotePattern(url, remote),\n );\n}\n\nfunction matchesRemoteOrigin(url: URL, origin: string) {\n try {\n return url.origin === new URL(origin).origin;\n } catch {\n return false;\n }\n}\n\nfunction matchesRemotePattern(url: URL, pattern: RemoteImagePattern) {\n if (pattern.protocol && url.protocol !== pattern.protocol) {\n return false;\n }\n\n if (url.hostname !== pattern.hostname) {\n return false;\n }\n\n if (pattern.port !== undefined && url.port !== pattern.port) {\n return false;\n }\n\n return pattern.pathname\n ? matchesPathnamePattern(url.pathname, pattern.pathname)\n : true;\n}\n\nfunction matchesPathnamePattern(pathname: string, pattern: string) {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n\n return pathname === pattern;\n}\n\nfunction validateImageDimension(name: \"height\" | \"width\", value: number) {\n if (!Number.isInteger(value) || value <= 0) {\n throw new Error(`Image ${name} must be a positive integer.`);\n }\n}\n\nfunction validateImageQuality(quality: number | undefined) {\n if (quality === undefined) {\n return;\n }\n\n if (!Number.isInteger(quality) || quality < 1 || quality > 100) {\n throw new Error(\"Image quality must be an integer between 1 and 100.\");\n }\n}\n\nfunction normalizeVariantWidths(width: number, widths: readonly number[] | undefined) {\n const candidates = widths ?? [width, width * 2];\n const uniqueWidths = [...new Set(candidates)];\n\n for (const candidate of uniqueWidths) {\n validateImageDimension(\"width\", candidate);\n }\n\n return uniqueWidths.sort((left, right) => left - right);\n}\n\nexport type ImageRequestRejection = {\n reason: string;\n status: 400 | 403;\n};\n\nexport type ImageRequestResult =\n | { descriptor: ImageVariantDescriptor; ok: true }\n | { ok: false; rejection: ImageRequestRejection };\n\nconst imageFormats = new Set<ImageFormat>([\n \"avif\",\n \"jpeg\",\n \"png\",\n \"webp\",\n]);\n\n// The runtime optimizer reads a query that any client can write. It repeats\n// the policy check that the planner made, so an unallowed source never\n// reaches the file system or the network.\nexport function parseImageOptimizerRequest(\n url: URL,\n policy: ImagePolicy = {},\n): ImageRequestResult {\n const src = url.searchParams.get(\"src\");\n\n if (!src) {\n return reject(400, \"The image request must declare a src parameter.\");\n }\n\n const source = classifyImageSource(src, policy);\n\n if (!source) {\n return reject(403, \"The image policy does not allow this image source.\");\n }\n\n const width = Number(url.searchParams.get(\"w\"));\n\n if (!Number.isInteger(width) || width <= 0) {\n return reject(400, \"The image width must be a positive integer.\");\n }\n\n const rawQuality = url.searchParams.get(\"q\");\n const quality = rawQuality === null ? undefined : Number(rawQuality);\n\n if (\n quality !== undefined &&\n (!Number.isInteger(quality) || quality < 1 || quality > 100)\n ) {\n return reject(400, \"The image quality must be an integer from 1 through 100.\");\n }\n\n const rawFormat = url.searchParams.get(\"f\");\n\n // TYPE-EVIDENCE: the set membership check confirms the raw format is a known image format. The cast matches that check.\n if (rawFormat !== null && !imageFormats.has(rawFormat as ImageFormat)) {\n return reject(400, \"The image format is not supported.\");\n }\n\n // TYPE-EVIDENCE: the raw format value is a string that names an image format or is null. The cast labels it with the format union.\n return {\n descriptor: {\n format: (rawFormat as ImageFormat | null) ?? \"auto\",\n quality,\n sourceKind: source.kind,\n src: source.src,\n width,\n },\n ok: true,\n };\n}\n\nfunction reject(status: 400 | 403, reason: string): ImageRequestResult {\n return { ok: false, rejection: { reason, status } };\n}\n"],"names":["urlPath","url","urlExtension","name","defaultFontPath","fontFormats","fontFaceFormats","fontMediaTypes","font","options","src","isRemoteSource","assertKnownFormat","defineFonts","fonts","fontAssetFileName","definition","family","slug","weight","fontFormat","fontAssetUrl","basePath","fontStylesheetUrl","fontMediaType","file","format","fontLinks","fontPreloadLinks","preload","renderFontFaceCss","escapeCss","fontSources","origins","value","defaultImageOptimizerPath","formatExtensions","extensionFormats","variantNamePattern","createImageOptimizerUrl","descriptor","optimizerPath","params","createImageVariantPath","quality","resolveVariantExtension","parseImageVariantPath","pathname","match","rawWidth","rawQuality","extension","width","imageSourceExtension","collectImageVariantPaths","html","pattern","escapeRegExp","defineImages","policy","isAllowedImageSource","classifyImageSource","planImageTransform","source","validateImageDimension","validateImageQuality","loader","variants","normalizeVariantWidths","height","primaryVariant","variant","isAllowedRemoteImage","remotes","remote","matchesRemoteOrigin","matchesRemotePattern","origin","matchesPathnamePattern","widths","candidates","uniqueWidths","candidate","left","right","imageFormats","parseImageOptimizerRequest","reject","rawFormat","status","reason"],"mappings":"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"}
|