gutterpress 0.11.23-beta.1 → 0.11.23-beta.3

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 (65) hide show
  1. package/README.md +13 -3
  2. package/dist/api/index.d.ts +5 -5
  3. package/dist/api/index.js +19 -7
  4. package/dist/{build-dg8a566j.js → build-fq3mexhy.js} +9 -9
  5. package/dist/checks/asset/approved-fonts.d.ts +8 -0
  6. package/dist/checks/asset/extensions.d.ts +1 -1
  7. package/dist/checks/asset/index.d.ts +1 -0
  8. package/dist/{cli-e31jshz6.js → cli-5zbdb6mt.js} +296 -65
  9. package/dist/{cli-ttj95aex.js → cli-7mt0dftw.js} +47 -18
  10. package/dist/{cli-989eg8jz.js → cli-ah93yyzb.js} +163 -55
  11. package/dist/{cli-31anr0r9.js → cli-eymdsefg.js} +69 -29
  12. package/dist/{cli-1fy1pm9d.js → cli-fh685nqs.js} +1 -1
  13. package/dist/{cli-k087gj0p.js → cli-fsjre61x.js} +123 -12
  14. package/dist/{cli-s1zt779w.js → cli-q7t04gjt.js} +1 -1
  15. package/dist/{cli-vhav8g82.js → cli-rybz2dfs.js} +1 -1
  16. package/dist/cli.js +12 -12
  17. package/dist/{doctor-g4a42tcz.js → doctor-tg9ht1n3.js} +3 -3
  18. package/dist/engine/compiler/postprocess.d.ts +3 -0
  19. package/dist/engine/shared/pdf-inspect.d.ts +33 -0
  20. package/dist/{engine-jvkcahr1.js → engine-17v87vq5.js} +1 -1
  21. package/dist/{engine-wgkaqjsc.js → engine-y9fnarfa.js} +2 -2
  22. package/dist/{ext-w9d5ftcg.js → ext-esz03jz4.js} +27 -10
  23. package/dist/{extension-restore-5x4mj79d.js → extension-restore-91gy1e28.js} +3 -3
  24. package/dist/{extension-restore-as0g38p1.js → extension-restore-q70wqah5.js} +5 -5
  25. package/dist/{gutterpress-agent-d29ry3ak.js → gutterpress-agent-wyryqehx.js} +13 -4
  26. package/dist/{gutterpress-viewer-ze691rrd.js → gutterpress-viewer-ywkf49q5.js} +38 -153
  27. package/dist/{index-a4j3xcfp.js → index-67g8f7r4.js} +47 -18
  28. package/dist/{index-798jt0qc.js → index-d9w3r89w.js} +3 -3
  29. package/dist/{index-rj5vrhz6.js → index-fntpr44x.js} +321 -66
  30. package/dist/{index-5x42amh8.js → index-g3te5ey1.js} +2 -1
  31. package/dist/{index-cw03e9p4.js → index-kw4tbthz.js} +69 -29
  32. package/dist/{index-fk2kpf2t.js → index-santcs4q.js} +121 -10
  33. package/dist/{index-c6y0p7jy.js → index-z6vzj3s5.js} +243 -73
  34. package/dist/index.js +35 -8
  35. package/dist/lib/check-options.d.ts +70 -0
  36. package/dist/lib/extension-manager.d.ts +16 -1
  37. package/dist/lib/extension-scaffold.d.ts +15 -2
  38. package/dist/lib/extension-specifier.d.ts +8 -1
  39. package/dist/lib/manifest-config.d.ts +3 -1
  40. package/dist/lib/manifest-old-spellings.d.ts +32 -9
  41. package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
  42. package/dist/lib/markdown/math.d.ts +1 -1
  43. package/dist/lib/markdown/typography.d.ts +1 -0
  44. package/dist/lib/page-size.d.ts +12 -4
  45. package/dist/lib/plugin-vendor.d.ts +6 -0
  46. package/dist/lib/presets.d.ts +2 -2
  47. package/dist/lib/root-tokens.d.ts +2 -1
  48. package/dist/lib/source-provider.d.ts +27 -0
  49. package/dist/lib/style-resolver.d.ts +2 -1
  50. package/dist/lib/version-changes.d.ts +22 -6
  51. package/dist/{manifest.schema-0jgj0jt1.json → manifest.schema-5cm13vr3.json} +215 -5
  52. package/dist/{new-jtk028rf.js → new-rmfyb7va.js} +22 -15
  53. package/dist/{plugins-bcbe7xs8.js → plugins-gs21xz5s.js} +2 -2
  54. package/dist/{plugins-zsm6wv79.js → plugins-tqv1s16f.js} +4 -4
  55. package/dist/{preflight-cs6mj1d6.js → preflight-bjyeeq0d.js} +9 -9
  56. package/dist/{preview-d1j1g4qf.js → preview-ke03fk5d.js} +9 -9
  57. package/dist/{publish-7yw4jyrt.js → publish-wpnz0qng.js} +9 -9
  58. package/dist/render.js +55 -13
  59. package/dist/schema/manifest.types.d.ts +45 -7
  60. package/dist/{source-provider-n7vehh6t.js → source-provider-3g3yrn1f.js} +6 -2
  61. package/dist/{source-provider-tgzet3j5.js → source-provider-azg9ywhb.js} +6 -2
  62. package/dist/test-helpers/vocabulary.d.ts +12 -0
  63. package/dist/{validate-rkcdnzhw.js → validate-zcwykb43.js} +9 -9
  64. package/package.json +1 -1
  65. /package/dist/{cli-y28j019d.js → cli-1dha1nxk.js} +0 -0
@@ -24,12 +24,14 @@ import {
24
24
  resolvePort,
25
25
  resolveTargets,
26
26
  restoreForCommand,
27
+ rewriteOldThresholds,
27
28
  scalarString,
29
+ setCheckOption,
28
30
  uniqueExtensionId,
29
31
  validatePageMargin,
30
32
  withFetchTimeout,
31
33
  writeManifestDoc
32
- } from "./index-rj5vrhz6.js";
34
+ } from "./index-fntpr44x.js";
33
35
  import {
34
36
  EXTENSION_MANIFEST_FILENAME,
35
37
  GUTTERPRESS_CSS,
@@ -65,7 +67,7 @@ import {
65
67
  setLogLevel,
66
68
  slugify,
67
69
  warn
68
- } from "./index-a4j3xcfp.js";
70
+ } from "./index-67g8f7r4.js";
69
71
  import {
70
72
  blackTextToGray
71
73
  } from "./index-ht1bcqdd.js";
@@ -76,7 +78,7 @@ import {
76
78
  getAssetPath,
77
79
  lastPageMode,
78
80
  resolvePage
79
- } from "./index-798jt0qc.js";
81
+ } from "./index-d9w3r89w.js";
80
82
  import {
81
83
  BuildError,
82
84
  cssLength,
@@ -124,20 +126,22 @@ import {
124
126
  hasUncommittedChanges,
125
127
  isContained,
126
128
  listWorkdirChanges,
129
+ nextInHistory,
127
130
  readRevisionRefs,
128
131
  resolveGitAuthor,
129
132
  resolveLogger,
130
133
  revisionNameFrom,
131
134
  snapshotStagingMarkerPath,
132
135
  snapshotWorkingTreeUnlocked,
136
+ startHistoryWalk,
133
137
  withRepoLock
134
- } from "./index-cw03e9p4.js";
138
+ } from "./index-kw4tbthz.js";
135
139
  import {
136
140
  EXTENSIONS_DIR,
137
141
  resolveVendoredPluginInstallRoot,
138
142
  toPosixPath,
139
143
  vendoredNpmPluginPackageDir
140
- } from "./index-5x42amh8.js";
144
+ } from "./index-g3te5ey1.js";
141
145
  import {
142
146
  detectProjectSource,
143
147
  repoSubPath,
@@ -282,6 +286,14 @@ ${TABLE_ALIGN_CSS.trim()}`),
282
286
  ${pageGeometry}`)
283
287
  ];
284
288
  }
289
+ function resolveOldFootnoteLinks(html, ids) {
290
+ if (ids.size === 0)
291
+ return html;
292
+ return html.replace(/ href=(["'])#(fn(?:ref)?\d+(?::\d+)?)\1/g, (link, quote, old) => {
293
+ const id = ids.get(old);
294
+ return id && !html.includes(` id="${old}"`) ? ` href=${quote}#${id}${quote}` : link;
295
+ });
296
+ }
285
297
  async function assembleBookHtml(opts) {
286
298
  const title = opts.title ?? "Document";
287
299
  const projectCss = opts.projectCss ?? "";
@@ -294,6 +306,7 @@ async function assembleBookHtml(opts) {
294
306
  const md = createMarkdownRenderer(opts.plugins, { language });
295
307
  let bodyContent = "";
296
308
  const imageRefs = new Set;
309
+ const oldFootnoteIds = new Map;
297
310
  for (const file of files) {
298
311
  const chapterId = canonicalChapterId(file);
299
312
  let content;
@@ -312,9 +325,14 @@ async function assembleBookHtml(opts) {
312
325
  }
313
326
  for (const ref of env.imageRefs ?? [])
314
327
  imageRefs.add(ref);
328
+ for (const [, kind, n] of rendered.matchAll(new RegExp(` id="(fn|fnref)-${env.docId}-(\\d+(?::\\d+)?)"`, "g"))) {
329
+ if (!oldFootnoteIds.has(`${kind}${n}`))
330
+ oldFootnoteIds.set(`${kind}${n}`, `${kind}-${env.docId}-${n}`);
331
+ }
315
332
  bodyContent += rendered + `
316
333
  `;
317
334
  }
335
+ bodyContent = resolveOldFootnoteLinks(bodyContent, oldFootnoteIds);
318
336
  if (opts.onImageRefs) {
319
337
  for (const ref of collectHtmlImageRefs(bodyContent))
320
338
  imageRefs.add(ref);
@@ -353,7 +371,13 @@ import { existsSync } from "node:fs";
353
371
  import { readdir } from "node:fs/promises";
354
372
  import path from "node:path";
355
373
  var STYLES_SUBDIR = "styles";
356
- var DEFAULT_STYLESHEET = "styles/book.css";
374
+ var FALLBACK_PRIORITY = [
375
+ "styles/book.css",
376
+ "css/print.css",
377
+ "css/index.css",
378
+ "css/style.css",
379
+ "css/main.css"
380
+ ];
357
381
  function relDisplay(projectDir, absPath) {
358
382
  return path.relative(projectDir, absPath).split(path.sep).join("/");
359
383
  }
@@ -391,8 +415,10 @@ async function resolveActiveStyles(projectDir, manifestStyles) {
391
415
  const manifest = configured.filter((s) => typeof s === "string" && s.trim().length > 0);
392
416
  if (manifest.length > 0)
393
417
  return manifest;
394
- if (existsSync(path.join(projectDir, DEFAULT_STYLESHEET)))
395
- return [DEFAULT_STYLESHEET];
418
+ for (const rel of FALLBACK_PRIORITY) {
419
+ if (existsSync(path.join(projectDir, rel)))
420
+ return [rel];
421
+ }
396
422
  const discovered = await discoverCssFiles(projectDir);
397
423
  if (discovered.length > 0) {
398
424
  const first = discovered.map((abs) => relDisplay(projectDir, abs)).sort((a, b) => a.localeCompare(b))[0];
@@ -4576,6 +4602,58 @@ var check30 = {
4576
4602
  };
4577
4603
  registerCheck(check30);
4578
4604
 
4605
+ // src/checks/asset/approved-fonts.ts
4606
+ var check31 = {
4607
+ id: "asset.font.approved-files",
4608
+ name: "Approved Font Files",
4609
+ description: "Checks font files against the approved file patterns",
4610
+ category: "asset",
4611
+ phase: "pre-build",
4612
+ async run(ctx) {
4613
+ const patterns = ctx.config.validate.assets.approvedFontFiles;
4614
+ if (!patterns || patterns.length === 0)
4615
+ return [];
4616
+ const { glob } = await import("glob");
4617
+ const dirs = ctx.assetDirs ?? [ctx.inputDir];
4618
+ const allFonts = [];
4619
+ for (const dir of dirs) {
4620
+ const matches = await glob(`**/*.{${FONT_EXTS2.join(",")}}`, {
4621
+ cwd: dir,
4622
+ absolute: true,
4623
+ ignore: [...ASSET_SCAN_IGNORE_GLOBS]
4624
+ });
4625
+ allFonts.push(...matches);
4626
+ }
4627
+ if (allFonts.length === 0)
4628
+ return [];
4629
+ const approvedFonts = new Set;
4630
+ for (const dir of dirs) {
4631
+ for (const pattern of patterns) {
4632
+ const matches = await glob(pattern, {
4633
+ cwd: dir,
4634
+ absolute: true,
4635
+ ignore: [...ASSET_SCAN_IGNORE_GLOBS]
4636
+ });
4637
+ for (const m of matches)
4638
+ approvedFonts.add(m);
4639
+ }
4640
+ }
4641
+ const results = [];
4642
+ for (const font of allFonts) {
4643
+ if (!approvedFonts.has(font)) {
4644
+ results.push({
4645
+ checkId: check31.id,
4646
+ severity: "warning",
4647
+ message: "Font file not in approved list",
4648
+ file: font
4649
+ });
4650
+ }
4651
+ }
4652
+ return results;
4653
+ }
4654
+ };
4655
+ registerCheck(check31);
4656
+
4579
4657
  // src/checks/asset/font-license.ts
4580
4658
  import { existsSync as existsSync6 } from "node:fs";
4581
4659
  import { resolve as resolve4 } from "node:path";
@@ -4589,7 +4667,7 @@ var LICENSE_NAMES = [
4589
4667
  "OFL-1.1.txt",
4590
4668
  "COPYING"
4591
4669
  ];
4592
- var check31 = {
4670
+ var check32 = {
4593
4671
  id: "asset.font.license",
4594
4672
  name: "Font License",
4595
4673
  description: "Checks for license files in font directories",
@@ -4614,7 +4692,7 @@ var check31 = {
4614
4692
  const hasLicense = LICENSE_NAMES.some((name) => existsSync6(resolve4(fontDir, name)));
4615
4693
  if (!hasLicense) {
4616
4694
  results.push({
4617
- checkId: check31.id,
4695
+ checkId: check32.id,
4618
4696
  severity: "warning",
4619
4697
  message: `No font license file found in directory`,
4620
4698
  file: fontDir
@@ -4624,10 +4702,10 @@ var check31 = {
4624
4702
  return results;
4625
4703
  }
4626
4704
  };
4627
- registerCheck(check31);
4705
+ registerCheck(check32);
4628
4706
 
4629
4707
  // src/checks/heuristic/text-density.ts
4630
- var check32 = {
4708
+ var check33 = {
4631
4709
  id: "heuristic.whitespace.text-density",
4632
4710
  name: "Text Density",
4633
4711
  description: "Checks characters-per-page ratio",
@@ -4656,7 +4734,7 @@ var check32 = {
4656
4734
  });
4657
4735
  if (lowPages.length > 0) {
4658
4736
  results.push({
4659
- checkId: check32.id,
4737
+ checkId: check33.id,
4660
4738
  severity: "info",
4661
4739
  message: `Low text density on pages: ${lowPages.join(", ")} (below ${range.min} chars)`,
4662
4740
  file: ctx.pdfPath
@@ -4664,7 +4742,7 @@ var check32 = {
4664
4742
  }
4665
4743
  if (highPages.length > 0) {
4666
4744
  results.push({
4667
- checkId: check32.id,
4745
+ checkId: check33.id,
4668
4746
  severity: "info",
4669
4747
  message: `High text density on pages: ${highPages.join(", ")} (above ${range.max} chars)`,
4670
4748
  file: ctx.pdfPath
@@ -4673,11 +4751,11 @@ var check32 = {
4673
4751
  return results;
4674
4752
  }
4675
4753
  };
4676
- registerCheck(check32);
4754
+ registerCheck(check33);
4677
4755
 
4678
4756
  // src/checks/heuristic/section-density.ts
4679
4757
  import { readFile as readFile19 } from "node:fs/promises";
4680
- var check33 = {
4758
+ var check34 = {
4681
4759
  id: "heuristic.chunking.section-density",
4682
4760
  name: "Section Density",
4683
4761
  description: "Checks heading/paragraph/callout density from source Markdown",
@@ -4703,7 +4781,7 @@ var check33 = {
4703
4781
  const line = lines[i];
4704
4782
  if (/^#{1,6}\s/.test(line)) {
4705
4783
  if (paragraphCount > maxParas) {
4706
- results.push(finding(check33.id, {
4784
+ results.push(finding(check34.id, {
4707
4785
  severity: "info",
4708
4786
  message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
4709
4787
  file,
@@ -4723,7 +4801,7 @@ var check33 = {
4723
4801
  }
4724
4802
  }
4725
4803
  if (paragraphCount > maxParas) {
4726
- results.push(finding(check33.id, {
4804
+ results.push(finding(check34.id, {
4727
4805
  severity: "info",
4728
4806
  message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
4729
4807
  file,
@@ -4731,7 +4809,7 @@ var check33 = {
4731
4809
  }));
4732
4810
  }
4733
4811
  } catch {
4734
- results.push(inspectionFailed(check33.id, `Could not read source file: ${file}`, {
4812
+ results.push(inspectionFailed(check34.id, `Could not read source file: ${file}`, {
4735
4813
  file
4736
4814
  }));
4737
4815
  }
@@ -4739,10 +4817,10 @@ var check33 = {
4739
4817
  return results;
4740
4818
  }
4741
4819
  };
4742
- registerCheck(check33);
4820
+ registerCheck(check34);
4743
4821
 
4744
4822
  // src/checks/heuristic/layer-count.ts
4745
- var check34 = {
4823
+ var check35 = {
4746
4824
  id: "heuristic.decoration.layer-count",
4747
4825
  name: "Layer Count",
4748
4826
  description: "Counts image objects per page",
@@ -4767,7 +4845,7 @@ var check34 = {
4767
4845
  heavyPages.sort((a, b) => a - b);
4768
4846
  return [
4769
4847
  {
4770
- checkId: check34.id,
4848
+ checkId: check35.id,
4771
4849
  severity: "info",
4772
4850
  message: `Pages with many image layers (>${maxLayers}): ${heavyPages.join(", ")}`,
4773
4851
  file: ctx.pdfPath
@@ -4777,10 +4855,10 @@ var check34 = {
4777
4855
  return [];
4778
4856
  }
4779
4857
  };
4780
- registerCheck(check34);
4858
+ registerCheck(check35);
4781
4859
 
4782
4860
  // src/checks/heuristic/placement-variance.ts
4783
- var check35 = {
4861
+ var check36 = {
4784
4862
  id: "heuristic.layout.placement-variance",
4785
4863
  name: "Placement Variance",
4786
4864
  description: "Analyzes text baseline coordinates for layout consistency",
@@ -4798,7 +4876,7 @@ var check35 = {
4798
4876
  const uniqueX = new Set(positions.map((p) => Math.round(p.x)));
4799
4877
  return [
4800
4878
  {
4801
- checkId: check35.id,
4879
+ checkId: check36.id,
4802
4880
  severity: "info",
4803
4881
  message: `Layout analysis: ${uniqueX.size} unique horizontal text positions across ${positions.length} text blocks.`,
4804
4882
  file: ctx.pdfPath
@@ -4806,7 +4884,7 @@ var check35 = {
4806
4884
  ];
4807
4885
  }
4808
4886
  };
4809
- registerCheck(check35);
4887
+ registerCheck(check36);
4810
4888
 
4811
4889
  // src/checks/runner.ts
4812
4890
  function getCheckSeverityOverride(checkId, config) {
@@ -4831,25 +4909,25 @@ async function runChecks(ctx, opts = {}) {
4831
4909
  }
4832
4910
  const release = retainPdfCache();
4833
4911
  try {
4834
- for (const check36 of checks2) {
4912
+ for (const check37 of checks2) {
4835
4913
  try {
4836
- const results = await check36.run(ctx);
4837
- const severityOverride = getCheckSeverityOverride(check36.id, ctx.config);
4914
+ const results = await check37.run(ctx);
4915
+ const severityOverride = getCheckSeverityOverride(check37.id, ctx.config);
4838
4916
  if (severityOverride) {
4839
4917
  for (const r of results) {
4840
4918
  r.severity = severityOverride;
4841
4919
  }
4842
4920
  }
4843
4921
  if (results.length === 0) {
4844
- passed.push(check36.id);
4922
+ passed.push(check37.id);
4845
4923
  } else {
4846
4924
  allResults.push(...results);
4847
4925
  }
4848
4926
  } catch (err) {
4849
4927
  allResults.push({
4850
- checkId: check36.id,
4928
+ checkId: check37.id,
4851
4929
  severity: "error",
4852
- message: `Check "${check36.id}" threw: ${err instanceof Error ? err.message : String(err)}`
4930
+ message: `Check "${check37.id}" threw: ${err instanceof Error ? err.message : String(err)}`
4853
4931
  });
4854
4932
  }
4855
4933
  }
@@ -4879,15 +4957,15 @@ async function runChecks(ctx, opts = {}) {
4879
4957
  async function checkToolAvailability(config, opts = {}) {
4880
4958
  const { checks: checks2 } = selectChecks(opts, config);
4881
4959
  const toolToChecks = new Map;
4882
- for (const check36 of checks2) {
4883
- if (!check36.requiredTools?.length)
4960
+ for (const check37 of checks2) {
4961
+ if (!check37.requiredTools?.length)
4884
4962
  continue;
4885
- for (const tool of check36.requiredTools) {
4963
+ for (const tool of check37.requiredTools) {
4886
4964
  const existing = toolToChecks.get(tool);
4887
4965
  if (existing) {
4888
- existing.push(check36.id);
4966
+ existing.push(check37.id);
4889
4967
  } else {
4890
- toolToChecks.set(tool, [check36.id]);
4968
+ toolToChecks.set(tool, [check37.id]);
4891
4969
  }
4892
4970
  }
4893
4971
  }
@@ -4903,11 +4981,11 @@ async function checkToolAvailability(config, opts = {}) {
4903
4981
  const missing = results.filter((r) => !r.found).map((r) => r.tool);
4904
4982
  const missingSet = new Set(missing);
4905
4983
  const skippedChecks = [];
4906
- for (const check36 of checks2) {
4907
- if (!check36.requiredTools?.length)
4984
+ for (const check37 of checks2) {
4985
+ if (!check37.requiredTools?.length)
4908
4986
  continue;
4909
- if (check36.requiredTools.some((t) => missingSet.has(t))) {
4910
- skippedChecks.push(check36.id);
4987
+ if (check37.requiredTools.some((t) => missingSet.has(t))) {
4988
+ skippedChecks.push(check37.id);
4911
4989
  }
4912
4990
  }
4913
4991
  return { available, missing, skippedChecks, toolToChecks };
@@ -5208,7 +5286,7 @@ async function executeValidation(args) {
5208
5286
  };
5209
5287
  if (args.fix) {
5210
5288
  const selected = selectChecks(runnerOptions, config).checks;
5211
- if (selected.some((check36) => check36.id === MARKDOWNLINT_CHECK_ID)) {
5289
+ if (selected.some((check37) => check37.id === MARKDOWNLINT_CHECK_ID)) {
5212
5290
  await applyMarkdownlintFixes(context);
5213
5291
  } else {
5214
5292
  log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
@@ -5577,7 +5655,7 @@ class PdfOutput {
5577
5655
  const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
5578
5656
  await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
5579
5657
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
5580
- const { buildNativePdf } = await import("./engine-wgkaqjsc.js");
5658
+ const { buildNativePdf } = await import("./engine-y9fnarfa.js");
5581
5659
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
5582
5660
  title: config.title,
5583
5661
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -7123,11 +7201,13 @@ import { existsSync as existsSync8 } from "node:fs";
7123
7201
  import { readFile as readFile24 } from "node:fs/promises";
7124
7202
  import path13 from "node:path";
7125
7203
  import { isMap } from "yaml";
7204
+ var PAGE_SIZE_CHECK = "pdf.print.page-size";
7126
7205
  function writePageBounds(doc, page) {
7127
7206
  ensurePageMap(doc);
7128
7207
  doc.setIn(["page", "width"], page.width);
7129
7208
  doc.setIn(["page", "height"], page.height);
7130
- doc.deleteIn(["page", "tolerance"]);
7209
+ if (page.tolerance !== undefined)
7210
+ setCheckOption(doc, PAGE_SIZE_CHECK, "tolerance", page.tolerance);
7131
7211
  }
7132
7212
  function deletePageBounds(doc) {
7133
7213
  const block = doc.get("page", true);
@@ -7135,7 +7215,7 @@ function deletePageBounds(doc) {
7135
7215
  doc.delete("page");
7136
7216
  return;
7137
7217
  }
7138
- for (const key of ["width", "height", "tolerance"])
7218
+ for (const key of ["width", "height"])
7139
7219
  block.delete(key);
7140
7220
  if (block.items.length === 0)
7141
7221
  doc.delete("page");
@@ -7183,7 +7263,7 @@ function manifestGeometry(doc) {
7183
7263
  const base = preset ? PRESETS[preset].page : null;
7184
7264
  const width = numberAt(doc, ["page", "width"]) ?? base?.width;
7185
7265
  const height = numberAt(doc, ["page", "height"]) ?? base?.height;
7186
- const tolerance = base?.tolerance ?? 0.5;
7266
+ const tolerance = numberAt(doc, ["checks", PAGE_SIZE_CHECK, "tolerance"]) ?? numberAt(doc, ["page", "tolerance"]) ?? base?.tolerance ?? 0.5;
7187
7267
  const bounds = width !== undefined && height !== undefined ? { width, height, tolerance } : null;
7188
7268
  const presetSizeOverridden = base !== null && (numberAt(doc, ["page", "width"]) !== undefined || numberAt(doc, ["page", "height"]) !== undefined);
7189
7269
  const at = (edge) => doc.getIn(["page", "margin", edge]);
@@ -7231,8 +7311,10 @@ async function readPageSetup(projectDir) {
7231
7311
  const { doc } = await loadManifestDoc(projectDir);
7232
7312
  return setupOf(projectDir, doc);
7233
7313
  }
7234
- async function setPageSetup(projectDir, change) {
7314
+ async function setPageSetup(projectDir, given) {
7315
+ const change = toPageSetupChange(given);
7235
7316
  const { doc, file } = await loadManifestDoc(projectDir);
7317
+ rewriteOldThresholds(doc);
7236
7318
  const size2 = change.size ? pageSizeForChoice(change.size) : null;
7237
7319
  let margins;
7238
7320
  if (change.margins) {
@@ -7255,6 +7337,16 @@ async function setPageSetup(projectDir, change) {
7255
7337
  await writeManifestDoc(file, doc);
7256
7338
  return setupOf(projectDir, doc);
7257
7339
  }
7340
+ function toPageSetupChange(change) {
7341
+ const keys = typeof change === "object" && change !== null ? Object.keys(change) : null;
7342
+ if (keys?.includes("preset") && !keys.includes("size") && !keys.includes("margins")) {
7343
+ return { size: change };
7344
+ }
7345
+ if (!keys || keys.some((k) => k !== "size" && k !== "margins")) {
7346
+ throw new UsageError(`setPageSetup takes { size?: { preset, page? }, margins? } (or 0.11.22's { preset, page? }), got ${JSON.stringify(change)}.`);
7347
+ }
7348
+ return change;
7349
+ }
7258
7350
 
7259
7351
  // src/lib/project-scaffold.ts
7260
7352
  function starterOverridesCss() {
@@ -7303,6 +7395,9 @@ function requirePreset(preset, customPage) {
7303
7395
  } else if (customPage && (!isPositivePoints(customPage.width) || !isPositivePoints(customPage.height))) {
7304
7396
  throw new CreateProjectErrorImpl("custom-page-required", "Page overrides need a positive width and height in points (72pt = 1in).");
7305
7397
  }
7398
+ if (customPage?.tolerance !== undefined && !isPositivePoints(customPage.tolerance)) {
7399
+ throw new CreateProjectErrorImpl("custom-page-required", "Page tolerance must be a positive number of points.");
7400
+ }
7306
7401
  return preset;
7307
7402
  }
7308
7403
  function resolveScaffoldTargets(requested, preset) {
@@ -7406,7 +7501,7 @@ async function scaffoldProject(options) {
7406
7501
  let versionHistoryError;
7407
7502
  if (requested === "local-git") {
7408
7503
  try {
7409
- const { providerFor } = await import("./source-provider-tgzet3j5.js");
7504
+ const { providerFor } = await import("./source-provider-azg9ywhb.js");
7410
7505
  const provider = providerFor({ type: "local-folder", path: projectDir });
7411
7506
  await provider.initVersionHistory({
7412
7507
  projectDir,
@@ -7497,7 +7592,7 @@ styles:
7497
7592
  let versionHistoryError;
7498
7593
  if (requested === "local-git") {
7499
7594
  try {
7500
- const { providerFor } = await import("./source-provider-tgzet3j5.js");
7595
+ const { providerFor } = await import("./source-provider-azg9ywhb.js");
7501
7596
  const provider = providerFor({ type: "local-folder", path: dir });
7502
7597
  await provider.initVersionHistory({
7503
7598
  projectDir: dir,
@@ -7546,6 +7641,12 @@ import { access as access2, mkdir as mkdir6, readFile as readFile26, writeFile a
7546
7641
  import { constants as FS2 } from "node:fs";
7547
7642
  import path15 from "node:path";
7548
7643
  var EXTENSION_KINDS = ["plugin", "look"];
7644
+ var EXTENSION_KIND_ALIASES = { theme: "look" };
7645
+ function extensionKindFor(word) {
7646
+ if (EXTENSION_KINDS.includes(word))
7647
+ return word;
7648
+ return Object.hasOwn(EXTENSION_KIND_ALIASES, word) ? EXTENSION_KIND_ALIASES[word] : undefined;
7649
+ }
7549
7650
  var RESERVED_PREFIX = "gp-";
7550
7651
  var TEMPLATE_FILES = {
7551
7652
  plugin: [
@@ -7608,9 +7709,9 @@ function escapeJsonScalar(value) {
7608
7709
  return JSON.stringify(value).slice(1, -1);
7609
7710
  }
7610
7711
  async function scaffoldExtension(options) {
7611
- const kind = options.kind;
7612
- if (kind !== "plugin" && kind !== "look") {
7613
- throw new ExtensionScaffoldError("invalid-name", `Unknown extension kind "${String(kind)}". Choose one of: ${EXTENSION_KINDS.join(", ")}.`);
7712
+ const kind = extensionKindFor(String(options.kind));
7713
+ if (!kind) {
7714
+ throw new ExtensionScaffoldError("invalid-name", `Unknown extension kind "${String(options.kind)}". Choose one of: ${EXTENSION_KINDS.join(", ")}.`);
7614
7715
  }
7615
7716
  const name = (options.name ?? "").trim();
7616
7717
  if (!name) {
@@ -8578,6 +8679,7 @@ function hasKey(obj, key) {
8578
8679
  }
8579
8680
  async function setManifestFields(projectDir, updates) {
8580
8681
  const { doc, file } = await loadManifestDoc(projectDir);
8682
+ rewriteOldThresholds(doc);
8581
8683
  if (hasKey(updates, "title")) {
8582
8684
  if (updates.title === undefined || updates.title === "") {
8583
8685
  doc.delete("title");
@@ -9154,8 +9256,9 @@ function changeHint(filepath, before, after) {
9154
9256
  return count > 0 ? `${plural(count, unit)} changed` : "changed";
9155
9257
  }
9156
9258
  async function listVersionChanges(projectDir, oid) {
9157
- const dir = await repoDirFor(projectDir);
9158
- const cache2 = {};
9259
+ return changesOf(await repoDirFor(projectDir), {}, oid);
9260
+ }
9261
+ async function changesOf(dir, cache2, oid) {
9159
9262
  const parent = (await git3.readCommit({ fs: gitFs, dir, cache: cache2, oid })).commit.parent[0] ?? null;
9160
9263
  const found = [];
9161
9264
  await git3.walk({
@@ -9265,25 +9368,67 @@ async function describeVersions(projectDir, entries) {
9265
9368
  }
9266
9369
  return out;
9267
9370
  }
9371
+ var CLOCK_SKEW_SECONDS = 10 * 60;
9268
9372
  async function commitsAhead(dir, fromOid, baseOid, cache2 = {}, limit = 100) {
9269
9373
  if (fromOid === baseOid)
9270
9374
  return [];
9271
- const bases = await git3.findMergeBase({ fs: gitFs, dir, cache: cache2, oids: [fromOid, baseOid] });
9272
- const stopAt = new Set(bases);
9273
- if (stopAt.size === 0)
9274
- return [];
9275
- const commits = await git3.log({ fs: gitFs, dir, cache: cache2, ref: fromOid, depth: limit });
9276
- const seen = new Set;
9277
- const out = [];
9278
- for (const c of commits) {
9279
- if (stopAt.has(c.oid))
9375
+ const walk = await startHistoryWalk(dir, cache2, [baseOid, fromOid]);
9376
+ const local = new Set([baseOid]);
9377
+ const online = new Set([fromOid]);
9378
+ const parentsOf = new Map;
9379
+ const listed = [];
9380
+ let shared = false;
9381
+ const mark = (oid) => {
9382
+ const stack = [oid];
9383
+ for (let next = stack.pop();next !== undefined; next = stack.pop()) {
9384
+ if (local.has(next))
9385
+ continue;
9386
+ local.add(next);
9387
+ if (online.has(next))
9388
+ shared = true;
9389
+ stack.push(...parentsOf.get(next) ?? []);
9390
+ }
9391
+ };
9392
+ const firstAhead = () => {
9393
+ const out = [];
9394
+ for (const c of listed) {
9395
+ if (out.length === limit)
9396
+ break;
9397
+ if (!local.has(c.oid))
9398
+ out.push(c);
9399
+ }
9400
+ return out;
9401
+ };
9402
+ const time = (c) => c.commit.committer.timestamp;
9403
+ for (;; ) {
9404
+ const searching = walk.tips.some((c2) => !local.has(c2.oid));
9405
+ if (!searching || shared && listed.length >= limit) {
9406
+ const shown = firstAhead();
9407
+ if (!searching || shown.length === limit) {
9408
+ const oldest = Math.min(...shown.map(time));
9409
+ const newestMarked = walk.tips.findLast((c2) => local.has(c2.oid));
9410
+ if (!newestMarked || time(newestMarked) < oldest - CLOCK_SKEW_SECONDS)
9411
+ break;
9412
+ }
9413
+ }
9414
+ const c = await nextInHistory(dir, walk, cache2, 1);
9415
+ if (!c)
9280
9416
  break;
9281
- if (seen.has(c.oid))
9417
+ const parents = walk.shallow.has(c.oid) ? [] : c.commit.parent;
9418
+ parentsOf.set(c.oid, parents);
9419
+ if (local.has(c.oid)) {
9420
+ for (const p of parents)
9421
+ mark(p);
9282
9422
  continue;
9283
- seen.add(c.oid);
9284
- out.push(toEntry(c));
9423
+ }
9424
+ listed.push(c);
9425
+ for (const p of parents) {
9426
+ online.add(p);
9427
+ if (local.has(p))
9428
+ shared = true;
9429
+ }
9285
9430
  }
9286
- return out;
9431
+ return shared ? firstAhead().map(toEntry) : [];
9287
9432
  }
9288
9433
  async function listOnlineVersions(options) {
9289
9434
  const http2 = options.httpClient ?? defaultGitHttp;
@@ -9311,8 +9456,12 @@ async function listOnlineVersions(options) {
9311
9456
  const local = await resolveOrNull(dir, branch);
9312
9457
  if (!tip || !local)
9313
9458
  return { entries: [] };
9314
- const entries = await commitsAhead(dir, tip, local, cache2);
9315
- return { entries: entries.map((entry) => ({ ...entry, backedUp: true })) };
9459
+ const entries = [];
9460
+ for (const entry of await commitsAhead(dir, tip, local, cache2)) {
9461
+ const { files, more } = await changesOf(dir, cache2, entry.id);
9462
+ entries.push({ ...entry, backedUp: true, changes: files, moreChanges: more });
9463
+ }
9464
+ return { entries };
9316
9465
  } catch (e) {
9317
9466
  const message = e?.message ?? "";
9318
9467
  if (message === MSG_NO_REMOTE || message === MSG_SSH_REMOTE)
@@ -12761,7 +12910,7 @@ async function resolvePublishProvider(id, book) {
12761
12910
  const ext = await bookExtensions(book);
12762
12911
  const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
12763
12912
  if (npmEntry) {
12764
- const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-5x4mj79d.js");
12913
+ const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-91gy1e28.js");
12765
12914
  await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
12766
12915
  }
12767
12916
  const publishers = await discover(ext);
@@ -12799,7 +12948,7 @@ function infoFor(p) {
12799
12948
  }
12800
12949
  function pluginProvider(p) {
12801
12950
  let loading;
12802
- const load = () => loading ??= import("./plugins-bcbe7xs8.js").then((m) => m.loadPublishFunction(p));
12951
+ const load = () => loading ??= import("./plugins-gs21xz5s.js").then((m) => m.loadPublishFunction(p));
12803
12952
  return {
12804
12953
  info: infoFor(p),
12805
12954
  async authenticate() {
@@ -13099,7 +13248,7 @@ class PublishSelectionsStore {
13099
13248
  return {
13100
13249
  version: 1,
13101
13250
  global: parsed.global ?? {},
13102
- projects: parsed.projects ?? {}
13251
+ projects: readProjects(parsed.projects)
13103
13252
  };
13104
13253
  }
13105
13254
  } catch {}
@@ -13185,6 +13334,27 @@ class PublishSelectionsStore {
13185
13334
  });
13186
13335
  }
13187
13336
  }
13337
+ function readProjects(projects) {
13338
+ const out = {};
13339
+ if (!projects || typeof projects !== "object")
13340
+ return out;
13341
+ for (const [book, providers] of Object.entries(projects)) {
13342
+ if (!providers || typeof providers !== "object")
13343
+ continue;
13344
+ const values = {};
13345
+ for (const [provider, value] of Object.entries(providers)) {
13346
+ if (typeof value === "string") {
13347
+ if (value.trim())
13348
+ values[provider] = { credential: value };
13349
+ } else if (value && typeof value === "object") {
13350
+ values[provider] = value;
13351
+ }
13352
+ }
13353
+ if (Object.keys(values).length > 0)
13354
+ out[book] = values;
13355
+ }
13356
+ return out;
13357
+ }
13188
13358
  function normalizeProjectKey(projectDir) {
13189
13359
  return projectDir.replace(/[\\/]+$/, "");
13190
13360
  }
@@ -13270,4 +13440,4 @@ async function savePublishSettings(projectDir, providerId, values, selections) {
13270
13440
  await setPublishProviderConfig(projectDir, providerId, changes);
13271
13441
  return readPublishSettings(projectDir, selections);
13272
13442
  }
13273
- export { SYNC_SNAPSHOT_MESSAGE, assembleCssChunks, relDisplay, resolveActiveStyles, listProjectStyles, getChecks, getCheckById, resolveCheckSelectors, formatReport, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, readPageSetup, setPageSetup, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, saveSnippet, deleteSnippet, listMergedSnippets, listMarkerComponents, listLocationVariants, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, VERSION_CHANGES_SHOWN, listVersionChanges, describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, syncProject, refreshRemoteCopies, checkRemoteUpdates, isValidRepositoryName, setUpOnlineBackup, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, renameRevision, deleteRevision, REPAIR_SNAPSHOT_MESSAGE, repairOnlineBackup, scorchedEarth, listPublishProviders, publishProviderFor, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig, savePublishSettings };
13443
+ export { SYNC_SNAPSHOT_MESSAGE, assembleCssChunks, relDisplay, resolveActiveStyles, listProjectStyles, getChecks, getCheckById, resolveCheckSelectors, formatReport, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, readPageSetup, setPageSetup, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, EXTENSION_KIND_ALIASES, extensionKindFor, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, saveSnippet, deleteSnippet, listMergedSnippets, listMarkerComponents, listLocationVariants, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, VERSION_CHANGES_SHOWN, listVersionChanges, describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, syncProject, refreshRemoteCopies, checkRemoteUpdates, isValidRepositoryName, setUpOnlineBackup, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, renameRevision, deleteRevision, REPAIR_SNAPSHOT_MESSAGE, repairOnlineBackup, scorchedEarth, listPublishProviders, publishProviderFor, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig, savePublishSettings };