gutterpress 0.11.16 → 0.11.17-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.js +2 -2
- package/dist/{build-8epzrj8g.js → build-1p999cmg.js} +4 -4
- package/dist/{cli-ev175hx9.js → cli-6z5zthzt.js} +138 -93
- package/dist/{cli-0prrt9e4.js → cli-70xgehq2.js} +1 -1
- package/dist/{cli-wqy8hnnh.js → cli-gymfg04q.js} +8 -6
- package/dist/{cli-182j48xc.js → cli-ppc0vz4b.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-24mbx7y1.js → doctor-reqpnn3h.js} +2 -2
- package/dist/engine/shared/synthesis.d.ts +8 -0
- package/dist/{engine-j5h953pg.js → engine-078ggczp.js} +1 -1
- package/dist/{engine-w17dbt4f.js → engine-5jzhjjvv.js} +2 -2
- package/dist/{ext-p9gx5aac.js → ext-dsbfejt3.js} +4 -4
- package/dist/{gutterpress-viewer-swz6bwfa.js → gutterpress-viewer-zkv2stfy.js} +51 -6
- package/dist/{index-qep93v0z.js → index-5dcj1vts.js} +7 -5
- package/dist/{index-40achhs8.js → index-c275p061.js} +137 -90
- package/dist/{index-ee7wp8q3.js → index-eyaj6nkc.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/lib/markdown/assemble.d.ts +10 -0
- package/dist/lib/markdown/index.d.ts +10 -0
- package/dist/lib/static-serve.d.ts +6 -0
- package/dist/{new-wsjsrm7w.js → new-m5y2wepr.js} +4 -4
- package/dist/{preflight-0fjjnk9e.js → preflight-bwpqwwny.js} +4 -4
- package/dist/preview/file-watcher.d.ts +5 -1
- package/dist/preview/server-context.d.ts +10 -0
- package/dist/{preview-azy06gw0.js → preview-62y7qhkp.js} +4 -4
- package/dist/{preview-interface-5wnzrvhf.js → preview-interface-c44qk17f.js} +7 -2
- package/dist/{publish-8db67m2h.js → publish-k2zyt3x6.js} +4 -4
- package/dist/render.js +2 -1
- package/dist/{validate-e7mw1xyd.js → validate-fgwwxtbn.js} +4 -4
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
MARGIN_BOX_IGNORED_PROPERTIES,
|
|
5
5
|
getAssetPath,
|
|
6
6
|
getAssetsDir
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-eyaj6nkc.js";
|
|
8
8
|
import {
|
|
9
9
|
INSTALL_HINTS,
|
|
10
10
|
execCapture,
|
|
@@ -2859,8 +2859,9 @@ ${projectCss.trim()}` : null
|
|
|
2859
2859
|
`);
|
|
2860
2860
|
const preloadTags = (opts.preloadImages ?? []).map((href) => `
|
|
2861
2861
|
<link rel="preload" as="image" href="${href}">`).join("");
|
|
2862
|
+
const printAttrs = (opts.print?.signature && opts.print.signature > 1 ? ` data-gp-signature="${opts.print.signature}"` : "") + (opts.print?.reserveLastPage ? " data-gp-reserve-last-page" : "");
|
|
2862
2863
|
return `<!DOCTYPE html>
|
|
2863
|
-
<html lang="en">
|
|
2864
|
+
<html lang="en"${printAttrs}>
|
|
2864
2865
|
<head>
|
|
2865
2866
|
<meta charset="UTF-8">
|
|
2866
2867
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
@@ -3319,6 +3320,7 @@ ${css.trim()}
|
|
|
3319
3320
|
projectCss: inlined.css,
|
|
3320
3321
|
preloadImages: cssAssetCopies.map((c) => c.to),
|
|
3321
3322
|
title: opts.title,
|
|
3323
|
+
print: opts.print,
|
|
3322
3324
|
plugins: opts.plugins,
|
|
3323
3325
|
pluginCss,
|
|
3324
3326
|
annotateSourceChapters: opts.annotateSourceChapters,
|
|
@@ -3330,6 +3332,7 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
|
|
|
3330
3332
|
await mkdir(outDir, { recursive: true });
|
|
3331
3333
|
const html = await renderChapters(inputDir, {
|
|
3332
3334
|
title: opts.title,
|
|
3335
|
+
print: opts.print,
|
|
3333
3336
|
styles: opts.styles,
|
|
3334
3337
|
files: opts.files,
|
|
3335
3338
|
plugins: opts.plugins,
|
|
@@ -5638,7 +5641,7 @@ import git from "isomorphic-git";
|
|
|
5638
5641
|
// package.json
|
|
5639
5642
|
var package_default = {
|
|
5640
5643
|
name: "gutterpress",
|
|
5641
|
-
version: "0.11.
|
|
5644
|
+
version: "0.11.17-alpha.2",
|
|
5642
5645
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
5643
5646
|
author: "itlackey",
|
|
5644
5647
|
license: "MPL-2.0",
|
|
@@ -10106,6 +10109,7 @@ async function renderBook(ctx) {
|
|
|
10106
10109
|
const cssAssets = [];
|
|
10107
10110
|
const htmlFile = await renderChaptersToFile(renderDir, workDir, {
|
|
10108
10111
|
title: config.title,
|
|
10112
|
+
print: config.print,
|
|
10109
10113
|
styles: config.styles,
|
|
10110
10114
|
files: config.source.files,
|
|
10111
10115
|
plugins,
|
|
@@ -10257,7 +10261,7 @@ class PdfOutput {
|
|
|
10257
10261
|
const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
|
|
10258
10262
|
await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
|
|
10259
10263
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
10260
|
-
const { buildNativePdf } = await import("./engine-
|
|
10264
|
+
const { buildNativePdf } = await import("./engine-5jzhjjvv.js");
|
|
10261
10265
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
10262
10266
|
title: config.title,
|
|
10263
10267
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -10359,7 +10363,7 @@ async function runBuild(opts) {
|
|
|
10359
10363
|
}
|
|
10360
10364
|
}
|
|
10361
10365
|
// src/preview/lifecycle.ts
|
|
10362
|
-
import
|
|
10366
|
+
import path16 from "path";
|
|
10363
10367
|
import { tmpdir } from "os";
|
|
10364
10368
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
10365
10369
|
import { readdir as readdir5, readFile as readFile25, writeFile as writeFile6 } from "node:fs/promises";
|
|
@@ -10384,7 +10388,65 @@ async function mkdir6(dirPath) {
|
|
|
10384
10388
|
// src/preview/file-watcher.ts
|
|
10385
10389
|
import { watch } from "chokidar";
|
|
10386
10390
|
import fsp3 from "node:fs/promises";
|
|
10387
|
-
import
|
|
10391
|
+
import path15 from "path";
|
|
10392
|
+
|
|
10393
|
+
// src/lib/static-serve.ts
|
|
10394
|
+
import path14 from "node:path";
|
|
10395
|
+
var STATIC_MIME = {
|
|
10396
|
+
".html": "text/html; charset=utf-8",
|
|
10397
|
+
".htm": "text/html; charset=utf-8",
|
|
10398
|
+
".css": "text/css",
|
|
10399
|
+
".js": "application/javascript",
|
|
10400
|
+
".mjs": "application/javascript",
|
|
10401
|
+
".json": "application/json",
|
|
10402
|
+
".png": "image/png",
|
|
10403
|
+
".jpg": "image/jpeg",
|
|
10404
|
+
".jpeg": "image/jpeg",
|
|
10405
|
+
".gif": "image/gif",
|
|
10406
|
+
".svg": "image/svg+xml",
|
|
10407
|
+
".webp": "image/webp",
|
|
10408
|
+
".avif": "image/avif",
|
|
10409
|
+
".ico": "image/x-icon",
|
|
10410
|
+
".woff": "font/woff",
|
|
10411
|
+
".woff2": "font/woff2",
|
|
10412
|
+
".ttf": "font/ttf",
|
|
10413
|
+
".otf": "font/otf"
|
|
10414
|
+
};
|
|
10415
|
+
function resolveWithinRoot(relPath, root) {
|
|
10416
|
+
const resolvedRoot = path14.resolve(root);
|
|
10417
|
+
const candidate = path14.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
|
|
10418
|
+
if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path14.sep)) {
|
|
10419
|
+
return null;
|
|
10420
|
+
}
|
|
10421
|
+
return candidate;
|
|
10422
|
+
}
|
|
10423
|
+
function hasDotSegment(urlPathname) {
|
|
10424
|
+
let decoded;
|
|
10425
|
+
try {
|
|
10426
|
+
decoded = decodeURIComponent(urlPathname);
|
|
10427
|
+
} catch {
|
|
10428
|
+
return true;
|
|
10429
|
+
}
|
|
10430
|
+
return decoded.split(/[/\\]/).some((segment) => segment.startsWith("."));
|
|
10431
|
+
}
|
|
10432
|
+
function resolveStaticPath(urlPathname, root) {
|
|
10433
|
+
let decoded;
|
|
10434
|
+
try {
|
|
10435
|
+
decoded = decodeURIComponent(urlPathname);
|
|
10436
|
+
} catch {
|
|
10437
|
+
return null;
|
|
10438
|
+
}
|
|
10439
|
+
return resolveWithinRoot(decoded, root);
|
|
10440
|
+
}
|
|
10441
|
+
function imageRefKey(ref) {
|
|
10442
|
+
let key = ref.split(/[?#]/)[0].replace(/^\.\//, "").replace(/^\/+/, "");
|
|
10443
|
+
try {
|
|
10444
|
+
key = decodeURIComponent(key);
|
|
10445
|
+
} catch {}
|
|
10446
|
+
return key;
|
|
10447
|
+
}
|
|
10448
|
+
|
|
10449
|
+
// src/preview/file-watcher.ts
|
|
10388
10450
|
var EMPTY_BOOK_HTML = `<!doctype html>
|
|
10389
10451
|
<html lang="en">
|
|
10390
10452
|
<head>
|
|
@@ -10405,12 +10467,14 @@ async function renderPreviewBook(inputPath, config, opts) {
|
|
|
10405
10467
|
const { plugins, pluginStyles } = await loadPluginsWithCss(config.extensions, inputPath, (ref, err) => warn2(`Skipping plugin "${ref}" in preview — ${err.message}`));
|
|
10406
10468
|
return renderChapters(inputPath, {
|
|
10407
10469
|
title: config.title ?? "Document",
|
|
10470
|
+
print: config.print,
|
|
10408
10471
|
styles: config.styles,
|
|
10409
10472
|
files: opts.files,
|
|
10410
10473
|
plugins,
|
|
10411
10474
|
pluginStyles,
|
|
10412
10475
|
annotateSourceChapters: true,
|
|
10413
10476
|
...opts.onCssAssets ? { onCssAssets: opts.onCssAssets } : {},
|
|
10477
|
+
...opts.onImageRefs ? { onImageRefs: opts.onImageRefs } : {},
|
|
10414
10478
|
onChapterWarnings: (file, warnings) => {
|
|
10415
10479
|
for (const w of warnings) {
|
|
10416
10480
|
warn2(` ${file}, line ${w.line}: ${w.message}`);
|
|
@@ -10425,24 +10489,35 @@ function injectPreviewScripts(html) {
|
|
|
10425
10489
|
`;
|
|
10426
10490
|
return /<\/head>/i.test(html) ? html.replace(/<\/head>/i, scripts + "</head>") : html + scripts;
|
|
10427
10491
|
}
|
|
10428
|
-
async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
|
|
10492
|
+
async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, imageRefs) {
|
|
10429
10493
|
if (!inputPath) {
|
|
10430
10494
|
cssAssets.clear();
|
|
10431
|
-
|
|
10495
|
+
imageRefs?.clear();
|
|
10496
|
+
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), EMPTY_BOOK_HTML, "utf-8");
|
|
10432
10497
|
return;
|
|
10433
10498
|
}
|
|
10434
10499
|
const nextAssets = new Map;
|
|
10500
|
+
const nextImageRefs = new Set;
|
|
10435
10501
|
const html = await renderPreviewBook(inputPath, config, {
|
|
10436
10502
|
files: config.source?.files ?? null,
|
|
10437
10503
|
onCssAssets: (copies) => {
|
|
10438
10504
|
for (const copy of copies)
|
|
10439
10505
|
nextAssets.set(copy.to, copy.from);
|
|
10506
|
+
},
|
|
10507
|
+
onImageRefs: (refs) => {
|
|
10508
|
+
for (const ref of refs)
|
|
10509
|
+
nextImageRefs.add(imageRefKey(ref));
|
|
10440
10510
|
}
|
|
10441
10511
|
});
|
|
10442
10512
|
cssAssets.clear();
|
|
10443
10513
|
for (const [to, from] of nextAssets)
|
|
10444
10514
|
cssAssets.set(to, from);
|
|
10445
|
-
|
|
10515
|
+
if (imageRefs) {
|
|
10516
|
+
imageRefs.clear();
|
|
10517
|
+
for (const ref of nextImageRefs)
|
|
10518
|
+
imageRefs.add(ref);
|
|
10519
|
+
}
|
|
10520
|
+
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html), "utf-8");
|
|
10446
10521
|
}
|
|
10447
10522
|
function isDotPathUnderRoot(candidatePath, root) {
|
|
10448
10523
|
const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
@@ -10479,23 +10554,23 @@ function isIgnoredWatchPath(candidatePath, projectRoot) {
|
|
|
10479
10554
|
return isDotPathUnderRoot(candidatePath, projectRoot) || isGeneratedProjectPath(relative2);
|
|
10480
10555
|
}
|
|
10481
10556
|
function isExternalWatchCandidate(candidatePath, targets) {
|
|
10482
|
-
const candidate =
|
|
10557
|
+
const candidate = path15.resolve(candidatePath);
|
|
10483
10558
|
for (const rawTarget of targets) {
|
|
10484
|
-
const target =
|
|
10485
|
-
const rel =
|
|
10486
|
-
if (rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
10559
|
+
const target = path15.resolve(rawTarget);
|
|
10560
|
+
const rel = path15.relative(candidate, target);
|
|
10561
|
+
if (rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel))
|
|
10487
10562
|
return true;
|
|
10488
10563
|
}
|
|
10489
10564
|
return false;
|
|
10490
10565
|
}
|
|
10491
10566
|
async function nearestExistingDirectory(start) {
|
|
10492
|
-
let current =
|
|
10567
|
+
let current = path15.resolve(start);
|
|
10493
10568
|
while (true) {
|
|
10494
10569
|
try {
|
|
10495
10570
|
if ((await fsp3.stat(current)).isDirectory())
|
|
10496
10571
|
return current;
|
|
10497
10572
|
} catch {}
|
|
10498
|
-
const parent =
|
|
10573
|
+
const parent = path15.dirname(current);
|
|
10499
10574
|
if (parent === current)
|
|
10500
10575
|
return current;
|
|
10501
10576
|
current = parent;
|
|
@@ -10504,7 +10579,7 @@ async function nearestExistingDirectory(start) {
|
|
|
10504
10579
|
async function externalWatchRoots(targets) {
|
|
10505
10580
|
const roots = new Set;
|
|
10506
10581
|
for (const target of targets) {
|
|
10507
|
-
roots.add(await nearestExistingDirectory(
|
|
10582
|
+
roots.add(await nearestExistingDirectory(path15.dirname(path15.resolve(target))));
|
|
10508
10583
|
}
|
|
10509
10584
|
return [...roots];
|
|
10510
10585
|
}
|
|
@@ -10518,19 +10593,19 @@ async function extensionFolderFiles(dir) {
|
|
|
10518
10593
|
const meta = await readExtensionMeta(dir);
|
|
10519
10594
|
const entry = extensionEntry(meta);
|
|
10520
10595
|
return [
|
|
10521
|
-
|
|
10522
|
-
...entry ? [
|
|
10596
|
+
path15.join(dir, EXTENSION_MANIFEST_FILENAME),
|
|
10597
|
+
...entry ? [path15.resolve(dir, entry)] : [],
|
|
10523
10598
|
...await collectStyleDependencies(dir, extensionStyleList(meta))
|
|
10524
10599
|
];
|
|
10525
10600
|
}
|
|
10526
10601
|
async function externalWatchTargets(projectDir, config) {
|
|
10527
|
-
const root =
|
|
10602
|
+
const root = path15.resolve(projectDir);
|
|
10528
10603
|
let canonicalRoot = root;
|
|
10529
10604
|
try {
|
|
10530
10605
|
canonicalRoot = await fsp3.realpath(root);
|
|
10531
10606
|
} catch {}
|
|
10532
10607
|
const styles = await resolveActiveStyles(root, config.styles);
|
|
10533
|
-
const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) =>
|
|
10608
|
+
const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) => path15.resolve(root, p));
|
|
10534
10609
|
const candidates = [
|
|
10535
10610
|
...await collectStyleDependencies(root, styles),
|
|
10536
10611
|
...extensionPaths,
|
|
@@ -10538,17 +10613,17 @@ async function externalWatchTargets(projectDir, config) {
|
|
|
10538
10613
|
];
|
|
10539
10614
|
const external = new Set;
|
|
10540
10615
|
for (const abs of candidates) {
|
|
10541
|
-
const authoredPath =
|
|
10542
|
-
const authoredRel =
|
|
10543
|
-
if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${
|
|
10616
|
+
const authoredPath = path15.resolve(abs);
|
|
10617
|
+
const authoredRel = path15.relative(root, authoredPath);
|
|
10618
|
+
if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${path15.sep}`) || path15.isAbsolute(authoredRel))) {
|
|
10544
10619
|
external.add(authoredPath);
|
|
10545
10620
|
}
|
|
10546
10621
|
let canonicalPath = authoredPath;
|
|
10547
10622
|
try {
|
|
10548
10623
|
canonicalPath = await fsp3.realpath(canonicalPath);
|
|
10549
10624
|
} catch {}
|
|
10550
|
-
const rel =
|
|
10551
|
-
if (rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
10625
|
+
const rel = path15.relative(canonicalRoot, canonicalPath);
|
|
10626
|
+
if (rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel))
|
|
10552
10627
|
continue;
|
|
10553
10628
|
external.add(canonicalPath);
|
|
10554
10629
|
}
|
|
@@ -10575,7 +10650,7 @@ async function addAndAwaitWatch(watcher, roots) {
|
|
|
10575
10650
|
}
|
|
10576
10651
|
}
|
|
10577
10652
|
function createFileWatcher(state) {
|
|
10578
|
-
const inputResolved =
|
|
10653
|
+
const inputResolved = path15.resolve(state.currentInputPath);
|
|
10579
10654
|
const watcher = watch(inputResolved, {
|
|
10580
10655
|
persistent: true,
|
|
10581
10656
|
ignoreInitial: true,
|
|
@@ -10615,7 +10690,7 @@ function createFileWatcher(state) {
|
|
|
10615
10690
|
async function recordChange(event, filePath) {
|
|
10616
10691
|
if (closed)
|
|
10617
10692
|
return;
|
|
10618
|
-
const target =
|
|
10693
|
+
const target = path15.resolve(filePath);
|
|
10619
10694
|
const settled = settledWrites.get(target);
|
|
10620
10695
|
if (settled && event !== "unlink" && Date.now() <= settled.expiresAt) {
|
|
10621
10696
|
const diskContent = await fsp3.readFile(target, "utf8").catch(() => null);
|
|
@@ -10636,7 +10711,7 @@ function createFileWatcher(state) {
|
|
|
10636
10711
|
recordChange(event, filePath);
|
|
10637
10712
|
});
|
|
10638
10713
|
externalWatcher.on("all", (event, filePath) => {
|
|
10639
|
-
const target =
|
|
10714
|
+
const target = path15.resolve(filePath);
|
|
10640
10715
|
if (!desiredExternals.has(target))
|
|
10641
10716
|
return;
|
|
10642
10717
|
if (event === "add" && suppressInitialExternalAdds.delete(target))
|
|
@@ -10644,8 +10719,8 @@ function createFileWatcher(state) {
|
|
|
10644
10719
|
recordChange(event, target);
|
|
10645
10720
|
});
|
|
10646
10721
|
function isWatchedSource(target) {
|
|
10647
|
-
const rel =
|
|
10648
|
-
const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
10722
|
+
const rel = path15.relative(inputResolved, target);
|
|
10723
|
+
const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel);
|
|
10649
10724
|
if (inProject)
|
|
10650
10725
|
return !isIgnoredWatchPath(target, inputResolved);
|
|
10651
10726
|
return desiredExternals.has(target);
|
|
@@ -10670,7 +10745,7 @@ function createFileWatcher(state) {
|
|
|
10670
10745
|
state.notifySettledWrite = (filePath, writtenContent) => {
|
|
10671
10746
|
if (closed)
|
|
10672
10747
|
return;
|
|
10673
|
-
const target =
|
|
10748
|
+
const target = path15.resolve(filePath);
|
|
10674
10749
|
if (isWatchedSource(target)) {
|
|
10675
10750
|
acceptSettledWrite(target, writtenContent);
|
|
10676
10751
|
return;
|
|
@@ -10691,7 +10766,7 @@ function createFileWatcher(state) {
|
|
|
10691
10766
|
return;
|
|
10692
10767
|
let nextTargets;
|
|
10693
10768
|
try {
|
|
10694
|
-
nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) =>
|
|
10769
|
+
nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) => path15.resolve(target)));
|
|
10695
10770
|
} catch (err) {
|
|
10696
10771
|
debug(`Could not resolve external watch targets: ${err}`);
|
|
10697
10772
|
return;
|
|
@@ -10755,7 +10830,7 @@ function createFileWatcher(state) {
|
|
|
10755
10830
|
await syncExternalWatches();
|
|
10756
10831
|
if (closed)
|
|
10757
10832
|
return;
|
|
10758
|
-
await generateAndWriteHtml(inputResolved, state.tempDir, updatedConfig, state.cssAssets);
|
|
10833
|
+
await generateAndWriteHtml(inputResolved, state.tempDir, updatedConfig, state.cssAssets, state.imageRefs);
|
|
10759
10834
|
if (closed)
|
|
10760
10835
|
return;
|
|
10761
10836
|
state.previewServer?.broadcastReload();
|
|
@@ -10817,7 +10892,7 @@ async function stopFileWatcher(state) {
|
|
|
10817
10892
|
}
|
|
10818
10893
|
|
|
10819
10894
|
// src/preview/lifecycle.ts
|
|
10820
|
-
var TEMP_DIR_BASE =
|
|
10895
|
+
var TEMP_DIR_BASE = path16.join(tmpdir(), "gutterpress-preview");
|
|
10821
10896
|
var PID_FILE_NAME = ".gutterpress.pid";
|
|
10822
10897
|
function isProcessAlive(pid) {
|
|
10823
10898
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
@@ -10837,8 +10912,8 @@ async function cleanupOrphanTempDirs() {
|
|
|
10837
10912
|
return;
|
|
10838
10913
|
}
|
|
10839
10914
|
for (const entry of entries) {
|
|
10840
|
-
const dir =
|
|
10841
|
-
const pidFile =
|
|
10915
|
+
const dir = path16.join(TEMP_DIR_BASE, entry);
|
|
10916
|
+
const pidFile = path16.join(dir, PID_FILE_NAME);
|
|
10842
10917
|
try {
|
|
10843
10918
|
const raw = await readFile25(pidFile, "utf8");
|
|
10844
10919
|
const pid = parseInt(raw.trim(), 10);
|
|
@@ -10852,10 +10927,10 @@ async function cleanupOrphanTempDirs() {
|
|
|
10852
10927
|
async function initializePreviewDirectories() {
|
|
10853
10928
|
await cleanupOrphanTempDirs();
|
|
10854
10929
|
const tempDirSuffix = randomBytes2(8).toString("hex");
|
|
10855
|
-
const tempDir =
|
|
10930
|
+
const tempDir = path16.join(TEMP_DIR_BASE, tempDirSuffix);
|
|
10856
10931
|
await mkdir6(tempDir);
|
|
10857
10932
|
debug(`Created temporary directory: ${tempDir}`);
|
|
10858
|
-
await writeFile6(
|
|
10933
|
+
await writeFile6(path16.join(tempDir, PID_FILE_NAME), `${process.pid}
|
|
10859
10934
|
`, "utf8");
|
|
10860
10935
|
return tempDir;
|
|
10861
10936
|
}
|
|
@@ -10878,7 +10953,7 @@ async function restartPreview(newInputPath, state) {
|
|
|
10878
10953
|
state.currentInputPath = newInputPath;
|
|
10879
10954
|
const manifest = await loadManifest(newInputPath);
|
|
10880
10955
|
state.config = resolveConfig({}, manifest);
|
|
10881
|
-
await generateAndWriteHtml(newInputPath, state.tempDir, state.config, state.cssAssets);
|
|
10956
|
+
await generateAndWriteHtml(newInputPath, state.tempDir, state.config, state.cssAssets, state.imageRefs);
|
|
10882
10957
|
startFileWatcher(state);
|
|
10883
10958
|
state.previewServer?.broadcastReload();
|
|
10884
10959
|
info("Preview restarted successfully");
|
|
@@ -10938,7 +11013,8 @@ function createServerState(inputPath, tempDir, config, options) {
|
|
|
10938
11013
|
tempDir,
|
|
10939
11014
|
config,
|
|
10940
11015
|
options,
|
|
10941
|
-
cssAssets: new Map
|
|
11016
|
+
cssAssets: new Map,
|
|
11017
|
+
imageRefs: new Set
|
|
10942
11018
|
};
|
|
10943
11019
|
}
|
|
10944
11020
|
|
|
@@ -10978,55 +11054,6 @@ function openPath(filePath) {
|
|
|
10978
11054
|
});
|
|
10979
11055
|
}
|
|
10980
11056
|
|
|
10981
|
-
// src/lib/static-serve.ts
|
|
10982
|
-
import path16 from "node:path";
|
|
10983
|
-
var STATIC_MIME = {
|
|
10984
|
-
".html": "text/html; charset=utf-8",
|
|
10985
|
-
".htm": "text/html; charset=utf-8",
|
|
10986
|
-
".css": "text/css",
|
|
10987
|
-
".js": "application/javascript",
|
|
10988
|
-
".mjs": "application/javascript",
|
|
10989
|
-
".json": "application/json",
|
|
10990
|
-
".png": "image/png",
|
|
10991
|
-
".jpg": "image/jpeg",
|
|
10992
|
-
".jpeg": "image/jpeg",
|
|
10993
|
-
".gif": "image/gif",
|
|
10994
|
-
".svg": "image/svg+xml",
|
|
10995
|
-
".webp": "image/webp",
|
|
10996
|
-
".avif": "image/avif",
|
|
10997
|
-
".ico": "image/x-icon",
|
|
10998
|
-
".woff": "font/woff",
|
|
10999
|
-
".woff2": "font/woff2",
|
|
11000
|
-
".ttf": "font/ttf",
|
|
11001
|
-
".otf": "font/otf"
|
|
11002
|
-
};
|
|
11003
|
-
function resolveWithinRoot(relPath, root) {
|
|
11004
|
-
const resolvedRoot = path16.resolve(root);
|
|
11005
|
-
const candidate = path16.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
|
|
11006
|
-
if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path16.sep)) {
|
|
11007
|
-
return null;
|
|
11008
|
-
}
|
|
11009
|
-
return candidate;
|
|
11010
|
-
}
|
|
11011
|
-
function hasDotSegment(urlPathname) {
|
|
11012
|
-
let decoded;
|
|
11013
|
-
try {
|
|
11014
|
-
decoded = decodeURIComponent(urlPathname);
|
|
11015
|
-
} catch {
|
|
11016
|
-
return true;
|
|
11017
|
-
}
|
|
11018
|
-
return decoded.split(/[/\\]/).some((segment) => segment.startsWith("."));
|
|
11019
|
-
}
|
|
11020
|
-
function resolveStaticPath(urlPathname, root) {
|
|
11021
|
-
let decoded;
|
|
11022
|
-
try {
|
|
11023
|
-
decoded = decodeURIComponent(urlPathname);
|
|
11024
|
-
} catch {
|
|
11025
|
-
return null;
|
|
11026
|
-
}
|
|
11027
|
-
return resolveWithinRoot(decoded, root);
|
|
11028
|
-
}
|
|
11029
|
-
|
|
11030
11057
|
// src/preview/http-server.ts
|
|
11031
11058
|
var HMR_PATH = "/__gutterpress-hmr";
|
|
11032
11059
|
function shellHtml(initialRevision, instanceId) {
|
|
@@ -11166,6 +11193,22 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11166
11193
|
}
|
|
11167
11194
|
await serveStatic(absPath, res, PROJECT_ASSET_CACHE_CONTROL, { ETag: validator.etag });
|
|
11168
11195
|
}
|
|
11196
|
+
var missingImagePng;
|
|
11197
|
+
async function isMissingReferencedImage(pathname, absPath, refs) {
|
|
11198
|
+
if (!refs.has(imageRefKey(pathname)))
|
|
11199
|
+
return false;
|
|
11200
|
+
try {
|
|
11201
|
+
await stat5(absPath);
|
|
11202
|
+
return false;
|
|
11203
|
+
} catch (err) {
|
|
11204
|
+
return err?.code === "ENOENT";
|
|
11205
|
+
}
|
|
11206
|
+
}
|
|
11207
|
+
function serveMissingImage(res) {
|
|
11208
|
+
missingImagePng ??= Buffer.from(placeholderPng());
|
|
11209
|
+
res.writeHead(200, { "Content-Type": "image/png", "Cache-Control": "no-store" });
|
|
11210
|
+
res.end(missingImagePng);
|
|
11211
|
+
}
|
|
11169
11212
|
function matchesEmbedded(urlPathname) {
|
|
11170
11213
|
if (EMBEDDED_EXACT.has(urlPathname))
|
|
11171
11214
|
return true;
|
|
@@ -11317,6 +11360,10 @@ async function createPreviewServer(state, port) {
|
|
|
11317
11360
|
res.end("Not Found");
|
|
11318
11361
|
return;
|
|
11319
11362
|
}
|
|
11363
|
+
if (servingProjectRoot && await isMissingReferencedImage(pathname, absPath, state.imageRefs)) {
|
|
11364
|
+
serveMissingImage(res);
|
|
11365
|
+
return;
|
|
11366
|
+
}
|
|
11320
11367
|
const serve = servingProjectRoot ? serveRevalidatedStatic(req, absPath, res, projectAssetValidators) : serveStatic(absPath, res);
|
|
11321
11368
|
await serve.catch((err) => {
|
|
11322
11369
|
if (!res.headersSent) {
|
|
@@ -11392,7 +11439,7 @@ async function startPreviewServer(options) {
|
|
|
11392
11439
|
const config = await initializeConfiguration(inputPath);
|
|
11393
11440
|
const tempDir = await initializePreviewDirectories();
|
|
11394
11441
|
const state = createServerState(inputPath, tempDir, config, options);
|
|
11395
|
-
await generateAndWriteHtml(inputPath, tempDir, config, state.cssAssets);
|
|
11442
|
+
await generateAndWriteHtml(inputPath, tempDir, config, state.cssAssets, state.imageRefs);
|
|
11396
11443
|
const restartPreview2 = async (newInputPath) => {
|
|
11397
11444
|
await restartPreview(newInputPath, state);
|
|
11398
11445
|
};
|
|
@@ -29,7 +29,7 @@ var favicon_default = "./favicon-wkbm9cjn.ico";
|
|
|
29
29
|
var manifest_schema_default = "./manifest.schema-40sfq49z.json";
|
|
30
30
|
|
|
31
31
|
// src/assets/preview/scripts/preview-interface.js
|
|
32
|
-
var preview_interface_default = "./preview-interface-
|
|
32
|
+
var preview_interface_default = "./preview-interface-c44qk17f.js";
|
|
33
33
|
|
|
34
34
|
// src/assets/preview/scripts/preview-bridge.js
|
|
35
35
|
var preview_bridge_default = "./preview-bridge-8jhd1wpb.js";
|
|
@@ -41,7 +41,7 @@ var preview_shell_default = "./preview-shell-xwn84kqr.js";
|
|
|
41
41
|
var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
|
|
42
42
|
|
|
43
43
|
// src/assets/engine/gutterpress-viewer.js
|
|
44
|
-
var gutterpress_viewer_default = "./gutterpress-viewer-
|
|
44
|
+
var gutterpress_viewer_default = "./gutterpress-viewer-zkv2stfy.js";
|
|
45
45
|
|
|
46
46
|
// src/assets/engine/gutterpress-agent.js
|
|
47
47
|
var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
|
package/dist/index.js
CHANGED
|
@@ -148,13 +148,13 @@ import {
|
|
|
148
148
|
testRemoteAccess,
|
|
149
149
|
updateExtensions,
|
|
150
150
|
validateProjectExtensions
|
|
151
|
-
} from "./index-
|
|
151
|
+
} from "./index-c275p061.js";
|
|
152
152
|
import {
|
|
153
153
|
BUILD_DIAGNOSTIC_CODES
|
|
154
|
-
} from "./index-
|
|
154
|
+
} from "./index-5dcj1vts.js";
|
|
155
155
|
import {
|
|
156
156
|
BuildError
|
|
157
|
-
} from "./index-
|
|
157
|
+
} from "./index-eyaj6nkc.js";
|
|
158
158
|
import {
|
|
159
159
|
DEFAULT_PRINT_OPTS,
|
|
160
160
|
assertMilestone,
|
|
@@ -116,6 +116,16 @@ export interface AssembleBookHtmlOptions {
|
|
|
116
116
|
*/
|
|
117
117
|
preloadImages?: string[];
|
|
118
118
|
title?: string;
|
|
119
|
+
/**
|
|
120
|
+
* The manifest's `print` padding, written on `<html>` as
|
|
121
|
+
* `data-gp-signature` / `data-gp-reserve-last-page` so the viewer shows the
|
|
122
|
+
* blank pages the PDF build appends (`signaturePadding` in
|
|
123
|
+
* engine/shared/synthesis.ts) and the two page counts agree.
|
|
124
|
+
*/
|
|
125
|
+
print?: {
|
|
126
|
+
signature?: number;
|
|
127
|
+
reserveLastPage?: boolean;
|
|
128
|
+
};
|
|
119
129
|
plugins?: LoadedPlugin[];
|
|
120
130
|
pluginCss?: string;
|
|
121
131
|
/** Add a layout-neutral source-file id to source-mapped preview blocks. */
|
|
@@ -30,6 +30,11 @@ export declare function resolveActiveMarkdownFiles(inputDir: string, configuredF
|
|
|
30
30
|
*/
|
|
31
31
|
export declare function renderChapters(inputDir: string, opts?: {
|
|
32
32
|
title?: string;
|
|
33
|
+
/** See {@link AssembleBookHtmlOptions.print}. */
|
|
34
|
+
print?: {
|
|
35
|
+
signature?: number;
|
|
36
|
+
reserveLastPage?: boolean;
|
|
37
|
+
};
|
|
33
38
|
styles?: string[];
|
|
34
39
|
files?: string[] | null;
|
|
35
40
|
plugins?: LoadedPlugin[];
|
|
@@ -67,6 +72,11 @@ export declare function renderChapters(inputDir: string, opts?: {
|
|
|
67
72
|
*/
|
|
68
73
|
export declare function renderChaptersToFile(inputDir: string, outDir: string, opts?: {
|
|
69
74
|
title?: string;
|
|
75
|
+
/** See {@link AssembleBookHtmlOptions.print}. */
|
|
76
|
+
print?: {
|
|
77
|
+
signature?: number;
|
|
78
|
+
reserveLastPage?: boolean;
|
|
79
|
+
};
|
|
70
80
|
styles?: string[];
|
|
71
81
|
files?: string[] | null;
|
|
72
82
|
plugins?: LoadedPlugin[];
|
|
@@ -85,3 +85,9 @@ export declare function resolveStaticPath(urlPathname: string, root: string): st
|
|
|
85
85
|
* this helper.
|
|
86
86
|
*/
|
|
87
87
|
export declare function serveFile(filePath: string, res: http.ServerResponse): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* The URL path (no leading slash, decoded, no `./`) an image reference is
|
|
90
|
+
* served at from book.html — the key `ServerState.imageRefs` is looked
|
|
91
|
+
* up by. A query or fragment is dropped, as the server's own path is.
|
|
92
|
+
*/
|
|
93
|
+
export declare function imageRefKey(ref: string): string;
|
|
@@ -7,16 +7,16 @@ import {
|
|
|
7
7
|
TARGET_IDS,
|
|
8
8
|
scaffoldExtension,
|
|
9
9
|
scaffoldProject
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-6z5zthzt.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveGhostscript
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-70xgehq2.js";
|
|
14
14
|
import {
|
|
15
15
|
UsageError,
|
|
16
16
|
rejectExtraPositionals,
|
|
17
17
|
rejectUnknownFlags
|
|
18
|
-
} from "./cli-
|
|
19
|
-
import"./cli-
|
|
18
|
+
} from "./cli-ppc0vz4b.js";
|
|
19
|
+
import"./cli-gymfg04q.js";
|
|
20
20
|
import {
|
|
21
21
|
EXIT_CODES
|
|
22
22
|
} from "./cli-46ycxe6r.js";
|
|
@@ -2,16 +2,16 @@ import {
|
|
|
2
2
|
executeValidation,
|
|
3
3
|
publishTargetFor,
|
|
4
4
|
reportMissingTools
|
|
5
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-6z5zthzt.js";
|
|
6
6
|
import {
|
|
7
7
|
log
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-70xgehq2.js";
|
|
9
9
|
import {
|
|
10
10
|
UsageError,
|
|
11
11
|
rejectExtraPositionals,
|
|
12
12
|
rejectUnknownFlags
|
|
13
|
-
} from "./cli-
|
|
14
|
-
import"./cli-
|
|
13
|
+
} from "./cli-ppc0vz4b.js";
|
|
14
|
+
import"./cli-gymfg04q.js";
|
|
15
15
|
import {
|
|
16
16
|
BuildError,
|
|
17
17
|
EXIT_CODES
|
|
@@ -43,7 +43,11 @@ export declare function generateAndWriteHtml(inputPath: string, tempDir: string,
|
|
|
43
43
|
files?: string[] | null;
|
|
44
44
|
};
|
|
45
45
|
extensions?: ResolvedExtensionConfig[];
|
|
46
|
-
|
|
46
|
+
print?: {
|
|
47
|
+
signature?: number;
|
|
48
|
+
reserveLastPage?: boolean;
|
|
49
|
+
};
|
|
50
|
+
}, cssAssets: Map<string, string>, imageRefs?: Set<string>): Promise<void>;
|
|
47
51
|
/**
|
|
48
52
|
* Chokidar 5's `ignored` matcher (regex or function) is tested against the
|
|
49
53
|
* fully-qualified, forward-slash-normalized ABSOLUTE path — never a path
|
|
@@ -53,6 +53,16 @@ export interface ServerState {
|
|
|
53
53
|
* surface.
|
|
54
54
|
*/
|
|
55
55
|
cssAssets: Map<string, string>;
|
|
56
|
+
/**
|
|
57
|
+
* Every image the current render references (`onImageRefs`, the same list
|
|
58
|
+
* the build plans its asset copies from), normalized to the URL path the
|
|
59
|
+
* preview serves it at. A request for one whose file does not exist gets
|
|
60
|
+
* the build's magenta placeholder (`placeholderPng`) instead of a 404, so
|
|
61
|
+
* the preview lays out the same 640×480 box the PDF does rather than a
|
|
62
|
+
* small broken-image icon — that difference moved every later page by one
|
|
63
|
+
* in a real book (#354). Rebuilt on every render; exact-match lookups only.
|
|
64
|
+
*/
|
|
65
|
+
imageRefs: Set<string>;
|
|
56
66
|
}
|
|
57
67
|
/**
|
|
58
68
|
* Create initial server state
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
runBuild,
|
|
8
8
|
splitOutPath,
|
|
9
9
|
startPreviewServer
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-6z5zthzt.js";
|
|
11
11
|
import {
|
|
12
12
|
log
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-70xgehq2.js";
|
|
14
14
|
import {
|
|
15
15
|
UsageError,
|
|
16
16
|
parseFormat,
|
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
rejectExtraPositionals,
|
|
19
19
|
rejectUnknownFlags,
|
|
20
20
|
resolvePort
|
|
21
|
-
} from "./cli-
|
|
22
|
-
import"./cli-
|
|
21
|
+
} from "./cli-ppc0vz4b.js";
|
|
22
|
+
import"./cli-gymfg04q.js";
|
|
23
23
|
import {
|
|
24
24
|
BuildError
|
|
25
25
|
} from "./cli-46ycxe6r.js";
|