gutterpress 0.11.6-alpha.3 → 0.11.6

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.
@@ -13,12 +13,12 @@ import {
13
13
  stampCreator,
14
14
  stripAnnotations,
15
15
  warn
16
- } from "./cli-rra50cp6.js";
16
+ } from "./cli-emp8wz36.js";
17
17
  import {
18
18
  DEBOUNCE,
19
19
  UsageError,
20
20
  resolvePort
21
- } from "./cli-5c2xfsmz.js";
21
+ } from "./cli-1bccnym3.js";
22
22
  import {
23
23
  MARGIN_BOX_IGNORED_PROPERTIES,
24
24
  RENDER_TIMEOUT_MS,
@@ -41,9 +41,27 @@ import {
41
41
  BuildError
42
42
  } from "./cli-46ycxe6r.js";
43
43
  import {
44
+ PLUGINS_DIR,
45
+ VENDORED_NPM_DIR,
46
+ VENDOR_RECEIPT_FILE,
47
+ VENDOR_RECEIPT_VERSION,
48
+ assertWindowsSafeRelativePath,
49
+ computeVendorTreeDigest,
44
50
  hasUncommittedChanges,
45
- listWorkdirChanges
46
- } from "./cli-c5360prx.js";
51
+ isExactNpmVersion,
52
+ isValidNpmPackageName,
53
+ listWorkdirChanges,
54
+ npmRegistryUrl,
55
+ packageEntryFormat,
56
+ packageResolutionTargets,
57
+ parseNpmPluginSpec,
58
+ resolvePackageEntry,
59
+ resolveVendoredPluginInstallRoot,
60
+ vendoredNpmPluginPackageDir,
61
+ vendoredNpmPluginRoot,
62
+ verifyVendoredPlugin,
63
+ windowsPathKey
64
+ } from "./cli-4tx0szk7.js";
47
65
  import {
48
66
  detectProjectSource,
49
67
  repoSubPath
@@ -52,599 +70,6 @@ import {
52
70
  __require
53
71
  } from "./cli-37x76zdn.js";
54
72
 
55
- // src/lib/plugin-vendor.ts
56
- import { createHash } from "node:crypto";
57
- import { createReadStream } from "node:fs";
58
- import { lstat, readFile, readdir, realpath } from "node:fs/promises";
59
- import path from "node:path";
60
- import { exports as resolveExports } from "resolve.exports";
61
- import { satisfies, validRange } from "semver";
62
-
63
- // src/lib/npm-registry.ts
64
- var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
65
- var ENV_OVERRIDE = "GUTTERPRESS_NPM_REGISTRY";
66
- function npmRegistryUrl() {
67
- const configured = process.env[ENV_OVERRIDE]?.trim();
68
- if (!configured)
69
- return DEFAULT_NPM_REGISTRY;
70
- let scheme;
71
- try {
72
- scheme = new URL(configured).protocol;
73
- } catch {
74
- throw new Error(`Invalid ${ENV_OVERRIDE} URL "${configured}".`);
75
- }
76
- if (scheme !== "http:" && scheme !== "https:") {
77
- throw new Error(`${ENV_OVERRIDE} must be an http(s) URL — got "${scheme}".`);
78
- }
79
- return configured.replace(/\/+$/, "");
80
- }
81
-
82
- // src/lib/plugin-vendor.ts
83
- var PLUGINS_DIR = "plugins";
84
- var VENDORED_NPM_DIR = "npm";
85
- var VENDOR_RECEIPT_FILE = ".gutterpress-install.json";
86
- var VENDOR_RECEIPT_VERSION = 2;
87
- var NPM_SEGMENT = /^[a-z0-9][a-z0-9._~-]*$/;
88
- var EXACT_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
89
- var WINDOWS_RESERVED = /^(con|prn|aux|nul|clock\$|conin\$|conout\$|com[1-9¹²³]|lpt[1-9¹²³])(?:\..*)?$/i;
90
- var MAX_VERIFIED_FILES = 50000;
91
- var MAX_VERIFIED_BYTES = 512 * 1024 * 1024;
92
- function isValidNpmPackageName(name) {
93
- if (!name || name.length > 214 || name !== name.toLowerCase())
94
- return false;
95
- if (name.startsWith("@")) {
96
- const parts = name.slice(1).split("/");
97
- return parts.length === 2 && parts.every((part) => NPM_SEGMENT.test(part));
98
- }
99
- return !name.includes("/") && NPM_SEGMENT.test(name);
100
- }
101
- function parseNpmPluginSpec(input) {
102
- const spec = input.trim();
103
- if (!spec)
104
- throw new Error("An npm package name is required.");
105
- let name = spec;
106
- let selector;
107
- if (spec.startsWith("@")) {
108
- const slash = spec.indexOf("/");
109
- const versionAt = spec.lastIndexOf("@");
110
- if (slash > 1 && versionAt > slash) {
111
- name = spec.slice(0, versionAt);
112
- selector = spec.slice(versionAt + 1);
113
- }
114
- } else {
115
- const versionAt = spec.lastIndexOf("@");
116
- if (versionAt > 0) {
117
- name = spec.slice(0, versionAt);
118
- selector = spec.slice(versionAt + 1);
119
- }
120
- }
121
- if (!isValidNpmPackageName(name)) {
122
- throw new Error(`"${name}" is not a valid npm package name. Use a name like ` + "markdown-it-highlightjs or @scope/markdown-it-plugin.");
123
- }
124
- if (selector !== undefined && !selector) {
125
- throw new Error(`The package spec "${spec}" is missing a selector after @.`);
126
- }
127
- return selector === undefined ? { name } : { name, selector };
128
- }
129
- function isExactNpmVersion(version) {
130
- return EXACT_VERSION.test(version);
131
- }
132
- function encodePathPart(value) {
133
- return encodeURIComponent(value).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
134
- }
135
- function vendoredNpmPluginRoot(projectDir, name, version) {
136
- return path.join(projectDir, PLUGINS_DIR, VENDORED_NPM_DIR, encodePathPart(name), encodePathPart(version));
137
- }
138
- function vendoredNpmPluginPackageDir(installRoot, name) {
139
- return path.join(installRoot, "node_modules", ...name.split("/"));
140
- }
141
- function toPosixPath(value) {
142
- return value.split(path.sep).join("/");
143
- }
144
- function packageEntryFormat(manifest, relativeEntry) {
145
- const extension = path.posix.extname(relativeEntry);
146
- return extension === ".cjs" || extension === ".json" || extension !== ".mjs" && manifest.type !== "module" ? "commonjs" : "module";
147
- }
148
- function assertWindowsSafeRelativePath(relative) {
149
- if (!relative || relative.includes("\\") || relative.startsWith("/") || /^[a-zA-Z]:/.test(relative)) {
150
- throw new Error(`Unsafe package path: ${relative || "(empty)"}`);
151
- }
152
- const normalized = relative.normalize("NFKC");
153
- const parts = normalized.split("/");
154
- if (parts.some((part) => !part || part === "." || part === "..")) {
155
- throw new Error(`Unsafe package path: ${relative}`);
156
- }
157
- for (const part of parts) {
158
- if (part.length > 255 || /[\u0000-\u001f<>:"|?*]/.test(part) || part.endsWith(".") || part.endsWith(" ") || WINDOWS_RESERVED.test(part)) {
159
- throw new Error(`Package path is invalid on Windows: ${relative}`);
160
- }
161
- }
162
- }
163
- function windowsPathKey(relative) {
164
- return relative.normalize("NFKC").toLowerCase();
165
- }
166
- function safeReceiptPath(relative, label) {
167
- if (typeof relative !== "string")
168
- throw new Error(`${label} must be a string.`);
169
- assertWindowsSafeRelativePath(relative);
170
- return relative;
171
- }
172
- function isContained(root, candidate) {
173
- const relative = path.relative(root, candidate);
174
- return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
175
- }
176
- function object(value) {
177
- return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
178
- }
179
- function stringMap(value) {
180
- const map = object(value);
181
- if (!map)
182
- return {};
183
- const result = {};
184
- for (const [name, selector] of Object.entries(map)) {
185
- if (typeof selector === "string" && selector.trim())
186
- result[name] = selector.trim();
187
- }
188
- return result;
189
- }
190
- function dependencyDeclarations(manifest) {
191
- const required = stringMap(manifest.dependencies);
192
- const optional = stringMap(manifest.optionalDependencies);
193
- for (const name of Object.keys(optional))
194
- delete required[name];
195
- const peers = stringMap(manifest.peerDependencies);
196
- const peerMeta = object(manifest.peerDependenciesMeta) ?? {};
197
- const optionalPeers = {};
198
- for (const [name, selector] of Object.entries(peers)) {
199
- if (name in required || name in optional)
200
- continue;
201
- if (object(peerMeta[name])?.optional === true)
202
- optionalPeers[name] = selector;
203
- else
204
- required[name] = selector;
205
- }
206
- return { required, optional, optionalPeers };
207
- }
208
- function unsupportedRegistrySelector(selector) {
209
- return /^(?:file:|git\+|https?:|ssh:|github:|workspace:|link:|npm:)/i.test(selector);
210
- }
211
- async function readPackageJson(packageDir) {
212
- const packageJsonPath = path.join(packageDir, "package.json");
213
- const info2 = await lstat(packageJsonPath);
214
- if (!info2.isFile() || info2.isSymbolicLink()) {
215
- throw new Error(`Package metadata is not a regular file: ${packageJsonPath}`);
216
- }
217
- const parsed = object(JSON.parse(await readFile(packageJsonPath, "utf8")));
218
- if (!parsed)
219
- throw new Error(`Package metadata is not an object: ${packageJsonPath}`);
220
- return parsed;
221
- }
222
- async function verifyReceiptEntry(installRoot, packagePath, entry, label) {
223
- if (entry === undefined)
224
- return;
225
- const relative = safeReceiptPath(entry, label);
226
- if (!relative.startsWith(`${packagePath}/`)) {
227
- throw new Error(`${label} is outside its package.`);
228
- }
229
- const packageDir = path.resolve(installRoot, ...packagePath.split("/"));
230
- const entryPath = path.resolve(installRoot, ...relative.split("/"));
231
- const [realPackageDir, realEntry] = await Promise.all([
232
- realpath(packageDir),
233
- realpath(entryPath)
234
- ]);
235
- if (!isContained(realPackageDir, realEntry))
236
- throw new Error(`${label} escapes its package.`);
237
- const info2 = await lstat(realEntry);
238
- if (!info2.isFile() || info2.isSymbolicLink())
239
- throw new Error(`${label} is not a regular file.`);
240
- return realEntry;
241
- }
242
- function packageResolutionTargets(manifest, subpath, condition) {
243
- if (manifest.exports !== undefined) {
244
- try {
245
- const targets2 = resolveExports(manifest, subpath ? `./${subpath}` : ".", { require: condition === "require" }) ?? [];
246
- return targets2.map((target) => ({ target, exact: true }));
247
- } catch {
248
- return [];
249
- }
250
- }
251
- if (subpath)
252
- return [{ target: subpath, exact: false }];
253
- const targets = [
254
- ...condition === "import" && typeof manifest.module === "string" ? [manifest.module] : [],
255
- ...typeof manifest.main === "string" ? [manifest.main] : [],
256
- "index.mjs",
257
- "index.js",
258
- "index.cjs"
259
- ];
260
- return [...new Set(targets)].map((target) => ({ target, exact: false }));
261
- }
262
- function safePackageTarget(target) {
263
- if (!target || target.includes("\\") || target.includes("*") || target.includes("?") || target.includes("#")) {
264
- return null;
265
- }
266
- const relative = target.startsWith("./") ? target.slice(2) : target;
267
- if (!relative || path.isAbsolute(relative))
268
- return null;
269
- assertWindowsSafeRelativePath(relative);
270
- if (relative.normalize("NFKC").split("/").some((part) => part.toLowerCase() === "node_modules")) {
271
- return null;
272
- }
273
- return relative;
274
- }
275
- async function resolveEntryCandidate(packageDir, resolution) {
276
- const relative = safePackageTarget(resolution.target);
277
- if (!relative)
278
- return null;
279
- const base = path.resolve(packageDir, ...relative.split("/"));
280
- if (!isContained(packageDir, base))
281
- return null;
282
- const candidates = resolution.exact ? [base] : [
283
- base,
284
- `${base}.mjs`,
285
- `${base}.js`,
286
- `${base}.cjs`,
287
- `${base}.json`,
288
- path.join(base, "index.mjs"),
289
- path.join(base, "index.js"),
290
- path.join(base, "index.cjs"),
291
- path.join(base, "index.json")
292
- ];
293
- for (const candidate of candidates) {
294
- try {
295
- const info2 = await lstat(candidate);
296
- if (!info2.isFile() || info2.isSymbolicLink())
297
- continue;
298
- const extension = path.extname(candidate);
299
- if (extension && ![".js", ".mjs", ".cjs", ".json"].includes(extension))
300
- continue;
301
- const [realRoot, realCandidate] = await Promise.all([realpath(packageDir), realpath(candidate)]);
302
- if (!isContained(realRoot, realCandidate))
303
- continue;
304
- return toPosixPath(path.relative(packageDir, realCandidate));
305
- } catch {}
306
- }
307
- return null;
308
- }
309
- async function resolvePackageEntry(packageDir, packageJson, condition = "import") {
310
- const manifest = packageJson ?? await readPackageJson(packageDir);
311
- for (const target of packageResolutionTargets(manifest, "", condition)) {
312
- const resolved = await resolveEntryCandidate(packageDir, target);
313
- if (resolved)
314
- return resolved;
315
- }
316
- throw new Error("Package has no contained JavaScript entry point for ESM import.");
317
- }
318
- async function listTreeEntries(root) {
319
- const out = [];
320
- async function visit(dir) {
321
- const entries = await readdir(dir, { withFileTypes: true });
322
- entries.sort((a, b) => a.name.localeCompare(b.name));
323
- for (const entry of entries) {
324
- const absolute = path.join(dir, entry.name);
325
- const relative = toPosixPath(path.relative(root, absolute));
326
- if (relative === VENDOR_RECEIPT_FILE)
327
- continue;
328
- if (entry.isSymbolicLink())
329
- throw new Error(`Vendor tree contains a symbolic link: ${relative}`);
330
- if (entry.isDirectory()) {
331
- out.push({ relative, directory: true });
332
- await visit(absolute);
333
- } else if (entry.isFile())
334
- out.push({ relative, directory: false });
335
- else
336
- throw new Error(`Vendor tree contains an unsupported filesystem entry: ${relative}`);
337
- }
338
- }
339
- await visit(root);
340
- return out;
341
- }
342
- async function computeVendorTreeDigest(root) {
343
- const entries = await listTreeEntries(root);
344
- const files = entries.filter((entry) => !entry.directory);
345
- if (files.length > MAX_VERIFIED_FILES) {
346
- throw new Error(`Vendor tree contains more than ${MAX_VERIFIED_FILES} files.`);
347
- }
348
- const seen = new Set;
349
- const hash = createHash("sha256");
350
- let bytes = 0;
351
- for (const entry of entries) {
352
- const { relative } = entry;
353
- assertWindowsSafeRelativePath(relative);
354
- const key = windowsPathKey(relative);
355
- if (seen.has(key))
356
- throw new Error(`Vendor tree has a Windows-colliding path: ${relative}`);
357
- seen.add(key);
358
- if (entry.directory)
359
- continue;
360
- const absolute = path.join(root, ...relative.split("/"));
361
- const info2 = await lstat(absolute);
362
- if (!info2.isFile() || info2.isSymbolicLink() || info2.nlink !== 1) {
363
- throw new Error(`Vendor tree file is not an independent regular file: ${relative}`);
364
- }
365
- bytes += info2.size;
366
- if (bytes > MAX_VERIFIED_BYTES) {
367
- throw new Error(`Vendor tree exceeds ${Math.round(MAX_VERIFIED_BYTES / 1024 / 1024)}MB.`);
368
- }
369
- hash.update(`${Buffer.byteLength(relative)}:${relative}:${info2.size}\x00`);
370
- for await (const chunk of createReadStream(absolute))
371
- hash.update(chunk);
372
- }
373
- return { digest: hash.digest("hex"), files: files.length, bytes };
374
- }
375
- async function assertVendorPackageOwnership(root, packagePaths) {
376
- const packages = packagePaths.map((relative) => ({
377
- relative,
378
- key: windowsPathKey(relative),
379
- parts: relative.split("/").length
380
- })).sort((a, b) => b.key.length - a.key.length);
381
- for (const entry of await listTreeEntries(root)) {
382
- const actualParts = entry.relative.split("/");
383
- for (const part of actualParts) {
384
- if (part.normalize("NFKC").toLowerCase() === "node_modules" && part !== "node_modules") {
385
- throw new Error(`Vendor tree contains a non-canonical node_modules path: ${entry.relative}`);
386
- }
387
- }
388
- const key = windowsPathKey(entry.relative);
389
- const structural = packages.some((pkg) => pkg.key === key || pkg.key.startsWith(`${key}/`));
390
- if (entry.directory && structural)
391
- continue;
392
- const owner = packages.find((pkg) => key.startsWith(`${pkg.key}/`));
393
- if (!owner)
394
- throw new Error(`Vendor tree path is not owned by a receipt package: ${entry.relative}`);
395
- const packageRelative = actualParts.slice(owner.parts);
396
- const nodeModulesAt = packageRelative.findIndex((part) => part.normalize("NFKC").toLowerCase() === "node_modules");
397
- if (nodeModulesAt < 0)
398
- continue;
399
- const generatedEmptyDirectory = entry.directory && nodeModulesAt === 0 && (packageRelative.length === 1 || packageRelative.length === 2 && packageRelative[1].startsWith("@"));
400
- if (!generatedEmptyDirectory) {
401
- throw new Error(`Package contains bundled node_modules content: ${entry.relative}`);
402
- }
403
- }
404
- }
405
- async function recomputeReceiptEntry(packageDir, packagePath, manifest, condition) {
406
- try {
407
- const entry = await resolvePackageEntry(packageDir, manifest, condition);
408
- return `${packagePath}/${entry}`;
409
- } catch (error2) {
410
- if (error2 instanceof Error && error2.message.includes("no contained JavaScript entry point")) {
411
- return;
412
- }
413
- throw error2;
414
- }
415
- }
416
- async function resolveVendoredPluginInstallRoot(projectDir, expectedName, expectedVersion) {
417
- const requestedProjectRoot = path.resolve(projectDir);
418
- const requestedInstallRoot = vendoredNpmPluginRoot(requestedProjectRoot, expectedName, expectedVersion);
419
- let installInfo;
420
- try {
421
- installInfo = await lstat(requestedInstallRoot);
422
- } catch (error2) {
423
- if (error2.code === "ENOENT")
424
- return null;
425
- throw error2;
426
- }
427
- if (!installInfo.isDirectory() || installInfo.isSymbolicLink()) {
428
- throw new Error("Vendor install root is not a normal directory.");
429
- }
430
- const [realProjectRoot, installRoot] = await Promise.all([
431
- realpath(requestedProjectRoot),
432
- realpath(requestedInstallRoot)
433
- ]);
434
- if (!isContained(realProjectRoot, installRoot)) {
435
- throw new Error("Vendor install root resolves outside the book folder.");
436
- }
437
- return installRoot;
438
- }
439
- function reconcileReceiptGraph(receipt, packages, manifests) {
440
- if (!Array.isArray(receipt.skipped))
441
- throw new Error("Vendor receipt skipped list is invalid.");
442
- const declarations = new Map;
443
- for (const [packagePath, manifest] of manifests) {
444
- declarations.set(packagePath, dependencyDeclarations(manifest));
445
- }
446
- const skippedByEdge = new Map;
447
- for (const skipped of receipt.skipped) {
448
- if (!packages.has(skipped.from) || !isValidNpmPackageName(skipped.name) || typeof skipped.selector !== "string" || !["optional", "optional-peer"].includes(skipped.kind) || typeof skipped.reason !== "string") {
449
- throw new Error("Vendor receipt contains an invalid skipped dependency.");
450
- }
451
- const declared = declarations.get(skipped.from);
452
- const expectedSelector = skipped.kind === "optional" ? declared.optional[skipped.name] : declared.optionalPeers[skipped.name];
453
- if (expectedSelector !== skipped.selector) {
454
- throw new Error(`Skipped dependency is not declared as ${skipped.kind}: ${skipped.name}`);
455
- }
456
- const key = `${skipped.from}\x00${skipped.name}`;
457
- if (skippedByEdge.has(key))
458
- throw new Error(`Duplicate skipped dependency: ${skipped.name}`);
459
- skippedByEdge.set(key, skipped);
460
- }
461
- for (const pkg of receipt.packages) {
462
- if (!object(pkg.dependencies))
463
- throw new Error(`Invalid dependency map for ${pkg.name}.`);
464
- const declared = declarations.get(pkg.path);
465
- for (const [dependency, target] of Object.entries(pkg.dependencies)) {
466
- const targetPackage = packages.get(target);
467
- if (!isValidNpmPackageName(dependency) || !targetPackage || targetPackage.name !== dependency) {
468
- throw new Error(`Broken dependency edge ${pkg.name} -> ${dependency}.`);
469
- }
470
- const selector = declared.required[dependency] ?? declared.optional[dependency];
471
- if (!selector)
472
- throw new Error(`Undeclared dependency edge ${pkg.name} -> ${dependency}.`);
473
- if (unsupportedRegistrySelector(selector)) {
474
- throw new Error(`Unsupported selector on dependency edge ${pkg.name} -> ${dependency}.`);
475
- }
476
- const range = validRange(selector);
477
- if (range && !satisfies(targetPackage.version, range)) {
478
- throw new Error(`Dependency edge ${pkg.name} -> ${dependency}@${targetPackage.version} does not satisfy ${selector}.`);
479
- }
480
- if (skippedByEdge.has(`${pkg.path}\x00${dependency}`)) {
481
- throw new Error(`Dependency is both installed and skipped: ${pkg.name} -> ${dependency}.`);
482
- }
483
- }
484
- for (const dependency of Object.keys(declared.required)) {
485
- if (!(dependency in pkg.dependencies)) {
486
- throw new Error(`Missing required dependency edge ${pkg.name} -> ${dependency}.`);
487
- }
488
- }
489
- for (const dependency of Object.keys(declared.optional)) {
490
- if (!(dependency in pkg.dependencies) && !skippedByEdge.has(`${pkg.path}\x00${dependency}`)) {
491
- throw new Error(`Optional dependency is neither installed nor skipped: ${pkg.name} -> ${dependency}.`);
492
- }
493
- }
494
- for (const dependency of Object.keys(declared.optionalPeers)) {
495
- if (!skippedByEdge.has(`${pkg.path}\x00${dependency}`)) {
496
- throw new Error(`Optional peer dependency is not recorded as skipped: ${pkg.name} -> ${dependency}.`);
497
- }
498
- }
499
- }
500
- }
501
- async function verifyVendoredPlugin(projectDir, expectedName, expectedVersion) {
502
- try {
503
- const installRoot = await resolveVendoredPluginInstallRoot(projectDir, expectedName, expectedVersion);
504
- if (!installRoot)
505
- return null;
506
- const receiptPath = path.join(installRoot, VENDOR_RECEIPT_FILE);
507
- let raw;
508
- try {
509
- const info2 = await lstat(receiptPath);
510
- if (!info2.isFile() || info2.isSymbolicLink() || info2.nlink !== 1 || info2.size > 1024 * 1024) {
511
- throw new Error("Vendor receipt is not a small regular file.");
512
- }
513
- raw = await readFile(receiptPath, "utf8");
514
- } catch (error2) {
515
- if (error2.code === "ENOENT")
516
- return null;
517
- throw error2;
518
- }
519
- const receipt = JSON.parse(raw);
520
- if (receipt.schemaVersion !== VENDOR_RECEIPT_VERSION) {
521
- throw new Error(`Unsupported vendor receipt schema ${String(receipt.schemaVersion)}.`);
522
- }
523
- if (receipt.root?.name !== expectedName || receipt.root?.version !== expectedVersion) {
524
- throw new Error("Vendor receipt identity does not match the manifest entry.");
525
- }
526
- if (!Array.isArray(receipt.packages) || receipt.packages.length === 0) {
527
- throw new Error("Vendor receipt has no package graph.");
528
- }
529
- const tree = await computeVendorTreeDigest(installRoot);
530
- if (receipt.tree?.algorithm !== "sha256" || receipt.tree.digest !== tree.digest || receipt.tree.files !== tree.files || receipt.tree.bytes !== tree.bytes) {
531
- throw new Error("Vendor tree hash does not match its receipt.");
532
- }
533
- const packages = new Map;
534
- const manifests = new Map;
535
- const verifiedPackages = [];
536
- const pathKeys = new Set;
537
- for (const pkg of receipt.packages) {
538
- const relative = safeReceiptPath(pkg.path, "Package receipt path");
539
- const key = windowsPathKey(relative);
540
- if (pathKeys.has(key))
541
- throw new Error(`Duplicate package receipt path: ${relative}`);
542
- pathKeys.add(key);
543
- if (!isValidNpmPackageName(pkg.name) || !isExactNpmVersion(pkg.version)) {
544
- throw new Error(`Invalid package identity in receipt: ${pkg.name}@${pkg.version}`);
545
- }
546
- const expectedSuffix = `node_modules/${pkg.name}`;
547
- if (relative !== expectedSuffix && !relative.endsWith(`/${expectedSuffix}`)) {
548
- throw new Error(`Package receipt path does not match ${pkg.name}: ${relative}`);
549
- }
550
- if (typeof pkg.integrity !== "string" || !/^(?:sha512|sha384|sha256|sha1)-(?:hex-)?[A-Za-z0-9+/=]+$/.test(pkg.integrity) || typeof pkg.legacySha1 !== "boolean" || pkg.legacySha1 !== pkg.integrity.startsWith("sha1-")) {
551
- throw new Error(`Package receipt is missing provenance: ${pkg.name}@${pkg.version}`);
552
- }
553
- const tarball = new URL(pkg.tarball);
554
- if (tarball.origin !== new URL(npmRegistryUrl()).origin || tarball.username || tarball.password) {
555
- throw new Error(`Package receipt has an invalid tarball URL: ${pkg.name}@${pkg.version}`);
556
- }
557
- const packageDir = path.resolve(installRoot, ...relative.split("/"));
558
- if (!isContained(installRoot, packageDir))
559
- throw new Error(`Package escapes vendor root: ${relative}`);
560
- const realPackageDir2 = await realpath(packageDir);
561
- if (!isContained(installRoot, realPackageDir2)) {
562
- throw new Error(`Package resolves outside the vendor root: ${relative}`);
563
- }
564
- const manifest = await readPackageJson(packageDir);
565
- if (manifest.name !== pkg.name || manifest.version !== pkg.version) {
566
- throw new Error(`Installed package identity changed: ${pkg.name}@${pkg.version}`);
567
- }
568
- const [expectedEntry, expectedRequireEntry] = await Promise.all([
569
- recomputeReceiptEntry(packageDir, relative, manifest, "import"),
570
- recomputeReceiptEntry(packageDir, relative, manifest, "require")
571
- ]);
572
- if (pkg.entry !== expectedEntry || pkg.requireEntry !== expectedRequireEntry) {
573
- throw new Error(`Recorded package entries do not match package.json: ${pkg.name}@${pkg.version}`);
574
- }
575
- packages.set(relative, pkg);
576
- manifests.set(relative, manifest);
577
- verifiedPackages.push({
578
- path: relative,
579
- name: pkg.name,
580
- packageDir: realPackageDir2,
581
- manifest,
582
- entryPath: await verifyReceiptEntry(installRoot, relative, pkg.entry, "Package import entry"),
583
- requireEntryPath: await verifyReceiptEntry(installRoot, relative, pkg.requireEntry, "Package require entry"),
584
- dependencies: pkg.dependencies
585
- });
586
- }
587
- await assertVendorPackageOwnership(installRoot, receipt.packages.map((pkg) => pkg.path));
588
- reconcileReceiptGraph(receipt, packages, manifests);
589
- const rootPackagePath = safeReceiptPath(receipt.root.packagePath, "Root package path");
590
- const rootPackage = packages.get(rootPackagePath);
591
- if (!rootPackage || rootPackage.name !== expectedName || rootPackage.version !== expectedVersion) {
592
- throw new Error("Vendor receipt root package is missing.");
593
- }
594
- const reachablePackages = new Set([rootPackagePath]);
595
- const pendingPackages = [rootPackagePath];
596
- while (pendingPackages.length > 0) {
597
- const current = packages.get(pendingPackages.pop());
598
- for (const target of Object.values(current.dependencies)) {
599
- if (reachablePackages.has(target))
600
- continue;
601
- reachablePackages.add(target);
602
- pendingPackages.push(target);
603
- }
604
- }
605
- if (reachablePackages.size !== receipt.packages.length) {
606
- throw new Error("Vendor receipt contains a package that is not reachable from its root.");
607
- }
608
- const rootManifest = manifests.get(rootPackagePath);
609
- if (receipt.root.format !== "module" && receipt.root.format !== "commonjs") {
610
- throw new Error("Vendor receipt root format is invalid.");
611
- }
612
- const entryRelative = safeReceiptPath(receipt.root.entry, "Plugin entry path");
613
- if (!entryRelative.startsWith(`${rootPackagePath}/`)) {
614
- throw new Error("Plugin entry is outside its package.");
615
- }
616
- const expectedRootEntry = receipt.root.format === "commonjs" ? rootPackage.requireEntry ?? rootPackage.entry : rootPackage.entry;
617
- if (entryRelative !== expectedRootEntry) {
618
- throw new Error("Plugin entry does not match the package graph entry.");
619
- }
620
- if (packageEntryFormat(rootManifest, entryRelative) !== receipt.root.format) {
621
- throw new Error("Plugin entry format does not match its package metadata.");
622
- }
623
- const entryPath = path.resolve(installRoot, ...entryRelative.split("/"));
624
- const rootPackageDir = path.resolve(installRoot, ...rootPackagePath.split("/"));
625
- const [realPackageDir, realEntry] = await Promise.all([
626
- realpath(rootPackageDir),
627
- realpath(entryPath)
628
- ]);
629
- if (!isContained(installRoot, realEntry) || !isContained(realPackageDir, realEntry)) {
630
- throw new Error("Plugin entry resolves outside the verified vendor tree.");
631
- }
632
- const entryInfo = await lstat(realEntry);
633
- if (!entryInfo.isFile() || entryInfo.isSymbolicLink()) {
634
- throw new Error("Plugin entry is not a regular file.");
635
- }
636
- return {
637
- installRoot,
638
- entryPath: realEntry,
639
- format: receipt.root.format,
640
- packages: verifiedPackages,
641
- receipt
642
- };
643
- } catch (error2) {
644
- throw new Error(`Vendored plugin "${expectedName}@${expectedVersion}" failed verification: ` + `${error2 instanceof Error ? error2.message : String(error2)} Reinstall it before building.`, { cause: error2 });
645
- }
646
- }
647
-
648
73
  // src/lib/extension-specifier.ts
649
74
  var BUNDLED_EXTENSIONS = [
650
75
  "markdown-it-mark",
@@ -974,7 +399,7 @@ function applyDefaultPdfStrictChecks(config) {
974
399
  }
975
400
 
976
401
  // src/lib/manifest.ts
977
- import { readFile as readFile2 } from "node:fs/promises";
402
+ import { readFile } from "node:fs/promises";
978
403
  import { existsSync, statSync } from "node:fs";
979
404
  import { resolve, dirname } from "node:path";
980
405
  import { parse as parseYaml, YAMLParseError } from "yaml";
@@ -989,7 +414,7 @@ async function loadManifestWithPath(pathOrDir, opts) {
989
414
  const candidates = pathOrDir ? [resolve(pathOrDir), ...MANIFEST_FILENAMES.map((name) => resolve(pathOrDir, name))] : MANIFEST_FILENAMES.map((name) => resolve(name));
990
415
  for (const p of candidates) {
991
416
  if (existsSync(p) && statSync(p).isFile()) {
992
- const raw = await readFile2(p, "utf8");
417
+ const raw = await readFile(p, "utf8");
993
418
  try {
994
419
  const manifest = parseYaml(raw) ?? {};
995
420
  return { manifest, manifestDir: dirname(p), manifestPath: p };
@@ -1283,7 +708,7 @@ function inspectionFailed(checkId, message, extra = {}) {
1283
708
  }
1284
709
 
1285
710
  // src/lib/pdf-inspect.ts
1286
- import { stat, readFile as readFile3 } from "node:fs/promises";
711
+ import { stat, readFile as readFile2 } from "node:fs/promises";
1287
712
  import { getDocumentProxy } from "unpdf";
1288
713
  import * as pdfjs from "unpdf/pdfjs";
1289
714
  function getOps(mod) {
@@ -1319,17 +744,17 @@ function evictLru() {
1319
744
  destroyEntryAfterGrace(evicted);
1320
745
  }
1321
746
  }
1322
- async function loadPdf(path2) {
747
+ async function loadPdf(path) {
1323
748
  let st;
1324
749
  try {
1325
- st = await stat(path2);
750
+ st = await stat(path);
1326
751
  } catch {
1327
752
  return null;
1328
753
  }
1329
- const hit = docCache.get(path2);
754
+ const hit = docCache.get(path);
1330
755
  if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) {
1331
- docCache.delete(path2);
1332
- docCache.set(path2, hit);
756
+ docCache.delete(path);
757
+ docCache.set(path, hit);
1333
758
  try {
1334
759
  return await hit.doc;
1335
760
  } catch {
@@ -1338,15 +763,15 @@ async function loadPdf(path2) {
1338
763
  }
1339
764
  if (hit)
1340
765
  destroyEntry(hit);
1341
- const docPromise = readFile3(path2).then((buf) => getDocumentProxy(new Uint8Array(buf)));
1342
- docCache.delete(path2);
1343
- docCache.set(path2, { mtimeMs: st.mtimeMs, size: st.size, doc: docPromise });
766
+ const docPromise = readFile2(path).then((buf) => getDocumentProxy(new Uint8Array(buf)));
767
+ docCache.delete(path);
768
+ docCache.set(path, { mtimeMs: st.mtimeMs, size: st.size, doc: docPromise });
1344
769
  evictLru();
1345
770
  try {
1346
771
  return await docPromise;
1347
772
  } catch {
1348
- if (docCache.get(path2)?.doc === docPromise)
1349
- docCache.delete(path2);
773
+ if (docCache.get(path)?.doc === docPromise)
774
+ docCache.delete(path);
1350
775
  return null;
1351
776
  }
1352
777
  }
@@ -1797,9 +1222,9 @@ var check3 = {
1797
1222
  registerCheck(check3);
1798
1223
 
1799
1224
  // src/lib/pdf-parse.ts
1800
- import { readFile as readFile4 } from "node:fs/promises";
1225
+ import { readFile as readFile3 } from "node:fs/promises";
1801
1226
  async function readPdfBytes(pdfPath) {
1802
- return readFile4(pdfPath, "latin1");
1227
+ return readFile3(pdfPath, "latin1");
1803
1228
  }
1804
1229
  function parseInkCov(out) {
1805
1230
  const lines = out.split(/\r?\n/).filter((l) => l.includes("CMYK"));
@@ -2370,7 +1795,7 @@ var check15 = {
2370
1795
  registerCheck(check15);
2371
1796
 
2372
1797
  // src/checks/source/markdownlint.ts
2373
- import { readFile as readFile5 } from "node:fs/promises";
1798
+ import { readFile as readFile4 } from "node:fs/promises";
2374
1799
  import { lint } from "markdownlint/sync";
2375
1800
  import { parse as parseYaml2 } from "yaml";
2376
1801
 
@@ -2403,7 +1828,7 @@ function stripJsonComments(s) {
2403
1828
  return s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
2404
1829
  }
2405
1830
  async function loadConfig(configPath) {
2406
- const raw = await readFile5(configPath, "utf8");
1831
+ const raw = await readFile4(configPath, "utf8");
2407
1832
  let parsed;
2408
1833
  if (configPath.endsWith(".json")) {
2409
1834
  parsed = JSON.parse(raw);
@@ -2464,7 +1889,7 @@ registerCheck(check16);
2464
1889
 
2465
1890
  // src/checks/source/htmlhint.ts
2466
1891
  import { existsSync as existsSync3 } from "node:fs";
2467
- import { readFile as readFile6 } from "node:fs/promises";
1892
+ import { readFile as readFile5 } from "node:fs/promises";
2468
1893
  import htmlhint from "htmlhint";
2469
1894
  var { HTMLHint } = htmlhint;
2470
1895
  var CONFIG_NAMES2 = [".htmlhintrc"];
@@ -2484,8 +1909,8 @@ var check17 = {
2484
1909
  const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2, configPath);
2485
1910
  if (!resolvedConfig && !configPath)
2486
1911
  return [];
2487
- const ruleset = resolvedConfig ? JSON.parse(await readFile6(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
2488
- const html = await readFile6(ctx.htmlPath, "utf8");
1912
+ const ruleset = resolvedConfig ? JSON.parse(await readFile5(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
1913
+ const html = await readFile5(ctx.htmlPath, "utf8");
2489
1914
  const messages = HTMLHint.verify(html, ruleset);
2490
1915
  return messages.map((m) => ({
2491
1916
  checkId: check17.id,
@@ -2500,7 +1925,7 @@ var check17 = {
2500
1925
  registerCheck(check17);
2501
1926
 
2502
1927
  // src/checks/source/stylelint.ts
2503
- import { readFile as readFile7 } from "node:fs/promises";
1928
+ import { readFile as readFile6 } from "node:fs/promises";
2504
1929
 
2505
1930
  // src/lib/printsafe.ts
2506
1931
  import postcss from "postcss";
@@ -2776,7 +2201,7 @@ var check18 = {
2776
2201
  for (const file of files) {
2777
2202
  let css;
2778
2203
  try {
2779
- css = await readFile7(file, "utf8");
2204
+ css = await readFile6(file, "utf8");
2780
2205
  } catch (err) {
2781
2206
  results.push({
2782
2207
  checkId: check18.id,
@@ -2803,12 +2228,12 @@ var check18 = {
2803
2228
  registerCheck(check18);
2804
2229
 
2805
2230
  // src/checks/source/css-ownership.ts
2806
- import { readFile as readFile8 } from "node:fs/promises";
2231
+ import { readFile as readFile7 } from "node:fs/promises";
2807
2232
 
2808
2233
  // src/lib/style-resolver.ts
2809
2234
  import { existsSync as existsSync4 } from "node:fs";
2810
- import { readdir as readdir2 } from "node:fs/promises";
2811
- import path2 from "node:path";
2235
+ import { readdir } from "node:fs/promises";
2236
+ import path from "node:path";
2812
2237
  var STYLES_SUBDIR = "styles";
2813
2238
  var FALLBACK_PRIORITY = [
2814
2239
  "styles/book.css",
@@ -2818,21 +2243,21 @@ var FALLBACK_PRIORITY = [
2818
2243
  "css/main.css"
2819
2244
  ];
2820
2245
  function relDisplay(projectDir, absPath) {
2821
- return path2.relative(projectDir, absPath).split(path2.sep).join("/");
2246
+ return path.relative(projectDir, absPath).split(path.sep).join("/");
2822
2247
  }
2823
2248
  async function dirEntries(dir) {
2824
2249
  try {
2825
- return await readdir2(dir, { withFileTypes: true });
2250
+ return await readdir(dir, { withFileTypes: true });
2826
2251
  } catch {
2827
2252
  return [];
2828
2253
  }
2829
2254
  }
2830
2255
  function cssFilesFrom(dir, entries) {
2831
- return entries.filter((e) => e.isFile() && e.name.toLowerCase().endsWith(".css")).map((e) => path2.join(dir, e.name));
2256
+ return entries.filter((e) => e.isFile() && e.name.toLowerCase().endsWith(".css")).map((e) => path.join(dir, e.name));
2832
2257
  }
2833
2258
  async function discoverCssFiles(projectDir) {
2834
- const stylesDir = path2.join(projectDir, STYLES_SUBDIR);
2835
- const cssDir = path2.join(projectDir, "css");
2259
+ const stylesDir = path.join(projectDir, STYLES_SUBDIR);
2260
+ const cssDir = path.join(projectDir, "css");
2836
2261
  const [rootEntries, stylesEntries, cssEntries] = await Promise.all([
2837
2262
  dirEntries(projectDir),
2838
2263
  dirEntries(stylesDir),
@@ -2855,7 +2280,7 @@ async function resolveActiveStyles(projectDir, manifestStyles) {
2855
2280
  if (manifest.length > 0)
2856
2281
  return manifest;
2857
2282
  for (const rel of FALLBACK_PRIORITY) {
2858
- if (existsSync4(path2.join(projectDir, rel)))
2283
+ if (existsSync4(path.join(projectDir, rel)))
2859
2284
  return [rel];
2860
2285
  }
2861
2286
  const discovered = await discoverCssFiles(projectDir);
@@ -2871,7 +2296,7 @@ import postcss2 from "postcss";
2871
2296
  import { parse as parseYaml3 } from "yaml";
2872
2297
  var CONFIG_NAMES3 = [".gutterpress/css-contract.yaml", ".gutterpress/css-contract.yml"];
2873
2298
  async function loadContract(configPath) {
2874
- const raw = await readFile8(configPath, "utf8");
2299
+ const raw = await readFile7(configPath, "utf8");
2875
2300
  const parsed = parseYaml3(raw);
2876
2301
  if (parsed && typeof parsed === "object")
2877
2302
  return parsed;
@@ -3022,7 +2447,7 @@ var check19 = {
3022
2447
  continue;
3023
2448
  let css;
3024
2449
  try {
3025
- css = await readFile8(absFile, "utf8");
2450
+ css = await readFile7(absFile, "utf8");
3026
2451
  } catch {
3027
2452
  continue;
3028
2453
  }
@@ -3068,9 +2493,9 @@ import { existsSync as existsSync7 } from "node:fs";
3068
2493
  import { dirname as dirname3, resolve as resolve5 } from "node:path";
3069
2494
 
3070
2495
  // src/lib/asset-inline.ts
3071
- import { createHash as createHash2 } from "node:crypto";
3072
- import { readFile as readFile9 } from "node:fs/promises";
3073
- import path3 from "node:path";
2496
+ import { createHash } from "node:crypto";
2497
+ import { readFile as readFile8 } from "node:fs/promises";
2498
+ import path2 from "node:path";
3074
2499
  import postcss3 from "postcss";
3075
2500
  var FONT_EXTS = new Set([".woff2", ".woff", ".ttf", ".otf"]);
3076
2501
  var HASHED_ASSET_DIR = "assets";
@@ -3111,19 +2536,19 @@ function decodeRef(ref) {
3111
2536
  }
3112
2537
  }
3113
2538
  function toPosix(p) {
3114
- return p.split(path3.sep).join("/");
2539
+ return p.split(path2.sep).join("/");
3115
2540
  }
3116
2541
  function escapesProjectRoot(projectDir, absPath) {
3117
- const rel = path3.relative(projectDir, absPath);
3118
- return rel === ".." || rel.startsWith(`..${path3.sep}`) || path3.isAbsolute(rel);
2542
+ const rel = path2.relative(projectDir, absPath);
2543
+ return rel === ".." || rel.startsWith(`..${path2.sep}`) || path2.isAbsolute(rel);
3119
2544
  }
3120
2545
  function proseImageRefError(ref, projectDir) {
3121
2546
  const cleaned = stripUrlSuffix(decodeRef(ref));
3122
- if (/^file:/i.test(cleaned) || path3.isAbsolute(cleaned)) {
2547
+ if (/^file:/i.test(cleaned) || path2.isAbsolute(cleaned)) {
3123
2548
  return `Image reference must be relative to the book folder: ${ref}
3124
2549
  ` + ` Copy the file into your book folder and reference it from there.`;
3125
2550
  }
3126
- if (escapesProjectRoot(projectDir, path3.resolve(projectDir, cleaned))) {
2551
+ if (escapesProjectRoot(projectDir, path2.resolve(projectDir, cleaned))) {
3127
2552
  return `Image reference points outside the book folder: ${ref}
3128
2553
  ` + ` Copy the file into your book folder and reference it from there.`;
3129
2554
  }
@@ -3134,7 +2559,7 @@ function mimeFor(ext) {
3134
2559
  }
3135
2560
  async function readOrThrow(absPath, kind, referencedFrom) {
3136
2561
  try {
3137
- return await readFile9(absPath);
2562
+ return await readFile8(absPath);
3138
2563
  } catch {
3139
2564
  throw new BuildError(`Missing ${kind}: ${absPath}
3140
2565
  referenced from ${referencedFrom}
@@ -3145,7 +2570,7 @@ function dataUri(bytes, ext) {
3145
2570
  return `data:${mimeFor(ext)};base64,${bytes.toString("base64")}`;
3146
2571
  }
3147
2572
  function contentHash(bytes) {
3148
- return createHash2("sha256").update(bytes).digest("hex").slice(0, 16);
2573
+ return createHash("sha256").update(bytes).digest("hex").slice(0, 16);
3149
2574
  }
3150
2575
  async function rewriteUrls(value, rewrite) {
3151
2576
  const matches = [...value.matchAll(URL_TOKEN_RE)];
@@ -3193,12 +2618,12 @@ function importTarget(atRule) {
3193
2618
  return target;
3194
2619
  }
3195
2620
  async function inlineOne(cssPath, copies, warnings, seen) {
3196
- const abs = path3.resolve(cssPath);
2621
+ const abs = path2.resolve(cssPath);
3197
2622
  if (seen.has(abs))
3198
2623
  return "";
3199
2624
  seen.add(abs);
3200
2625
  const source = await readOrThrow(abs, "stylesheet", "the book manifest");
3201
- const cssDir = path3.dirname(abs);
2626
+ const cssDir = path2.dirname(abs);
3202
2627
  let root;
3203
2628
  try {
3204
2629
  root = postcss3.parse(source.toString("utf-8"), { from: abs });
@@ -3220,8 +2645,8 @@ async function inlineOne(cssPath, copies, warnings, seen) {
3220
2645
  return null;
3221
2646
  }
3222
2647
  const relPath = stripUrlSuffix(decodeRef(raw));
3223
- const absAsset = path3.resolve(cssDir, relPath);
3224
- const ext = path3.extname(absAsset).toLowerCase();
2648
+ const absAsset = path2.resolve(cssDir, relPath);
2649
+ const ext = path2.extname(absAsset).toLowerCase();
3225
2650
  if (FONT_EXTS.has(ext)) {
3226
2651
  const bytes2 = await readOrThrow(absAsset, "font file", abs);
3227
2652
  return dataUri(bytes2, ext);
@@ -3239,7 +2664,7 @@ async function inlineOne(cssPath, copies, warnings, seen) {
3239
2664
  imports.push({ node, target });
3240
2665
  });
3241
2666
  for (const { node, target } of imports) {
3242
- const importedAbs = path3.resolve(cssDir, stripUrlSuffix(decodeRef(target)));
2667
+ const importedAbs = path2.resolve(cssDir, stripUrlSuffix(decodeRef(target)));
3243
2668
  const inlined = await inlineOne(importedAbs, copies, warnings, seen);
3244
2669
  node.replaceWith(wrapImportConditions(node, postcss3.parse(inlined, { from: importedAbs })));
3245
2670
  }
@@ -3251,10 +2676,10 @@ async function inlineStyles(projectDir, stylePaths) {
3251
2676
  const seen = new Set;
3252
2677
  const parts = [];
3253
2678
  for (const rel of stylePaths) {
3254
- const abs = path3.resolve(projectDir, rel);
2679
+ const abs = path2.resolve(projectDir, rel);
3255
2680
  const css = await inlineOne(abs, copies, warnings, seen);
3256
2681
  if (css.trim().length > 0) {
3257
- parts.push(`/* ${toPosix(path3.relative(projectDir, abs))} */
2682
+ parts.push(`/* ${toPosix(path2.relative(projectDir, abs))} */
3258
2683
  ${css.trim()}`);
3259
2684
  }
3260
2685
  }
@@ -3270,14 +2695,14 @@ async function collectStyleDependencies(projectDir, stylePaths) {
3270
2695
  const found = new Set;
3271
2696
  const visited = new Set;
3272
2697
  async function walk(cssPath) {
3273
- const abs = path3.resolve(cssPath);
2698
+ const abs = path2.resolve(cssPath);
3274
2699
  if (visited.has(abs))
3275
2700
  return;
3276
2701
  visited.add(abs);
3277
2702
  found.add(abs);
3278
2703
  let source;
3279
2704
  try {
3280
- source = await readFile9(abs, "utf-8");
2705
+ source = await readFile8(abs, "utf-8");
3281
2706
  } catch {
3282
2707
  return;
3283
2708
  }
@@ -3287,14 +2712,14 @@ async function collectStyleDependencies(projectDir, stylePaths) {
3287
2712
  } catch {
3288
2713
  return;
3289
2714
  }
3290
- const cssDir = path3.dirname(abs);
2715
+ const cssDir = path2.dirname(abs);
3291
2716
  root.walkDecls((decl) => {
3292
2717
  if (!decl.value.includes("url("))
3293
2718
  return;
3294
2719
  for (const raw of extractCssUrls(decl.value)) {
3295
2720
  if (!raw || isNonFilesystemRef(raw))
3296
2721
  continue;
3297
- found.add(path3.resolve(cssDir, stripUrlSuffix(decodeRef(raw))));
2722
+ found.add(path2.resolve(cssDir, stripUrlSuffix(decodeRef(raw))));
3298
2723
  }
3299
2724
  });
3300
2725
  const imports = [];
@@ -3304,11 +2729,11 @@ async function collectStyleDependencies(projectDir, stylePaths) {
3304
2729
  imports.push(target);
3305
2730
  });
3306
2731
  for (const target of imports) {
3307
- await walk(path3.resolve(cssDir, stripUrlSuffix(decodeRef(target))));
2732
+ await walk(path2.resolve(cssDir, stripUrlSuffix(decodeRef(target))));
3308
2733
  }
3309
2734
  }
3310
2735
  for (const rel of stylePaths) {
3311
- await walk(path3.resolve(projectDir, rel));
2736
+ await walk(path2.resolve(projectDir, rel));
3312
2737
  }
3313
2738
  return [...found];
3314
2739
  }
@@ -3325,8 +2750,8 @@ async function planImageCopies(projectDir, refs) {
3325
2750
  continue;
3326
2751
  }
3327
2752
  const cleaned = stripUrlSuffix(decodeRef(ref));
3328
- const abs = path3.resolve(projectDir, cleaned);
3329
- const rel = path3.relative(projectDir, abs);
2753
+ const abs = path2.resolve(projectDir, cleaned);
2754
+ const rel = path2.relative(projectDir, abs);
3330
2755
  const dest = toPosix(rel);
3331
2756
  copies.set(dest, { from: abs, to: dest });
3332
2757
  destinations.set(ref, dest);
@@ -3347,18 +2772,18 @@ async function inlineShapeUrls(html, baseDir) {
3347
2772
  if (!raw || isNonFilesystemRef(raw))
3348
2773
  continue;
3349
2774
  const cleaned = stripUrlSuffix(decodeRef(raw));
3350
- if (path3.isAbsolute(cleaned))
2775
+ if (path2.isAbsolute(cleaned))
3351
2776
  continue;
3352
- const abs = path3.resolve(baseDir, cleaned);
2777
+ const abs = path2.resolve(baseDir, cleaned);
3353
2778
  if (escapesProjectRoot(baseDir, abs))
3354
2779
  continue;
3355
2780
  let bytes;
3356
2781
  try {
3357
- bytes = await readFile9(abs);
2782
+ bytes = await readFile8(abs);
3358
2783
  } catch {
3359
2784
  continue;
3360
2785
  }
3361
- const mime = mimeFor(path3.extname(abs).toLowerCase());
2786
+ const mime = mimeFor(path2.extname(abs).toLowerCase());
3362
2787
  const dataUri2 = `data:${mime};base64,${bytes.toString("base64")}`;
3363
2788
  replacements.set(m[0], `--gp-shape:url(&quot;${dataUri2}&quot;)`);
3364
2789
  }
@@ -3372,7 +2797,7 @@ async function inlineShapeUrls(html, baseDir) {
3372
2797
  }
3373
2798
 
3374
2799
  // src/checks/source/local-ref-parser.ts
3375
- import { readFile as readFile12 } from "node:fs/promises";
2800
+ import { readFile as readFile11 } from "node:fs/promises";
3376
2801
 
3377
2802
  // src/lib/markdown/renderer.ts
3378
2803
  import MarkdownIt from "markdown-it";
@@ -5191,9 +4616,9 @@ function layerSlug(name) {
5191
4616
  }
5192
4617
 
5193
4618
  // src/lib/markdown/plugins.ts
5194
- import { createHash as createHash3 } from "node:crypto";
4619
+ import { createHash as createHash2 } from "node:crypto";
5195
4620
  import { existsSync as existsSync6, lstatSync, realpathSync, rmSync, statSync as statSync2, unlinkSync } from "node:fs";
5196
- import { cp, link, mkdir, mkdtemp, readFile as readFile11, rm, unlink, writeFile } from "node:fs/promises";
4621
+ import { cp, link, mkdir, mkdtemp, readFile as readFile10, rm, unlink, writeFile } from "node:fs/promises";
5197
4622
  import { tmpdir } from "node:os";
5198
4623
  import { resolve as resolve4, join, dirname as dirname2, basename, extname, relative, isAbsolute } from "node:path";
5199
4624
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -5218,24 +4643,24 @@ function resolveDeclaredStyles(rawStyles, baseDir, subject) {
5218
4643
  }
5219
4644
 
5220
4645
  // src/lib/extension-manifest.ts
5221
- import { readFile as readFile10 } from "node:fs/promises";
5222
- import path4 from "node:path";
4646
+ import { readFile as readFile9 } from "node:fs/promises";
4647
+ import path3 from "node:path";
5223
4648
  var EXTENSION_MANIFEST_FILENAME = "package.json";
5224
4649
  var GUTTERPRESS_KEY = "gutterpress";
5225
- function object2(value) {
4650
+ function object(value) {
5226
4651
  return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
5227
4652
  }
5228
4653
  function str(value) {
5229
4654
  return typeof value === "string" ? value : undefined;
5230
4655
  }
5231
4656
  function authorName(value) {
5232
- return str(value) ?? str(object2(value)?.name);
4657
+ return str(value) ?? str(object(value)?.name);
5233
4658
  }
5234
4659
  function metaFromPackageJson(raw) {
5235
- const pkg = object2(raw);
4660
+ const pkg = object(raw);
5236
4661
  if (!pkg)
5237
4662
  return {};
5238
- const gp = object2(pkg[GUTTERPRESS_KEY]) ?? {};
4663
+ const gp = object(pkg[GUTTERPRESS_KEY]) ?? {};
5239
4664
  const keywords = Array.isArray(pkg.keywords) ? pkg.keywords.filter((k) => typeof k === "string") : undefined;
5240
4665
  return {
5241
4666
  ...str(pkg.name) ? { name: str(pkg.name) } : {},
@@ -5254,7 +4679,7 @@ function metaFromPackageJson(raw) {
5254
4679
  }
5255
4680
  async function readExtensionMeta(dir) {
5256
4681
  try {
5257
- return metaFromPackageJson(JSON.parse(await readFile10(path4.join(dir, EXTENSION_MANIFEST_FILENAME), "utf8")));
4682
+ return metaFromPackageJson(JSON.parse(await readFile9(path3.join(dir, EXTENSION_MANIFEST_FILENAME), "utf8")));
5258
4683
  } catch {
5259
4684
  return {};
5260
4685
  }
@@ -5277,7 +4702,7 @@ function extensionCarries(meta) {
5277
4702
  };
5278
4703
  }
5279
4704
  function pathEscapesFolder(rel) {
5280
- return path4.isAbsolute(rel) || rel.split(/[\\/]/).includes("..");
4705
+ return path3.isAbsolute(rel) || rel.split(/[\\/]/).includes("..");
5281
4706
  }
5282
4707
  function assertExtensionContained(meta) {
5283
4708
  if (meta.engineStyles !== undefined) {
@@ -5548,9 +4973,9 @@ function isReceiptBoundRequireCall(node) {
5548
4973
  return true;
5549
4974
  if (callee.type !== "MemberExpression")
5550
4975
  return false;
5551
- const object3 = callee.object;
4976
+ const object2 = callee.object;
5552
4977
  const property = memberName(callee);
5553
- return Boolean(object3 && (object3.type === "Identifier" && object3.name === "module" && property === "require" || object3.type === "Identifier" && object3.name === "require" && property === "resolve"));
4978
+ return Boolean(object2 && (object2.type === "Identifier" && object2.name === "module" && property === "require" || object2.type === "Identifier" && object2.name === "require" && property === "resolve"));
5554
4979
  }
5555
4980
  function rewriteCommonJsRequires(source, absolute, pkg, tree) {
5556
4981
  const ast = parseJavaScript(source, {
@@ -5601,7 +5026,7 @@ async function rewriteReachableModuleImports(entryPath, tree) {
5601
5026
  const pkg = packageOwningFile(tree, absolute);
5602
5027
  if (!pkg)
5603
5028
  throw new Error(`Reachable plugin module is outside the verified package tree: ${absolute}`);
5604
- const source = await readFile11(absolute, "utf8");
5029
+ const source = await readFile10(absolute, "utf8");
5605
5030
  const [imports] = parseModuleImports(source, absolute);
5606
5031
  const replacements = [];
5607
5032
  const targets = new Set;
@@ -5708,7 +5133,7 @@ async function createIsolatedVendorTree(verified, address) {
5708
5133
  }
5709
5134
  }
5710
5135
  async function isolateVendoredPlugin(verified) {
5711
- const address = createHash3("sha256").update(verified.receipt.tree.digest).update("\x00").update(JSON.stringify(verified.receipt)).digest("hex");
5136
+ const address = createHash2("sha256").update(verified.receipt.tree.digest).update("\x00").update(JSON.stringify(verified.receipt)).digest("hex");
5712
5137
  let pending = isolatedVendorTrees.get(address);
5713
5138
  if (!pending) {
5714
5139
  pending = createIsolatedVendorTree(verified, address).catch((error2) => {
@@ -6180,7 +5605,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
6180
5605
  for (const file of files) {
6181
5606
  let refs;
6182
5607
  try {
6183
- refs = collectRenderedLocalRefs(await readFile12(file, "utf8"));
5608
+ refs = collectRenderedLocalRefs(await readFile11(file, "utf8"));
6184
5609
  } catch {
6185
5610
  results.push(inspectionFailed(checkId, `Could not read source file: ${file}`, { file }));
6186
5611
  continue;
@@ -6242,15 +5667,15 @@ function localRefExists(ref, kind, sourceFile, projectRoot) {
6242
5667
  registerCheck(check20);
6243
5668
 
6244
5669
  // src/lib/build-staging.ts
6245
- import path5 from "node:path";
5670
+ import path4 from "node:path";
6246
5671
  import os from "node:os";
6247
5672
  import fsp from "node:fs/promises";
6248
5673
 
6249
5674
  // src/lib/missing-asset-placeholder.ts
6250
- import { createHash as createHash4 } from "node:crypto";
5675
+ import { createHash as createHash3 } from "node:crypto";
6251
5676
  import { deflateSync } from "node:zlib";
6252
5677
  function placeholderOutputPath(missingOutputPath) {
6253
- const hash = createHash4("sha256").update(missingOutputPath).digest("hex").slice(0, 16);
5678
+ const hash = createHash3("sha256").update(missingOutputPath).digest("hex").slice(0, 16);
6254
5679
  return `assets/gutterpress-missing/${hash}.png`;
6255
5680
  }
6256
5681
  function decodeHtmlAttribute(value) {
@@ -6427,8 +5852,8 @@ function placeholderPng(width = 640, height = 480, cell = 32) {
6427
5852
 
6428
5853
  // src/lib/build-staging.ts
6429
5854
  async function shipViewerHtml(htmlFile, outDir) {
6430
- await fsp.mkdir(path5.join(outDir, "engine"), { recursive: true });
6431
- await fsp.copyFile(await getAssetPath("engine/gutterpress-viewer.js"), path5.join(outDir, "engine/gutterpress-viewer.js"));
5855
+ await fsp.mkdir(path4.join(outDir, "engine"), { recursive: true });
5856
+ await fsp.copyFile(await getAssetPath("engine/gutterpress-viewer.js"), path4.join(outDir, "engine/gutterpress-viewer.js"));
6432
5857
  const tag = ` <script src="engine/gutterpress-viewer.js"></script>
6433
5858
  `;
6434
5859
  const html = await fsp.readFile(htmlFile, "utf-8");
@@ -6460,18 +5885,18 @@ async function stageBookAssets(options) {
6460
5885
  return { missing: [...missingPlaceholders.keys()].sort() };
6461
5886
  }
6462
5887
  async function copyReferencedAssets(copies, outDir) {
6463
- const dirs = new Set(copies.map((c) => path5.dirname(path5.resolve(outDir, c.to))));
5888
+ const dirs = new Set(copies.map((c) => path4.dirname(path4.resolve(outDir, c.to))));
6464
5889
  await Promise.all([...dirs].map((d) => fsp.mkdir(d, { recursive: true })));
6465
5890
  const missing = new Map;
6466
5891
  await Promise.all(copies.map(async (c) => {
6467
- const dest = path5.resolve(outDir, c.to);
5892
+ const dest = path4.resolve(outDir, c.to);
6468
5893
  try {
6469
5894
  await fsp.copyFile(c.from, dest);
6470
5895
  } catch (err) {
6471
5896
  if (err?.code === "ENOENT") {
6472
5897
  const placeholder = placeholderOutputPath(c.to);
6473
- const placeholderDest = path5.resolve(outDir, placeholder);
6474
- await fsp.mkdir(path5.dirname(placeholderDest), { recursive: true });
5898
+ const placeholderDest = path4.resolve(outDir, placeholder);
5899
+ await fsp.mkdir(path4.dirname(placeholderDest), { recursive: true });
6475
5900
  await fsp.writeFile(placeholderDest, placeholderPng());
6476
5901
  missing.set(c.to, placeholder);
6477
5902
  return;
@@ -6501,7 +5926,7 @@ function dropRelativeLinkHrefs(html) {
6501
5926
  });
6502
5927
  }
6503
5928
  async function createStageRoot() {
6504
- return fsp.mkdtemp(path5.join(os.tmpdir(), "gutterpress-stage-"));
5929
+ return fsp.mkdtemp(path4.join(os.tmpdir(), "gutterpress-stage-"));
6505
5930
  }
6506
5931
 
6507
5932
  // src/checks/source/dangling-links.ts
@@ -6531,7 +5956,7 @@ var check21 = {
6531
5956
  registerCheck(check21);
6532
5957
 
6533
5958
  // src/checks/source/accessibility-alt-text.ts
6534
- import { readFile as readFile13 } from "node:fs/promises";
5959
+ import { readFile as readFile12 } from "node:fs/promises";
6535
5960
  var check22 = {
6536
5961
  id: "source.accessibility.alt-text",
6537
5962
  name: "Image Alt Text",
@@ -6545,7 +5970,7 @@ var check22 = {
6545
5970
  const results = [];
6546
5971
  for (const file of files) {
6547
5972
  try {
6548
- const content = await readFile13(file, "utf8");
5973
+ const content = await readFile12(file, "utf8");
6549
5974
  const lines = content.split(`
6550
5975
  `);
6551
5976
  let inFence = false;
@@ -6589,7 +6014,7 @@ function extractImageAlts(line) {
6589
6014
  registerCheck(check22);
6590
6015
 
6591
6016
  // src/checks/source/accessibility-heading-order.ts
6592
- import { readFile as readFile14 } from "node:fs/promises";
6017
+ import { readFile as readFile13 } from "node:fs/promises";
6593
6018
  var check23 = {
6594
6019
  id: "source.accessibility.heading-order",
6595
6020
  name: "Heading Order",
@@ -6603,7 +6028,7 @@ var check23 = {
6603
6028
  const results = [];
6604
6029
  for (const file of files) {
6605
6030
  try {
6606
- const content = await readFile14(file, "utf8");
6031
+ const content = await readFile13(file, "utf8");
6607
6032
  const lines = content.split(`
6608
6033
  `);
6609
6034
  let inFence = false;
@@ -6639,7 +6064,7 @@ var check23 = {
6639
6064
  registerCheck(check23);
6640
6065
 
6641
6066
  // src/checks/source/layout-markers.ts
6642
- import { readFile as readFile15 } from "node:fs/promises";
6067
+ import { readFile as readFile14 } from "node:fs/promises";
6643
6068
  var check24 = {
6644
6069
  id: "source.markdown.layout-markers",
6645
6070
  name: "Layout Markers",
@@ -6657,7 +6082,7 @@ var check24 = {
6657
6082
  const md = createMarkdownRenderer(plugins);
6658
6083
  for (const file of files) {
6659
6084
  try {
6660
- const content = await readFile15(file, "utf8");
6085
+ const content = await readFile14(file, "utf8");
6661
6086
  const env = {};
6662
6087
  md.render(content, env);
6663
6088
  for (const w of env.layoutWarnings ?? []) {
@@ -6679,8 +6104,8 @@ var check24 = {
6679
6104
  registerCheck(check24);
6680
6105
 
6681
6106
  // src/checks/source/merge-markers.ts
6682
- import { readFile as readFile16 } from "node:fs/promises";
6683
- import path6 from "node:path";
6107
+ import { readFile as readFile15 } from "node:fs/promises";
6108
+ import path5 from "node:path";
6684
6109
 
6685
6110
  // src/checks/asset/extensions.ts
6686
6111
  var RASTER_INSPECTABLE_EXTS = [
@@ -6721,7 +6146,7 @@ var check25 = {
6721
6146
  for (const file of textFiles) {
6722
6147
  let content;
6723
6148
  try {
6724
- content = await readFile16(file, "utf8");
6149
+ content = await readFile15(file, "utf8");
6725
6150
  } catch {
6726
6151
  results.push(inspectionFailed(check25.id, `Could not read source file: ${file}`, { file }));
6727
6152
  continue;
@@ -6764,7 +6189,7 @@ var check25 = {
6764
6189
  ignore: [...ASSET_SCAN_IGNORE_GLOBS]
6765
6190
  });
6766
6191
  for (const sibling of siblings.sort()) {
6767
- const rel = path6.relative(ctx.inputDir, sibling).split(path6.sep).join("/");
6192
+ const rel = path5.relative(ctx.inputDir, sibling).split(path5.sep).join("/");
6768
6193
  results.push(finding(check25.id, {
6769
6194
  severity: "warning",
6770
6195
  code: "kept-both-versions",
@@ -6784,27 +6209,27 @@ registerCheck(check25);
6784
6209
  import { stat as stat3 } from "node:fs/promises";
6785
6210
 
6786
6211
  // src/lib/image-inspect.ts
6787
- import { stat as stat2, readFile as readFile17 } from "node:fs/promises";
6212
+ import { stat as stat2, readFile as readFile16 } from "node:fs/promises";
6788
6213
  var DEFAULT_DPI = 72;
6789
6214
  var cache = new Map;
6790
- async function inspectImage(path7) {
6215
+ async function inspectImage(path6) {
6791
6216
  let st;
6792
6217
  try {
6793
- st = await stat2(path7);
6218
+ st = await stat2(path6);
6794
6219
  } catch {
6795
6220
  return null;
6796
6221
  }
6797
- const hit = cache.get(path7);
6222
+ const hit = cache.get(path6);
6798
6223
  if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size)
6799
6224
  return hit.info;
6800
6225
  let info2 = null;
6801
6226
  try {
6802
- const buf = await readFile17(path7);
6227
+ const buf = await readFile16(path6);
6803
6228
  info2 = parseImage(buf);
6804
6229
  } catch {
6805
6230
  info2 = null;
6806
6231
  }
6807
- cache.set(path7, { mtimeMs: st.mtimeMs, size: st.size, info: info2 });
6232
+ cache.set(path6, { mtimeMs: st.mtimeMs, size: st.size, info: info2 });
6808
6233
  return info2;
6809
6234
  }
6810
6235
  function parseImage(b) {
@@ -7359,7 +6784,7 @@ var check33 = {
7359
6784
  registerCheck(check33);
7360
6785
 
7361
6786
  // src/checks/heuristic/section-density.ts
7362
- import { readFile as readFile18 } from "node:fs/promises";
6787
+ import { readFile as readFile17 } from "node:fs/promises";
7363
6788
  var check34 = {
7364
6789
  id: "heuristic.chunking.section-density",
7365
6790
  name: "Section Density",
@@ -7376,7 +6801,7 @@ var check34 = {
7376
6801
  const results = [];
7377
6802
  for (const file of files) {
7378
6803
  try {
7379
- const content = await readFile18(file, "utf8");
6804
+ const content = await readFile17(file, "utf8");
7380
6805
  const lines = content.split(`
7381
6806
  `);
7382
6807
  let currentSectionStart = 0;
@@ -7545,7 +6970,7 @@ import { existsSync as existsSync9 } from "node:fs";
7545
6970
  import { dirname as dirname4, join as join3, resolve as resolve7 } from "node:path";
7546
6971
 
7547
6972
  // src/lib/output-paths.ts
7548
- import path7 from "node:path";
6973
+ import path6 from "node:path";
7549
6974
 
7550
6975
  // src/lib/slug.ts
7551
6976
  function slugify(name, fallback = "") {
@@ -7563,7 +6988,7 @@ function bookSlug(title) {
7563
6988
  return slugify(title ?? "", "book");
7564
6989
  }
7565
6990
  function resolveOutputDir(manifestDir, title) {
7566
- return path7.resolve(manifestDir, DIST_DIRNAME, bookSlug(title));
6991
+ return path6.resolve(manifestDir, DIST_DIRNAME, bookSlug(title));
7567
6992
  }
7568
6993
  function artifactName(title, format) {
7569
6994
  return `${bookSlug(title)}-${format}.pdf`;
@@ -7573,7 +6998,7 @@ function artifactName(title, format) {
7573
6998
  var BOOK_HTML_FILENAME = "book.html";
7574
6999
 
7575
7000
  // src/lib/markdown/index.ts
7576
- import { readdir as readdir3, readFile as readFile19, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
7001
+ import { readdir as readdir2, readFile as readFile18, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
7577
7002
 
7578
7003
  // src/lib/remote-auth/sync-messages.ts
7579
7004
  function isOnlineSibling(filepath) {
@@ -7680,7 +7105,7 @@ ${bodyContent}
7680
7105
  async function resolveActiveMarkdownFiles(inputDir, configuredFiles) {
7681
7106
  if (configuredFiles && configuredFiles.length > 0)
7682
7107
  return configuredFiles;
7683
- return (await readdir3(inputDir)).filter((f) => f.endsWith(".md") && !isOnlineSibling(f)).sort();
7108
+ return (await readdir2(inputDir)).filter((f) => f.endsWith(".md") && !isOnlineSibling(f)).sort();
7684
7109
  }
7685
7110
  async function renderChapters(inputDir, opts = {}) {
7686
7111
  const styles = await resolveActiveStyles(inputDir, opts.styles);
@@ -7719,7 +7144,7 @@ ${css.trim()}
7719
7144
  }
7720
7145
  return assembleBookHtml({
7721
7146
  files,
7722
- readText: (relPath) => readFile19(join2(inputDir, canonicalChapterId(relPath)), "utf-8"),
7147
+ readText: (relPath) => readFile18(join2(inputDir, canonicalChapterId(relPath)), "utf-8"),
7723
7148
  projectCss: inlined.css,
7724
7149
  preloadImages: cssAssetCopies.map((c) => c.to),
7725
7150
  title: opts.title,
@@ -7750,7 +7175,7 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
7750
7175
  }
7751
7176
 
7752
7177
  // src/lib/markdownlint-fix.ts
7753
- import { readFile as readFile20, writeFile as writeFile3 } from "node:fs/promises";
7178
+ import { readFile as readFile19, writeFile as writeFile3 } from "node:fs/promises";
7754
7179
  import { applyFixes } from "markdownlint";
7755
7180
  import { lint as lint2 } from "markdownlint/sync";
7756
7181
  async function uncommittedAmong(inputDir, files) {
@@ -7790,7 +7215,7 @@ async function applyMarkdownlintFixes(ctx) {
7790
7215
  for (const [file, violations] of Object.entries(results)) {
7791
7216
  if (!Array.isArray(violations) || violations.length === 0)
7792
7217
  continue;
7793
- const before = await readFile20(file, "utf8");
7218
+ const before = await readFile19(file, "utf8");
7794
7219
  const after = applyFixes(before, violations);
7795
7220
  if (after !== before)
7796
7221
  pending.push({ file, content: after });
@@ -8286,7 +7711,7 @@ function buildPdfSummaryLines(results) {
8286
7711
  }
8287
7712
 
8288
7713
  // src/lib/build-runner.ts
8289
- import path9 from "node:path";
7714
+ import path8 from "node:path";
8290
7715
  import fs2 from "node:fs";
8291
7716
  import fsp2 from "node:fs/promises";
8292
7717
  import os2 from "node:os";
@@ -8294,9 +7719,9 @@ import { randomBytes } from "node:crypto";
8294
7719
 
8295
7720
  // src/lib/build-fingerprint.ts
8296
7721
  import * as fs from "node:fs";
8297
- import { mkdir as mkdir3, readFile as readFile21, writeFile as writeFile4 } from "node:fs/promises";
8298
- import { createHash as createHash5 } from "node:crypto";
8299
- import path8 from "node:path";
7722
+ import { mkdir as mkdir3, readFile as readFile20, writeFile as writeFile4 } from "node:fs/promises";
7723
+ import { createHash as createHash4 } from "node:crypto";
7724
+ import path7 from "node:path";
8300
7725
  import git from "isomorphic-git";
8301
7726
  var FINGERPRINT_FILENAME = "build-fingerprint.json";
8302
7727
  var VERSION_TIMEOUT_MS = 4000;
@@ -8345,7 +7770,7 @@ async function getGitRevision(sourceDir) {
8345
7770
  const candidateDirs = [sourceDir, process.cwd()].filter((v) => Boolean(v));
8346
7771
  const seen = new Set;
8347
7772
  for (const dir of candidateDirs) {
8348
- const abs = path8.resolve(dir);
7773
+ const abs = path7.resolve(dir);
8349
7774
  if (seen.has(abs))
8350
7775
  continue;
8351
7776
  seen.add(abs);
@@ -8381,10 +7806,10 @@ async function getEngineBundleHash() {
8381
7806
  getAssetPath("engine/gutterpress-agent.js")
8382
7807
  ]);
8383
7808
  const [viewerBytes, agentBytes] = await Promise.all([
8384
- readFile21(viewerPath),
8385
- readFile21(agentPath)
7809
+ readFile20(viewerPath),
7810
+ readFile20(agentPath)
8386
7811
  ]);
8387
- const hash = createHash5("sha256");
7812
+ const hash = createHash4("sha256");
8388
7813
  hash.update(viewerBytes);
8389
7814
  hash.update(agentBytes);
8390
7815
  return hash.digest("hex").slice(0, 12);
@@ -8430,8 +7855,8 @@ function sanitizeArgs(args) {
8430
7855
  return out;
8431
7856
  }
8432
7857
  async function writeBuildFingerprint(input) {
8433
- const outputDir = path8.resolve(input.outputDir);
8434
- const outPath = path8.join(outputDir, FINGERPRINT_FILENAME);
7858
+ const outputDir = path7.resolve(input.outputDir);
7859
+ const outPath = path7.join(outputDir, FINGERPRINT_FILENAME);
8435
7860
  const [tools, sourceRevision] = await Promise.all([
8436
7861
  getToolVersions(),
8437
7862
  getGitRevision(input.sourceDir)
@@ -8447,7 +7872,7 @@ async function writeBuildFingerprint(input) {
8447
7872
  iccPath: input.pdfx.iccPath,
8448
7873
  stripAnnotations: input.pdfx.stripAnnotations
8449
7874
  },
8450
- outputDir: input.recordedOutputDir ? path8.resolve(input.recordedOutputDir) : outputDir
7875
+ outputDir: input.recordedOutputDir ? path7.resolve(input.recordedOutputDir) : outputDir
8451
7876
  },
8452
7877
  sourceRevision,
8453
7878
  tools
@@ -8527,18 +7952,18 @@ function splitOutPath(outArg, format) {
8527
7952
  if (typeof outArg !== "string" || outArg.length === 0) {
8528
7953
  return { outDir: undefined, pdfFileOverride: null };
8529
7954
  }
8530
- const resolved = path9.resolve(outArg);
7955
+ const resolved = path8.resolve(outArg);
8531
7956
  if ((format === "pdf" || format === "pdfx") && resolved.toLowerCase().endsWith(".pdf")) {
8532
- return { outDir: path9.dirname(resolved), pdfFileOverride: resolved };
7957
+ return { outDir: path8.dirname(resolved), pdfFileOverride: resolved };
8533
7958
  }
8534
7959
  return { outDir: resolved, pdfFileOverride: null };
8535
7960
  }
8536
7961
  function layoutWarningKey(file, line, message) {
8537
- return `${path9.resolve(file)}\x00${line ?? 0}\x00${message}`;
7962
+ return `${path8.resolve(file)}\x00${line ?? 0}\x00${message}`;
8538
7963
  }
8539
7964
  async function resolveBuildContext(opts) {
8540
7965
  const { format } = opts;
8541
- const inputDir = path9.resolve(opts.inputDir);
7966
+ const inputDir = path8.resolve(opts.inputDir);
8542
7967
  const { manifest, manifestDir, manifestPath } = await loadManifestWithPath(opts.manifestPath ?? inputDir, { explicit: opts.manifestPath !== undefined });
8543
7968
  if (manifestPath === null) {
8544
7969
  throw new UsageError(`No book manifest found in ${inputDir}. Looked for ${MANIFEST_FILENAMES.join(" or ")}. ` + "Run from your book folder or pass that folder with `gutterpress build <book-dir>`. " + "For a custom manifest filename, pass `--manifest <path>`.");
@@ -8552,10 +7977,10 @@ async function resolveBuildContext(opts) {
8552
7977
  title: opts.title,
8553
7978
  pdfx: pdfxConfigOverride
8554
7979
  }, manifest);
8555
- const target = opts.pdfFileOverride ? { kind: "file", file: path9.resolve(opts.pdfFileOverride) } : opts.outDir ? { kind: "directory", dir: opts.outDir } : { kind: "project", dir: resolveOutputDir(manifestDir, config.title) };
8556
- const outDir = target.kind === "file" ? path9.dirname(target.file) : target.dir;
7980
+ const target = opts.pdfFileOverride ? { kind: "file", file: path8.resolve(opts.pdfFileOverride) } : opts.outDir ? { kind: "directory", dir: opts.outDir } : { kind: "project", dir: resolveOutputDir(manifestDir, config.title) };
7981
+ const outDir = target.kind === "file" ? path8.dirname(target.file) : target.dir;
8557
7982
  const gates = computeGates(format, opts, config);
8558
- const workDir = target.kind === "project" ? path9.join(path9.dirname(target.dir), `.${path9.basename(target.dir)}-build-${randomBytes(6).toString("hex")}`) : path9.join(os2.tmpdir(), `gutterpress-build-${randomBytes(6).toString("hex")}`);
7983
+ const workDir = target.kind === "project" ? path8.join(path8.dirname(target.dir), `.${path8.basename(target.dir)}-build-${randomBytes(6).toString("hex")}`) : path8.join(os2.tmpdir(), `gutterpress-build-${randomBytes(6).toString("hex")}`);
8559
7984
  return {
8560
7985
  opts,
8561
7986
  format,
@@ -8625,7 +8050,7 @@ async function renderBook(ctx) {
8625
8050
  pluginStyles,
8626
8051
  onChapterWarnings: (file, warnings) => {
8627
8052
  for (const w of warnings) {
8628
- const key = layoutWarningKey(path9.resolve(renderDir, file), w.line, w.message);
8053
+ const key = layoutWarningKey(path8.resolve(renderDir, file), w.line, w.message);
8629
8054
  if (!ctx.prevalidatedLayoutWarningKeys.has(key)) {
8630
8055
  log.warn(` ${file}, line ${w.line}: ${w.message}`);
8631
8056
  }
@@ -8664,9 +8089,9 @@ async function renderBook(ctx) {
8664
8089
  return htmlFile;
8665
8090
  }
8666
8091
  async function resolveIccProfile(icc, manifestDir, explicitIccPath) {
8667
- const iccCandidates = path9.isAbsolute(icc) ? [icc] : [path9.resolve(manifestDir, icc), path9.resolve(icc)];
8092
+ const iccCandidates = path8.isAbsolute(icc) ? [icc] : [path8.resolve(manifestDir, icc), path8.resolve(icc)];
8668
8093
  let effectiveIccPath = iccCandidates.find((candidate) => fs2.existsSync(candidate)) ?? null;
8669
- if (!effectiveIccPath && !explicitIccPath && path9.basename(icc) === "CGATS21_CRPC1.icc") {
8094
+ if (!effectiveIccPath && !explicitIccPath && path8.basename(icc) === "CGATS21_CRPC1.icc") {
8670
8095
  effectiveIccPath = await getAssetPath("profiles/CGATS21_CRPC1.icc");
8671
8096
  }
8672
8097
  if (!effectiveIccPath) {
@@ -8682,13 +8107,13 @@ async function finalizeBuild(ctx, fingerprint, wroteMessage, paths, artifactName
8682
8107
  });
8683
8108
  await publishBuild(ctx, artifactName2);
8684
8109
  const delivered = ctx.target.kind === "project" || ctx.target.kind === "directory" && ctx.format === "html";
8685
- const fingerprintPath = delivered ? path9.join(ctx.outDir, path9.basename(workFingerprint)) : null;
8110
+ const fingerprintPath = delivered ? path8.join(ctx.outDir, path8.basename(workFingerprint)) : null;
8686
8111
  log.success(wroteMessage);
8687
8112
  if (fingerprintPath)
8688
8113
  log.info(`Fingerprint: ${fingerprintPath}`);
8689
8114
  return {
8690
8115
  outDir: ctx.outDir,
8691
- htmlPath: delivered ? path9.join(ctx.outDir, path9.relative(ctx.workDir, paths.htmlPath)) : null,
8116
+ htmlPath: delivered ? path8.join(ctx.outDir, path8.relative(ctx.workDir, paths.htmlPath)) : null,
8692
8117
  pdfPath: paths.pdfPath,
8693
8118
  fingerprintPath,
8694
8119
  diagnostics
@@ -8699,7 +8124,7 @@ async function publishToDirectory(workDir, targetDir, format, artifactName2) {
8699
8124
  if (format !== "html") {
8700
8125
  if (!artifactName2)
8701
8126
  throw new BuildError("No artifact to write for this format", 1);
8702
- await fsp2.copyFile(path9.join(workDir, artifactName2), path9.join(targetDir, artifactName2));
8127
+ await fsp2.copyFile(path8.join(workDir, artifactName2), path8.join(targetDir, artifactName2));
8703
8128
  return;
8704
8129
  }
8705
8130
  await fsp2.cp(workDir, targetDir, { recursive: true, force: true });
@@ -8709,8 +8134,8 @@ async function publishBuild(ctx, artifactName2) {
8709
8134
  if (target.kind === "file") {
8710
8135
  if (!artifactName2)
8711
8136
  throw new BuildError("No artifact to write for this format", 1);
8712
- await fsp2.mkdir(path9.dirname(target.file), { recursive: true });
8713
- await fsp2.copyFile(path9.join(workDir, artifactName2), target.file);
8137
+ await fsp2.mkdir(path8.dirname(target.file), { recursive: true });
8138
+ await fsp2.copyFile(path8.join(workDir, artifactName2), target.file);
8714
8139
  return;
8715
8140
  }
8716
8141
  if (target.kind === "directory") {
@@ -8718,12 +8143,12 @@ async function publishBuild(ctx, artifactName2) {
8718
8143
  return;
8719
8144
  }
8720
8145
  for (const name of await listPdfs(target.dir)) {
8721
- if (!fs2.existsSync(path9.join(workDir, name))) {
8722
- await fsp2.rename(path9.join(target.dir, name), path9.join(workDir, name));
8146
+ if (!fs2.existsSync(path8.join(workDir, name))) {
8147
+ await fsp2.rename(path8.join(target.dir, name), path8.join(workDir, name));
8723
8148
  }
8724
8149
  }
8725
8150
  await fsp2.rm(target.dir, { recursive: true, force: true });
8726
- await fsp2.mkdir(path9.dirname(target.dir), { recursive: true });
8151
+ await fsp2.mkdir(path8.dirname(target.dir), { recursive: true });
8727
8152
  await fsp2.rename(workDir, target.dir);
8728
8153
  }
8729
8154
  async function listPdfs(dir) {
@@ -8739,7 +8164,7 @@ class HtmlOutput {
8739
8164
  const { workDir, outDir, inputDir, config, opts } = ctx;
8740
8165
  log.info("Shipping self-contained HTML + viewer bundle (native engine)");
8741
8166
  await shipViewerHtml(htmlFile, workDir);
8742
- await fsp2.writeFile(path9.join(workDir, "index.html"), `<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=book.html"><title>Gutterpress</title></head><body></body></html>
8167
+ await fsp2.writeFile(path8.join(workDir, "index.html"), `<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=book.html"><title>Gutterpress</title></head><body></body></html>
8743
8168
  `, "utf-8");
8744
8169
  return finalizeBuild(ctx, {
8745
8170
  command: "build",
@@ -8752,7 +8177,7 @@ class HtmlOutput {
8752
8177
  iccPath: null,
8753
8178
  stripAnnotations: null
8754
8179
  }
8755
- }, `Wrote: ${path9.join(outDir, BOOK_HTML)}`, { htmlPath: htmlFile, pdfPath: null });
8180
+ }, `Wrote: ${path8.join(outDir, BOOK_HTML)}`, { htmlPath: htmlFile, pdfPath: null });
8756
8181
  }
8757
8182
  }
8758
8183
 
@@ -8761,12 +8186,12 @@ class PdfOutput {
8761
8186
  const { workDir, outDir, inputDir, config, opts, format, manifestDir, gates } = ctx;
8762
8187
  const pdfxMode = format === "pdfx" ? opts.pdfxFlavor ?? config.pdfx.flavor : undefined;
8763
8188
  const pdfName = artifactName(config.title, pdfxMode ? "pdfx" : "pdf");
8764
- const pdfFile = path9.join(workDir, pdfName);
8765
- const reportedPdf = ctx.target.kind === "file" ? ctx.target.file : path9.join(outDir, pdfName);
8189
+ const pdfFile = path8.join(workDir, pdfName);
8190
+ const reportedPdf = ctx.target.kind === "file" ? ctx.target.file : path8.join(outDir, pdfName);
8766
8191
  const stage = await createStageRoot();
8767
8192
  try {
8768
- const rawPdf = pdfxMode ? path9.join(stage, "raw.pdf") : path9.resolve(pdfFile);
8769
- await fsp2.mkdir(path9.dirname(path9.resolve(pdfFile)), { recursive: true });
8193
+ const rawPdf = pdfxMode ? path8.join(stage, "raw.pdf") : path8.resolve(pdfFile);
8194
+ await fsp2.mkdir(path8.dirname(path8.resolve(pdfFile)), { recursive: true });
8770
8195
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
8771
8196
  const { buildNativePdf } = await import("./engine-amxqsfka.js");
8772
8197
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
@@ -8799,7 +8224,7 @@ class PdfOutput {
8799
8224
  await stripAnnotations(rawPdf, stage);
8800
8225
  }
8801
8226
  log.info(`Converting to CMYK PDF/X (${pdfxMode})`);
8802
- await convertToPdfxCmyk(rawPdf, path9.resolve(pdfFile), {
8227
+ await convertToPdfxCmyk(rawPdf, path8.resolve(pdfFile), {
8803
8228
  iccPath: effectiveIccPath,
8804
8229
  pdfx: pdfxMode,
8805
8230
  title: config.title,
@@ -8888,10 +8313,10 @@ function openPath(filePath) {
8888
8313
  }
8889
8314
 
8890
8315
  // src/preview/lifecycle.ts
8891
- import path11 from "path";
8316
+ import path10 from "path";
8892
8317
  import { tmpdir as tmpdir2 } from "os";
8893
8318
  import { randomBytes as randomBytes2 } from "crypto";
8894
- import { readdir as readdir4, readFile as readFile22, writeFile as writeFile5 } from "node:fs/promises";
8319
+ import { readdir as readdir3, readFile as readFile21, writeFile as writeFile5 } from "node:fs/promises";
8895
8320
 
8896
8321
  // src/utils/file-utils.ts
8897
8322
  import { promises as fs3 } from "fs";
@@ -8913,7 +8338,7 @@ async function mkdir4(dirPath) {
8913
8338
  // src/preview/file-watcher.ts
8914
8339
  import { watch } from "chokidar";
8915
8340
  import fsp3 from "node:fs/promises";
8916
- import path10 from "path";
8341
+ import path9 from "path";
8917
8342
  var EMPTY_BOOK_HTML = `<!doctype html>
8918
8343
  <html lang="en">
8919
8344
  <head>
@@ -8966,7 +8391,7 @@ function injectPreviewScripts(html, pageIsolateChapters) {
8966
8391
  async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
8967
8392
  if (!inputPath) {
8968
8393
  cssAssets.clear();
8969
- await fsp3.writeFile(path10.join(tempDir, BOOK_HTML_FILENAME), EMPTY_BOOK_HTML, "utf-8");
8394
+ await fsp3.writeFile(path9.join(tempDir, BOOK_HTML_FILENAME), EMPTY_BOOK_HTML, "utf-8");
8970
8395
  return;
8971
8396
  }
8972
8397
  const nextAssets = new Map;
@@ -8981,7 +8406,7 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
8981
8406
  cssAssets.clear();
8982
8407
  for (const [to, from] of nextAssets)
8983
8408
  cssAssets.set(to, from);
8984
- await fsp3.writeFile(path10.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html, false), "utf-8");
8409
+ await fsp3.writeFile(path9.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html, false), "utf-8");
8985
8410
  }
8986
8411
  async function renderChapterPreviewHtml(inputPath, file, config) {
8987
8412
  const html = await renderPreviewBook(inputPath, config, {
@@ -8993,12 +8418,12 @@ async function renderChapterPreviewHtml(inputPath, file, config) {
8993
8418
  function describeChanges(changes, inputResolved) {
8994
8419
  const files = [];
8995
8420
  for (const [changedPath, event] of changes) {
8996
- const relative2 = path10.relative(inputResolved, path10.resolve(changedPath));
8997
- if (relative2 === "" || relative2 === ".." || relative2.startsWith(`..${path10.sep}`) || path10.isAbsolute(relative2))
8421
+ const relative2 = path9.relative(inputResolved, path9.resolve(changedPath));
8422
+ if (relative2 === "" || relative2 === ".." || relative2.startsWith(`..${path9.sep}`) || path9.isAbsolute(relative2))
8998
8423
  continue;
8999
8424
  files.push({
9000
8425
  relativePath: canonicalChapterId(relative2),
9001
- ext: path10.extname(changedPath).toLowerCase(),
8426
+ ext: path9.extname(changedPath).toLowerCase(),
9002
8427
  event
9003
8428
  });
9004
8429
  }
@@ -9050,23 +8475,23 @@ function isIgnoredWatchPath(candidatePath, projectRoot) {
9050
8475
  return isDotPathUnderRoot(candidatePath, projectRoot) || isGeneratedProjectPath(relative2);
9051
8476
  }
9052
8477
  function isExternalWatchCandidate(candidatePath, targets) {
9053
- const candidate = path10.resolve(candidatePath);
8478
+ const candidate = path9.resolve(candidatePath);
9054
8479
  for (const rawTarget of targets) {
9055
- const target = path10.resolve(rawTarget);
9056
- const rel = path10.relative(candidate, target);
9057
- if (rel === "" || rel !== ".." && !rel.startsWith(`..${path10.sep}`) && !path10.isAbsolute(rel))
8480
+ const target = path9.resolve(rawTarget);
8481
+ const rel = path9.relative(candidate, target);
8482
+ if (rel === "" || rel !== ".." && !rel.startsWith(`..${path9.sep}`) && !path9.isAbsolute(rel))
9058
8483
  return true;
9059
8484
  }
9060
8485
  return false;
9061
8486
  }
9062
8487
  async function nearestExistingDirectory(start) {
9063
- let current = path10.resolve(start);
8488
+ let current = path9.resolve(start);
9064
8489
  while (true) {
9065
8490
  try {
9066
8491
  if ((await fsp3.stat(current)).isDirectory())
9067
8492
  return current;
9068
8493
  } catch {}
9069
- const parent = path10.dirname(current);
8494
+ const parent = path9.dirname(current);
9070
8495
  if (parent === current)
9071
8496
  return current;
9072
8497
  current = parent;
@@ -9075,7 +8500,7 @@ async function nearestExistingDirectory(start) {
9075
8500
  async function externalWatchRoots(targets) {
9076
8501
  const roots = new Set;
9077
8502
  for (const target of targets) {
9078
- roots.add(await nearestExistingDirectory(path10.dirname(path10.resolve(target))));
8503
+ roots.add(await nearestExistingDirectory(path9.dirname(path9.resolve(target))));
9079
8504
  }
9080
8505
  return [...roots];
9081
8506
  }
@@ -9089,19 +8514,19 @@ async function extensionFolderFiles(dir) {
9089
8514
  const meta = await readExtensionMeta(dir);
9090
8515
  const entry = extensionEntry(meta);
9091
8516
  return [
9092
- path10.join(dir, EXTENSION_MANIFEST_FILENAME),
9093
- ...entry ? [path10.resolve(dir, entry)] : [],
8517
+ path9.join(dir, EXTENSION_MANIFEST_FILENAME),
8518
+ ...entry ? [path9.resolve(dir, entry)] : [],
9094
8519
  ...await collectStyleDependencies(dir, extensionStyleList(meta))
9095
8520
  ];
9096
8521
  }
9097
8522
  async function externalWatchTargets(projectDir, config) {
9098
- const root = path10.resolve(projectDir);
8523
+ const root = path9.resolve(projectDir);
9099
8524
  let canonicalRoot = root;
9100
8525
  try {
9101
8526
  canonicalRoot = await fsp3.realpath(root);
9102
8527
  } catch {}
9103
8528
  const styles = await resolveActiveStyles(root, config.styles);
9104
- const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) => path10.resolve(root, p));
8529
+ const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) => path9.resolve(root, p));
9105
8530
  const candidates = [
9106
8531
  ...await collectStyleDependencies(root, styles),
9107
8532
  ...extensionPaths,
@@ -9109,17 +8534,17 @@ async function externalWatchTargets(projectDir, config) {
9109
8534
  ];
9110
8535
  const external = new Set;
9111
8536
  for (const abs of candidates) {
9112
- const authoredPath = path10.resolve(abs);
9113
- const authoredRel = path10.relative(root, authoredPath);
9114
- if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${path10.sep}`) || path10.isAbsolute(authoredRel))) {
8537
+ const authoredPath = path9.resolve(abs);
8538
+ const authoredRel = path9.relative(root, authoredPath);
8539
+ if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${path9.sep}`) || path9.isAbsolute(authoredRel))) {
9115
8540
  external.add(authoredPath);
9116
8541
  }
9117
8542
  let canonicalPath = authoredPath;
9118
8543
  try {
9119
8544
  canonicalPath = await fsp3.realpath(canonicalPath);
9120
8545
  } catch {}
9121
- const rel = path10.relative(canonicalRoot, canonicalPath);
9122
- if (rel === "" || rel !== ".." && !rel.startsWith(`..${path10.sep}`) && !path10.isAbsolute(rel))
8546
+ const rel = path9.relative(canonicalRoot, canonicalPath);
8547
+ if (rel === "" || rel !== ".." && !rel.startsWith(`..${path9.sep}`) && !path9.isAbsolute(rel))
9123
8548
  continue;
9124
8549
  external.add(canonicalPath);
9125
8550
  }
@@ -9146,7 +8571,7 @@ async function addAndAwaitWatch(watcher, roots) {
9146
8571
  }
9147
8572
  }
9148
8573
  function createFileWatcher(state) {
9149
- const inputResolved = path10.resolve(state.currentInputPath);
8574
+ const inputResolved = path9.resolve(state.currentInputPath);
9150
8575
  const watcher = watch(inputResolved, {
9151
8576
  persistent: true,
9152
8577
  ignoreInitial: true,
@@ -9186,7 +8611,7 @@ function createFileWatcher(state) {
9186
8611
  async function recordChange(event, filePath) {
9187
8612
  if (closed)
9188
8613
  return;
9189
- const target = path10.resolve(filePath);
8614
+ const target = path9.resolve(filePath);
9190
8615
  const settled = settledWrites.get(target);
9191
8616
  if (settled && event !== "unlink" && Date.now() <= settled.expiresAt) {
9192
8617
  const diskContent = await fsp3.readFile(target, "utf8").catch(() => null);
@@ -9207,7 +8632,7 @@ function createFileWatcher(state) {
9207
8632
  recordChange(event, filePath);
9208
8633
  });
9209
8634
  externalWatcher.on("all", (event, filePath) => {
9210
- const target = path10.resolve(filePath);
8635
+ const target = path9.resolve(filePath);
9211
8636
  if (!desiredExternals.has(target))
9212
8637
  return;
9213
8638
  if (event === "add" && suppressInitialExternalAdds.delete(target))
@@ -9215,8 +8640,8 @@ function createFileWatcher(state) {
9215
8640
  recordChange(event, target);
9216
8641
  });
9217
8642
  function isWatchedSource(target) {
9218
- const rel = path10.relative(inputResolved, target);
9219
- const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${path10.sep}`) && !path10.isAbsolute(rel);
8643
+ const rel = path9.relative(inputResolved, target);
8644
+ const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${path9.sep}`) && !path9.isAbsolute(rel);
9220
8645
  if (inProject)
9221
8646
  return !isIgnoredWatchPath(target, inputResolved);
9222
8647
  return desiredExternals.has(target);
@@ -9241,7 +8666,7 @@ function createFileWatcher(state) {
9241
8666
  state.notifySettledWrite = (filePath, writtenContent) => {
9242
8667
  if (closed)
9243
8668
  return;
9244
- const target = path10.resolve(filePath);
8669
+ const target = path9.resolve(filePath);
9245
8670
  if (isWatchedSource(target)) {
9246
8671
  acceptSettledWrite(target, writtenContent);
9247
8672
  return;
@@ -9262,7 +8687,7 @@ function createFileWatcher(state) {
9262
8687
  return;
9263
8688
  let nextTargets;
9264
8689
  try {
9265
- nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) => path10.resolve(target)));
8690
+ nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) => path9.resolve(target)));
9266
8691
  } catch (err) {
9267
8692
  debug(`Could not resolve external watch targets: ${err}`);
9268
8693
  return;
@@ -9394,7 +8819,7 @@ async function stopFileWatcher(state) {
9394
8819
  }
9395
8820
 
9396
8821
  // src/preview/lifecycle.ts
9397
- var TEMP_DIR_BASE = path11.join(tmpdir2(), "gutterpress-preview");
8822
+ var TEMP_DIR_BASE = path10.join(tmpdir2(), "gutterpress-preview");
9398
8823
  var PID_FILE_NAME = ".gutterpress.pid";
9399
8824
  function isProcessAlive(pid) {
9400
8825
  if (!Number.isFinite(pid) || pid <= 0)
@@ -9409,15 +8834,15 @@ function isProcessAlive(pid) {
9409
8834
  async function cleanupOrphanTempDirs() {
9410
8835
  let entries;
9411
8836
  try {
9412
- entries = await readdir4(TEMP_DIR_BASE);
8837
+ entries = await readdir3(TEMP_DIR_BASE);
9413
8838
  } catch {
9414
8839
  return;
9415
8840
  }
9416
8841
  for (const entry of entries) {
9417
- const dir = path11.join(TEMP_DIR_BASE, entry);
9418
- const pidFile = path11.join(dir, PID_FILE_NAME);
8842
+ const dir = path10.join(TEMP_DIR_BASE, entry);
8843
+ const pidFile = path10.join(dir, PID_FILE_NAME);
9419
8844
  try {
9420
- const raw = await readFile22(pidFile, "utf8");
8845
+ const raw = await readFile21(pidFile, "utf8");
9421
8846
  const pid = parseInt(raw.trim(), 10);
9422
8847
  if (!isProcessAlive(pid)) {
9423
8848
  debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
@@ -9429,10 +8854,10 @@ async function cleanupOrphanTempDirs() {
9429
8854
  async function initializePreviewDirectories() {
9430
8855
  await cleanupOrphanTempDirs();
9431
8856
  const tempDirSuffix = randomBytes2(8).toString("hex");
9432
- const tempDir = path11.join(TEMP_DIR_BASE, tempDirSuffix);
8857
+ const tempDir = path10.join(TEMP_DIR_BASE, tempDirSuffix);
9433
8858
  await mkdir4(tempDir);
9434
8859
  debug(`Created temporary directory: ${tempDir}`);
9435
- await writeFile5(path11.join(tempDir, PID_FILE_NAME), `${process.pid}
8860
+ await writeFile5(path10.join(tempDir, PID_FILE_NAME), `${process.pid}
9436
8861
  `, "utf8");
9437
8862
  return tempDir;
9438
8863
  }
@@ -9522,13 +8947,13 @@ function createServerState(inputPath, tempDir, config, options) {
9522
8947
  // src/preview/http-server.ts
9523
8948
  import http from "node:http";
9524
8949
  import net from "node:net";
9525
- import { createHash as createHash6, randomUUID } from "node:crypto";
9526
- import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
9527
- import path13 from "path";
8950
+ import { createHash as createHash5, randomUUID } from "node:crypto";
8951
+ import { readFile as readFile22, stat as stat4 } from "node:fs/promises";
8952
+ import path12 from "path";
9528
8953
  import { WebSocket, WebSocketServer } from "ws";
9529
8954
 
9530
8955
  // src/lib/static-serve.ts
9531
- import path12 from "node:path";
8956
+ import path11 from "node:path";
9532
8957
  var STATIC_MIME = {
9533
8958
  ".html": "text/html; charset=utf-8",
9534
8959
  ".htm": "text/html; charset=utf-8",
@@ -9550,9 +8975,9 @@ var STATIC_MIME = {
9550
8975
  ".otf": "font/otf"
9551
8976
  };
9552
8977
  function resolveWithinRoot(relPath, root) {
9553
- const resolvedRoot = path12.resolve(root);
9554
- const candidate = path12.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
9555
- if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path12.sep)) {
8978
+ const resolvedRoot = path11.resolve(root);
8979
+ const candidate = path11.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
8980
+ if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path11.sep)) {
9556
8981
  return null;
9557
8982
  }
9558
8983
  return candidate;
@@ -9805,7 +9230,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
9805
9230
  try {
9806
9231
  const s = await stat4(filePath);
9807
9232
  if (s.isDirectory())
9808
- filePath = path13.join(filePath, "index.html");
9233
+ filePath = path12.join(filePath, "index.html");
9809
9234
  } catch {
9810
9235
  res.writeHead(404);
9811
9236
  res.end("Not Found");
@@ -9813,7 +9238,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
9813
9238
  }
9814
9239
  let data;
9815
9240
  try {
9816
- data = await readFile23(filePath);
9241
+ data = await readFile22(filePath);
9817
9242
  } catch {
9818
9243
  res.writeHead(404);
9819
9244
  res.end("Not Found");
@@ -9826,7 +9251,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
9826
9251
  res.end(withHmr);
9827
9252
  return;
9828
9253
  }
9829
- const ct = STATIC_MIME[path13.extname(filePath).toLowerCase()] ?? "application/octet-stream";
9254
+ const ct = STATIC_MIME[path12.extname(filePath).toLowerCase()] ?? "application/octet-stream";
9830
9255
  res.writeHead(200, { "Content-Type": ct, "Cache-Control": cacheControl, ...extraHeaders });
9831
9256
  res.end(data);
9832
9257
  }
@@ -9836,7 +9261,7 @@ var EMBEDDED_CACHE_CONTROL = "public, no-cache";
9836
9261
  var EMBEDDED_ETAG = `"gutterpress-${PACKAGE_VERSION}"`;
9837
9262
  var PROJECT_ASSET_CACHE_CONTROL = "private, no-cache";
9838
9263
  async function serveRevalidatedStatic(req, absPath, res, validators) {
9839
- const extension = path13.extname(absPath).toLowerCase();
9264
+ const extension = path12.extname(absPath).toLowerCase();
9840
9265
  if (extension === ".html" || extension === ".htm") {
9841
9266
  await serveStatic(absPath, res);
9842
9267
  return;
@@ -9863,12 +9288,12 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
9863
9288
  let data;
9864
9289
  if (!validator || validator.stamp !== stamp) {
9865
9290
  try {
9866
- data = await readFile23(absPath);
9291
+ data = await readFile22(absPath);
9867
9292
  } catch {
9868
9293
  await serveStatic(absPath, res);
9869
9294
  return;
9870
9295
  }
9871
- const digest = createHash6("sha256").update(data).digest("base64url");
9296
+ const digest = createHash5("sha256").update(data).digest("base64url");
9872
9297
  validator = { stamp, etag: `"gutterpress-file-${digest}"` };
9873
9298
  validators.set(absPath, validator);
9874
9299
  }
@@ -10002,7 +9427,7 @@ async function createPreviewServer(state, port) {
10002
9427
  const file = rawFile ? canonicalChapterId(rawFile) : "";
10003
9428
  const revision = Number(url.searchParams.get("revision"));
10004
9429
  const configuredFiles = state.config.source?.files;
10005
- if (!file || !state.currentInputPath || !incrementalPreviewEnabled() || !Number.isSafeInteger(revision) || revision !== reloadRevision || path13.extname(file).toLowerCase() !== ".md" || hasDotSegment(file) || !resolveWithinRoot(file, state.currentInputPath) || Array.isArray(configuredFiles) && configuredFiles.length > 0 && !configuredFiles.some((configured) => canonicalChapterId(configured) === file)) {
9430
+ if (!file || !state.currentInputPath || !incrementalPreviewEnabled() || !Number.isSafeInteger(revision) || revision !== reloadRevision || path12.extname(file).toLowerCase() !== ".md" || hasDotSegment(file) || !resolveWithinRoot(file, state.currentInputPath) || Array.isArray(configuredFiles) && configuredFiles.length > 0 && !configuredFiles.some((configured) => canonicalChapterId(configured) === file)) {
10006
9431
  res.writeHead(400);
10007
9432
  res.end("Bad Request");
10008
9433
  return;
@@ -10202,25 +9627,25 @@ async function startPreviewServer(options) {
10202
9627
  }
10203
9628
 
10204
9629
  // src/lib/project-scaffold.ts
10205
- import { access, copyFile, cp as cp2, mkdir as mkdir6, readdir as readdir5, readFile as readFile25, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
9630
+ import { access, copyFile, cp as cp2, mkdir as mkdir6, readdir as readdir4, readFile as readFile24, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
10206
9631
  import { constants as FS, existsSync as existsSync11 } from "node:fs";
10207
- import path15 from "node:path";
9632
+ import path14 from "node:path";
10208
9633
 
10209
9634
  // src/lib/manifest-doc.ts
10210
9635
  import { existsSync as existsSync10 } from "node:fs";
10211
9636
  import { randomUUID as randomUUID2 } from "node:crypto";
10212
- import { mkdir as mkdir5, open, readFile as readFile24, rename, rm as rm2 } from "node:fs/promises";
10213
- import path14 from "node:path";
9637
+ import { mkdir as mkdir5, open, readFile as readFile23, rename, rm as rm2 } from "node:fs/promises";
9638
+ import path13 from "node:path";
10214
9639
  import { parseDocument, isSeq, YAMLSeq } from "yaml";
10215
9640
  function resolveManifestPath(projectDir) {
10216
- const existing = MANIFEST_FILENAMES.find((name) => existsSync10(path14.join(projectDir, name)));
10217
- return path14.join(projectDir, existing ?? MANIFEST_FILENAMES[0]);
9641
+ const existing = MANIFEST_FILENAMES.find((name) => existsSync10(path13.join(projectDir, name)));
9642
+ return path13.join(projectDir, existing ?? MANIFEST_FILENAMES[0]);
10218
9643
  }
10219
9644
  async function loadManifestDoc(projectDir) {
10220
9645
  const file = resolveManifestPath(projectDir);
10221
9646
  let text = "";
10222
9647
  try {
10223
- text = await readFile24(file, "utf8");
9648
+ text = await readFile23(file, "utf8");
10224
9649
  } catch (error2) {
10225
9650
  if (error2.code !== "ENOENT")
10226
9651
  throw error2;
@@ -10228,9 +9653,9 @@ async function loadManifestDoc(projectDir) {
10228
9653
  return { doc: parseDocument(text), file };
10229
9654
  }
10230
9655
  async function writeManifestDoc(file, doc) {
10231
- const dir = path14.dirname(file);
9656
+ const dir = path13.dirname(file);
10232
9657
  await mkdir5(dir, { recursive: true });
10233
- const temporary = path14.join(dir, `.${path14.basename(file)}.tmp-${process.pid}-${randomUUID2()}`);
9658
+ const temporary = path13.join(dir, `.${path13.basename(file)}.tmp-${process.pid}-${randomUUID2()}`);
10234
9659
  try {
10235
9660
  const handle = await open(temporary, "wx", 438);
10236
9661
  try {
@@ -10332,7 +9757,7 @@ async function scaffoldProject(options) {
10332
9757
  throw new CreateProjectErrorImpl("invalid-name", `Could not derive a valid folder name from "${name}".`);
10333
9758
  }
10334
9759
  const parentDir = options.parentDir;
10335
- if (!parentDir || !path15.isAbsolute(parentDir)) {
9760
+ if (!parentDir || !path14.isAbsolute(parentDir)) {
10336
9761
  throw new CreateProjectErrorImpl("parent-not-writable", "The save location must be an absolute path.");
10337
9762
  }
10338
9763
  try {
@@ -10340,7 +9765,7 @@ async function scaffoldProject(options) {
10340
9765
  } catch {
10341
9766
  throw new CreateProjectErrorImpl("parent-not-writable", `The chosen save location can't be written to: ${parentDir}`);
10342
9767
  }
10343
- const projectDir = path15.join(parentDir, folderName);
9768
+ const projectDir = path14.join(parentDir, folderName);
10344
9769
  let targetExists = true;
10345
9770
  try {
10346
9771
  await access(projectDir, FS.F_OK);
@@ -10357,21 +9782,21 @@ async function scaffoldProject(options) {
10357
9782
  try {
10358
9783
  await mkdir6(projectDir, { recursive: true });
10359
9784
  if (customTemplateDir) {
10360
- const entries = await readdir5(customTemplateDir, { withFileTypes: true });
9785
+ const entries = await readdir4(customTemplateDir, { withFileTypes: true });
10361
9786
  for (const entry of entries) {
10362
9787
  if (entry.name === ".gutterpress-template.json")
10363
9788
  continue;
10364
- await cp2(path15.join(customTemplateDir, entry.name), path15.join(projectDir, entry.name), { recursive: true });
9789
+ await cp2(path14.join(customTemplateDir, entry.name), path14.join(projectDir, entry.name), { recursive: true });
10365
9790
  }
10366
- await mkdir6(path15.join(projectDir, "assets"), { recursive: true });
9791
+ await mkdir6(path14.join(projectDir, "assets"), { recursive: true });
10367
9792
  } else {
10368
9793
  const tplManifest = await getAssetPath(`templates/${template}/manifest.yaml`);
10369
9794
  const tplChapter = await getAssetPath(`templates/${template}/chapter-01.md`);
10370
- await mkdir6(path15.join(projectDir, "assets"), { recursive: true });
10371
- await copyFile(tplManifest, path15.join(projectDir, MANIFEST_FILENAMES[0]));
10372
- await copyFile(tplChapter, path15.join(projectDir, "chapter-01.md"));
10373
- await mkdir6(path15.join(projectDir, "styles"), { recursive: true });
10374
- await writeFile6(path15.join(projectDir, "styles", "book.css"), starterOverridesCss(), "utf8");
9795
+ await mkdir6(path14.join(projectDir, "assets"), { recursive: true });
9796
+ await copyFile(tplManifest, path14.join(projectDir, MANIFEST_FILENAMES[0]));
9797
+ await copyFile(tplChapter, path14.join(projectDir, "chapter-01.md"));
9798
+ await mkdir6(path14.join(projectDir, "styles"), { recursive: true });
9799
+ await writeFile6(path14.join(projectDir, "styles", "book.css"), starterOverridesCss(), "utf8");
10375
9800
  }
10376
9801
  } catch (e) {
10377
9802
  throw new CreateProjectErrorImpl("scaffold-io", `Could not create the book files: ${e instanceof Error ? e.message : String(e)}`);
@@ -10381,13 +9806,13 @@ async function scaffoldProject(options) {
10381
9806
  } catch (e) {
10382
9807
  throw new CreateProjectErrorImpl("scaffold-io", `Could not write .gitignore: ${e instanceof Error ? e.message : String(e)}`);
10383
9808
  }
10384
- const manifestPath = MANIFEST_FILENAMES.map((name2) => path15.join(projectDir, name2)).find(existsSync11) ?? path15.join(projectDir, MANIFEST_FILENAMES[0]);
9809
+ const manifestPath = MANIFEST_FILENAMES.map((name2) => path14.join(projectDir, name2)).find(existsSync11) ?? path14.join(projectDir, MANIFEST_FILENAMES[0]);
10385
9810
  const author = (options.author ?? "").trim() || DEFAULT_AUTHOR;
10386
9811
  const substitutions = {
10387
9812
  "{{TITLE}}": escapeYamlScalar(name),
10388
9813
  "{{AUTHOR}}": escapeYamlScalar(author)
10389
9814
  };
10390
- let openFile = path15.join(projectDir, "chapter-01.md");
9815
+ let openFile = path14.join(projectDir, "chapter-01.md");
10391
9816
  try {
10392
9817
  await fillTemplateFile(manifestPath, substitutions);
10393
9818
  if (preset) {
@@ -10408,7 +9833,7 @@ async function scaffoldProject(options) {
10408
9833
  }
10409
9834
  const firstSource = await firstSourceFile(manifestPath);
10410
9835
  if (firstSource)
10411
- openFile = path15.join(projectDir, firstSource);
9836
+ openFile = path14.join(projectDir, firstSource);
10412
9837
  await fillTemplateFile(openFile, { "{{TITLE}}": name }).catch(() => {});
10413
9838
  } catch (e) {
10414
9839
  throw new CreateProjectErrorImpl("scaffold-io", `Could not finalize the book files: ${e instanceof Error ? e.message : String(e)}`);
@@ -10418,7 +9843,7 @@ async function scaffoldProject(options) {
10418
9843
  let versionHistoryError;
10419
9844
  if (requested === "local-git") {
10420
9845
  try {
10421
- const { providerFor } = await import("./source-provider-exy1wakv.js");
9846
+ const { providerFor } = await import("./source-provider-gy3cn7kw.js");
10422
9847
  const provider = providerFor({ type: "local-folder", path: projectDir });
10423
9848
  await provider.initVersionHistory({
10424
9849
  projectDir,
@@ -10430,7 +9855,7 @@ async function scaffoldProject(options) {
10430
9855
  versionHistory = "none";
10431
9856
  const { findEnclosingRepoDir } = await import("./project-source-ekcyp63q.js");
10432
9857
  const enclosingRepoDir = await findEnclosingRepoDir(projectDir);
10433
- versionHistoryError = enclosingRepoDir ? `This book was added to ${path15.basename(enclosingRepoDir)}'s shared version history; save a snapshot to record it.` : e instanceof Error ? e.message : String(e);
9858
+ versionHistoryError = enclosingRepoDir ? `This book was added to ${path14.basename(enclosingRepoDir)}'s shared version history; save a snapshot to record it.` : e instanceof Error ? e.message : String(e);
10434
9859
  }
10435
9860
  }
10436
9861
  const result = {
@@ -10445,10 +9870,10 @@ async function scaffoldProject(options) {
10445
9870
  return result;
10446
9871
  }
10447
9872
  async function ensureGitignoreHasDist(projectDir) {
10448
- const gitignorePath = path15.join(projectDir, ".gitignore");
9873
+ const gitignorePath = path14.join(projectDir, ".gitignore");
10449
9874
  let existing = null;
10450
9875
  try {
10451
- existing = await readFile25(gitignorePath, "utf8");
9876
+ existing = await readFile24(gitignorePath, "utf8");
10452
9877
  } catch {}
10453
9878
  if (existing === null) {
10454
9879
  await writeFile6(gitignorePath, `dist/
@@ -10468,7 +9893,7 @@ async function ensureGitignoreHasDist(projectDir) {
10468
9893
  async function firstSourceFile(manifestPath) {
10469
9894
  let text;
10470
9895
  try {
10471
- text = await readFile25(manifestPath, "utf8");
9896
+ text = await readFile24(manifestPath, "utf8");
10472
9897
  } catch {
10473
9898
  return;
10474
9899
  }
@@ -10480,7 +9905,7 @@ async function firstSourceFile(manifestPath) {
10480
9905
  return m ? m[1].trim() : undefined;
10481
9906
  }
10482
9907
  async function fillTemplateFile(filePath, substitutions) {
10483
- let text = await readFile25(filePath, "utf8");
9908
+ let text = await readFile24(filePath, "utf8");
10484
9909
  for (const [token, value] of Object.entries(substitutions)) {
10485
9910
  text = text.split(token).join(value);
10486
9911
  }
@@ -10488,9 +9913,9 @@ async function fillTemplateFile(filePath, substitutions) {
10488
9913
  }
10489
9914
 
10490
9915
  // src/lib/extension-scaffold.ts
10491
- import { access as access2, mkdir as mkdir7, readFile as readFile26, writeFile as writeFile7 } from "node:fs/promises";
9916
+ import { access as access2, mkdir as mkdir7, readFile as readFile25, writeFile as writeFile7 } from "node:fs/promises";
10492
9917
  import { constants as FS2 } from "node:fs";
10493
- import path16 from "node:path";
9918
+ import path15 from "node:path";
10494
9919
  var EXTENSION_KINDS = ["plugin", "theme"];
10495
9920
  var RESERVED_PREFIX = "gp-";
10496
9921
  var TEMPLATE_FILES = {
@@ -10568,7 +9993,7 @@ async function scaffoldExtension(options) {
10568
9993
  }
10569
9994
  const prefix = resolveExtensionPrefix(slug, options.prefix);
10570
9995
  const parentDir = options.parentDir;
10571
- if (!parentDir || !path16.isAbsolute(parentDir)) {
9996
+ if (!parentDir || !path15.isAbsolute(parentDir)) {
10572
9997
  throw new ExtensionScaffoldError("parent-not-writable", "The save location must be an absolute path.");
10573
9998
  }
10574
9999
  try {
@@ -10576,7 +10001,7 @@ async function scaffoldExtension(options) {
10576
10001
  } catch {
10577
10002
  throw new ExtensionScaffoldError("parent-not-writable", `The chosen save location can't be written to: ${parentDir}`);
10578
10003
  }
10579
- const extensionDir = path16.join(parentDir, slug);
10004
+ const extensionDir = path15.join(parentDir, slug);
10580
10005
  let targetExists = true;
10581
10006
  try {
10582
10007
  await access2(extensionDir, FS2.F_OK);
@@ -10603,9 +10028,9 @@ async function scaffoldExtension(options) {
10603
10028
  await mkdir7(extensionDir, { recursive: true });
10604
10029
  for (const [assetName, relDest] of entries) {
10605
10030
  const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
10606
- const dest = path16.join(extensionDir, relDest);
10607
- await mkdir7(path16.dirname(dest), { recursive: true });
10608
- const text = await readFile26(src, "utf8");
10031
+ const dest = path15.join(extensionDir, relDest);
10032
+ await mkdir7(path15.dirname(dest), { recursive: true });
10033
+ const text = await readFile25(src, "utf8");
10609
10034
  const table = relDest.endsWith(".json") ? jsonSafe : plain;
10610
10035
  await writeFile7(dest, substitute(text, table), "utf8");
10611
10036
  written.push(relDest);
@@ -10615,11 +10040,11 @@ async function scaffoldExtension(options) {
10615
10040
  }
10616
10041
  return {
10617
10042
  extensionDir,
10618
- manifestPath: path16.join(extensionDir, "package.json"),
10043
+ manifestPath: path15.join(extensionDir, "package.json"),
10619
10044
  kind,
10620
10045
  slug,
10621
10046
  prefix,
10622
- openFile: path16.join(extensionDir, OPEN_FILE[kind]),
10047
+ openFile: path15.join(extensionDir, OPEN_FILE[kind]),
10623
10048
  files: written
10624
10049
  };
10625
10050
  }
@@ -10649,29 +10074,29 @@ var SKIP_ENTRIES = new Set([
10649
10074
  ]);
10650
10075
 
10651
10076
  // src/lib/extension-manager.ts
10652
- import { cp as cp3, mkdir as mkdir9, readFile as readFile28, rm as rm4, stat as stat6 } from "node:fs/promises";
10077
+ import { cp as cp3, mkdir as mkdir9, readFile as readFile27, rm as rm4, stat as stat6 } from "node:fs/promises";
10653
10078
  import { existsSync as existsSync12 } from "node:fs";
10654
- import path18 from "node:path";
10079
+ import path17 from "node:path";
10655
10080
  import { isSeq as isSeq3, isMap as isMap2, isScalar as isScalar2, YAMLMap, Scalar } from "yaml";
10656
10081
 
10657
10082
  // src/lib/npm-plugin-installer.ts
10658
- import { createHash as createHash7, randomUUID as randomUUID3, timingSafeEqual } from "node:crypto";
10659
- import { createReadStream as createReadStream2 } from "node:fs";
10083
+ import { createHash as createHash6, randomUUID as randomUUID3, timingSafeEqual } from "node:crypto";
10084
+ import { createReadStream } from "node:fs";
10660
10085
  import {
10661
- lstat as lstat2,
10086
+ lstat,
10662
10087
  mkdir as mkdir8,
10663
10088
  mkdtemp as mkdtemp2,
10664
10089
  open as open2,
10665
- readFile as readFile27,
10666
- realpath as realpath2,
10090
+ readFile as readFile26,
10091
+ realpath,
10667
10092
  rename as rename2,
10668
10093
  rm as rm3
10669
10094
  } from "node:fs/promises";
10670
- import path17 from "node:path";
10095
+ import path16 from "node:path";
10671
10096
  import { Transform } from "node:stream";
10672
10097
  import { pipeline } from "node:stream/promises";
10673
10098
  import { createGunzip } from "node:zlib";
10674
- import { maxSatisfying, satisfies as satisfies2, validRange as validRange2 } from "semver";
10099
+ import { maxSatisfying, satisfies, validRange } from "semver";
10675
10100
 
10676
10101
  // src/lib/fetch-timeout.ts
10677
10102
  class FetchPassthroughError extends Error {
@@ -10728,11 +10153,11 @@ class PackageUnavailableError extends Error {
10728
10153
  function isOptionalAvailabilityError(error2) {
10729
10154
  return error2 instanceof PackageUnavailableError || error2 instanceof FriendlyHttpError || error2 instanceof FetchUnavailableError;
10730
10155
  }
10731
- function object3(value) {
10156
+ function object2(value) {
10732
10157
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
10733
10158
  }
10734
- function stringMap2(value) {
10735
- const map = object3(value);
10159
+ function stringMap(value) {
10160
+ const map = object2(value);
10736
10161
  if (!map)
10737
10162
  return {};
10738
10163
  const result = {};
@@ -10745,9 +10170,9 @@ function stringMap2(value) {
10745
10170
  function mb(bytes) {
10746
10171
  return `${Math.ceil(bytes / 1024 / 1024)}MB`;
10747
10172
  }
10748
- function isContained2(root, candidate) {
10749
- const relative2 = path17.relative(root, candidate);
10750
- return relative2 === "" || !relative2.startsWith("..") && !path17.isAbsolute(relative2);
10173
+ function isContained(root, candidate) {
10174
+ const relative2 = path16.relative(root, candidate);
10175
+ return relative2 === "" || !relative2.startsWith("..") && !path16.isAbsolute(relative2);
10751
10176
  }
10752
10177
  function mergeLimits(overrides) {
10753
10178
  const limits = { ...DEFAULT_LIMITS, ...overrides };
@@ -10825,7 +10250,7 @@ async function fetchPackument(ctx, name) {
10825
10250
  }
10826
10251
  let metadata = null;
10827
10252
  try {
10828
- metadata = object3(JSON.parse(new TextDecoder().decode(bytes)));
10253
+ metadata = object2(JSON.parse(new TextDecoder().decode(bytes)));
10829
10254
  } catch {}
10830
10255
  if (!metadata || metadata.name !== name) {
10831
10256
  throw new FriendlyHttpError(`npm returned invalid metadata for "${name}".`);
@@ -10881,29 +10306,29 @@ async function selectPackage(ctx, name, selector) {
10881
10306
  throw new PackageUnavailableError(`Dependency selector "${selector}" for ${name} is not a registry semver range or dist-tag.`);
10882
10307
  }
10883
10308
  const metadata = await fetchPackument(ctx, name);
10884
- const versions = object3(metadata.versions);
10885
- const tags = object3(metadata["dist-tags"]);
10309
+ const versions = object2(metadata.versions);
10310
+ const tags = object2(metadata["dist-tags"]);
10886
10311
  if (!versions || !tags)
10887
10312
  throw new PackageUnavailableError(`npm metadata for "${name}" has no versions.`);
10888
10313
  let version;
10889
10314
  if (!selector) {
10890
10315
  if (typeof tags.latest === "string")
10891
10316
  version = tags.latest;
10892
- } else if (object3(versions[selector])) {
10317
+ } else if (object2(versions[selector])) {
10893
10318
  version = selector;
10894
10319
  } else if (typeof tags[selector] === "string") {
10895
10320
  version = tags[selector];
10896
- } else if (validRange2(selector)) {
10321
+ } else if (validRange(selector)) {
10897
10322
  version = maxSatisfying(Object.keys(versions), selector) ?? undefined;
10898
10323
  }
10899
10324
  if (!version || !isExactNpmVersion(version)) {
10900
10325
  throw new PackageUnavailableError(`No exact npm version of "${name}" satisfies "${selector ?? "latest"}".`);
10901
10326
  }
10902
- const selected = object3(versions[version]);
10327
+ const selected = object2(versions[version]);
10903
10328
  if (!selected || selected.name !== name || selected.version !== version) {
10904
10329
  throw new SecurityInstallError(`npm metadata identity failed for "${name}@${version}".`);
10905
10330
  }
10906
- const dist = object3(selected.dist);
10331
+ const dist = object2(selected.dist);
10907
10332
  if (!dist || typeof dist.tarball !== "string") {
10908
10333
  throw new PackageUnavailableError(`npm metadata for "${name}@${version}" has no tarball.`);
10909
10334
  }
@@ -10920,7 +10345,7 @@ async function selectPackage(ctx, name, selector) {
10920
10345
  }
10921
10346
  async function downloadTarball(ctx, pkg, archivePath) {
10922
10347
  const file = await open2(archivePath, "wx");
10923
- const hash = createHash7(pkg.integrity.algorithm);
10348
+ const hash = createHash6(pkg.integrity.algorithm);
10924
10349
  try {
10925
10350
  await withFetchTimeout({
10926
10351
  timeoutMs: TARBALL_TIMEOUT_MS,
@@ -11042,7 +10467,7 @@ async function extractTarball(ctx, archivePath, packageDir, packageName) {
11042
10467
  }
11043
10468
  });
11044
10469
  try {
11045
- await pipeline(createReadStream2(archivePath), createGunzip(), limiter, unpack);
10470
+ await pipeline(createReadStream(archivePath), createGunzip(), limiter, unpack);
11046
10471
  } catch (error2) {
11047
10472
  if (rejected)
11048
10473
  throw rejected;
@@ -11054,13 +10479,13 @@ async function extractTarball(ctx, archivePath, packageDir, packageName) {
11054
10479
  throw rejected;
11055
10480
  }
11056
10481
  async function readInstalledManifest(packageDir, selected) {
11057
- const packageJsonPath = path17.join(packageDir, "package.json");
10482
+ const packageJsonPath = path16.join(packageDir, "package.json");
11058
10483
  let manifest = null;
11059
10484
  try {
11060
- const info2 = await lstat2(packageJsonPath);
10485
+ const info2 = await lstat(packageJsonPath);
11061
10486
  if (!info2.isFile() || info2.isSymbolicLink())
11062
10487
  throw new Error("not a regular file");
11063
- manifest = object3(JSON.parse(await readFile27(packageJsonPath, "utf8")));
10488
+ manifest = object2(JSON.parse(await readFile26(packageJsonPath, "utf8")));
11064
10489
  } catch (error2) {
11065
10490
  throw new SecurityInstallError(`Downloaded ${selected.name}@${selected.version} has no valid package.json (${error2 instanceof Error ? error2.message : String(error2)}).`);
11066
10491
  }
@@ -11123,17 +10548,17 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
11123
10548
  }
11124
10549
  throw error2;
11125
10550
  }
11126
- const ancestor = ancestors.find((candidate) => candidate.name === name && (candidate.version === selected.version || (selector ? satisfies2(candidate.version, selector) : false)));
10551
+ const ancestor = ancestors.find((candidate) => candidate.name === name && (candidate.version === selected.version || (selector ? satisfies(candidate.version, selector) : false)));
11127
10552
  if (ancestor)
11128
10553
  return { path: ancestor.path };
11129
10554
  if (ctx.records.length >= ctx.limits.totalPackages) {
11130
10555
  throw new SecurityInstallError(`Dependency graph exceeds ${ctx.limits.totalPackages} packages.`);
11131
10556
  }
11132
10557
  const relativePath = relativePackagePath(parentPackagePath, name);
11133
- const packageDir = path17.join(ctx.stageRoot, ...relativePath.split("/"));
11134
- const archivePath = path17.join(ctx.downloadsDir, `${ctx.archiveCounter++}.tgz`);
10558
+ const packageDir = path16.join(ctx.stageRoot, ...relativePath.split("/"));
10559
+ const archivePath = path16.join(ctx.downloadsDir, `${ctx.archiveCounter++}.tgz`);
11135
10560
  try {
11136
- await mkdir8(path17.dirname(packageDir), { recursive: true });
10561
+ await mkdir8(path16.dirname(packageDir), { recursive: true });
11137
10562
  await downloadTarball(ctx, selected, archivePath);
11138
10563
  await extractTarball(ctx, archivePath, packageDir, selected.name);
11139
10564
  const manifest = await readInstalledManifest(packageDir, selected);
@@ -11167,19 +10592,19 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
11167
10592
  if (selected.integrity.legacySha1) {
11168
10593
  ctx.warnings.add(`${name}@${selected.version} is an old npm release with only SHA-1 registry integrity. It was accepted for compatibility and recorded as legacy SHA-1 in the vendor receipt.`);
11169
10594
  }
11170
- const dependencies = stringMap2(manifest.dependencies);
11171
- const optionalDependencies = stringMap2(manifest.optionalDependencies);
10595
+ const dependencies = stringMap(manifest.dependencies);
10596
+ const optionalDependencies = stringMap(manifest.optionalDependencies);
11172
10597
  for (const optionalName of Object.keys(optionalDependencies))
11173
10598
  delete dependencies[optionalName];
11174
- const peerDependencies = stringMap2(manifest.peerDependencies);
11175
- const peerMeta = object3(manifest.peerDependenciesMeta) ?? {};
10599
+ const peerDependencies = stringMap(manifest.peerDependencies);
10600
+ const peerMeta = object2(manifest.peerDependenciesMeta) ?? {};
11176
10601
  for (const existing of [...Object.keys(dependencies), ...Object.keys(optionalDependencies)]) {
11177
10602
  delete peerDependencies[existing];
11178
10603
  }
11179
10604
  const nextAncestors = [...ancestors, record];
11180
10605
  const requiredEntries = [
11181
10606
  ...Object.entries(dependencies).map(([dependency, range]) => ({ dependency, range, kind: "required" })),
11182
- ...Object.entries(peerDependencies).filter(([dependency]) => object3(peerMeta[dependency])?.optional !== true).map(([dependency, range]) => ({ dependency, range, kind: "peer" }))
10607
+ ...Object.entries(peerDependencies).filter(([dependency]) => object2(peerMeta[dependency])?.optional !== true).map(([dependency, range]) => ({ dependency, range, kind: "peer" }))
11183
10608
  ].sort((a, b) => a.dependency.localeCompare(b.dependency));
11184
10609
  for (const { dependency, range } of requiredEntries) {
11185
10610
  const child = await installPackage(ctx, dependency, range, relativePath, nextAncestors, depth + 1, false);
@@ -11197,7 +10622,7 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
11197
10622
  }
11198
10623
  }
11199
10624
  for (const [dependency, range] of Object.entries(peerDependencies)) {
11200
- if (object3(peerMeta[dependency])?.optional === true) {
10625
+ if (object2(peerMeta[dependency])?.optional === true) {
11201
10626
  ctx.skipped.push({
11202
10627
  from: relativePath,
11203
10628
  name: dependency,
@@ -11221,7 +10646,7 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
11221
10646
  }
11222
10647
  async function ensureDirectory(pathname) {
11223
10648
  try {
11224
- const info2 = await lstat2(pathname);
10649
+ const info2 = await lstat(pathname);
11225
10650
  if (info2.isSymbolicLink() || !info2.isDirectory()) {
11226
10651
  throw new Error(`Plugin install path is not a normal directory: ${pathname}`);
11227
10652
  }
@@ -11232,18 +10657,18 @@ async function ensureDirectory(pathname) {
11232
10657
  }
11233
10658
  }
11234
10659
  async function prepareVendorParent(projectDir, name) {
11235
- const plugins = path17.join(projectDir, PLUGINS_DIR);
11236
- const npm = path17.join(plugins, VENDORED_NPM_DIR);
11237
- const packageParent = path17.dirname(vendoredNpmPluginRoot(projectDir, name, "0.0.0"));
10660
+ const plugins = path16.join(projectDir, PLUGINS_DIR);
10661
+ const npm = path16.join(plugins, VENDORED_NPM_DIR);
10662
+ const packageParent = path16.dirname(vendoredNpmPluginRoot(projectDir, name, "0.0.0"));
11238
10663
  await mkdir8(projectDir, { recursive: true });
11239
10664
  await ensureDirectory(plugins);
11240
10665
  await ensureDirectory(npm);
11241
10666
  await ensureDirectory(packageParent);
11242
10667
  const [realNpm, realPackageParent] = await Promise.all([
11243
- realpath2(npm),
11244
- realpath2(packageParent)
10668
+ realpath(npm),
10669
+ realpath(packageParent)
11245
10670
  ]);
11246
- if (!isContained2(projectDir, realNpm) || !isContained2(projectDir, realPackageParent)) {
10671
+ if (!isContained(projectDir, realNpm) || !isContained(projectDir, realPackageParent)) {
11247
10672
  throw new Error("Plugin install path resolves outside the book folder.");
11248
10673
  }
11249
10674
  return realNpm;
@@ -11262,14 +10687,14 @@ function publicReceipt(record) {
11262
10687
  };
11263
10688
  }
11264
10689
  async function installNpmPlugin(projectDirInput, packageSpec, options = {}) {
11265
- const requestedProjectDir = path17.resolve(projectDirInput);
10690
+ const requestedProjectDir = path16.resolve(projectDirInput);
11266
10691
  await mkdir8(requestedProjectDir, { recursive: true });
11267
- const projectDir = await realpath2(requestedProjectDir);
10692
+ const projectDir = await realpath(requestedProjectDir);
11268
10693
  const requested = parseNpmPluginSpec(packageSpec);
11269
10694
  const npmRoot = await prepareVendorParent(projectDir, requested.name);
11270
- const container = await mkdtemp2(path17.join(npmRoot, ".install-"));
11271
- const stageRoot = path17.join(container, "root");
11272
- const downloadsDir = path17.join(container, "downloads");
10695
+ const container = await mkdtemp2(path16.join(npmRoot, ".install-"));
10696
+ const stageRoot = path16.join(container, "root");
10697
+ const downloadsDir = path16.join(container, "downloads");
11273
10698
  await Promise.all([mkdir8(stageRoot), mkdir8(downloadsDir)]);
11274
10699
  const ctx = {
11275
10700
  fetch: options.fetch ?? globalThis.fetch,
@@ -11315,7 +10740,7 @@ async function installNpmPlugin(projectDirInput, packageSpec, options = {}) {
11315
10740
  skipped: ctx.skipped,
11316
10741
  tree: { algorithm: "sha256", ...tree }
11317
10742
  };
11318
- const receiptFile = await open2(path17.join(stageRoot, VENDOR_RECEIPT_FILE), "wx");
10743
+ const receiptFile = await open2(path16.join(stageRoot, VENDOR_RECEIPT_FILE), "wx");
11319
10744
  try {
11320
10745
  await receiptFile.writeFile(`${JSON.stringify(receipt, null, 2)}
11321
10746
  `, "utf8");
@@ -11324,12 +10749,12 @@ async function installNpmPlugin(projectDirInput, packageSpec, options = {}) {
11324
10749
  await receiptFile.close();
11325
10750
  }
11326
10751
  finalRoot = vendoredNpmPluginRoot(projectDir, rootRecord.name, rootRecord.version);
11327
- const realFinalParent = await realpath2(path17.dirname(finalRoot));
11328
- if (!isContained2(projectDir, realFinalParent)) {
10752
+ const realFinalParent = await realpath(path16.dirname(finalRoot));
10753
+ if (!isContained(projectDir, realFinalParent)) {
11329
10754
  throw new Error("Plugin install destination resolves outside the book folder.");
11330
10755
  }
11331
10756
  try {
11332
- await lstat2(finalRoot);
10757
+ await lstat(finalRoot);
11333
10758
  backupRoot = `${finalRoot}.backup-${randomUUID3()}`;
11334
10759
  await rename2(finalRoot, backupRoot);
11335
10760
  } catch (error2) {
@@ -11402,7 +10827,7 @@ var RECOMMENDED_EXTENSIONS = [
11402
10827
  var BUILT_IN_STYLE_SET_IDS = ["clean-book", "zine", "technical-doc"];
11403
10828
  var mutationQueues = new Map;
11404
10829
  function withMutationLock(projectDir, mutation) {
11405
- const resolved = path18.resolve(projectDir);
10830
+ const resolved = path17.resolve(projectDir);
11406
10831
  const key = process.platform === "win32" ? resolved.toLowerCase() : resolved;
11407
10832
  const previous = mutationQueues.get(key) ?? Promise.resolve();
11408
10833
  const run = previous.then(mutation, mutation);
@@ -11464,7 +10889,7 @@ function indexOfUse(seq, use) {
11464
10889
  });
11465
10890
  }
11466
10891
  function manifestPathFor(projectDir, abs) {
11467
- const rel = path18.relative(path18.resolve(projectDir), abs).split(path18.sep).join("/");
10892
+ const rel = path17.relative(path17.resolve(projectDir), abs).split(path17.sep).join("/");
11468
10893
  if (rel === "") {
11469
10894
  throw new Error("An extension cannot be the book folder itself.");
11470
10895
  }
@@ -11523,21 +10948,21 @@ async function describeEntry(projectDir, raw) {
11523
10948
  });
11524
10949
  }
11525
10950
  if (parsed.kind === "path") {
11526
- const abs = path18.resolve(projectDir, parsed.path);
10951
+ const abs = path17.resolve(projectDir, parsed.path);
11527
10952
  const base2 = { ...common, kind: "path", name: parsed.path };
11528
10953
  let info2;
11529
10954
  try {
11530
10955
  info2 = await stat6(abs);
11531
10956
  } catch {
11532
10957
  warnings.push(`Not found: ${abs}`);
11533
- return withWarnings({ ...base2, label: path18.basename(abs), carries: NO_CARRIES });
10958
+ return withWarnings({ ...base2, label: path17.basename(abs), carries: NO_CARRIES });
11534
10959
  }
11535
10960
  if (info2.isDirectory()) {
11536
- return withWarnings(await describeFolder(abs, base2, prettify(path18.basename(abs))));
10961
+ return withWarnings(await describeFolder(abs, base2, prettify(path17.basename(abs))));
11537
10962
  }
11538
10963
  return withWarnings({
11539
10964
  ...base2,
11540
- label: path18.basename(abs),
10965
+ label: path17.basename(abs),
11541
10966
  carries: { ...NO_CARRIES, markdown: true }
11542
10967
  });
11543
10968
  }
@@ -11562,7 +10987,7 @@ async function describeEntry(projectDir, raw) {
11562
10987
  return withWarnings({ ...base, label: parsed.name, carries: { ...NO_CARRIES, markdown: true } });
11563
10988
  }
11564
10989
  const pkgDir = vendoredNpmPluginPackageDir(installRoot, parsed.name);
11565
- if (!existsSync12(path18.join(pkgDir, EXTENSION_MANIFEST_FILENAME))) {
10990
+ if (!existsSync12(path17.join(pkgDir, EXTENSION_MANIFEST_FILENAME))) {
11566
10991
  return withWarnings({ ...base, label: parsed.name, carries: { ...NO_CARRIES, markdown: true } });
11567
10992
  }
11568
10993
  const described = await describeFolder(pkgDir, base, parsed.name, (name) => name);
@@ -11698,11 +11123,11 @@ async function addExtension(projectDir, specifier, options = {}) {
11698
11123
  async function addExtensionUnlocked(projectDir, specifier, options) {
11699
11124
  const input = specifier.trim();
11700
11125
  const exportName = options.exportName?.trim() || undefined;
11701
- if (path18.isAbsolute(input))
11126
+ if (path17.isAbsolute(input))
11702
11127
  return addPathExtension(projectDir, input, exportName);
11703
11128
  const parsed = parseExtensionSpecifier(input);
11704
11129
  if (parsed.kind === "path") {
11705
- return addPathExtension(projectDir, path18.resolve(projectDir, parsed.path), exportName);
11130
+ return addPathExtension(projectDir, path17.resolve(projectDir, parsed.path), exportName);
11706
11131
  }
11707
11132
  if (parsed.kind === "bundled") {
11708
11133
  if (exportName)
@@ -11743,7 +11168,7 @@ async function addExtensionUnlocked(projectDir, specifier, options) {
11743
11168
  async function uniqueExtensionId(projectDir, base) {
11744
11169
  const slug = slugify(base) || "extension";
11745
11170
  let candidate = slug;
11746
- for (let n = 2;existsSync12(path18.join(projectDir, EXTENSIONS_DIR, candidate)); n++) {
11171
+ for (let n = 2;existsSync12(path17.join(projectDir, EXTENSIONS_DIR, candidate)); n++) {
11747
11172
  candidate = `${slug}-${n}`;
11748
11173
  }
11749
11174
  return candidate;
@@ -11753,10 +11178,10 @@ async function addBuiltInStyleSet(projectDir, id) {
11753
11178
  throw new Error(`Unknown built-in look "${id}" (one of: ${BUILT_IN_STYLE_SET_IDS.join(", ")}).`);
11754
11179
  }
11755
11180
  return withMutationLock(projectDir, async () => {
11756
- const dest = path18.join(projectDir, EXTENSIONS_DIR, id);
11181
+ const dest = path17.join(projectDir, EXTENSIONS_DIR, id);
11757
11182
  if (!existsSync12(dest)) {
11758
- const src = path18.join(await getAssetsDir(), "themes", id);
11759
- await mkdir9(path18.dirname(dest), { recursive: true });
11183
+ const src = path17.join(await getAssetsDir(), "themes", id);
11184
+ await mkdir9(path17.dirname(dest), { recursive: true });
11760
11185
  await cp3(src, dest, { recursive: true });
11761
11186
  }
11762
11187
  return addExtensionUnlocked(projectDir, `./${EXTENSIONS_DIR}/${id}`, {});
@@ -11765,9 +11190,9 @@ async function addBuiltInStyleSet(projectDir, id) {
11765
11190
 
11766
11191
  // src/lib/extension-import.ts
11767
11192
  import { existsSync as existsSync13 } from "node:fs";
11768
- import { cp as cp4, mkdir as mkdir10, mkdtemp as mkdtemp3, readFile as readFile29, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
11193
+ import { cp as cp4, mkdir as mkdir10, mkdtemp as mkdtemp3, readFile as readFile28, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
11769
11194
  import { tmpdir as tmpdir3 } from "node:os";
11770
- import path19 from "node:path";
11195
+ import path18 from "node:path";
11771
11196
  import { unzipSync } from "fflate";
11772
11197
  var MAX_THEME_ARCHIVE_BYTES = 25 * 1024 * 1024;
11773
11198
  var MAX_THEME_UNZIPPED_BYTES = 25 * 1024 * 1024;
@@ -11834,11 +11259,11 @@ function mb2(n) {
11834
11259
  return `${Math.round(n / (1024 * 1024))}MB`;
11835
11260
  }
11836
11261
  async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallbackName) {
11837
- const cssPath = path19.join(sourceDir, "theme.css");
11262
+ const cssPath = path18.join(sourceDir, "theme.css");
11838
11263
  if (!existsSync13(cssPath)) {
11839
11264
  throw new Error("A theme must contain a theme.css file.");
11840
11265
  }
11841
- const css = await readFile29(cssPath, "utf8");
11266
+ const css = await readFile28(cssPath, "utf8");
11842
11267
  const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
11843
11268
  if (reject) {
11844
11269
  throw new Error(`theme.css could not be parsed — ${reject.message}`);
@@ -11847,7 +11272,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11847
11272
  for (const w of printFindings) {
11848
11273
  warnings.push({ code: "print-safety", message: w.message });
11849
11274
  }
11850
- const metaExists = existsSync13(path19.join(sourceDir, EXTENSION_MANIFEST_FILENAME));
11275
+ const metaExists = existsSync13(path18.join(sourceDir, EXTENSION_MANIFEST_FILENAME));
11851
11276
  const meta = metaExists ? await readExtensionMeta(sourceDir) : {};
11852
11277
  if (!metaExists) {
11853
11278
  warnings.push({
@@ -11866,7 +11291,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11866
11291
  for (let i = 0;i < extraSheets.length; i++) {
11867
11292
  const rel = extraSheets[i];
11868
11293
  const sheetPath = extraSheetPaths[i];
11869
- const sheetCss = await readFile29(sheetPath, "utf8");
11294
+ const sheetCss = await readFile28(sheetPath, "utf8");
11870
11295
  const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
11871
11296
  if (sheetReject) {
11872
11297
  throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
@@ -11885,8 +11310,8 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11885
11310
  });
11886
11311
  }
11887
11312
  const id = await uniqueExtensionId(projectDir, meta.name?.trim() || fallbackName);
11888
- const dest = path19.join(projectDir, EXTENSIONS_DIR, id);
11889
- await mkdir10(path19.dirname(dest), { recursive: true });
11313
+ const dest = path18.join(projectDir, EXTENSIONS_DIR, id);
11314
+ await mkdir10(path18.dirname(dest), { recursive: true });
11890
11315
  await cp4(sourceDir, dest, { recursive: true });
11891
11316
  await completeLandedManifest(dest, id, meta, metaExists);
11892
11317
  const entry = await addExtension(projectDir, `./${EXTENSIONS_DIR}/${id}`);
@@ -11895,11 +11320,11 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11895
11320
  async function completeLandedManifest(dest, id, meta, metaExists) {
11896
11321
  if (metaExists && extensionStyleList(meta).length > 0)
11897
11322
  return;
11898
- const file = path19.join(dest, EXTENSION_MANIFEST_FILENAME);
11323
+ const file = path18.join(dest, EXTENSION_MANIFEST_FILENAME);
11899
11324
  let pkg = {};
11900
11325
  if (metaExists) {
11901
11326
  try {
11902
- const parsed = JSON.parse(await readFile29(file, "utf8"));
11327
+ const parsed = JSON.parse(await readFile28(file, "utf8"));
11903
11328
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
11904
11329
  pkg = parsed;
11905
11330
  }
@@ -11953,7 +11378,7 @@ async function importExtensionFromZip(projectDir, archive) {
11953
11378
  throw new Error("No theme.css found in the package. A theme needs a theme.css at the package root or inside a single folder.");
11954
11379
  }
11955
11380
  const prefix = root === "" ? "" : `${root}/`;
11956
- const tmp = await mkdtemp3(path19.join(tmpdir3(), "gutterpress-theme-"));
11381
+ const tmp = await mkdtemp3(path18.join(tmpdir3(), "gutterpress-theme-"));
11957
11382
  try {
11958
11383
  const relPaths = [];
11959
11384
  for (const [name, data] of Object.entries(files)) {
@@ -11965,12 +11390,12 @@ async function importExtensionFromZip(projectDir, archive) {
11965
11390
  const rel = prefix ? norm.slice(prefix.length) : norm;
11966
11391
  if (!rel || rel.split("/").some((seg) => seg === ".."))
11967
11392
  continue;
11968
- const dest = path19.join(tmp, rel);
11969
- if (dest !== tmp && !dest.startsWith(tmp + path19.sep)) {
11393
+ const dest = path18.join(tmp, rel);
11394
+ if (dest !== tmp && !dest.startsWith(tmp + path18.sep)) {
11970
11395
  throw new Error(`The package contains an unsafe path and was rejected: ${name}`);
11971
11396
  }
11972
11397
  relPaths.push(rel);
11973
- await mkdir10(path19.dirname(dest), { recursive: true });
11398
+ await mkdir10(path18.dirname(dest), { recursive: true });
11974
11399
  await writeFile8(dest, data);
11975
11400
  }
11976
11401
  return await finalizeExtensionImport(projectDir, tmp, relPaths, root || "imported-look");
@@ -11984,10 +11409,10 @@ async function importExtensionFromCssText(projectDir, css, name) {
11984
11409
  throw new Error(`The CSS could not be parsed — ${reject.message}`);
11985
11410
  }
11986
11411
  const displayName = name.trim() || "Imported theme";
11987
- const tmp = await mkdtemp3(path19.join(tmpdir3(), "gutterpress-theme-"));
11412
+ const tmp = await mkdtemp3(path18.join(tmpdir3(), "gutterpress-theme-"));
11988
11413
  try {
11989
- await writeFile8(path19.join(tmp, "theme.css"), css, "utf8");
11990
- await writeFile8(path19.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
11414
+ await writeFile8(path18.join(tmp, "theme.css"), css, "utf8");
11415
+ await writeFile8(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
11991
11416
  const result = await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], displayName);
11992
11417
  result.warnings.unshift({
11993
11418
  code: "no-theme-json",
@@ -11999,14 +11424,14 @@ async function importExtensionFromCssText(projectDir, css, name) {
11999
11424
  }
12000
11425
  }
12001
11426
  async function importExtensionFromFile(projectDir, filePath) {
12002
- const ext = path19.extname(filePath).toLowerCase();
11427
+ const ext = path18.extname(filePath).toLowerCase();
12003
11428
  if (ext === ".zip") {
12004
- const buf = await readFile29(filePath);
11429
+ const buf = await readFile28(filePath);
12005
11430
  return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
12006
11431
  }
12007
11432
  if (ext === ".css") {
12008
- const css = await readFile29(filePath, "utf8");
12009
- return importExtensionFromCssText(projectDir, css, prettify(path19.basename(filePath, ".css")));
11433
+ const css = await readFile28(filePath, "utf8");
11434
+ return importExtensionFromCssText(projectDir, css, prettify(path18.basename(filePath, ".css")));
12010
11435
  }
12011
11436
  throw new Error("Choose a .zip extension package or a .css stylesheet.");
12012
11437
  }
@@ -12054,7 +11479,7 @@ async function importExtensionFromUrl(projectDir, url) {
12054
11479
  let baseName;
12055
11480
  if (looksLikeCssUrl(trimmed)) {
12056
11481
  css = await fetchText(trimmed);
12057
- baseName = path19.basename(new URL(trimmed, "https://x/").pathname, ".css") || "look";
11482
+ baseName = path18.basename(new URL(trimmed, "https://x/").pathname, ".css") || "look";
12058
11483
  } else {
12059
11484
  const base = trimmed.endsWith("/") ? trimmed : `${trimmed}/`;
12060
11485
  css = await fetchText(`${base}theme.css`);
@@ -12063,14 +11488,14 @@ async function importExtensionFromUrl(projectDir, url) {
12063
11488
  if (parsed && typeof parsed === "object")
12064
11489
  meta = parsed;
12065
11490
  } catch {}
12066
- baseName = typeof meta.name === "string" && meta.name || path19.basename(new URL(base, "https://x/").pathname.replace(/\/$/, "")) || "look";
11491
+ baseName = typeof meta.name === "string" && meta.name || path18.basename(new URL(base, "https://x/").pathname.replace(/\/$/, "")) || "look";
12067
11492
  }
12068
11493
  if (!css.trim())
12069
11494
  throw new Error(`Fetched CSS from ${trimmed} was empty.`);
12070
11495
  assertLooksLikeCss(css, trimmed);
12071
- const tmp = await mkdtemp3(path19.join(tmpdir3(), "gutterpress-ext-"));
11496
+ const tmp = await mkdtemp3(path18.join(tmpdir3(), "gutterpress-ext-"));
12072
11497
  try {
12073
- await writeFile8(path19.join(tmp, "theme.css"), css, "utf8");
11498
+ await writeFile8(path18.join(tmp, "theme.css"), css, "utf8");
12074
11499
  const gp = meta.gutterpress && typeof meta.gutterpress === "object" && !Array.isArray(meta.gutterpress) ? meta.gutterpress : {};
12075
11500
  const finalMeta = {
12076
11501
  name: typeof meta.name === "string" && meta.name || slugify(baseName, "look"),
@@ -12082,7 +11507,7 @@ async function importExtensionFromUrl(projectDir, url) {
12082
11507
  preview: typeof gp.preview === "string" ? gp.preview : null
12083
11508
  }
12084
11509
  };
12085
- await writeFile8(path19.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
11510
+ await writeFile8(path18.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
12086
11511
  return await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], baseName);
12087
11512
  } finally {
12088
11513
  await rm5(tmp, { recursive: true, force: true });
@@ -12100,7 +11525,7 @@ var KIND_FOR_KEYWORD = {
12100
11525
  function invalid(reason) {
12101
11526
  throw new Error(`Malformed npm search response: ${reason}.`);
12102
11527
  }
12103
- function object4(value) {
11528
+ function object3(value) {
12104
11529
  return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
12105
11530
  }
12106
11531
  function str2(value) {
@@ -12113,7 +11538,7 @@ function parseSearchPage(text, keyword) {
12113
11538
  } catch {
12114
11539
  invalid("not valid JSON");
12115
11540
  }
12116
- const root = object4(parsed);
11541
+ const root = object3(parsed);
12117
11542
  if (!root)
12118
11543
  invalid("root is not an object");
12119
11544
  if (!Array.isArray(root.objects))
@@ -12123,10 +11548,10 @@ function parseSearchPage(text, keyword) {
12123
11548
  const packages = [];
12124
11549
  const scores = [];
12125
11550
  root.objects.forEach((raw, i) => {
12126
- const entry = object4(raw);
11551
+ const entry = object3(raw);
12127
11552
  if (!entry)
12128
11553
  invalid(`objects[${i}] is not an object`);
12129
- const pkg = object4(entry.package);
11554
+ const pkg = object3(entry.package);
12130
11555
  if (!pkg)
12131
11556
  invalid(`objects[${i}].package is not an object`);
12132
11557
  const name = str2(pkg.name);
@@ -12140,7 +11565,7 @@ function parseSearchPage(text, keyword) {
12140
11565
  return;
12141
11566
  if (name === "markdown-it" || name.startsWith("@types/"))
12142
11567
  return;
12143
- const links = object4(pkg.links) ?? {};
11568
+ const links = object3(pkg.links) ?? {};
12144
11569
  packages.push({
12145
11570
  name,
12146
11571
  version,
@@ -12709,24 +12134,24 @@ ${tail}` : ""}`);
12709
12134
 
12710
12135
  // src/lib/publish/providers/guided.ts
12711
12136
  import { copyFile as copyFile2, mkdir as mkdir11, writeFile as writeFile9 } from "node:fs/promises";
12712
- import path20 from "node:path";
12137
+ import path19 from "node:path";
12713
12138
  async function stageGuidedPackage(req, providerId, listingLines) {
12714
- const packageDir = path20.join(path20.dirname(req.artifact.path), "publish", providerId);
12139
+ const packageDir = path19.join(path19.dirname(req.artifact.path), "publish", providerId);
12715
12140
  await mkdir11(packageDir, { recursive: true });
12716
- await copyFile2(req.artifact.path, path20.join(packageDir, path20.basename(req.artifact.path)));
12141
+ await copyFile2(req.artifact.path, path19.join(packageDir, path19.basename(req.artifact.path)));
12717
12142
  const { title, authors } = req.project;
12718
12143
  const sheet = [
12719
12144
  `# ${title || "Untitled"}`,
12720
12145
  "",
12721
12146
  `- **Authors:** ${authors.length ? authors.join(", ") : "(not set)"}`,
12722
- `- **File:** ${path20.basename(req.artifact.path)}`,
12147
+ `- **File:** ${path19.basename(req.artifact.path)}`,
12723
12148
  ...listingLines,
12724
12149
  "",
12725
12150
  "Copy these details into the platform's listing form when uploading.",
12726
12151
  ""
12727
12152
  ].join(`
12728
12153
  `);
12729
- await writeFile9(path20.join(packageDir, "LISTING.md"), sheet, "utf8");
12154
+ await writeFile9(path19.join(packageDir, "LISTING.md"), sheet, "utf8");
12730
12155
  return packageDir;
12731
12156
  }
12732
12157
 
@@ -12789,9 +12214,9 @@ var drivethrurpgProvider = {
12789
12214
  };
12790
12215
 
12791
12216
  // src/lib/publish/providers/gdrive.ts
12792
- import { mkdtemp as mkdtemp4, readFile as readFile30, readdir as readdir6, rm as rm6, stat as stat7, writeFile as writeFile10 } from "node:fs/promises";
12217
+ import { mkdtemp as mkdtemp4, readFile as readFile29, readdir as readdir5, rm as rm6, stat as stat7, writeFile as writeFile10 } from "node:fs/promises";
12793
12218
  import { tmpdir as tmpdir4 } from "node:os";
12794
- import path21 from "node:path";
12219
+ import path20 from "node:path";
12795
12220
  import { Zip, ZipDeflate } from "fflate";
12796
12221
 
12797
12222
  // src/lib/publish/google-drive.ts
@@ -13174,26 +12599,26 @@ function zipEntriesNonBlocking(entries, opts) {
13174
12599
  });
13175
12600
  }
13176
12601
  async function collectZipEntries(root, dir, out, onWarn) {
13177
- const entries = await readdir6(dir, { withFileTypes: true });
12602
+ const entries = await readdir5(dir, { withFileTypes: true });
13178
12603
  for (const entry of entries) {
13179
- const full = path21.join(dir, entry.name);
12604
+ const full = path20.join(dir, entry.name);
13180
12605
  if (entry.isDirectory()) {
13181
12606
  await collectZipEntries(root, full, out, onWarn);
13182
12607
  } else if (entry.isFile()) {
13183
- const rel = path21.relative(root, full).split(path21.sep).join("/");
13184
- out[rel] = await readFile30(full);
12608
+ const rel = path20.relative(root, full).split(path20.sep).join("/");
12609
+ out[rel] = await readFile29(full);
13185
12610
  } else if (entry.isSymbolicLink()) {
13186
12611
  const resolved = await stat7(full).catch(() => null);
13187
12612
  if (resolved?.isFile()) {
13188
- const rel = path21.relative(root, full).split(path21.sep).join("/");
13189
- out[rel] = await readFile30(full);
12613
+ const rel = path20.relative(root, full).split(path20.sep).join("/");
12614
+ out[rel] = await readFile29(full);
13190
12615
  } else if (resolved?.isDirectory()) {
13191
12616
  await collectZipEntries(root, full, out, onWarn);
13192
12617
  } else {
13193
- onWarn?.(`Skipped "${path21.relative(root, full)}" in the website export — it's a broken symlink.`);
12618
+ onWarn?.(`Skipped "${path20.relative(root, full)}" in the website export — it's a broken symlink.`);
13194
12619
  }
13195
12620
  } else {
13196
- onWarn?.(`Skipped "${path21.relative(root, full)}" in the website export — not a file, folder, or symlink.`);
12621
+ onWarn?.(`Skipped "${path20.relative(root, full)}" in the website export — not a file, folder, or symlink.`);
13197
12622
  }
13198
12623
  }
13199
12624
  }
@@ -13201,9 +12626,9 @@ async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeF
13201
12626
  const entries = {};
13202
12627
  await collectZipEntries(exportDir, exportDir, entries, onWarn);
13203
12628
  const fileName = `${bookSlug(title)}-website.zip`;
13204
- const tmpRoot = await mkdtemp4(path21.join(tmpdir4(), "gutterpress-gdrive-"));
12629
+ const tmpRoot = await mkdtemp4(path20.join(tmpdir4(), "gutterpress-gdrive-"));
13205
12630
  try {
13206
- const filePath = path21.join(tmpRoot, fileName);
12631
+ const filePath = path20.join(tmpRoot, fileName);
13207
12632
  const zipped = await zipEntriesNonBlocking(entries, { level: 6 });
13208
12633
  await writeArchiveImpl(filePath, zipped);
13209
12634
  return {
@@ -13251,7 +12676,7 @@ var gdriveProvider = {
13251
12676
  const isHtml = req.artifact.format === "html";
13252
12677
  const source = isHtml ? await zipHtmlExport(req.artifact.path, req.project.title, (msg) => req.deps.onProgress?.(msg)) : {
13253
12678
  filePath: req.artifact.path,
13254
- fileName: path21.basename(req.artifact.path),
12679
+ fileName: path20.basename(req.artifact.path),
13255
12680
  mimeType: "application/pdf",
13256
12681
  cleanup: async () => {}
13257
12682
  };
@@ -13302,7 +12727,7 @@ var gdriveProvider = {
13302
12727
 
13303
12728
  // src/lib/publish/butler.ts
13304
12729
  import { chmod, mkdir as mkdir12, stat as stat8, writeFile as writeFile11 } from "node:fs/promises";
13305
- import path22 from "node:path";
12730
+ import path21 from "node:path";
13306
12731
  import { unzipSync as unzipSync2 } from "fflate";
13307
12732
  var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
13308
12733
  function butlerBrothChannel(platform = process.platform, arch = process.arch) {
@@ -13339,8 +12764,8 @@ async function ensureButler(deps) {
13339
12764
  }
13340
12765
  if (await commandExists("butler", runCommand, deps.env))
13341
12766
  return "butler";
13342
- const cacheDir = path22.join(deps.configDir ?? defaultConfigDir(), "tools", "butler");
13343
- const cached = path22.join(cacheDir, butlerBinaryName());
12767
+ const cacheDir = path21.join(deps.configDir ?? defaultConfigDir(), "tools", "butler");
12768
+ const cached = path21.join(cacheDir, butlerBinaryName());
13344
12769
  if (await fileExists2(cached))
13345
12770
  return cached;
13346
12771
  const channel = butlerBrothChannel();
@@ -13367,9 +12792,9 @@ async function ensureButler(deps) {
13367
12792
  for (const [name, data] of Object.entries(files)) {
13368
12793
  if (name.endsWith("/"))
13369
12794
  continue;
13370
- const target = path22.join(cacheDir, path22.basename(name));
12795
+ const target = path21.join(cacheDir, path21.basename(name));
13371
12796
  await writeFile11(target, data);
13372
- if (path22.basename(name) === butlerBinaryName()) {
12797
+ if (path21.basename(name) === butlerBinaryName()) {
13373
12798
  await chmod(target, 493).catch(() => {});
13374
12799
  foundBinary = true;
13375
12800
  }
@@ -13798,8 +13223,8 @@ function publishProviderFor(id) {
13798
13223
  }
13799
13224
 
13800
13225
  // src/lib/publish/run-publish.ts
13801
- import { readdir as readdir7, stat as stat9 } from "node:fs/promises";
13802
- import path23 from "node:path";
13226
+ import { readdir as readdir6, stat as stat9 } from "node:fs/promises";
13227
+ import path22 from "node:path";
13803
13228
  function resolvePublishFormat(info8, providerConfig) {
13804
13229
  if (info8.formats && info8.formats.length > 0) {
13805
13230
  const configured = typeof providerConfig.format === "string" ? providerConfig.format.trim() : "";
@@ -13820,9 +13245,9 @@ async function resolvePublishRequest(options, deps) {
13820
13245
  const effectiveDeps = effectiveAccount ? { ...deps, credentialAccount: effectiveAccount } : deps;
13821
13246
  const outDir = resolveOutputDir(manifestDir, config.title);
13822
13247
  const effectiveFormat = resolvePublishFormat(provider.info, providerConfig);
13823
- const defaultArtifact = effectiveFormat === "pdf" ? path23.join(outDir, artifactName(config.title, "pdf")) : outDir;
13248
+ const defaultArtifact = effectiveFormat === "pdf" ? path22.join(outDir, artifactName(config.title, "pdf")) : outDir;
13824
13249
  const artifact = {
13825
- path: options.artifactPath ? path23.resolve(options.projectDir, options.artifactPath) : defaultArtifact,
13250
+ path: options.artifactPath ? path22.resolve(options.projectDir, options.artifactPath) : defaultArtifact,
13826
13251
  format: effectiveFormat
13827
13252
  };
13828
13253
  return {
@@ -13886,7 +13311,7 @@ async function artifactIssues(artifact) {
13886
13311
  var BUILD_FINGERPRINT_FILENAME = "build-fingerprint.json";
13887
13312
  async function htmlDirIssues(dir) {
13888
13313
  const issues = [];
13889
- const isThere = async (rel) => stat9(path23.join(dir, rel)).then(() => true, () => false);
13314
+ const isThere = async (rel) => stat9(path22.join(dir, rel)).then(() => true, () => false);
13890
13315
  if (!await isThere(BOOK_HTML)) {
13891
13316
  issues.push({
13892
13317
  severity: "error",
@@ -13894,7 +13319,7 @@ async function htmlDirIssues(dir) {
13894
13319
  message: `${dir} has no ${BOOK_HTML} — it isn't an HTML export. ${HTML_HINT}`
13895
13320
  });
13896
13321
  }
13897
- const entries = await readdir7(dir).catch(() => []);
13322
+ const entries = await readdir6(dir).catch(() => []);
13898
13323
  const extras = entries.filter((name) => name.toLowerCase().endsWith(".pdf") || name === BUILD_FINGERPRINT_FILENAME);
13899
13324
  if (extras.length > 0) {
13900
13325
  issues.push({
@@ -14117,17 +13542,17 @@ import git6 from "isomorphic-git";
14117
13542
  import git5 from "isomorphic-git";
14118
13543
  import diff3Merge from "diff3";
14119
13544
  // src/lib/publish/selections.ts
14120
- import { chmod as chmod2, mkdir as mkdir13, readFile as readFile31, writeFile as writeFile12 } from "node:fs/promises";
14121
- import path24 from "node:path";
13545
+ import { chmod as chmod2, mkdir as mkdir13, readFile as readFile30, writeFile as writeFile12 } from "node:fs/promises";
13546
+ import path23 from "node:path";
14122
13547
  class PublishSelectionsStore {
14123
13548
  filePath;
14124
13549
  queue = Promise.resolve();
14125
13550
  constructor(filePath) {
14126
- this.filePath = filePath ?? path24.join(defaultConfigDir(), "publish-selections.json");
13551
+ this.filePath = filePath ?? path23.join(defaultConfigDir(), "publish-selections.json");
14127
13552
  }
14128
13553
  async read() {
14129
13554
  try {
14130
- const raw = await readFile31(this.filePath, "utf8");
13555
+ const raw = await readFile30(this.filePath, "utf8");
14131
13556
  const parsed = JSON.parse(raw);
14132
13557
  if (parsed && typeof parsed === "object") {
14133
13558
  return {
@@ -14140,7 +13565,7 @@ class PublishSelectionsStore {
14140
13565
  return { version: 1, global: {}, projects: {} };
14141
13566
  }
14142
13567
  async write(data) {
14143
- await mkdir13(path24.dirname(this.filePath), { recursive: true });
13568
+ await mkdir13(path23.dirname(this.filePath), { recursive: true });
14144
13569
  await writeFile12(this.filePath, JSON.stringify(data, null, 2), {
14145
13570
  encoding: "utf8",
14146
13571
  mode: 384
@@ -14208,7 +13633,7 @@ function normalizeProjectKey(projectDir) {
14208
13633
  import { isMap as isMap4 } from "yaml";
14209
13634
  // src/lib/lint-runner.ts
14210
13635
  import { resolve as resolve8 } from "node:path";
14211
- import { readFile as readFile32 } from "node:fs/promises";
13636
+ import { readFile as readFile31 } from "node:fs/promises";
14212
13637
  async function runLint(opts = {}) {
14213
13638
  const { glob } = await import("glob");
14214
13639
  const { manifest, manifestDir } = await loadManifestWithPath(opts.manifest, {
@@ -14239,7 +13664,7 @@ async function runLint(opts = {}) {
14239
13664
  for (const file of files) {
14240
13665
  let css;
14241
13666
  try {
14242
- css = await readFile32(file, "utf8");
13667
+ css = await readFile31(file, "utf8");
14243
13668
  } catch (err) {
14244
13669
  log.error(` ${file}`);
14245
13670
  log.error(` cannot read stylesheet: ${err instanceof Error ? err.message : String(err)}`);