@xsynaptic/astro-image-pipeline 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,296 @@
1
+ import { d as parseImageName, l as isImageSource, n as isWithinSource, r as imageRecordsVariable, s as getImageStem } from "./image-presets-ZN7_n2p8.mjs";
2
+ import { a as writeManifest, h as renderImage, i as writeBuildId, m as readSourceSize, o as UserError, r as readManifest, t as getImageCachePaths, u as formatList } from "./image-state-Bdi_-yWQ.mjs";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import { promises } from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ //#region src/dev-resolver.ts
8
+ async function getModifiedTime(filePath) {
9
+ try {
10
+ return (await promises.stat(filePath)).mtimeMs;
11
+ } catch {
12
+ return;
13
+ }
14
+ }
15
+ function isWithinDirectory(directory, filePath) {
16
+ const relativePath = path.relative(directory, filePath);
17
+ return relativePath !== "" && relativePath.split(path.sep)[0] !== ".." && !path.isAbsolute(relativePath);
18
+ }
19
+ async function isNewerThanSource(target, sourcePath) {
20
+ const [sourceTime, targetTime] = await Promise.all([getModifiedTime(sourcePath), getModifiedTime(target)]);
21
+ return sourceTime !== void 0 && targetTime !== void 0 && targetTime >= sourceTime;
22
+ }
23
+ async function writeImage(target, data) {
24
+ const temporary = `${target}.${randomUUID()}.tmp`;
25
+ await promises.mkdir(path.dirname(target), { recursive: true });
26
+ await promises.writeFile(temporary, data);
27
+ await promises.rename(temporary, target);
28
+ }
29
+ function createDevImageResolver({ builtPath, cachePath, encoding, limitInputPixels, mediaPath, render = renderImage, sources }) {
30
+ const inFlight = /* @__PURE__ */ new Map();
31
+ async function resolveImage(name) {
32
+ const parsed = parseImageName(name);
33
+ if (!parsed) return;
34
+ const id = await sources.resolve(parsed.stem);
35
+ if (id === void 0) return;
36
+ const sourcePath = path.resolve(mediaPath, id);
37
+ if (!isWithinDirectory(mediaPath, sourcePath)) return;
38
+ if (builtPath) {
39
+ const built = path.join(builtPath, name);
40
+ if (await isNewerThanSource(built, sourcePath)) return built;
41
+ }
42
+ const target = path.join(cachePath, name);
43
+ if (await isNewerThanSource(target, sourcePath)) return target;
44
+ if (!isWithinSource(parsed, await readSourceSize(sourcePath))) return;
45
+ const { data } = await render(sourcePath, {
46
+ encoding,
47
+ format: parsed.format,
48
+ height: parsed.height,
49
+ limitInputPixels,
50
+ width: parsed.width
51
+ });
52
+ await writeImage(target, data);
53
+ return target;
54
+ }
55
+ async function resolveOnce(name) {
56
+ try {
57
+ return await resolveImage(name);
58
+ } finally {
59
+ inFlight.delete(name);
60
+ }
61
+ }
62
+ return function getDevImage(name) {
63
+ const pending = inFlight.get(name);
64
+ if (pending) return pending;
65
+ const request = resolveOnce(name);
66
+ inFlight.set(name, request);
67
+ return request;
68
+ };
69
+ }
70
+ //#endregion
71
+ //#region src/image-records.ts
72
+ async function listRecordFiles(recordsPath) {
73
+ try {
74
+ return (await promises.readdir(recordsPath)).filter((entry) => entry.endsWith(".ndjson")).toSorted((first, second) => first.localeCompare(second));
75
+ } catch {
76
+ return [];
77
+ }
78
+ }
79
+ function createRecordedValues() {
80
+ return {
81
+ conflicts: /* @__PURE__ */ new Map(),
82
+ values: /* @__PURE__ */ new Map()
83
+ };
84
+ }
85
+ function addRecordedValue(recorded, name, value) {
86
+ const existing = recorded.values.get(name);
87
+ if (existing === void 0) {
88
+ recorded.values.set(name, value);
89
+ return;
90
+ }
91
+ if (existing === value) return;
92
+ const conflict = recorded.conflicts.get(name) ?? /* @__PURE__ */ new Set([existing]);
93
+ recorded.conflicts.set(name, conflict.add(value));
94
+ }
95
+ function sortByName(entries) {
96
+ return new Map([...entries].toSorted(([first], [second]) => first.localeCompare(second)));
97
+ }
98
+ function describeConflicts(renditions, cards) {
99
+ const messages = [];
100
+ if (renditions.conflicts.size > 0) {
101
+ const conflicts = [...renditions.conflicts].map(([name, sourcePaths]) => `${name} (${[...sourcePaths].join(", ")})`);
102
+ messages.push(`${String(conflicts.length)} image names were recorded from more than one source:\n${formatList(conflicts.toSorted((first, second) => first.localeCompare(second)))}`);
103
+ }
104
+ if (cards.conflicts.size > 0) messages.push(`${String(cards.conflicts.size)} OpenGraph cards were recorded with different input:\n${formatList([...cards.conflicts.keys()].toSorted((first, second) => first.localeCompare(second)))}`);
105
+ return messages;
106
+ }
107
+ async function resetImageRecords(recordsPath) {
108
+ const buildRecordsPath = path.join(recordsPath, randomUUID());
109
+ await promises.rm(recordsPath, {
110
+ force: true,
111
+ recursive: true
112
+ });
113
+ await promises.mkdir(buildRecordsPath, { recursive: true });
114
+ return buildRecordsPath;
115
+ }
116
+ async function readImageRecords(recordsPath) {
117
+ const renditions = createRecordedValues();
118
+ const cards = createRecordedValues();
119
+ const recordFiles = await listRecordFiles(recordsPath);
120
+ for (const recordFile of recordFiles) {
121
+ const text = await promises.readFile(path.join(recordsPath, recordFile), "utf8");
122
+ for (const line of text.split("\n")) {
123
+ if (line === "") continue;
124
+ const record = JSON.parse(line);
125
+ if ("kind" in record) addRecordedValue(cards, record.name, JSON.stringify(record.card));
126
+ else addRecordedValue(renditions, record.name, record.sourcePath);
127
+ }
128
+ }
129
+ const messages = describeConflicts(renditions, cards);
130
+ if (messages.length > 0) throw new Error(messages.join("\n"));
131
+ return {
132
+ cards: sortByName([...cards.values].map(([name, value]) => [name, JSON.parse(value)])),
133
+ renditions: sortByName(renditions.values)
134
+ };
135
+ }
136
+ //#endregion
137
+ //#region src/image-sources.ts
138
+ async function readDirectory(directory) {
139
+ try {
140
+ return await promises.readdir(directory);
141
+ } catch {
142
+ return [];
143
+ }
144
+ }
145
+ function createDirectorySources(mediaPath) {
146
+ return { async resolve(stem) {
147
+ const directory = path.posix.dirname(stem);
148
+ const basename = path.posix.basename(stem);
149
+ const entry = (await readDirectory(path.join(mediaPath, directory))).find((name) => isImageSource(name) && getImageStem(name) === basename);
150
+ return entry === void 0 ? void 0 : path.posix.join(directory, entry);
151
+ } };
152
+ }
153
+ //#endregion
154
+ //#region src/astro-integration.ts
155
+ const sharpDefaultInputPixelLimit = 268402689;
156
+ function decodeImageName(pathname) {
157
+ try {
158
+ return decodeURIComponent(pathname).replace(/^\/+/, "");
159
+ } catch {
160
+ return;
161
+ }
162
+ }
163
+ async function readPreviousManifest(cachePath) {
164
+ try {
165
+ return await readManifest(cachePath);
166
+ } catch (error) {
167
+ if (error instanceof UserError) return;
168
+ throw error;
169
+ }
170
+ }
171
+ async function readRecorded({ cachePath, isIncremental, logger, pageCount, recordsPath }) {
172
+ const recorded = await readImageRecords(recordsPath);
173
+ if (isIncremental) {
174
+ logger.warn("Incremental build: pages restored from cache record nothing, so the manifest keeps the previous build's names too; names only fall out on a full build");
175
+ const previous = await readPreviousManifest(cachePath);
176
+ return {
177
+ cards: new Map([...Object.entries(previous?.openGraphCards ?? {}), ...recorded.cards]),
178
+ renditions: new Map([...Object.entries(previous?.renditions ?? {}), ...recorded.renditions])
179
+ };
180
+ }
181
+ if (recorded.renditions.size === 0 && recorded.cards.size === 0 && pageCount > 0) throw new Error(`No image names were recorded while building ${String(pageCount)} pages; build image URLs with getName at render time, in a runtime that has node:fs`);
182
+ return recorded;
183
+ }
184
+ async function writeBuildManifest({ cachePath, distPath, logger, manifest, recorded: { cards, renditions } }) {
185
+ const buildId = randomUUID();
186
+ await writeManifest(cachePath, {
187
+ ...manifest,
188
+ buildId,
189
+ distPath,
190
+ openGraphCards: Object.fromEntries(cards),
191
+ renditions: Object.fromEntries(renditions),
192
+ version: 4
193
+ });
194
+ await writeBuildId(distPath, buildId);
195
+ logger.info(`${String(renditions.size)} renditions from ${String(new Set(renditions.values()).size)} sources, ${String(cards.size)} OpenGraph cards`);
196
+ }
197
+ function createDevImageHandler(getDevImage, logger) {
198
+ return async function serveDevImage(request, response) {
199
+ const { pathname } = new URL(request.url ?? "/", "http://localhost");
200
+ const name = decodeImageName(pathname);
201
+ if (name === void 0) {
202
+ response.statusCode = 400;
203
+ response.end();
204
+ return;
205
+ }
206
+ try {
207
+ const filePath = await getDevImage(name);
208
+ if (!filePath) {
209
+ response.statusCode = 404;
210
+ response.end();
211
+ return;
212
+ }
213
+ response.setHeader("Cache-Control", "no-cache");
214
+ response.setHeader("Content-Type", filePath.endsWith(".webp") ? "image/webp" : "image/jpeg");
215
+ response.end(await promises.readFile(filePath));
216
+ } catch (error) {
217
+ logger.error(`${pathname}: ${error instanceof Error ? error.message : String(error)}`);
218
+ response.statusCode = 500;
219
+ response.end();
220
+ }
221
+ };
222
+ }
223
+ async function isBuiltFrom(cachePath, mediaPath) {
224
+ try {
225
+ return (await readManifest(cachePath))?.mediaPath === mediaPath;
226
+ } catch {
227
+ return false;
228
+ }
229
+ }
230
+ function imagePipeline({ baseUrl, cachePath, limitInputPixels = sharpDefaultInputPixelLimit, mediaPath, pipeline, sources }) {
231
+ if (baseUrl.replace(/\/+$/, "") === "") throw new Error("imagePipeline needs a baseUrl below the site root; at the root, every request and every root-relative URL would count as an image");
232
+ const absoluteMediaPath = path.resolve(mediaPath);
233
+ const absoluteCachePath = path.resolve(cachePath);
234
+ const { devPath, recordsPath, renditionsPath } = getImageCachePaths(absoluteCachePath);
235
+ let isIncremental = false;
236
+ let buildRecordsPath = recordsPath;
237
+ return {
238
+ hooks: {
239
+ "astro:build:done": async ({ dir, logger, pages }) => {
240
+ try {
241
+ const distPath = fileURLToPath(dir);
242
+ const recorded = await readRecorded({
243
+ cachePath: absoluteCachePath,
244
+ isIncremental,
245
+ logger,
246
+ pageCount: pages.length,
247
+ recordsPath: buildRecordsPath
248
+ });
249
+ await writeBuildManifest({
250
+ cachePath: absoluteCachePath,
251
+ distPath,
252
+ logger,
253
+ manifest: {
254
+ encoding: pipeline.encoding,
255
+ limitInputPixels,
256
+ mediaPath: absoluteMediaPath
257
+ },
258
+ recorded
259
+ });
260
+ await promises.rm(recordsPath, {
261
+ force: true,
262
+ recursive: true
263
+ });
264
+ } finally {
265
+ Reflect.deleteProperty(process.env, imageRecordsVariable);
266
+ }
267
+ },
268
+ "astro:config:setup": async ({ command, config }) => {
269
+ if (command !== "build") return;
270
+ isIncremental = config.experimental.incrementalBuild;
271
+ buildRecordsPath = await resetImageRecords(recordsPath);
272
+ process.env[imageRecordsVariable] = buildRecordsPath;
273
+ },
274
+ "astro:server:setup": async ({ logger, server }) => {
275
+ if (!baseUrl.startsWith("/")) return;
276
+ const mediaPathKey = createHash("sha256").update(absoluteMediaPath).digest("hex").slice(0, 8);
277
+ const serveDevImage = createDevImageHandler(createDevImageResolver({
278
+ builtPath: await isBuiltFrom(absoluteCachePath, absoluteMediaPath) ? renditionsPath : void 0,
279
+ cachePath: path.resolve(devPath, mediaPathKey),
280
+ encoding: pipeline.encoding,
281
+ limitInputPixels,
282
+ mediaPath: absoluteMediaPath,
283
+ sources: sources ?? createDirectorySources(absoluteMediaPath)
284
+ }), logger);
285
+ server.middlewares.use(baseUrl.replace(/\/+$/, ""), (request, response) => {
286
+ serveDevImage(request, response);
287
+ });
288
+ }
289
+ },
290
+ name: "@xsynaptic/astro-image-pipeline"
291
+ };
292
+ }
293
+ //#endregion
294
+ export { imagePipeline as default };
295
+
296
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["fs","fs","fs","fs"],"sources":["../src/dev-resolver.ts","../src/image-records.ts","../src/image-sources.ts","../src/astro-integration.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport type { ResolvedImageEncoding } from './image-encoding.js';\nimport type { ImageSourceResolver } from './image-sources.js';\n\nimport { parseImageName } from './image-name.js';\nimport { isWithinSource } from './image-presets.js';\nimport { readSourceSize, renderImage } from './image-render.js';\n\ninterface DevImageOptions {\n\tbuiltPath: string | undefined;\n\tcachePath: string;\n\tencoding: ResolvedImageEncoding;\n\tlimitInputPixels: number;\n\tmediaPath: string;\n\trender?: typeof renderImage;\n\tsources: ImageSourceResolver;\n}\n\nasync function getModifiedTime(filePath: string) {\n\ttry {\n\t\tconst stats = await fs.stat(filePath);\n\n\t\treturn stats.mtimeMs;\n\t} catch {\n\t\treturn;\n\t}\n}\n\nfunction isWithinDirectory(directory: string, filePath: string) {\n\tconst relativePath = path.relative(directory, filePath);\n\n\treturn (\n\t\trelativePath !== '' &&\n\t\trelativePath.split(path.sep)[0] !== '..' &&\n\t\t!path.isAbsolute(relativePath)\n\t);\n}\n\nasync function isNewerThanSource(target: string, sourcePath: string) {\n\tconst [sourceTime, targetTime] = await Promise.all([\n\t\tgetModifiedTime(sourcePath),\n\t\tgetModifiedTime(target),\n\t]);\n\n\treturn sourceTime !== undefined && targetTime !== undefined && targetTime >= sourceTime;\n}\n\nasync function writeImage(target: string, data: Uint8Array) {\n\tconst temporary = `${target}.${randomUUID()}.tmp`;\n\n\tawait fs.mkdir(path.dirname(target), { recursive: true });\n\tawait fs.writeFile(temporary, data);\n\tawait fs.rename(temporary, target);\n}\n\nexport function createDevImageResolver({\n\tbuiltPath,\n\tcachePath,\n\tencoding,\n\tlimitInputPixels,\n\tmediaPath,\n\trender = renderImage,\n\tsources,\n}: DevImageOptions) {\n\tconst inFlight = new Map<string, Promise<string | undefined>>();\n\n\tasync function resolveImage(name: string) {\n\t\tconst parsed = parseImageName(name);\n\n\t\tif (!parsed) return;\n\n\t\tconst id = await sources.resolve(parsed.stem);\n\n\t\tif (id === undefined) return;\n\n\t\tconst sourcePath = path.resolve(mediaPath, id);\n\n\t\tif (!isWithinDirectory(mediaPath, sourcePath)) return;\n\n\t\tif (builtPath) {\n\t\t\tconst built = path.join(builtPath, name);\n\n\t\t\tif (await isNewerThanSource(built, sourcePath)) return built;\n\t\t}\n\n\t\tconst target = path.join(cachePath, name);\n\n\t\tif (await isNewerThanSource(target, sourcePath)) return target;\n\n\t\tif (!isWithinSource(parsed, await readSourceSize(sourcePath))) return;\n\n\t\tconst { data } = await render(sourcePath, {\n\t\t\tencoding,\n\t\t\tformat: parsed.format,\n\t\t\theight: parsed.height,\n\t\t\tlimitInputPixels,\n\t\t\twidth: parsed.width,\n\t\t});\n\n\t\tawait writeImage(target, data);\n\n\t\treturn target;\n\t}\n\n\tasync function resolveOnce(name: string) {\n\t\ttry {\n\t\t\treturn await resolveImage(name);\n\t\t} finally {\n\t\t\tinFlight.delete(name);\n\t\t}\n\t}\n\n\treturn function getDevImage(name: string) {\n\t\tconst pending = inFlight.get(name);\n\n\t\tif (pending) return pending;\n\n\t\tconst request = resolveOnce(name);\n\n\t\tinFlight.set(name, request);\n\n\t\treturn request;\n\t};\n}\n","import { randomUUID } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport type { OpenGraphCard } from './open-graph-cards.js';\n\nimport { formatList } from './format.js';\n\ninterface OpenGraphCardRecord {\n\tcard: OpenGraphCard;\n\tkind: 'open-graph-card';\n\tname: string;\n}\n\ninterface RenditionRecord {\n\tname: string;\n\tsourcePath: string;\n}\n\ntype ImageRecord = OpenGraphCardRecord | RenditionRecord;\n\ninterface RecordedValues {\n\tconflicts: Map<string, Set<string>>;\n\tvalues: Map<string, string>;\n}\n\nasync function listRecordFiles(recordsPath: string) {\n\ttry {\n\t\tconst entries = await fs.readdir(recordsPath);\n\n\t\treturn entries\n\t\t\t.filter((entry) => entry.endsWith('.ndjson'))\n\t\t\t.toSorted((first, second) => first.localeCompare(second));\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction createRecordedValues(): RecordedValues {\n\treturn { conflicts: new Map(), values: new Map() };\n}\n\nfunction addRecordedValue(recorded: RecordedValues, name: string, value: string) {\n\tconst existing = recorded.values.get(name);\n\n\tif (existing === undefined) {\n\t\trecorded.values.set(name, value);\n\t\treturn;\n\t}\n\n\tif (existing === value) return;\n\n\tconst conflict = recorded.conflicts.get(name) ?? new Set([existing]);\n\n\trecorded.conflicts.set(name, conflict.add(value));\n}\n\nfunction sortByName<Value>(entries: Iterable<[string, Value]>) {\n\treturn new Map([...entries].toSorted(([first], [second]) => first.localeCompare(second)));\n}\n\nfunction describeConflicts(renditions: RecordedValues, cards: RecordedValues) {\n\tconst messages: Array<string> = [];\n\n\tif (renditions.conflicts.size > 0) {\n\t\tconst conflicts = [...renditions.conflicts].map(\n\t\t\t([name, sourcePaths]) => `${name} (${[...sourcePaths].join(', ')})`,\n\t\t);\n\n\t\tmessages.push(\n\t\t\t`${String(conflicts.length)} image names were recorded from more than one source:\\n${formatList(conflicts.toSorted((first, second) => first.localeCompare(second)))}`,\n\t\t);\n\t}\n\n\tif (cards.conflicts.size > 0) {\n\t\tmessages.push(\n\t\t\t`${String(cards.conflicts.size)} OpenGraph cards were recorded with different input:\\n${formatList([...cards.conflicts.keys()].toSorted((first, second) => first.localeCompare(second)))}`,\n\t\t);\n\t}\n\n\treturn messages;\n}\n\nexport async function resetImageRecords(recordsPath: string) {\n\tconst buildRecordsPath = path.join(recordsPath, randomUUID());\n\n\tawait fs.rm(recordsPath, { force: true, recursive: true });\n\tawait fs.mkdir(buildRecordsPath, { recursive: true });\n\n\treturn buildRecordsPath;\n}\n\nexport async function readImageRecords(recordsPath: string) {\n\tconst renditions = createRecordedValues();\n\tconst cards = createRecordedValues();\n\n\tconst recordFiles = await listRecordFiles(recordsPath);\n\n\tfor (const recordFile of recordFiles) {\n\t\tconst text = await fs.readFile(path.join(recordsPath, recordFile), 'utf8');\n\n\t\tfor (const line of text.split('\\n')) {\n\t\t\tif (line === '') continue;\n\n\t\t\tconst record = JSON.parse(line) as ImageRecord;\n\n\t\t\tif ('kind' in record) {\n\t\t\t\taddRecordedValue(cards, record.name, JSON.stringify(record.card));\n\t\t\t} else {\n\t\t\t\taddRecordedValue(renditions, record.name, record.sourcePath);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst messages = describeConflicts(renditions, cards);\n\n\tif (messages.length > 0) throw new Error(messages.join('\\n'));\n\n\treturn {\n\t\tcards: sortByName(\n\t\t\t[...cards.values].map(([name, value]): [string, OpenGraphCard] => [\n\t\t\t\tname,\n\t\t\t\tJSON.parse(value) as OpenGraphCard,\n\t\t\t]),\n\t\t),\n\t\trenditions: sortByName(renditions.values),\n\t};\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport { getImageStem, isImageSource } from './image-name.js';\n\nexport interface ImageSourceResolver {\n\tresolve(stem: string): Promise<string | undefined>;\n}\n\nasync function readDirectory(directory: string) {\n\ttry {\n\t\treturn await fs.readdir(directory);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n// No directory cache, so files added while dev runs resolve without a restart\nexport function createDirectorySources(mediaPath: string): ImageSourceResolver {\n\treturn {\n\t\tasync resolve(stem) {\n\t\t\tconst directory = path.posix.dirname(stem);\n\t\t\tconst basename = path.posix.basename(stem);\n\t\t\tconst entries = await readDirectory(path.join(mediaPath, directory));\n\t\t\tconst entry = entries.find((name) => isImageSource(name) && getImageStem(name) === basename);\n\n\t\t\treturn entry === undefined ? undefined : path.posix.join(directory, entry);\n\t\t},\n\t};\n}\n","import type { AstroIntegration, AstroIntegrationLogger } from 'astro';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\nimport { createHash, randomUUID } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { ResolvedImageEncoding } from './image-encoding.js';\nimport type { ImageSourceResolver } from './image-sources.js';\nimport type { ImageManifest } from './image-state.js';\nimport type { OpenGraphCard } from './open-graph-cards.js';\n\nimport { createDevImageResolver } from './dev-resolver.js';\nimport { imageRecordsVariable } from './image-recorder.js';\nimport { readImageRecords, resetImageRecords } from './image-records.js';\nimport { createDirectorySources } from './image-sources.js';\nimport {\n\tgetImageCachePaths,\n\timageManifestVersion,\n\treadManifest,\n\twriteBuildId,\n\twriteManifest,\n} from './image-state.js';\nimport { UserError } from './user-error.js';\n\nexport type { ImageSourceResolver } from './image-sources.js';\n\nexport interface ImagePipelineOptions {\n\tbaseUrl: string;\n\tcachePath: string;\n\tlimitInputPixels?: number;\n\tmediaPath: string;\n\tpipeline: { encoding: ResolvedImageEncoding };\n\tsources?: ImageSourceResolver;\n}\n\nconst sharpDefaultInputPixelLimit = 0x3f_ff * 0x3f_ff;\n\nfunction decodeImageName(pathname: string) {\n\ttry {\n\t\treturn decodeURIComponent(pathname).replace(/^\\/+/, '');\n\t} catch {\n\t\treturn;\n\t}\n}\n\nasync function readPreviousManifest(cachePath: string) {\n\ttry {\n\t\treturn await readManifest(cachePath);\n\t} catch (error) {\n\t\tif (error instanceof UserError) return;\n\n\t\tthrow error;\n\t}\n}\n\nasync function readRecorded({\n\tcachePath,\n\tisIncremental,\n\tlogger,\n\tpageCount,\n\trecordsPath,\n}: {\n\tcachePath: string;\n\tisIncremental: boolean;\n\tlogger: AstroIntegrationLogger;\n\tpageCount: number;\n\trecordsPath: string;\n}) {\n\tconst recorded = await readImageRecords(recordsPath);\n\n\t// Pages an incremental build skips still count in `pages`, but record nothing\n\tif (isIncremental) {\n\t\tlogger.warn(\n\t\t\t\"Incremental build: pages restored from cache record nothing, so the manifest keeps the previous build's names too; names only fall out on a full build\",\n\t\t);\n\n\t\tconst previous = await readPreviousManifest(cachePath);\n\n\t\treturn {\n\t\t\tcards: new Map([...Object.entries(previous?.openGraphCards ?? {}), ...recorded.cards]),\n\t\t\trenditions: new Map([...Object.entries(previous?.renditions ?? {}), ...recorded.renditions]),\n\t\t};\n\t}\n\n\tif (recorded.renditions.size === 0 && recorded.cards.size === 0 && pageCount > 0) {\n\t\tthrow new Error(\n\t\t\t`No image names were recorded while building ${String(pageCount)} pages; build image URLs with getName at render time, in a runtime that has node:fs`,\n\t\t);\n\t}\n\n\treturn recorded;\n}\n\nasync function writeBuildManifest({\n\tcachePath,\n\tdistPath,\n\tlogger,\n\tmanifest,\n\trecorded: { cards, renditions },\n}: {\n\tcachePath: string;\n\tdistPath: string;\n\tlogger: AstroIntegrationLogger;\n\tmanifest: Pick<ImageManifest, 'encoding' | 'limitInputPixels' | 'mediaPath'>;\n\trecorded: { cards: ReadonlyMap<string, OpenGraphCard>; renditions: ReadonlyMap<string, string> };\n}) {\n\tconst buildId = randomUUID();\n\n\tawait writeManifest(cachePath, {\n\t\t...manifest,\n\t\tbuildId,\n\t\tdistPath,\n\t\topenGraphCards: Object.fromEntries(cards),\n\t\trenditions: Object.fromEntries(renditions),\n\t\tversion: imageManifestVersion,\n\t});\n\tawait writeBuildId(distPath, buildId);\n\n\tlogger.info(\n\t\t`${String(renditions.size)} renditions from ${String(new Set(renditions.values()).size)} sources, ${String(cards.size)} OpenGraph cards`,\n\t);\n}\n\nfunction createDevImageHandler(\n\tgetDevImage: ReturnType<typeof createDevImageResolver>,\n\tlogger: AstroIntegrationLogger,\n) {\n\treturn async function serveDevImage(request: IncomingMessage, response: ServerResponse) {\n\t\tconst { pathname } = new URL(request.url ?? '/', 'http://localhost');\n\t\tconst name = decodeImageName(pathname);\n\n\t\tif (name === undefined) {\n\t\t\tresponse.statusCode = 400;\n\t\t\tresponse.end();\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst filePath = await getDevImage(name);\n\n\t\t\tif (!filePath) {\n\t\t\t\tresponse.statusCode = 404;\n\t\t\t\tresponse.end();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresponse.setHeader('Cache-Control', 'no-cache');\n\t\t\tresponse.setHeader('Content-Type', filePath.endsWith('.webp') ? 'image/webp' : 'image/jpeg');\n\t\t\tresponse.end(await fs.readFile(filePath));\n\t\t} catch (error) {\n\t\t\tlogger.error(`${pathname}: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\tresponse.statusCode = 500;\n\t\t\tresponse.end();\n\t\t}\n\t};\n}\n\nasync function isBuiltFrom(cachePath: string, mediaPath: string) {\n\ttry {\n\t\tconst manifest = await readManifest(cachePath);\n\n\t\treturn manifest?.mediaPath === mediaPath;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport default function imagePipeline({\n\tbaseUrl,\n\tcachePath,\n\tlimitInputPixels = sharpDefaultInputPixelLimit,\n\tmediaPath,\n\tpipeline,\n\tsources,\n}: ImagePipelineOptions): AstroIntegration {\n\tif (baseUrl.replace(/\\/+$/, '') === '') {\n\t\tthrow new Error(\n\t\t\t'imagePipeline needs a baseUrl below the site root; at the root, every request and every root-relative URL would count as an image',\n\t\t);\n\t}\n\n\tconst absoluteMediaPath = path.resolve(mediaPath);\n\tconst absoluteCachePath = path.resolve(cachePath);\n\tconst { devPath, recordsPath, renditionsPath } = getImageCachePaths(absoluteCachePath);\n\tlet isIncremental = false;\n\tlet buildRecordsPath = recordsPath;\n\n\treturn {\n\t\thooks: {\n\t\t\t'astro:build:done': async ({ dir, logger, pages }) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst distPath = fileURLToPath(dir);\n\t\t\t\t\tconst recorded = await readRecorded({\n\t\t\t\t\t\tcachePath: absoluteCachePath,\n\t\t\t\t\t\tisIncremental,\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t\tpageCount: pages.length,\n\t\t\t\t\t\trecordsPath: buildRecordsPath,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait writeBuildManifest({\n\t\t\t\t\t\tcachePath: absoluteCachePath,\n\t\t\t\t\t\tdistPath,\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t\tmanifest: {\n\t\t\t\t\t\t\tencoding: pipeline.encoding,\n\t\t\t\t\t\t\tlimitInputPixels,\n\t\t\t\t\t\t\tmediaPath: absoluteMediaPath,\n\t\t\t\t\t\t},\n\t\t\t\t\t\trecorded,\n\t\t\t\t\t});\n\t\t\t\t\tawait fs.rm(recordsPath, { force: true, recursive: true });\n\t\t\t\t} finally {\n\t\t\t\t\tReflect.deleteProperty(process.env, imageRecordsVariable);\n\t\t\t\t}\n\t\t\t},\n\t\t\t'astro:config:setup': async ({ command, config }) => {\n\t\t\t\tif (command !== 'build') return;\n\n\t\t\t\tisIncremental = config.experimental.incrementalBuild;\n\t\t\t\tbuildRecordsPath = await resetImageRecords(recordsPath);\n\t\t\t\tprocess.env[imageRecordsVariable] = buildRecordsPath;\n\t\t\t},\n\t\t\t'astro:server:setup': async ({ logger, server }) => {\n\t\t\t\t// An absolute base URL means dev fetches images from the live host\n\t\t\t\tif (!baseUrl.startsWith('/')) return;\n\n\t\t\t\tconst mediaPathKey = createHash('sha256')\n\t\t\t\t\t.update(absoluteMediaPath)\n\t\t\t\t\t.digest('hex')\n\t\t\t\t\t.slice(0, 8);\n\t\t\t\tconst getDevImage = createDevImageResolver({\n\t\t\t\t\tbuiltPath: (await isBuiltFrom(absoluteCachePath, absoluteMediaPath))\n\t\t\t\t\t\t? renditionsPath\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tcachePath: path.resolve(devPath, mediaPathKey),\n\t\t\t\t\tencoding: pipeline.encoding,\n\t\t\t\t\tlimitInputPixels,\n\t\t\t\t\tmediaPath: absoluteMediaPath,\n\t\t\t\t\tsources: sources ?? createDirectorySources(absoluteMediaPath),\n\t\t\t\t});\n\n\t\t\t\tconst serveDevImage = createDevImageHandler(getDevImage, logger);\n\n\t\t\t\tserver.middlewares.use(baseUrl.replace(/\\/+$/, ''), (request, response) => {\n\t\t\t\t\tvoid serveDevImage(request, response);\n\t\t\t\t});\n\t\t\t},\n\t\t},\n\t\tname: '@xsynaptic/astro-image-pipeline',\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,148 @@
1
+ import { n as ResolvedImageEncoding } from "./image-encoding-CPYBEK0T.mjs";
2
+ import { c as OpenGraphCardInput, n as ImageDimensions, o as OpenGraphCard, s as OpenGraphCardImage } from "./image-presets-CS7TnTsE.mjs";
3
+ import { SharpInput, SharpOptions } from "sharp";
4
+ //#region src/run-render-jobs.d.ts
5
+ interface RenderJob {
6
+ key: string;
7
+ name: string;
8
+ render: () => Promise<Uint8Array>;
9
+ }
10
+ interface RenderCounts {
11
+ fresh: number;
12
+ overwritten: number;
13
+ rendered: number;
14
+ written: number;
15
+ }
16
+ interface RenderFailure {
17
+ message: string;
18
+ name: string;
19
+ }
20
+ interface RenderJobOptions {
21
+ concurrency?: number;
22
+ directory: string;
23
+ jobs: ReadonlyArray<RenderJob>;
24
+ onFailure?: 'report' | 'throw';
25
+ onProgress?: (progress: RenderCounts & {
26
+ done: number;
27
+ total: number;
28
+ }) => void;
29
+ onReplace?: (name: string) => Promise<void>;
30
+ signal?: AbortSignal;
31
+ }
32
+ export declare function runRenderJobs(options: RenderJobOptions): Promise<{
33
+ failures: RenderFailure[];
34
+ total: number;
35
+ fresh: number;
36
+ overwritten: number;
37
+ rendered: number;
38
+ written: number;
39
+ }>;
40
+ //#endregion
41
+ //#region src/image-state.d.ts
42
+ declare const imageManifestVersion = 4;
43
+ interface ImageManifest {
44
+ buildId: string;
45
+ distPath: string;
46
+ encoding: ResolvedImageEncoding;
47
+ limitInputPixels: number;
48
+ mediaPath: string;
49
+ openGraphCards: Record<string, OpenGraphCard>;
50
+ renditions: Record<string, string>;
51
+ version: typeof imageManifestVersion;
52
+ }
53
+ export declare function getImageCachePaths(cachePath: string): {
54
+ devPath: string;
55
+ openGraphCardsPath: string;
56
+ recordsPath: string;
57
+ renditionsPath: string;
58
+ };
59
+ export declare function readManifest(cachePath: string): Promise<ImageManifest | undefined>;
60
+ //#endregion
61
+ //#region src/image-build.d.ts
62
+ interface ImageRenderOptions extends Pick<RenderJobOptions, 'onFailure' | 'onProgress' | 'onReplace' | 'signal'> {
63
+ cachePath: string;
64
+ }
65
+ export declare function renderImages(options: ImageRenderOptions): Promise<{
66
+ failures: RenderFailure[];
67
+ total: number;
68
+ fresh: number;
69
+ overwritten: number;
70
+ rendered: number;
71
+ written: number;
72
+ }>;
73
+ //#endregion
74
+ //#region src/image-render.d.ts
75
+ export declare const engineVersions: {
76
+ aom?: string | undefined;
77
+ archive?: string | undefined;
78
+ cairo?: string | undefined;
79
+ cgif?: string | undefined;
80
+ exif?: string | undefined;
81
+ expat?: string | undefined;
82
+ ffi?: string | undefined;
83
+ fontconfig?: string | undefined;
84
+ freetype?: string | undefined;
85
+ fribidi?: string | undefined;
86
+ glib?: string | undefined;
87
+ harfbuzz?: string | undefined;
88
+ heif?: string | undefined;
89
+ highway?: string | undefined;
90
+ imagequant?: string | undefined;
91
+ lcms?: string | undefined;
92
+ mozjpeg?: string | undefined;
93
+ pango?: string | undefined;
94
+ pixman?: string | undefined;
95
+ png?: string | undefined;
96
+ "proxy-libintl"?: string | undefined;
97
+ rsvg?: string | undefined;
98
+ sharp: string;
99
+ spng?: string | undefined;
100
+ tiff?: string | undefined;
101
+ vips: string;
102
+ webp?: string | undefined;
103
+ xml?: string | undefined;
104
+ "zlib-ng"?: string | undefined;
105
+ };
106
+ export declare function openImageSource(input: SharpInput, options?: Omit<SharpOptions, 'autoOrient'>): import("sharp").Sharp;
107
+ export declare function readSourceSize(sourcePath: string): Promise<{
108
+ height: number;
109
+ width: number;
110
+ }>;
111
+ //#endregion
112
+ //#region src/open-graph-build.d.ts
113
+ interface OpenGraphCardSource extends OpenGraphCardImage {
114
+ path: string;
115
+ }
116
+ interface OpenGraphCardRenderOptions<Decoded> extends Pick<RenderJobOptions, 'concurrency' | 'onFailure' | 'onProgress' | 'onReplace' | 'signal'> {
117
+ cachePath: string;
118
+ decode: (source: OpenGraphCardSource) => Promise<Decoded>;
119
+ render: (input: OpenGraphCardInput, decoded?: Decoded) => Promise<Uint8Array>;
120
+ templateVersion: string;
121
+ }
122
+ export declare function renderOpenGraphCards<Decoded>({ cachePath, decode, render, templateVersion, ...options }: OpenGraphCardRenderOptions<Decoded>): Promise<{
123
+ sources: number;
124
+ failures: RenderFailure[];
125
+ total: number;
126
+ fresh: number;
127
+ overwritten: number;
128
+ rendered: number;
129
+ written: number;
130
+ }>;
131
+ //#endregion
132
+ //#region src/source-fingerprints.d.ts
133
+ interface SourceFingerprint extends ImageDimensions {
134
+ sha256: string;
135
+ }
136
+ interface SourceFingerprints {
137
+ close(): void;
138
+ get(filePath: string): Promise<SourceFingerprint | undefined>;
139
+ }
140
+ export declare function createSourceFingerprints(cachePath: string): SourceFingerprints;
141
+ //#endregion
142
+ //#region src/user-error.d.ts
143
+ export declare class UserError extends Error {
144
+ name: string;
145
+ }
146
+ //#endregion
147
+ export type { OpenGraphCardRenderOptions, OpenGraphCardSource, RenderCounts, RenderFailure, RenderJob, SourceFingerprints };
148
+ //# sourceMappingURL=node.d.mts.map