@marktiderman/genesis-sites 0.1.0 → 0.2.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.
Files changed (47) hide show
  1. package/README.md +152 -8
  2. package/dist/assets/islands.77d11f5697.js +1 -0
  3. package/dist/assets/sites-forms.4e6aa42497.css +10 -0
  4. package/dist/assets/sites-forms.css +1 -1
  5. package/dist/assets/sites.css +1 -1
  6. package/dist/assets/sites.e1ffd2708b.css +2 -0
  7. package/dist/blocks.d.ts +1 -1
  8. package/dist/blocks.js +5 -1
  9. package/dist/blocks.js.map +1 -1
  10. package/dist/chunk-3VKTBE7S.js +69 -0
  11. package/dist/chunk-3VKTBE7S.js.map +1 -0
  12. package/dist/chunk-C375ZPU2.js +2241 -0
  13. package/dist/chunk-C375ZPU2.js.map +1 -0
  14. package/dist/{chunk-GA7U3CIN.js → chunk-IXMY4B56.js} +229 -10
  15. package/dist/chunk-IXMY4B56.js.map +1 -0
  16. package/dist/chunk-VZUDRPFG.js +13 -0
  17. package/dist/chunk-VZUDRPFG.js.map +1 -0
  18. package/dist/{chunk-KEF3V5ZN.js → chunk-ZGWGQGT2.js} +169 -73
  19. package/dist/chunk-ZGWGQGT2.js.map +1 -0
  20. package/dist/import.d.ts +130 -0
  21. package/dist/import.js +330 -0
  22. package/dist/import.js.map +1 -0
  23. package/dist/index.d.ts +40 -7
  24. package/dist/index.js +5 -3
  25. package/dist/index.js.map +1 -1
  26. package/dist/{registry-CdgVymsu.d.ts → registry-D_DCWRTc.d.ts} +274 -8
  27. package/dist/sections.d.ts +422 -6
  28. package/dist/sections.js +4 -2
  29. package/dist/{store-BzGw2i5J.d.ts → store-DkSycDhq.d.ts} +119 -53
  30. package/dist/supabase.d.ts +5 -5
  31. package/dist/supabase.js +115 -6
  32. package/dist/supabase.js.map +1 -1
  33. package/dist/web.d.ts +26 -8
  34. package/dist/web.js +142 -18
  35. package/dist/web.js.map +1 -1
  36. package/migrations/0001_genesis_sites.sql +64 -6
  37. package/migrations/0002_genesis_sites_posts.sql +404 -0
  38. package/migrations/tests/0001_genesis_sites.test.sql +30 -1
  39. package/migrations/tests/0002_genesis_sites_posts.test.sql +242 -0
  40. package/package.json +18 -10
  41. package/dist/assets/islands.230b20b9c4.js +0 -1
  42. package/dist/assets/sites-forms.5e6ebf31c3.css +0 -10
  43. package/dist/assets/sites.b28b796c6f.css +0 -2
  44. package/dist/chunk-43XUAO63.js +0 -1255
  45. package/dist/chunk-43XUAO63.js.map +0 -1
  46. package/dist/chunk-GA7U3CIN.js.map +0 -1
  47. package/dist/chunk-KEF3V5ZN.js.map +0 -1
@@ -0,0 +1,130 @@
1
+ import { S as SiteStore } from './store-DkSycDhq.js';
2
+ import { LookupOptions, LookupAddress } from 'node:dns';
3
+ import './registry-D_DCWRTc.js';
4
+ import 'react';
5
+ import 'zod';
6
+ import '@marktiderman/genesis-design-system';
7
+
8
+ /**
9
+ * What a downloaded file is, from its first bytes (never from its name or
10
+ * the server's Content-Type), and an image's size from its header. Only the
11
+ * types a site stores: PNG, JPEG, GIF, WebP, AVIF and PDF. SVG, HTML and
12
+ * everything else are refused, since a browser runs them as a page.
13
+ */
14
+ interface Sniffed {
15
+ mime: "image/png" | "image/jpeg" | "image/gif" | "image/webp" | "image/avif" | "application/pdf";
16
+ ext: string;
17
+ width: number | null;
18
+ height: number | null;
19
+ }
20
+ /** The file's type and size, or null when it isn't one a site stores. */
21
+ declare function sniff(bytes: Uint8Array): Sniffed | null;
22
+
23
+ /**
24
+ * The network guard for importing remote files: which addresses a server
25
+ * may fetch from on an editor's say-so. Only public unicast addresses: no
26
+ * loopback, private, link-local (cloud metadata lives at 169.254.169.254),
27
+ * carrier-grade NAT, documentation, benchmark, multicast or reserved
28
+ * ranges, and no IPv6 form that hides one of those (IPv4-mapped, NAT64,
29
+ * 6to4, unique local, site-local).
30
+ *
31
+ * The check runs on every address a name resolves to, at the moment the
32
+ * connection is made (`guardedLookup` is the socket's DNS lookup), so a name
33
+ * that answers a public address to a first lookup and a private one to the
34
+ * connection's (DNS rebinding) is still refused.
35
+ */
36
+
37
+ /**
38
+ * May a server connect to this address on an editor's say-so? True only for
39
+ * a public unicast IPv4 or IPv6 address; false for anything else, including
40
+ * text that isn't an address.
41
+ */
42
+ declare function isPublicAddress(ip: string): boolean;
43
+ declare class BlockedAddressError extends Error {
44
+ readonly code = "EGSBLOCKED";
45
+ /** What the name resolved to, for the server's log; never shown to an editor. */
46
+ readonly address: string;
47
+ constructor(host: string, address: string);
48
+ }
49
+ type LookupCallback = (err: NodeJS.ErrnoException | null, address: string | LookupAddress[], family?: number) => void;
50
+ /**
51
+ * A DNS lookup for sockets (`http.request({ lookup })`) that refuses a name
52
+ * if any address it resolves to isn't public. It runs when the connection
53
+ * is made, so the address checked is the address connected to.
54
+ */
55
+ declare function guardedLookup(hostname: string, options: LookupOptions | number | LookupCallback, callback?: LookupCallback): void;
56
+ /** Problems with a URL a server is asked to fetch, before any connection: empty when it may try. */
57
+ declare function urlProblems(url: URL, allowedPorts: readonly number[]): string[];
58
+
59
+ /** One HTTP response, unfollowed. */
60
+ interface FetchedResponse {
61
+ status: number;
62
+ /** Lowercase header names. */
63
+ headers: Record<string, string | undefined>;
64
+ body: AsyncIterable<Uint8Array>;
65
+ /** Stop reading (the size cap was hit). */
66
+ cancel(): void;
67
+ }
68
+ /** Makes one GET request and doesn't follow redirects. The default is the guarded Node transport. */
69
+ type Transport = (url: URL, signal: AbortSignal) => Promise<FetchedResponse>;
70
+ /**
71
+ * The default transport: Node's http(s) with `guardedLookup` as the
72
+ * socket's DNS lookup and a fresh agent (no pooled sockets, no proxy from
73
+ * the environment), so the address connected to is the address checked.
74
+ */
75
+ declare const guardedTransport: Transport;
76
+ interface ImportAssetsOptions {
77
+ /** The largest file, in bytes (default 15 MiB). */
78
+ maxBytes?: number;
79
+ /** The time one URL may take, redirects included, in ms (default 20 s). */
80
+ timeoutMs?: number;
81
+ /** At most this many redirects per URL (default 3). */
82
+ maxRedirects?: number;
83
+ /** The ports fetched from (default 80 and 443). */
84
+ allowedPorts?: readonly number[];
85
+ /** Alt text for an image, when the importer knows it (the old page's `alt`). */
86
+ alt?: (url: string) => string | undefined;
87
+ /** Replaces the guarded Node transport (tests, another runtime). It must keep the address guard. */
88
+ transport?: Transport;
89
+ }
90
+ interface ImportedAsset {
91
+ /** Where the site loads it now. */
92
+ url: string;
93
+ assetId: string;
94
+ /** The storage key, under `sites/<site_id>/` (`files/` for a PDF). */
95
+ path: string;
96
+ mime: Sniffed["mime"];
97
+ width: number | null;
98
+ height: number | null;
99
+ bytes: number;
100
+ /** An image with no alt text yet: an editor writes it before the page publishes. */
101
+ needsAlt: boolean;
102
+ }
103
+ interface ImportAssetsResult {
104
+ /** Old URL → new URL, for `rewriteUrls`. */
105
+ map: Record<string, string>;
106
+ assets: Record<string, ImportedAsset>;
107
+ failed: {
108
+ url: string;
109
+ reason: string;
110
+ }[];
111
+ }
112
+ /** The most URLs one `importAssets` call fetches (one at a time, each with its own time limit). */
113
+ declare const MAX_IMPORT_URLS = 500;
114
+ /**
115
+ * Re-host remote images and files on a site: fetch, check, store, and map
116
+ * each old URL to its new one. A URL that fails (refused by the guard, not
117
+ * an image or PDF, too big, a server error) is listed in `failed` and the
118
+ * rest go on.
119
+ *
120
+ * @stability Beta
121
+ */
122
+ declare function importAssets(store: Pick<SiteStore, "putAsset">, siteId: string, urls: readonly string[], options?: ImportAssetsOptions): Promise<ImportAssetsResult>;
123
+ /**
124
+ * A copy of a document (a page, a post, a site) with every string that is
125
+ * exactly an old URL in `map` replaced by its new one: image sources, file
126
+ * links, rich text links. Nothing else changes.
127
+ */
128
+ declare function rewriteUrls<T>(value: T, map: Readonly<Record<string, string>>): T;
129
+
130
+ export { BlockedAddressError, type FetchedResponse, type ImportAssetsOptions, type ImportAssetsResult, type ImportedAsset, MAX_IMPORT_URLS, type Sniffed, type Transport, guardedLookup, guardedTransport, importAssets, isPublicAddress, rewriteUrls, sniff, urlProblems };
package/dist/import.js ADDED
@@ -0,0 +1,330 @@
1
+ import { MAX_URL_LENGTH } from './chunk-3VKTBE7S.js';
2
+ import { request as request$1, Agent as Agent$1 } from 'http';
3
+ import { request, Agent } from 'https';
4
+ import { lookup } from 'dns';
5
+ import { isIP } from 'net';
6
+
7
+ function v4(ip) {
8
+ const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(ip);
9
+ if (!m) return null;
10
+ const parts = m.slice(1).map(Number);
11
+ return parts.every((n) => n <= 255) ? parts : null;
12
+ }
13
+ function v4IsPublic([a, b, c]) {
14
+ if (a === 0 || a === 10 || a === 127) return false;
15
+ if (a === 100 && b >= 64 && b <= 127) return false;
16
+ if (a === 169 && b === 254) return false;
17
+ if (a === 172 && b >= 16 && b <= 31) return false;
18
+ if (a === 192 && b === 168) return false;
19
+ if (a === 192 && b === 0 && (c === 0 || c === 2)) return false;
20
+ if (a === 192 && b === 88 && c === 99) return false;
21
+ if (a === 198 && (b === 18 || b === 19)) return false;
22
+ if (a === 198 && b === 51 && c === 100) return false;
23
+ if (a === 203 && b === 0 && c === 113) return false;
24
+ if (a >= 224) return false;
25
+ return true;
26
+ }
27
+ function v6(input) {
28
+ let ip = input.replace(/^\[|\]$/g, "");
29
+ const zone = ip.indexOf("%");
30
+ if (zone >= 0) ip = ip.slice(0, zone);
31
+ let tail = [];
32
+ const lastColon = ip.lastIndexOf(":");
33
+ const maybeV4 = ip.slice(lastColon + 1);
34
+ if (maybeV4.includes(".")) {
35
+ const quad = v4(maybeV4);
36
+ if (!quad) return null;
37
+ tail = quad;
38
+ ip = `${ip.slice(0, lastColon + 1)}0:0`;
39
+ }
40
+ const halves = ip.split("::");
41
+ if (halves.length > 2) return null;
42
+ const groups = (s) => s === "" ? [] : s.split(":");
43
+ const head = groups(halves[0]);
44
+ const rest = halves.length === 2 ? groups(halves[1]) : [];
45
+ const missing = 8 - head.length - rest.length;
46
+ if (halves.length === 1 ? head.length !== 8 : missing < 1) return null;
47
+ const all = [...head, ...Array(halves.length === 2 ? missing : 0).fill("0"), ...rest];
48
+ const bytes = [];
49
+ for (const g of all) {
50
+ if (!/^[0-9a-f]{1,4}$/i.test(g)) return null;
51
+ const n = parseInt(g, 16);
52
+ bytes.push(n >> 8, n & 255);
53
+ }
54
+ if (tail.length) bytes.splice(12, 4, ...tail);
55
+ return bytes.length === 16 ? bytes : null;
56
+ }
57
+ function v6IsPublic(b) {
58
+ const zeros = (from, to) => b.slice(from, to).every((x) => x === 0);
59
+ const embedded = (at) => v4IsPublic(b.slice(at, at + 4));
60
+ if (zeros(0, 15) && (b[15] === 0 || b[15] === 1)) return false;
61
+ if (zeros(0, 10) && b[10] === 255 && b[11] === 255) return embedded(12);
62
+ if (zeros(0, 12)) return embedded(12);
63
+ if (b[0] === 0 && b[1] === 100 && b[2] === 255 && b[3] === 155) {
64
+ if (zeros(4, 12)) return embedded(12);
65
+ if (b[4] === 0 && b[5] === 1) return false;
66
+ }
67
+ if (b[0] === 1 && b[1] === 0 && zeros(2, 8)) return false;
68
+ if (b[0] === 32 && b[1] === 1 && b[2] < 2) return false;
69
+ if (b[0] === 32 && b[1] === 1 && b[2] === 13 && b[3] === 184) return false;
70
+ if (b[0] === 63 && (b[1] & 240) === 240) return false;
71
+ if (b[0] === 32 && b[1] === 2) return embedded(2);
72
+ if ((b[0] & 254) === 252) return false;
73
+ if (b[0] === 254 && (b[1] & 192) === 128) return false;
74
+ if (b[0] === 254 && (b[1] & 192) === 192) return false;
75
+ if (b[0] === 255) return false;
76
+ return (b[0] & 224) === 32;
77
+ }
78
+ function isPublicAddress(ip) {
79
+ const four = v4(ip);
80
+ if (four) return v4IsPublic(four);
81
+ const six = v6(ip);
82
+ return six ? v6IsPublic(six) : false;
83
+ }
84
+ var BlockedAddressError = class extends Error {
85
+ code = "EGSBLOCKED";
86
+ /** What the name resolved to, for the server's log; never shown to an editor. */
87
+ address;
88
+ constructor(host, address) {
89
+ super(`${host} isn't a public address.`);
90
+ this.address = address;
91
+ this.name = "BlockedAddressError";
92
+ }
93
+ };
94
+ function guardedLookup(hostname, options, callback) {
95
+ const cb = typeof options === "function" ? options : callback;
96
+ const opts = typeof options === "object" && options ? options : typeof options === "number" ? { family: options } : {};
97
+ lookup(hostname, { ...opts, all: true }, (err, addresses) => {
98
+ if (err) return cb(err, "");
99
+ const list = addresses;
100
+ const bad = list.find((a) => !isPublicAddress(a.address));
101
+ if (bad || list.length === 0) return cb(new BlockedAddressError(hostname, bad?.address ?? "nothing"), "");
102
+ if (opts.all) return cb(null, list);
103
+ cb(null, list[0].address, list[0].family);
104
+ });
105
+ }
106
+ function urlProblems(url, allowedPorts) {
107
+ const problems = [];
108
+ if (url.protocol !== "http:" && url.protocol !== "https:") problems.push("Only http and https URLs are fetched.");
109
+ if (url.username || url.password) problems.push("A URL with a user name or password isn't fetched.");
110
+ const port = url.port ? Number(url.port) : url.protocol === "https:" ? 443 : 80;
111
+ if (!allowedPorts.includes(port)) problems.push(`Port ${port} isn't fetched (only ${allowedPorts.join(", ")}).`);
112
+ const host = url.hostname.replace(/^\[|\]$/g, "").replace(/\.+$/, "");
113
+ if (!host) problems.push("The URL has no host.");
114
+ if (isIP(host) && !isPublicAddress(host)) problems.push(`${host} isn't a public address.`);
115
+ if (/^localhost$|\.localhost$|\.local$|\.internal$/i.test(host)) problems.push(`${host} is a local name.`);
116
+ return problems;
117
+ }
118
+
119
+ // src/import/sniff.ts
120
+ var ascii = (b, at, len) => String.fromCharCode(...b.subarray(at, at + len));
121
+ var u16be = (b, at) => b[at] << 8 | b[at + 1];
122
+ var u16le = (b, at) => b[at] | b[at + 1] << 8;
123
+ var u24le = (b, at) => b[at] | b[at + 1] << 8 | b[at + 2] << 16;
124
+ var u32be = (b, at) => (b[at] << 24 >>> 0) + (b[at + 1] << 16) + (b[at + 2] << 8) + b[at + 3];
125
+ function jpegSize(b) {
126
+ let i = 2;
127
+ while (i + 9 < b.length) {
128
+ if (b[i] !== 255) return null;
129
+ const marker = b[i + 1];
130
+ if (marker === 255) {
131
+ i += 1;
132
+ continue;
133
+ }
134
+ const len = u16be(b, i + 2);
135
+ if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) {
136
+ return { height: u16be(b, i + 5), width: u16be(b, i + 7) };
137
+ }
138
+ if (len < 2) return null;
139
+ i += 2 + len;
140
+ }
141
+ return null;
142
+ }
143
+ function webpSize(b) {
144
+ const chunk = ascii(b, 12, 4);
145
+ if (chunk === "VP8 " && b.length >= 30) return { width: u16le(b, 26) & 16383, height: u16le(b, 28) & 16383 };
146
+ if (chunk === "VP8L" && b.length >= 25 && b[20] === 47) {
147
+ const bits = b[21] | b[22] << 8 | b[23] << 16 | b[24] << 24;
148
+ return { width: (bits & 16383) + 1, height: (bits >> 14 & 16383) + 1 };
149
+ }
150
+ if (chunk === "VP8X" && b.length >= 30) return { width: u24le(b, 24) + 1, height: u24le(b, 27) + 1 };
151
+ return null;
152
+ }
153
+ function sniff(bytes) {
154
+ const b = bytes;
155
+ if (b.length >= 24 && b[0] === 137 && ascii(b, 1, 3) === "PNG" && b[4] === 13 && b[5] === 10 && b[6] === 26 && b[7] === 10) {
156
+ return { mime: "image/png", ext: "png", width: u32be(b, 16), height: u32be(b, 20) };
157
+ }
158
+ if (b.length >= 4 && b[0] === 255 && b[1] === 216 && b[2] === 255) {
159
+ const size = jpegSize(b);
160
+ return { mime: "image/jpeg", ext: "jpg", width: size?.width ?? null, height: size?.height ?? null };
161
+ }
162
+ if (b.length >= 10 && (ascii(b, 0, 6) === "GIF87a" || ascii(b, 0, 6) === "GIF89a")) {
163
+ return { mime: "image/gif", ext: "gif", width: u16le(b, 6), height: u16le(b, 8) };
164
+ }
165
+ if (b.length >= 16 && ascii(b, 0, 4) === "RIFF" && ascii(b, 8, 4) === "WEBP") {
166
+ const size = webpSize(b);
167
+ return { mime: "image/webp", ext: "webp", width: size?.width ?? null, height: size?.height ?? null };
168
+ }
169
+ if (b.length >= 12 && ascii(b, 4, 4) === "ftyp") {
170
+ const boxEnd = Math.min(u32be(b, 0), b.length, 64);
171
+ const brands = [ascii(b, 8, 4)];
172
+ for (let at = 16; at + 4 <= boxEnd; at += 4) brands.push(ascii(b, at, 4));
173
+ if (brands.includes("avif") || brands.includes("avis")) return { mime: "image/avif", ext: "avif", width: null, height: null };
174
+ return null;
175
+ }
176
+ if (b.length >= 5 && ascii(b, 0, 5) === "%PDF-") return { mime: "application/pdf", ext: "pdf", width: null, height: null };
177
+ return null;
178
+ }
179
+
180
+ // src/import/index.ts
181
+ var guardedTransport = (url, signal) => new Promise((resolve, reject) => {
182
+ const secure = url.protocol === "https:";
183
+ const req = (secure ? request : request$1)(
184
+ url,
185
+ {
186
+ method: "GET",
187
+ lookup: guardedLookup,
188
+ agent: secure ? new Agent({ keepAlive: false }) : new Agent$1({ keepAlive: false }),
189
+ headers: { accept: "image/*,application/pdf;q=0.9,*/*;q=0.1", "user-agent": "genesis-sites-import/1" },
190
+ signal
191
+ },
192
+ (res) => {
193
+ const headers = {};
194
+ for (const [k, v] of Object.entries(res.headers)) headers[k.toLowerCase()] = Array.isArray(v) ? v.join(", ") : v;
195
+ resolve({ status: res.statusCode ?? 0, headers, body: res, cancel: () => res.destroy() });
196
+ }
197
+ );
198
+ req.on("error", reject);
199
+ req.end();
200
+ });
201
+ var REDIRECTS = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
202
+ var MAX_IMPORT_URLS = 500;
203
+ var MAX_DIMENSION = 2e4;
204
+ var MAX_PIXELS = 5e7;
205
+ var ImportRefused = class extends Error {
206
+ };
207
+ async function readCapped(res, maxBytes) {
208
+ const declared = Number(res.headers["content-length"]);
209
+ if (Number.isFinite(declared) && declared > maxBytes) {
210
+ res.cancel();
211
+ throw new ImportRefused(`it is ${declared} bytes; the limit is ${maxBytes}.`);
212
+ }
213
+ const chunks = [];
214
+ let total = 0;
215
+ for await (const chunk of res.body) {
216
+ total += chunk.byteLength;
217
+ if (total > maxBytes) {
218
+ res.cancel();
219
+ throw new ImportRefused(`it is over the ${maxBytes}-byte limit.`);
220
+ }
221
+ chunks.push(chunk);
222
+ }
223
+ const out = new Uint8Array(total);
224
+ let at = 0;
225
+ for (const c of chunks) {
226
+ out.set(c, at);
227
+ at += c.byteLength;
228
+ }
229
+ return out;
230
+ }
231
+ async function fetchGuarded(start, o) {
232
+ if (start.length > MAX_URL_LENGTH) throw new ImportRefused("the URL is too long.");
233
+ let url;
234
+ try {
235
+ url = new URL(start);
236
+ } catch {
237
+ throw new ImportRefused("it isn't a URL.");
238
+ }
239
+ const signal = AbortSignal.timeout(o.timeoutMs);
240
+ for (let hop = 0; ; hop++) {
241
+ const problems = urlProblems(url, o.allowedPorts);
242
+ if (problems.length) throw new ImportRefused(hop ? `it redirects to ${url.host}: ${problems.join(" ")}` : problems.join(" "));
243
+ const res = await o.transport(url, signal);
244
+ if (REDIRECTS.has(res.status)) {
245
+ res.cancel();
246
+ const location = res.headers.location;
247
+ if (!location) throw new ImportRefused(`a ${res.status} with no Location.`);
248
+ if (hop >= o.maxRedirects) throw new ImportRefused(`more than ${o.maxRedirects} redirects.`);
249
+ const next = new URL(location, url);
250
+ if (url.protocol === "https:" && next.protocol === "http:") throw new ImportRefused(`it redirects from https to http (${next.host}).`);
251
+ url = next;
252
+ continue;
253
+ }
254
+ if (res.status !== 200) {
255
+ res.cancel();
256
+ throw new ImportRefused(`the server answered ${res.status}.`);
257
+ }
258
+ return { bytes: await readCapped(res, o.maxBytes), finalUrl: url };
259
+ }
260
+ }
261
+ function fileName(url, ext) {
262
+ const segment = url.pathname.split("/").pop() ?? "";
263
+ let decoded;
264
+ try {
265
+ decoded = decodeURIComponent(segment);
266
+ } catch {
267
+ decoded = "";
268
+ }
269
+ const last = decoded.replace(/\.[a-z0-9]{1,5}$/i, "");
270
+ const base = last.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "file";
271
+ return `${base}.${ext}`;
272
+ }
273
+ async function importAssets(store, siteId, urls, options = {}) {
274
+ if (!store.putAsset) throw new Error("importAssets: the store can't store files (no putAsset).");
275
+ if (urls.length > MAX_IMPORT_URLS) throw new Error(`importAssets: at most ${MAX_IMPORT_URLS} URLs a call (got ${urls.length}).`);
276
+ const o = {
277
+ maxBytes: options.maxBytes ?? 15 * 1024 * 1024,
278
+ timeoutMs: options.timeoutMs ?? 2e4,
279
+ maxRedirects: options.maxRedirects ?? 3,
280
+ allowedPorts: options.allowedPorts ?? [80, 443],
281
+ transport: options.transport ?? guardedTransport
282
+ };
283
+ const result = { map: {}, assets: {}, failed: [] };
284
+ for (const url of [...new Set(urls)]) {
285
+ try {
286
+ const { bytes, finalUrl } = await fetchGuarded(url, o);
287
+ const kind = sniff(bytes);
288
+ if (!kind) throw new ImportRefused("it isn't a PNG, JPEG, GIF, WebP, AVIF or PDF (by its bytes).");
289
+ if ((kind.width ?? 0) > MAX_DIMENSION || (kind.height ?? 0) > MAX_DIMENSION) throw new ImportRefused(`it is ${kind.width}\xD7${kind.height} pixels; the limit is ${MAX_DIMENSION} a side.`);
290
+ if ((kind.width ?? 0) * (kind.height ?? 0) > MAX_PIXELS) throw new ImportRefused(`it is ${kind.width}\xD7${kind.height} pixels; the limit is ${MAX_PIXELS / 1e6} million in all.`);
291
+ const alt = kind.mime === "application/pdf" ? void 0 : options.alt?.(url)?.trim().slice(0, 300) || void 0;
292
+ const blob = new Blob([bytes], { type: kind.mime });
293
+ const asset = await store.putAsset(siteId, blob, {
294
+ name: fileName(finalUrl, kind.ext),
295
+ ...alt ? { alt } : {},
296
+ ...kind.width ? { width: kind.width } : {},
297
+ ...kind.height ? { height: kind.height } : {}
298
+ });
299
+ result.map[url] = asset.url;
300
+ result.assets[url] = {
301
+ url: asset.url,
302
+ assetId: asset.id,
303
+ path: asset.path,
304
+ mime: kind.mime,
305
+ width: kind.width,
306
+ height: kind.height,
307
+ bytes: bytes.byteLength,
308
+ needsAlt: kind.mime !== "application/pdf" && !alt
309
+ };
310
+ } catch (err) {
311
+ const reason = err instanceof ImportRefused ? err.message : `${err?.message ?? String(err)}`;
312
+ if (err && typeof err === "object" && "address" in err) console.warn(`[genesis-sites] import refused ${url}: it resolves to ${err.address}.`);
313
+ result.failed.push({ url, reason });
314
+ }
315
+ }
316
+ return result;
317
+ }
318
+ function rewriteUrls(value, map) {
319
+ const walk = (v) => {
320
+ if (typeof v === "string") return Object.prototype.hasOwnProperty.call(map, v) ? map[v] : v;
321
+ if (Array.isArray(v)) return v.map(walk);
322
+ if (v && typeof v === "object") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));
323
+ return v;
324
+ };
325
+ return walk(value);
326
+ }
327
+
328
+ export { BlockedAddressError, MAX_IMPORT_URLS, guardedLookup, guardedTransport, importAssets, isPublicAddress, rewriteUrls, sniff, urlProblems };
329
+ //# sourceMappingURL=import.js.map
330
+ //# sourceMappingURL=import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/import/guard.ts","../src/import/sniff.ts","../src/import/index.ts"],"names":["dnsLookup","httpsRequest","httpRequest","HttpsAgent","HttpAgent"],"mappings":"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","file":"import.js","sourcesContent":["/**\n * The network guard for importing remote files: which addresses a server\n * may fetch from on an editor's say-so. Only public unicast addresses: no\n * loopback, private, link-local (cloud metadata lives at 169.254.169.254),\n * carrier-grade NAT, documentation, benchmark, multicast or reserved\n * ranges, and no IPv6 form that hides one of those (IPv4-mapped, NAT64,\n * 6to4, unique local, site-local).\n *\n * The check runs on every address a name resolves to, at the moment the\n * connection is made (`guardedLookup` is the socket's DNS lookup), so a name\n * that answers a public address to a first lookup and a private one to the\n * connection's (DNS rebinding) is still refused.\n */\nimport { lookup as dnsLookup, type LookupAddress, type LookupOptions } from \"node:dns\";\nimport { isIP } from \"node:net\";\n\n/** An IPv4 address as four numbers, or null. */\nfunction v4(ip: string): [number, number, number, number] | null {\n const m = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(ip);\n if (!m) return null;\n const parts = m.slice(1).map(Number) as [number, number, number, number];\n return parts.every((n) => n <= 255) ? parts : null;\n}\n\nfunction v4IsPublic([a, b, c]: [number, number, number, number]): boolean {\n if (a === 0 || a === 10 || a === 127) return false; // this network, private, loopback\n if (a === 100 && b >= 64 && b <= 127) return false; // carrier-grade NAT\n if (a === 169 && b === 254) return false; // link-local (cloud metadata)\n if (a === 172 && b >= 16 && b <= 31) return false; // private\n if (a === 192 && b === 168) return false; // private\n if (a === 192 && b === 0 && (c === 0 || c === 2)) return false; // IETF protocol assignments, TEST-NET-1\n if (a === 192 && b === 88 && c === 99) return false; // 6to4 relay anycast\n if (a === 198 && (b === 18 || b === 19)) return false; // benchmarking\n if (a === 198 && b === 51 && c === 100) return false; // TEST-NET-2\n if (a === 203 && b === 0 && c === 113) return false; // TEST-NET-3\n if (a >= 224) return false; // multicast, reserved, broadcast\n return true;\n}\n\n/** An IPv6 address as 16 bytes, or null. Accepts `::`, an embedded IPv4 tail and a zone (`%eth0`). */\nfunction v6(input: string): number[] | null {\n let ip = input.replace(/^\\[|\\]$/g, \"\");\n const zone = ip.indexOf(\"%\");\n if (zone >= 0) ip = ip.slice(0, zone);\n let tail: number[] = [];\n const lastColon = ip.lastIndexOf(\":\");\n const maybeV4 = ip.slice(lastColon + 1);\n if (maybeV4.includes(\".\")) {\n const quad = v4(maybeV4);\n if (!quad) return null;\n tail = quad;\n ip = `${ip.slice(0, lastColon + 1)}0:0`;\n }\n const halves = ip.split(\"::\");\n if (halves.length > 2) return null;\n const groups = (s: string) => (s === \"\" ? [] : s.split(\":\"));\n const head = groups(halves[0]!);\n const rest = halves.length === 2 ? groups(halves[1]!) : [];\n const missing = 8 - head.length - rest.length;\n if (halves.length === 1 ? head.length !== 8 : missing < 1) return null;\n const all = [...head, ...Array(halves.length === 2 ? missing : 0).fill(\"0\"), ...rest];\n const bytes: number[] = [];\n for (const g of all) {\n if (!/^[0-9a-f]{1,4}$/i.test(g)) return null;\n const n = parseInt(g, 16);\n bytes.push(n >> 8, n & 0xff);\n }\n if (tail.length) bytes.splice(12, 4, ...tail);\n return bytes.length === 16 ? bytes : null;\n}\n\nfunction v6IsPublic(b: number[]): boolean {\n const zeros = (from: number, to: number) => b.slice(from, to).every((x) => x === 0);\n const embedded = (at: number) => v4IsPublic(b.slice(at, at + 4) as [number, number, number, number]);\n if (zeros(0, 15) && (b[15] === 0 || b[15] === 1)) return false; // ::, ::1\n if (zeros(0, 10) && b[10] === 0xff && b[11] === 0xff) return embedded(12); // IPv4-mapped\n if (zeros(0, 12)) return embedded(12); // IPv4-compatible (deprecated)\n if (b[0] === 0x00 && b[1] === 0x64 && b[2] === 0xff && b[3] === 0x9b) {\n if (zeros(4, 12)) return embedded(12); // NAT64 well-known prefix\n if (b[4] === 0x00 && b[5] === 0x01) return false; // local-use NAT64\n }\n if (b[0] === 0x01 && b[1] === 0x00 && zeros(2, 8)) return false; // discard-only\n if (b[0] === 0x20 && b[1] === 0x01 && b[2]! < 0x02) return false; // IETF special (Teredo and others)\n if (b[0] === 0x20 && b[1] === 0x01 && b[2] === 0x0d && b[3] === 0xb8) return false; // documentation\n if (b[0] === 0x3f && (b[1]! & 0xf0) === 0xf0) return false; // documentation (3fff::/20, RFC 9637)\n if (b[0] === 0x20 && b[1] === 0x02) return embedded(2); // 6to4\n if ((b[0]! & 0xfe) === 0xfc) return false; // unique local\n if (b[0] === 0xfe && (b[1]! & 0xc0) === 0x80) return false; // link-local\n if (b[0] === 0xfe && (b[1]! & 0xc0) === 0xc0) return false; // site-local (deprecated)\n if (b[0] === 0xff) return false; // multicast\n return (b[0]! & 0xe0) === 0x20; // global unicast is 2000::/3\n}\n\n/**\n * May a server connect to this address on an editor's say-so? True only for\n * a public unicast IPv4 or IPv6 address; false for anything else, including\n * text that isn't an address.\n */\nexport function isPublicAddress(ip: string): boolean {\n const four = v4(ip);\n if (four) return v4IsPublic(four);\n const six = v6(ip);\n return six ? v6IsPublic(six) : false;\n}\n\nexport class BlockedAddressError extends Error {\n readonly code = \"EGSBLOCKED\";\n /** What the name resolved to, for the server's log; never shown to an editor. */\n readonly address: string;\n constructor(host: string, address: string) {\n // The address stays out of the message: an editor shouldn't learn what an internal name resolves to.\n super(`${host} isn't a public address.`);\n this.address = address;\n this.name = \"BlockedAddressError\";\n }\n}\n\ntype LookupCallback = (err: NodeJS.ErrnoException | null, address: string | LookupAddress[], family?: number) => void;\n\n/**\n * A DNS lookup for sockets (`http.request({ lookup })`) that refuses a name\n * if any address it resolves to isn't public. It runs when the connection\n * is made, so the address checked is the address connected to.\n */\nexport function guardedLookup(hostname: string, options: LookupOptions | number | LookupCallback, callback?: LookupCallback): void {\n const cb = (typeof options === \"function\" ? options : callback) as LookupCallback;\n const opts: LookupOptions = typeof options === \"object\" && options ? options : typeof options === \"number\" ? { family: options } : {};\n dnsLookup(hostname, { ...opts, all: true }, (err, addresses) => {\n if (err) return cb(err, \"\");\n const list = addresses as LookupAddress[];\n const bad = list.find((a) => !isPublicAddress(a.address));\n if (bad || list.length === 0) return cb(new BlockedAddressError(hostname, bad?.address ?? \"nothing\") as NodeJS.ErrnoException, \"\");\n if (opts.all) return cb(null, list);\n cb(null, list[0]!.address, list[0]!.family);\n });\n}\n\n/** Problems with a URL a server is asked to fetch, before any connection: empty when it may try. */\nexport function urlProblems(url: URL, allowedPorts: readonly number[]): string[] {\n const problems: string[] = [];\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") problems.push(\"Only http and https URLs are fetched.\");\n if (url.username || url.password) problems.push(\"A URL with a user name or password isn't fetched.\");\n const port = url.port ? Number(url.port) : url.protocol === \"https:\" ? 443 : 80;\n if (!allowedPorts.includes(port)) problems.push(`Port ${port} isn't fetched (only ${allowedPorts.join(\", \")}).`);\n const host = url.hostname.replace(/^\\[|\\]$/g, \"\").replace(/\\.+$/, \"\");\n if (!host) problems.push(\"The URL has no host.\");\n // An address written as the host never goes through DNS, so it is checked here.\n if (isIP(host) && !isPublicAddress(host)) problems.push(`${host} isn't a public address.`);\n if (/^localhost$|\\.localhost$|\\.local$|\\.internal$/i.test(host)) problems.push(`${host} is a local name.`);\n return problems;\n}\n","/**\n * What a downloaded file is, from its first bytes (never from its name or\n * the server's Content-Type), and an image's size from its header. Only the\n * types a site stores: PNG, JPEG, GIF, WebP, AVIF and PDF. SVG, HTML and\n * everything else are refused, since a browser runs them as a page.\n */\n\nexport interface Sniffed {\n mime: \"image/png\" | \"image/jpeg\" | \"image/gif\" | \"image/webp\" | \"image/avif\" | \"application/pdf\";\n ext: string;\n width: number | null;\n height: number | null;\n}\n\nconst ascii = (b: Uint8Array, at: number, len: number) => String.fromCharCode(...b.subarray(at, at + len));\nconst u16be = (b: Uint8Array, at: number) => (b[at]! << 8) | b[at + 1]!;\nconst u16le = (b: Uint8Array, at: number) => b[at]! | (b[at + 1]! << 8);\nconst u24le = (b: Uint8Array, at: number) => b[at]! | (b[at + 1]! << 8) | (b[at + 2]! << 16);\nconst u32be = (b: Uint8Array, at: number) => ((b[at]! << 24) >>> 0) + (b[at + 1]! << 16) + (b[at + 2]! << 8) + b[at + 3]!;\n\nfunction jpegSize(b: Uint8Array): { width: number; height: number } | null {\n let i = 2;\n while (i + 9 < b.length) {\n if (b[i] !== 0xff) return null;\n const marker = b[i + 1]!;\n if (marker === 0xff) {\n i += 1;\n continue;\n }\n const len = u16be(b, i + 2);\n // Start of frame (not DHT C4, JPG C8 or DAC CC): height then width.\n if (marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc) {\n return { height: u16be(b, i + 5), width: u16be(b, i + 7) };\n }\n if (len < 2) return null;\n i += 2 + len;\n }\n return null;\n}\n\nfunction webpSize(b: Uint8Array): { width: number; height: number } | null {\n const chunk = ascii(b, 12, 4);\n if (chunk === \"VP8 \" && b.length >= 30) return { width: u16le(b, 26) & 0x3fff, height: u16le(b, 28) & 0x3fff };\n if (chunk === \"VP8L\" && b.length >= 25 && b[20] === 0x2f) {\n const bits = b[21]! | (b[22]! << 8) | (b[23]! << 16) | (b[24]! << 24);\n return { width: (bits & 0x3fff) + 1, height: ((bits >> 14) & 0x3fff) + 1 };\n }\n if (chunk === \"VP8X\" && b.length >= 30) return { width: u24le(b, 24) + 1, height: u24le(b, 27) + 1 };\n return null;\n}\n\n/** The file's type and size, or null when it isn't one a site stores. */\nexport function sniff(bytes: Uint8Array): Sniffed | null {\n const b = bytes;\n if (b.length >= 24 && b[0] === 0x89 && ascii(b, 1, 3) === \"PNG\" && b[4] === 0x0d && b[5] === 0x0a && b[6] === 0x1a && b[7] === 0x0a) {\n return { mime: \"image/png\", ext: \"png\", width: u32be(b, 16), height: u32be(b, 20) };\n }\n if (b.length >= 4 && b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff) {\n const size = jpegSize(b);\n return { mime: \"image/jpeg\", ext: \"jpg\", width: size?.width ?? null, height: size?.height ?? null };\n }\n if (b.length >= 10 && (ascii(b, 0, 6) === \"GIF87a\" || ascii(b, 0, 6) === \"GIF89a\")) {\n return { mime: \"image/gif\", ext: \"gif\", width: u16le(b, 6), height: u16le(b, 8) };\n }\n if (b.length >= 16 && ascii(b, 0, 4) === \"RIFF\" && ascii(b, 8, 4) === \"WEBP\") {\n const size = webpSize(b);\n return { mime: \"image/webp\", ext: \"webp\", width: size?.width ?? null, height: size?.height ?? null };\n }\n if (b.length >= 12 && ascii(b, 4, 4) === \"ftyp\") {\n const boxEnd = Math.min(u32be(b, 0), b.length, 64);\n const brands = [ascii(b, 8, 4)];\n for (let at = 16; at + 4 <= boxEnd; at += 4) brands.push(ascii(b, at, 4));\n if (brands.includes(\"avif\") || brands.includes(\"avis\")) return { mime: \"image/avif\", ext: \"avif\", width: null, height: null };\n return null;\n }\n if (b.length >= 5 && ascii(b, 0, 5) === \"%PDF-\") return { mime: \"application/pdf\", ext: \"pdf\", width: null, height: null };\n return null;\n}\n","/**\n * @marktiderman/genesis-sites/import: moving a site in. Server only (Node).\n *\n * `importAssets(store, siteId, urls)` re-hosts the images and files an old\n * site points at: it fetches each URL, checks what came back by its bytes\n * (images and PDF only; never SVG or HTML) and its size, stores it under\n * `sites/<site_id>/...` through the store's `putAsset` (which writes the\n * `site_assets` row, with the image's dimensions), and returns a map from\n * each old URL to its new one. `rewriteUrls(doc, map)` then points the\n * imported pages and posts at the copies.\n *\n * Every fetch is guarded against server-side request forgery: http(s)\n * only, ports 80 and 443, no credentials in the URL, no address that isn't\n * public (checked on every address a name resolves to, when the connection\n * is made, so DNS rebinding doesn't get past it), at most three redirects,\n * each checked the same way, a size cap and a time limit.\n *\n * Posts come in through the store's own `importPosts`.\n *\n * @packageDocumentation\n */\nimport { Agent as HttpAgent, request as httpRequest, type IncomingMessage } from \"node:http\";\nimport { Agent as HttpsAgent, request as httpsRequest } from \"node:https\";\nimport type { SiteStore } from \"../core/store\";\nimport { MAX_URL_LENGTH } from \"../core/urls\";\nimport { guardedLookup, urlProblems } from \"./guard\";\nimport { sniff, type Sniffed } from \"./sniff\";\n\nexport { BlockedAddressError, guardedLookup, isPublicAddress, urlProblems } from \"./guard\";\nexport { sniff, type Sniffed } from \"./sniff\";\n\n/** One HTTP response, unfollowed. */\nexport interface FetchedResponse {\n status: number;\n /** Lowercase header names. */\n headers: Record<string, string | undefined>;\n body: AsyncIterable<Uint8Array>;\n /** Stop reading (the size cap was hit). */\n cancel(): void;\n}\n\n/** Makes one GET request and doesn't follow redirects. The default is the guarded Node transport. */\nexport type Transport = (url: URL, signal: AbortSignal) => Promise<FetchedResponse>;\n\n/**\n * The default transport: Node's http(s) with `guardedLookup` as the\n * socket's DNS lookup and a fresh agent (no pooled sockets, no proxy from\n * the environment), so the address connected to is the address checked.\n */\nexport const guardedTransport: Transport = (url, signal) =>\n new Promise((resolve, reject) => {\n const secure = url.protocol === \"https:\";\n const req = (secure ? httpsRequest : httpRequest)(\n url,\n {\n method: \"GET\",\n lookup: guardedLookup as never,\n agent: secure ? new HttpsAgent({ keepAlive: false }) : new HttpAgent({ keepAlive: false }),\n headers: { accept: \"image/*,application/pdf;q=0.9,*/*;q=0.1\", \"user-agent\": \"genesis-sites-import/1\" },\n signal,\n },\n (res: IncomingMessage) => {\n const headers: Record<string, string | undefined> = {};\n for (const [k, v] of Object.entries(res.headers)) headers[k.toLowerCase()] = Array.isArray(v) ? v.join(\", \") : v;\n resolve({ status: res.statusCode ?? 0, headers, body: res, cancel: () => res.destroy() });\n },\n );\n req.on(\"error\", reject);\n req.end();\n });\n\nexport interface ImportAssetsOptions {\n /** The largest file, in bytes (default 15 MiB). */\n maxBytes?: number;\n /** The time one URL may take, redirects included, in ms (default 20 s). */\n timeoutMs?: number;\n /** At most this many redirects per URL (default 3). */\n maxRedirects?: number;\n /** The ports fetched from (default 80 and 443). */\n allowedPorts?: readonly number[];\n /** Alt text for an image, when the importer knows it (the old page's `alt`). */\n alt?: (url: string) => string | undefined;\n /** Replaces the guarded Node transport (tests, another runtime). It must keep the address guard. */\n transport?: Transport;\n}\n\nexport interface ImportedAsset {\n /** Where the site loads it now. */\n url: string;\n assetId: string;\n /** The storage key, under `sites/<site_id>/` (`files/` for a PDF). */\n path: string;\n mime: Sniffed[\"mime\"];\n width: number | null;\n height: number | null;\n bytes: number;\n /** An image with no alt text yet: an editor writes it before the page publishes. */\n needsAlt: boolean;\n}\n\nexport interface ImportAssetsResult {\n /** Old URL → new URL, for `rewriteUrls`. */\n map: Record<string, string>;\n assets: Record<string, ImportedAsset>;\n failed: { url: string; reason: string }[];\n}\n\nconst REDIRECTS = new Set([301, 302, 303, 307, 308]);\n/** The most URLs one `importAssets` call fetches (one at a time, each with its own time limit). */\nexport const MAX_IMPORT_URLS = 500;\nconst MAX_DIMENSION = 20000;\n/** And at most this many pixels in all: a bigger header is a decompression bomb waiting for a resizer. */\nconst MAX_PIXELS = 50_000_000;\n\nclass ImportRefused extends Error {}\n\nasync function readCapped(res: FetchedResponse, maxBytes: number): Promise<Uint8Array> {\n const declared = Number(res.headers[\"content-length\"]);\n if (Number.isFinite(declared) && declared > maxBytes) {\n res.cancel();\n throw new ImportRefused(`it is ${declared} bytes; the limit is ${maxBytes}.`);\n }\n const chunks: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of res.body) {\n total += chunk.byteLength;\n if (total > maxBytes) {\n res.cancel();\n throw new ImportRefused(`it is over the ${maxBytes}-byte limit.`);\n }\n chunks.push(chunk);\n }\n const out = new Uint8Array(total);\n let at = 0;\n for (const c of chunks) {\n out.set(c, at);\n at += c.byteLength;\n }\n return out;\n}\n\n/** Fetch one URL through the guard, following at most `maxRedirects` checked redirects. */\nasync function fetchGuarded(start: string, o: Required<Pick<ImportAssetsOptions, \"maxBytes\" | \"timeoutMs\" | \"maxRedirects\" | \"allowedPorts\">> & { transport: Transport }): Promise<{ bytes: Uint8Array; finalUrl: URL }> {\n if (start.length > MAX_URL_LENGTH) throw new ImportRefused(\"the URL is too long.\");\n let url: URL;\n try {\n url = new URL(start);\n } catch {\n throw new ImportRefused(\"it isn't a URL.\");\n }\n const signal = AbortSignal.timeout(o.timeoutMs);\n for (let hop = 0; ; hop++) {\n const problems = urlProblems(url, o.allowedPorts);\n if (problems.length) throw new ImportRefused(hop ? `it redirects to ${url.host}: ${problems.join(\" \")}` : problems.join(\" \"));\n const res = await o.transport(url, signal);\n if (REDIRECTS.has(res.status)) {\n res.cancel();\n const location = res.headers.location;\n if (!location) throw new ImportRefused(`a ${res.status} with no Location.`);\n if (hop >= o.maxRedirects) throw new ImportRefused(`more than ${o.maxRedirects} redirects.`);\n const next = new URL(location, url);\n // Never from https down to http: the copy would come over a connection anyone on the path can change.\n if (url.protocol === \"https:\" && next.protocol === \"http:\") throw new ImportRefused(`it redirects from https to http (${next.host}).`);\n url = next;\n continue;\n }\n if (res.status !== 200) {\n res.cancel();\n throw new ImportRefused(`the server answered ${res.status}.`);\n }\n return { bytes: await readCapped(res, o.maxBytes), finalUrl: url };\n }\n}\n\n/** A storage-friendly name from the URL's last segment, with the extension of what the bytes are. */\nfunction fileName(url: URL, ext: string): string {\n const segment = url.pathname.split(\"/\").pop() ?? \"\";\n let decoded: string;\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n // A malformed escape (`%zz`, a lone `%`): the name falls back to \"file\", the import goes on.\n decoded = \"\";\n }\n const last = decoded.replace(/\\.[a-z0-9]{1,5}$/i, \"\");\n const base = last.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 60) || \"file\";\n return `${base}.${ext}`;\n}\n\n/**\n * Re-host remote images and files on a site: fetch, check, store, and map\n * each old URL to its new one. A URL that fails (refused by the guard, not\n * an image or PDF, too big, a server error) is listed in `failed` and the\n * rest go on.\n *\n * @stability Beta\n */\nexport async function importAssets(store: Pick<SiteStore, \"putAsset\">, siteId: string, urls: readonly string[], options: ImportAssetsOptions = {}): Promise<ImportAssetsResult> {\n if (!store.putAsset) throw new Error(\"importAssets: the store can't store files (no putAsset).\");\n if (urls.length > MAX_IMPORT_URLS) throw new Error(`importAssets: at most ${MAX_IMPORT_URLS} URLs a call (got ${urls.length}).`);\n const o = {\n maxBytes: options.maxBytes ?? 15 * 1024 * 1024,\n timeoutMs: options.timeoutMs ?? 20_000,\n maxRedirects: options.maxRedirects ?? 3,\n allowedPorts: options.allowedPorts ?? [80, 443],\n transport: options.transport ?? guardedTransport,\n };\n const result: ImportAssetsResult = { map: {}, assets: {}, failed: [] };\n for (const url of [...new Set(urls)]) {\n try {\n const { bytes, finalUrl } = await fetchGuarded(url, o);\n const kind = sniff(bytes);\n if (!kind) throw new ImportRefused(\"it isn't a PNG, JPEG, GIF, WebP, AVIF or PDF (by its bytes).\");\n // AVIF (and an odd JPEG or WebP) gives no size here; the byte cap still bounds it.\n if ((kind.width ?? 0) > MAX_DIMENSION || (kind.height ?? 0) > MAX_DIMENSION) throw new ImportRefused(`it is ${kind.width}×${kind.height} pixels; the limit is ${MAX_DIMENSION} a side.`);\n if ((kind.width ?? 0) * (kind.height ?? 0) > MAX_PIXELS) throw new ImportRefused(`it is ${kind.width}×${kind.height} pixels; the limit is ${MAX_PIXELS / 1_000_000} million in all.`);\n const alt = kind.mime === \"application/pdf\" ? undefined : options.alt?.(url)?.trim().slice(0, 300) || undefined;\n const blob = new Blob([bytes as BlobPart], { type: kind.mime });\n const asset = await store.putAsset(siteId, blob, {\n name: fileName(finalUrl, kind.ext),\n ...(alt ? { alt } : {}),\n ...(kind.width ? { width: kind.width } : {}),\n ...(kind.height ? { height: kind.height } : {}),\n });\n result.map[url] = asset.url;\n result.assets[url] = {\n url: asset.url,\n assetId: asset.id,\n path: asset.path,\n mime: kind.mime,\n width: kind.width,\n height: kind.height,\n bytes: bytes.byteLength,\n needsAlt: kind.mime !== \"application/pdf\" && !alt,\n };\n } catch (err) {\n const reason = err instanceof ImportRefused ? err.message : `${(err as Error)?.message ?? String(err)}`;\n if (err && typeof err === \"object\" && \"address\" in err) console.warn(`[genesis-sites] import refused ${url}: it resolves to ${(err as { address: string }).address}.`);\n result.failed.push({ url, reason });\n }\n }\n return result;\n}\n\n/**\n * A copy of a document (a page, a post, a site) with every string that is\n * exactly an old URL in `map` replaced by its new one: image sources, file\n * links, rich text links. Nothing else changes.\n */\nexport function rewriteUrls<T>(value: T, map: Readonly<Record<string, string>>): T {\n const walk = (v: unknown): unknown => {\n if (typeof v === \"string\") return Object.prototype.hasOwnProperty.call(map, v) ? map[v] : v;\n if (Array.isArray(v)) return v.map(walk);\n if (v && typeof v === \"object\") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));\n return v;\n };\n return walk(value) as T;\n}\n"]}