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.
Files changed (30) hide show
  1. package/dist/api/index.js +2 -2
  2. package/dist/{build-8epzrj8g.js → build-1p999cmg.js} +4 -4
  3. package/dist/{cli-ev175hx9.js → cli-6z5zthzt.js} +138 -93
  4. package/dist/{cli-0prrt9e4.js → cli-70xgehq2.js} +1 -1
  5. package/dist/{cli-wqy8hnnh.js → cli-gymfg04q.js} +8 -6
  6. package/dist/{cli-182j48xc.js → cli-ppc0vz4b.js} +1 -1
  7. package/dist/cli.js +12 -12
  8. package/dist/{doctor-24mbx7y1.js → doctor-reqpnn3h.js} +2 -2
  9. package/dist/engine/shared/synthesis.d.ts +8 -0
  10. package/dist/{engine-j5h953pg.js → engine-078ggczp.js} +1 -1
  11. package/dist/{engine-w17dbt4f.js → engine-5jzhjjvv.js} +2 -2
  12. package/dist/{ext-p9gx5aac.js → ext-dsbfejt3.js} +4 -4
  13. package/dist/{gutterpress-viewer-swz6bwfa.js → gutterpress-viewer-zkv2stfy.js} +51 -6
  14. package/dist/{index-qep93v0z.js → index-5dcj1vts.js} +7 -5
  15. package/dist/{index-40achhs8.js → index-c275p061.js} +137 -90
  16. package/dist/{index-ee7wp8q3.js → index-eyaj6nkc.js} +2 -2
  17. package/dist/index.js +3 -3
  18. package/dist/lib/markdown/assemble.d.ts +10 -0
  19. package/dist/lib/markdown/index.d.ts +10 -0
  20. package/dist/lib/static-serve.d.ts +6 -0
  21. package/dist/{new-wsjsrm7w.js → new-m5y2wepr.js} +4 -4
  22. package/dist/{preflight-0fjjnk9e.js → preflight-bwpqwwny.js} +4 -4
  23. package/dist/preview/file-watcher.d.ts +5 -1
  24. package/dist/preview/server-context.d.ts +10 -0
  25. package/dist/{preview-azy06gw0.js → preview-62y7qhkp.js} +4 -4
  26. package/dist/{preview-interface-5wnzrvhf.js → preview-interface-c44qk17f.js} +7 -2
  27. package/dist/{publish-8db67m2h.js → publish-k2zyt3x6.js} +4 -4
  28. package/dist/render.js +2 -1
  29. package/dist/{validate-e7mw1xyd.js → validate-fgwwxtbn.js} +4 -4
  30. package/package.json +1 -1
package/dist/api/index.js CHANGED
@@ -131,10 +131,10 @@ import {
131
131
  testRemoteAccess,
132
132
  updateExtensions,
133
133
  validateProjectExtensions
134
- } from "../index-40achhs8.js";
134
+ } from "../index-c275p061.js";
135
135
  import {
136
136
  BuildError
137
- } from "../index-ee7wp8q3.js";
137
+ } from "../index-eyaj6nkc.js";
138
138
  import {
139
139
  DEFAULT_PRINT_OPTS,
140
140
  assertMilestone,
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  runBuild,
3
3
  splitOutPath
4
- } from "./cli-ev175hx9.js";
4
+ } from "./cli-6z5zthzt.js";
5
5
  import {
6
6
  log
7
- } from "./cli-0prrt9e4.js";
7
+ } from "./cli-70xgehq2.js";
8
8
  import {
9
9
  UsageError,
10
10
  parseFormat,
11
11
  parsePdfxFlavor,
12
12
  rejectExtraPositionals,
13
13
  rejectUnknownFlags
14
- } from "./cli-182j48xc.js";
15
- import"./cli-wqy8hnnh.js";
14
+ } from "./cli-ppc0vz4b.js";
15
+ import"./cli-gymfg04q.js";
16
16
  import {
17
17
  BuildError
18
18
  } from "./cli-46ycxe6r.js";
@@ -13,17 +13,17 @@ import {
13
13
  stampCreator,
14
14
  stripAnnotations,
15
15
  warn
16
- } from "./cli-0prrt9e4.js";
16
+ } from "./cli-70xgehq2.js";
17
17
  import {
18
18
  DEBOUNCE,
19
19
  UsageError,
20
20
  resolvePort
21
- } from "./cli-182j48xc.js";
21
+ } from "./cli-ppc0vz4b.js";
22
22
  import {
23
23
  MARGIN_BOX_IGNORED_PROPERTIES,
24
24
  getAssetPath,
25
25
  getAssetsDir
26
- } from "./cli-wqy8hnnh.js";
26
+ } from "./cli-gymfg04q.js";
27
27
  import {
28
28
  BuildError,
29
29
  EXIT_CODES
@@ -8333,8 +8333,9 @@ ${projectCss.trim()}` : null
8333
8333
  `);
8334
8334
  const preloadTags = (opts.preloadImages ?? []).map((href) => `
8335
8335
  <link rel="preload" as="image" href="${href}">`).join("");
8336
+ const printAttrs = (opts.print?.signature && opts.print.signature > 1 ? ` data-gp-signature="${opts.print.signature}"` : "") + (opts.print?.reserveLastPage ? " data-gp-reserve-last-page" : "");
8336
8337
  return `<!DOCTYPE html>
8337
- <html lang="en">
8338
+ <html lang="en"${printAttrs}>
8338
8339
  <head>
8339
8340
  <meta charset="UTF-8">
8340
8341
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -8396,6 +8397,7 @@ ${css.trim()}
8396
8397
  projectCss: inlined.css,
8397
8398
  preloadImages: cssAssetCopies.map((c) => c.to),
8398
8399
  title: opts.title,
8400
+ print: opts.print,
8399
8401
  plugins: opts.plugins,
8400
8402
  pluginCss,
8401
8403
  annotateSourceChapters: opts.annotateSourceChapters,
@@ -8407,6 +8409,7 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
8407
8409
  await mkdir4(outDir, { recursive: true });
8408
8410
  const html = await renderChapters(inputDir, {
8409
8411
  title: opts.title,
8412
+ print: opts.print,
8410
8413
  styles: opts.styles,
8411
8414
  files: opts.files,
8412
8415
  plugins: opts.plugins,
@@ -9527,6 +9530,7 @@ async function renderBook(ctx) {
9527
9530
  const cssAssets = [];
9528
9531
  const htmlFile = await renderChaptersToFile(renderDir, workDir, {
9529
9532
  title: config.title,
9533
+ print: config.print,
9530
9534
  styles: config.styles,
9531
9535
  files: config.source.files,
9532
9536
  plugins,
@@ -9678,7 +9682,7 @@ class PdfOutput {
9678
9682
  const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
9679
9683
  await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
9680
9684
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
9681
- const { buildNativePdf } = await import("./engine-j5h953pg.js");
9685
+ const { buildNativePdf } = await import("./engine-078ggczp.js");
9682
9686
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
9683
9687
  title: config.title,
9684
9688
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -9809,7 +9813,7 @@ function openPath(filePath) {
9809
9813
  }
9810
9814
 
9811
9815
  // src/preview/lifecycle.ts
9812
- import path15 from "path";
9816
+ import path16 from "path";
9813
9817
  import { tmpdir } from "os";
9814
9818
  import { randomBytes as randomBytes2 } from "crypto";
9815
9819
  import { readdir as readdir4, readFile as readFile24, writeFile as writeFile5 } from "node:fs/promises";
@@ -9834,7 +9838,65 @@ async function mkdir6(dirPath) {
9834
9838
  // src/preview/file-watcher.ts
9835
9839
  import { watch } from "chokidar";
9836
9840
  import fsp3 from "node:fs/promises";
9837
- import path14 from "path";
9841
+ import path15 from "path";
9842
+
9843
+ // src/lib/static-serve.ts
9844
+ import path14 from "node:path";
9845
+ var STATIC_MIME = {
9846
+ ".html": "text/html; charset=utf-8",
9847
+ ".htm": "text/html; charset=utf-8",
9848
+ ".css": "text/css",
9849
+ ".js": "application/javascript",
9850
+ ".mjs": "application/javascript",
9851
+ ".json": "application/json",
9852
+ ".png": "image/png",
9853
+ ".jpg": "image/jpeg",
9854
+ ".jpeg": "image/jpeg",
9855
+ ".gif": "image/gif",
9856
+ ".svg": "image/svg+xml",
9857
+ ".webp": "image/webp",
9858
+ ".avif": "image/avif",
9859
+ ".ico": "image/x-icon",
9860
+ ".woff": "font/woff",
9861
+ ".woff2": "font/woff2",
9862
+ ".ttf": "font/ttf",
9863
+ ".otf": "font/otf"
9864
+ };
9865
+ function resolveWithinRoot(relPath, root) {
9866
+ const resolvedRoot = path14.resolve(root);
9867
+ const candidate = path14.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
9868
+ if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path14.sep)) {
9869
+ return null;
9870
+ }
9871
+ return candidate;
9872
+ }
9873
+ function hasDotSegment(urlPathname) {
9874
+ let decoded;
9875
+ try {
9876
+ decoded = decodeURIComponent(urlPathname);
9877
+ } catch {
9878
+ return true;
9879
+ }
9880
+ return decoded.split(/[/\\]/).some((segment) => segment.startsWith("."));
9881
+ }
9882
+ function resolveStaticPath(urlPathname, root) {
9883
+ let decoded;
9884
+ try {
9885
+ decoded = decodeURIComponent(urlPathname);
9886
+ } catch {
9887
+ return null;
9888
+ }
9889
+ return resolveWithinRoot(decoded, root);
9890
+ }
9891
+ function imageRefKey(ref) {
9892
+ let key = ref.split(/[?#]/)[0].replace(/^\.\//, "").replace(/^\/+/, "");
9893
+ try {
9894
+ key = decodeURIComponent(key);
9895
+ } catch {}
9896
+ return key;
9897
+ }
9898
+
9899
+ // src/preview/file-watcher.ts
9838
9900
  var EMPTY_BOOK_HTML = `<!doctype html>
9839
9901
  <html lang="en">
9840
9902
  <head>
@@ -9855,12 +9917,14 @@ async function renderPreviewBook(inputPath, config, opts) {
9855
9917
  const { plugins, pluginStyles } = await loadPluginsWithCss(config.extensions, inputPath, (ref, err) => warn(`Skipping plugin "${ref}" in preview — ${err.message}`));
9856
9918
  return renderChapters(inputPath, {
9857
9919
  title: config.title ?? "Document",
9920
+ print: config.print,
9858
9921
  styles: config.styles,
9859
9922
  files: opts.files,
9860
9923
  plugins,
9861
9924
  pluginStyles,
9862
9925
  annotateSourceChapters: true,
9863
9926
  ...opts.onCssAssets ? { onCssAssets: opts.onCssAssets } : {},
9927
+ ...opts.onImageRefs ? { onImageRefs: opts.onImageRefs } : {},
9864
9928
  onChapterWarnings: (file, warnings) => {
9865
9929
  for (const w of warnings) {
9866
9930
  warn(` ${file}, line ${w.line}: ${w.message}`);
@@ -9875,24 +9939,35 @@ function injectPreviewScripts(html) {
9875
9939
  `;
9876
9940
  return /<\/head>/i.test(html) ? html.replace(/<\/head>/i, scripts + "</head>") : html + scripts;
9877
9941
  }
9878
- async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
9942
+ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, imageRefs) {
9879
9943
  if (!inputPath) {
9880
9944
  cssAssets.clear();
9881
- await fsp3.writeFile(path14.join(tempDir, BOOK_HTML_FILENAME), EMPTY_BOOK_HTML, "utf-8");
9945
+ imageRefs?.clear();
9946
+ await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), EMPTY_BOOK_HTML, "utf-8");
9882
9947
  return;
9883
9948
  }
9884
9949
  const nextAssets = new Map;
9950
+ const nextImageRefs = new Set;
9885
9951
  const html = await renderPreviewBook(inputPath, config, {
9886
9952
  files: config.source?.files ?? null,
9887
9953
  onCssAssets: (copies) => {
9888
9954
  for (const copy of copies)
9889
9955
  nextAssets.set(copy.to, copy.from);
9956
+ },
9957
+ onImageRefs: (refs) => {
9958
+ for (const ref of refs)
9959
+ nextImageRefs.add(imageRefKey(ref));
9890
9960
  }
9891
9961
  });
9892
9962
  cssAssets.clear();
9893
9963
  for (const [to, from] of nextAssets)
9894
9964
  cssAssets.set(to, from);
9895
- await fsp3.writeFile(path14.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html), "utf-8");
9965
+ if (imageRefs) {
9966
+ imageRefs.clear();
9967
+ for (const ref of nextImageRefs)
9968
+ imageRefs.add(ref);
9969
+ }
9970
+ await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html), "utf-8");
9896
9971
  }
9897
9972
  function isDotPathUnderRoot(candidatePath, root) {
9898
9973
  const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+$/, "");
@@ -9929,23 +10004,23 @@ function isIgnoredWatchPath(candidatePath, projectRoot) {
9929
10004
  return isDotPathUnderRoot(candidatePath, projectRoot) || isGeneratedProjectPath(relative2);
9930
10005
  }
9931
10006
  function isExternalWatchCandidate(candidatePath, targets) {
9932
- const candidate = path14.resolve(candidatePath);
10007
+ const candidate = path15.resolve(candidatePath);
9933
10008
  for (const rawTarget of targets) {
9934
- const target = path14.resolve(rawTarget);
9935
- const rel = path14.relative(candidate, target);
9936
- if (rel === "" || rel !== ".." && !rel.startsWith(`..${path14.sep}`) && !path14.isAbsolute(rel))
10009
+ const target = path15.resolve(rawTarget);
10010
+ const rel = path15.relative(candidate, target);
10011
+ if (rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel))
9937
10012
  return true;
9938
10013
  }
9939
10014
  return false;
9940
10015
  }
9941
10016
  async function nearestExistingDirectory(start) {
9942
- let current = path14.resolve(start);
10017
+ let current = path15.resolve(start);
9943
10018
  while (true) {
9944
10019
  try {
9945
10020
  if ((await fsp3.stat(current)).isDirectory())
9946
10021
  return current;
9947
10022
  } catch {}
9948
- const parent = path14.dirname(current);
10023
+ const parent = path15.dirname(current);
9949
10024
  if (parent === current)
9950
10025
  return current;
9951
10026
  current = parent;
@@ -9954,7 +10029,7 @@ async function nearestExistingDirectory(start) {
9954
10029
  async function externalWatchRoots(targets) {
9955
10030
  const roots = new Set;
9956
10031
  for (const target of targets) {
9957
- roots.add(await nearestExistingDirectory(path14.dirname(path14.resolve(target))));
10032
+ roots.add(await nearestExistingDirectory(path15.dirname(path15.resolve(target))));
9958
10033
  }
9959
10034
  return [...roots];
9960
10035
  }
@@ -9968,19 +10043,19 @@ async function extensionFolderFiles(dir) {
9968
10043
  const meta = await readExtensionMeta(dir);
9969
10044
  const entry = extensionEntry(meta);
9970
10045
  return [
9971
- path14.join(dir, EXTENSION_MANIFEST_FILENAME),
9972
- ...entry ? [path14.resolve(dir, entry)] : [],
10046
+ path15.join(dir, EXTENSION_MANIFEST_FILENAME),
10047
+ ...entry ? [path15.resolve(dir, entry)] : [],
9973
10048
  ...await collectStyleDependencies(dir, extensionStyleList(meta))
9974
10049
  ];
9975
10050
  }
9976
10051
  async function externalWatchTargets(projectDir, config) {
9977
- const root = path14.resolve(projectDir);
10052
+ const root = path15.resolve(projectDir);
9978
10053
  let canonicalRoot = root;
9979
10054
  try {
9980
10055
  canonicalRoot = await fsp3.realpath(root);
9981
10056
  } catch {}
9982
10057
  const styles = await resolveActiveStyles(root, config.styles);
9983
- const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) => path14.resolve(root, p));
10058
+ const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) => path15.resolve(root, p));
9984
10059
  const candidates = [
9985
10060
  ...await collectStyleDependencies(root, styles),
9986
10061
  ...extensionPaths,
@@ -9988,17 +10063,17 @@ async function externalWatchTargets(projectDir, config) {
9988
10063
  ];
9989
10064
  const external = new Set;
9990
10065
  for (const abs of candidates) {
9991
- const authoredPath = path14.resolve(abs);
9992
- const authoredRel = path14.relative(root, authoredPath);
9993
- if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${path14.sep}`) || path14.isAbsolute(authoredRel))) {
10066
+ const authoredPath = path15.resolve(abs);
10067
+ const authoredRel = path15.relative(root, authoredPath);
10068
+ if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${path15.sep}`) || path15.isAbsolute(authoredRel))) {
9994
10069
  external.add(authoredPath);
9995
10070
  }
9996
10071
  let canonicalPath = authoredPath;
9997
10072
  try {
9998
10073
  canonicalPath = await fsp3.realpath(canonicalPath);
9999
10074
  } catch {}
10000
- const rel = path14.relative(canonicalRoot, canonicalPath);
10001
- if (rel === "" || rel !== ".." && !rel.startsWith(`..${path14.sep}`) && !path14.isAbsolute(rel))
10075
+ const rel = path15.relative(canonicalRoot, canonicalPath);
10076
+ if (rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel))
10002
10077
  continue;
10003
10078
  external.add(canonicalPath);
10004
10079
  }
@@ -10025,7 +10100,7 @@ async function addAndAwaitWatch(watcher, roots) {
10025
10100
  }
10026
10101
  }
10027
10102
  function createFileWatcher(state) {
10028
- const inputResolved = path14.resolve(state.currentInputPath);
10103
+ const inputResolved = path15.resolve(state.currentInputPath);
10029
10104
  const watcher = watch(inputResolved, {
10030
10105
  persistent: true,
10031
10106
  ignoreInitial: true,
@@ -10065,7 +10140,7 @@ function createFileWatcher(state) {
10065
10140
  async function recordChange(event, filePath) {
10066
10141
  if (closed)
10067
10142
  return;
10068
- const target = path14.resolve(filePath);
10143
+ const target = path15.resolve(filePath);
10069
10144
  const settled = settledWrites.get(target);
10070
10145
  if (settled && event !== "unlink" && Date.now() <= settled.expiresAt) {
10071
10146
  const diskContent = await fsp3.readFile(target, "utf8").catch(() => null);
@@ -10086,7 +10161,7 @@ function createFileWatcher(state) {
10086
10161
  recordChange(event, filePath);
10087
10162
  });
10088
10163
  externalWatcher.on("all", (event, filePath) => {
10089
- const target = path14.resolve(filePath);
10164
+ const target = path15.resolve(filePath);
10090
10165
  if (!desiredExternals.has(target))
10091
10166
  return;
10092
10167
  if (event === "add" && suppressInitialExternalAdds.delete(target))
@@ -10094,8 +10169,8 @@ function createFileWatcher(state) {
10094
10169
  recordChange(event, target);
10095
10170
  });
10096
10171
  function isWatchedSource(target) {
10097
- const rel = path14.relative(inputResolved, target);
10098
- const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${path14.sep}`) && !path14.isAbsolute(rel);
10172
+ const rel = path15.relative(inputResolved, target);
10173
+ const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel);
10099
10174
  if (inProject)
10100
10175
  return !isIgnoredWatchPath(target, inputResolved);
10101
10176
  return desiredExternals.has(target);
@@ -10120,7 +10195,7 @@ function createFileWatcher(state) {
10120
10195
  state.notifySettledWrite = (filePath, writtenContent) => {
10121
10196
  if (closed)
10122
10197
  return;
10123
- const target = path14.resolve(filePath);
10198
+ const target = path15.resolve(filePath);
10124
10199
  if (isWatchedSource(target)) {
10125
10200
  acceptSettledWrite(target, writtenContent);
10126
10201
  return;
@@ -10141,7 +10216,7 @@ function createFileWatcher(state) {
10141
10216
  return;
10142
10217
  let nextTargets;
10143
10218
  try {
10144
- nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) => path14.resolve(target)));
10219
+ nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) => path15.resolve(target)));
10145
10220
  } catch (err) {
10146
10221
  debug(`Could not resolve external watch targets: ${err}`);
10147
10222
  return;
@@ -10205,7 +10280,7 @@ function createFileWatcher(state) {
10205
10280
  await syncExternalWatches();
10206
10281
  if (closed)
10207
10282
  return;
10208
- await generateAndWriteHtml(inputResolved, state.tempDir, updatedConfig, state.cssAssets);
10283
+ await generateAndWriteHtml(inputResolved, state.tempDir, updatedConfig, state.cssAssets, state.imageRefs);
10209
10284
  if (closed)
10210
10285
  return;
10211
10286
  state.previewServer?.broadcastReload();
@@ -10267,7 +10342,7 @@ async function stopFileWatcher(state) {
10267
10342
  }
10268
10343
 
10269
10344
  // src/preview/lifecycle.ts
10270
- var TEMP_DIR_BASE = path15.join(tmpdir(), "gutterpress-preview");
10345
+ var TEMP_DIR_BASE = path16.join(tmpdir(), "gutterpress-preview");
10271
10346
  var PID_FILE_NAME = ".gutterpress.pid";
10272
10347
  function isProcessAlive(pid) {
10273
10348
  if (!Number.isFinite(pid) || pid <= 0)
@@ -10287,8 +10362,8 @@ async function cleanupOrphanTempDirs() {
10287
10362
  return;
10288
10363
  }
10289
10364
  for (const entry of entries) {
10290
- const dir = path15.join(TEMP_DIR_BASE, entry);
10291
- const pidFile = path15.join(dir, PID_FILE_NAME);
10365
+ const dir = path16.join(TEMP_DIR_BASE, entry);
10366
+ const pidFile = path16.join(dir, PID_FILE_NAME);
10292
10367
  try {
10293
10368
  const raw = await readFile24(pidFile, "utf8");
10294
10369
  const pid = parseInt(raw.trim(), 10);
@@ -10302,10 +10377,10 @@ async function cleanupOrphanTempDirs() {
10302
10377
  async function initializePreviewDirectories() {
10303
10378
  await cleanupOrphanTempDirs();
10304
10379
  const tempDirSuffix = randomBytes2(8).toString("hex");
10305
- const tempDir = path15.join(TEMP_DIR_BASE, tempDirSuffix);
10380
+ const tempDir = path16.join(TEMP_DIR_BASE, tempDirSuffix);
10306
10381
  await mkdir6(tempDir);
10307
10382
  debug(`Created temporary directory: ${tempDir}`);
10308
- await writeFile5(path15.join(tempDir, PID_FILE_NAME), `${process.pid}
10383
+ await writeFile5(path16.join(tempDir, PID_FILE_NAME), `${process.pid}
10309
10384
  `, "utf8");
10310
10385
  return tempDir;
10311
10386
  }
@@ -10328,7 +10403,7 @@ async function restartPreview(newInputPath, state) {
10328
10403
  state.currentInputPath = newInputPath;
10329
10404
  const manifest = await loadManifest(newInputPath);
10330
10405
  state.config = resolveConfig({}, manifest);
10331
- await generateAndWriteHtml(newInputPath, state.tempDir, state.config, state.cssAssets);
10406
+ await generateAndWriteHtml(newInputPath, state.tempDir, state.config, state.cssAssets, state.imageRefs);
10332
10407
  startFileWatcher(state);
10333
10408
  state.previewServer?.broadcastReload();
10334
10409
  info("Preview restarted successfully");
@@ -10388,7 +10463,8 @@ function createServerState(inputPath, tempDir, config, options) {
10388
10463
  tempDir,
10389
10464
  config,
10390
10465
  options,
10391
- cssAssets: new Map
10466
+ cssAssets: new Map,
10467
+ imageRefs: new Set
10392
10468
  };
10393
10469
  }
10394
10470
 
@@ -10399,57 +10475,6 @@ import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypt
10399
10475
  import { readFile as readFile25, stat as stat5 } from "node:fs/promises";
10400
10476
  import path17 from "path";
10401
10477
  import { WebSocket, WebSocketServer } from "ws";
10402
-
10403
- // src/lib/static-serve.ts
10404
- import path16 from "node:path";
10405
- var STATIC_MIME = {
10406
- ".html": "text/html; charset=utf-8",
10407
- ".htm": "text/html; charset=utf-8",
10408
- ".css": "text/css",
10409
- ".js": "application/javascript",
10410
- ".mjs": "application/javascript",
10411
- ".json": "application/json",
10412
- ".png": "image/png",
10413
- ".jpg": "image/jpeg",
10414
- ".jpeg": "image/jpeg",
10415
- ".gif": "image/gif",
10416
- ".svg": "image/svg+xml",
10417
- ".webp": "image/webp",
10418
- ".avif": "image/avif",
10419
- ".ico": "image/x-icon",
10420
- ".woff": "font/woff",
10421
- ".woff2": "font/woff2",
10422
- ".ttf": "font/ttf",
10423
- ".otf": "font/otf"
10424
- };
10425
- function resolveWithinRoot(relPath, root) {
10426
- const resolvedRoot = path16.resolve(root);
10427
- const candidate = path16.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
10428
- if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path16.sep)) {
10429
- return null;
10430
- }
10431
- return candidate;
10432
- }
10433
- function hasDotSegment(urlPathname) {
10434
- let decoded;
10435
- try {
10436
- decoded = decodeURIComponent(urlPathname);
10437
- } catch {
10438
- return true;
10439
- }
10440
- return decoded.split(/[/\\]/).some((segment) => segment.startsWith("."));
10441
- }
10442
- function resolveStaticPath(urlPathname, root) {
10443
- let decoded;
10444
- try {
10445
- decoded = decodeURIComponent(urlPathname);
10446
- } catch {
10447
- return null;
10448
- }
10449
- return resolveWithinRoot(decoded, root);
10450
- }
10451
-
10452
- // src/preview/http-server.ts
10453
10478
  var HMR_PATH = "/__gutterpress-hmr";
10454
10479
  function shellHtml(initialRevision, instanceId) {
10455
10480
  return `<!doctype html>
@@ -10588,6 +10613,22 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
10588
10613
  }
10589
10614
  await serveStatic(absPath, res, PROJECT_ASSET_CACHE_CONTROL, { ETag: validator.etag });
10590
10615
  }
10616
+ var missingImagePng;
10617
+ async function isMissingReferencedImage(pathname, absPath, refs) {
10618
+ if (!refs.has(imageRefKey(pathname)))
10619
+ return false;
10620
+ try {
10621
+ await stat5(absPath);
10622
+ return false;
10623
+ } catch (err) {
10624
+ return err?.code === "ENOENT";
10625
+ }
10626
+ }
10627
+ function serveMissingImage(res) {
10628
+ missingImagePng ??= Buffer.from(placeholderPng());
10629
+ res.writeHead(200, { "Content-Type": "image/png", "Cache-Control": "no-store" });
10630
+ res.end(missingImagePng);
10631
+ }
10591
10632
  function matchesEmbedded(urlPathname) {
10592
10633
  if (EMBEDDED_EXACT.has(urlPathname))
10593
10634
  return true;
@@ -10739,6 +10780,10 @@ async function createPreviewServer(state, port) {
10739
10780
  res.end("Not Found");
10740
10781
  return;
10741
10782
  }
10783
+ if (servingProjectRoot && await isMissingReferencedImage(pathname, absPath, state.imageRefs)) {
10784
+ serveMissingImage(res);
10785
+ return;
10786
+ }
10742
10787
  const serve = servingProjectRoot ? serveRevalidatedStatic(req, absPath, res, projectAssetValidators) : serveStatic(absPath, res);
10743
10788
  await serve.catch((err) => {
10744
10789
  if (!res.headersSent) {
@@ -10814,7 +10859,7 @@ async function startPreviewServer(options) {
10814
10859
  const config = await initializeConfiguration(inputPath);
10815
10860
  const tempDir = await initializePreviewDirectories();
10816
10861
  const state = createServerState(inputPath, tempDir, config, options);
10817
- await generateAndWriteHtml(inputPath, tempDir, config, state.cssAssets);
10862
+ await generateAndWriteHtml(inputPath, tempDir, config, state.cssAssets, state.imageRefs);
10818
10863
  const restartPreview2 = async (newInputPath) => {
10819
10864
  await restartPreview(newInputPath, state);
10820
10865
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./cli-182j48xc.js";
3
+ } from "./cli-ppc0vz4b.js";
4
4
  import {
5
5
  execCapture,
6
6
  findTool,
@@ -681,6 +681,11 @@ function planRectoBlanks(sites) {
681
681
  return wrong;
682
682
  });
683
683
  }
684
+ function signaturePadding(pageCount, signature = 1, reserveLastPage = false) {
685
+ const size = signature > 1 ? signature : 1;
686
+ const padded = (size - pageCount % size) % size;
687
+ return padded === 0 && reserveLastPage ? size : padded;
688
+ }
684
689
  var WHICH_VALUES = new Set(["first", "start", "last", "first-except"]);
685
690
  function parseWhich(raw) {
686
691
  const w = (raw ?? "").trim();
@@ -1109,7 +1114,7 @@ var favicon_default = "./favicon-wkbm9cjn.ico";
1109
1114
  var manifest_schema_default = "./manifest.schema-40sfq49z.json";
1110
1115
 
1111
1116
  // src/assets/preview/scripts/preview-interface.js
1112
- var preview_interface_default = "./preview-interface-5wnzrvhf.js";
1117
+ var preview_interface_default = "./preview-interface-c44qk17f.js";
1113
1118
 
1114
1119
  // src/assets/preview/scripts/preview-bridge.js
1115
1120
  var preview_bridge_default = "./preview-bridge-8jhd1wpb.js";
@@ -1121,7 +1126,7 @@ var preview_shell_default = "./preview-shell-xwn84kqr.js";
1121
1126
  var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
1122
1127
 
1123
1128
  // src/assets/engine/gutterpress-viewer.js
1124
- var gutterpress_viewer_default = "./gutterpress-viewer-swz6bwfa.js";
1129
+ var gutterpress_viewer_default = "./gutterpress-viewer-zkv2stfy.js";
1125
1130
 
1126
1131
  // src/assets/engine/gutterpress-agent.js
1127
1132
  var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
@@ -1450,10 +1455,7 @@ async function postprocess(input, opts) {
1450
1455
  g.media.width - inset,
1451
1456
  g.media.height - inset
1452
1457
  ];
1453
- const signature = opts.signature && opts.signature > 1 ? opts.signature : 1;
1454
- let padded = (signature - doc.getPageCount() % signature) % signature;
1455
- if (padded === 0 && opts.reserveLastPage)
1456
- padded = signature;
1458
+ const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.reserveLastPage);
1457
1459
  for (let i = 0;i < padded; i++)
1458
1460
  doc.addPage([g.media.width, g.media.height]);
1459
1461
  const wantMarks = opts.marks || g.marks.includes("crop") || g.marks.includes("cross");
@@ -4,7 +4,7 @@ import {
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "gutterpress",
7
- version: "0.11.16",
7
+ version: "0.11.17-alpha.2",
8
8
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
9
9
  author: "itlackey",
10
10
  license: "MPL-2.0",
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  UsageError,
7
7
  package_default,
8
8
  rejectUnknownFlags
9
- } from "./cli-182j48xc.js";
9
+ } from "./cli-ppc0vz4b.js";
10
10
  import {
11
11
  EXIT_CODES
12
12
  } from "./cli-46ycxe6r.js";
@@ -18,14 +18,14 @@ import {
18
18
  import { defineCommand, parseArgs, runMain } from "citty";
19
19
  import { statSync } from "node:fs";
20
20
  var SUBCOMMANDS = {
21
- new: () => import("./new-wsjsrm7w.js").then((m) => m.default),
22
- preview: () => import("./preview-azy06gw0.js").then((m) => m.default),
23
- build: () => import("./build-8epzrj8g.js").then((m) => m.default),
24
- publish: () => import("./publish-8db67m2h.js").then((m) => m.default),
25
- validate: () => import("./validate-e7mw1xyd.js").then((m) => m.default),
26
- preflight: () => import("./preflight-0fjjnk9e.js").then((m) => m.default),
27
- doctor: () => import("./doctor-24mbx7y1.js").then((m) => m.default),
28
- ext: () => import("./ext-p9gx5aac.js").then((m) => m.default)
21
+ new: () => import("./new-m5y2wepr.js").then((m) => m.default),
22
+ preview: () => import("./preview-62y7qhkp.js").then((m) => m.default),
23
+ build: () => import("./build-1p999cmg.js").then((m) => m.default),
24
+ publish: () => import("./publish-k2zyt3x6.js").then((m) => m.default),
25
+ validate: () => import("./validate-fgwwxtbn.js").then((m) => m.default),
26
+ preflight: () => import("./preflight-bwpqwwny.js").then((m) => m.default),
27
+ doctor: () => import("./doctor-reqpnn3h.js").then((m) => m.default),
28
+ ext: () => import("./ext-dsbfejt3.js").then((m) => m.default)
29
29
  };
30
30
  var VERSION = package_default.version;
31
31
  var main = defineCommand({
@@ -50,7 +50,7 @@ async function preflightRequiredInvocations(rawArgs) {
50
50
  const [command, ...commandArgs] = rawArgs;
51
51
  try {
52
52
  if (command === "new") {
53
- const { newArgs } = await import("./new-wsjsrm7w.js");
53
+ const { newArgs } = await import("./new-m5y2wepr.js");
54
54
  rejectUnknownFlags(commandArgs, newArgs, "new");
55
55
  const parsed = parseArgs(commandArgs, {
56
56
  ...newArgs,
@@ -62,7 +62,7 @@ async function preflightRequiredInvocations(rawArgs) {
62
62
  return;
63
63
  }
64
64
  if (command === "preflight") {
65
- const { preflightArgs } = await import("./preflight-0fjjnk9e.js");
65
+ const { preflightArgs } = await import("./preflight-bwpqwwny.js");
66
66
  rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
67
67
  const parsed = parseArgs(commandArgs, {
68
68
  ...preflightArgs,
@@ -82,7 +82,7 @@ async function preflightRequiredInvocations(rawArgs) {
82
82
  }
83
83
  if (subcommand.startsWith("-"))
84
84
  return;
85
- const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-p9gx5aac.js");
85
+ const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-dsbfejt3.js");
86
86
  if (!EXT_SUBCOMMANDS.includes(subcommand)) {
87
87
  throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
88
88
  }
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getSystemDiagnostics,
3
3
  log
4
- } from "./cli-0prrt9e4.js";
4
+ } from "./cli-70xgehq2.js";
5
5
  import {
6
6
  UsageError,
7
7
  rejectExtraPositionals,
8
8
  rejectUnknownFlags
9
- } from "./cli-182j48xc.js";
9
+ } from "./cli-ppc0vz4b.js";
10
10
  import"./cli-46ycxe6r.js";
11
11
  import"./cli-7fkhgtfn.js";
12
12
  import"./cli-37x76zdn.js";