gutterpress 0.11.17-alpha.2 → 0.11.17-alpha.4

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 (53) hide show
  1. package/dist/api/index.d.ts +4 -0
  2. package/dist/api/index.js +11 -2
  3. package/dist/black-text-gray-7dz61456.js +15 -0
  4. package/dist/{build-1p999cmg.js → build-fam0tqg6.js} +5 -4
  5. package/dist/checks/pdf/black-text.d.ts +3 -0
  6. package/dist/checks/pdf/index.d.ts +2 -0
  7. package/dist/checks/pdf/signature.d.ts +3 -0
  8. package/dist/{cli-6z5zthzt.js → cli-2kc34kme.js} +470 -489
  9. package/dist/{cli-70xgehq2.js → cli-8apk8571.js} +1 -1
  10. package/dist/cli-ht1bcqdd.js +493 -0
  11. package/dist/{cli-gymfg04q.js → cli-jyy9pqf3.js} +15 -10
  12. package/dist/{cli-ppc0vz4b.js → cli-pqcb2nnb.js} +1 -1
  13. package/dist/cli.js +12 -12
  14. package/dist/{doctor-reqpnn3h.js → doctor-zre5k5fg.js} +2 -2
  15. package/dist/engine/compiler/build.d.ts +3 -2
  16. package/dist/engine/compiler/postprocess.d.ts +6 -4
  17. package/dist/engine/shared/synthesis.d.ts +29 -5
  18. package/dist/{engine-5jzhjjvv.js → engine-3xqgm82d.js} +2 -2
  19. package/dist/{engine-078ggczp.js → engine-zdb41ay1.js} +1 -1
  20. package/dist/{ext-dsbfejt3.js → ext-hfqcg6ax.js} +5 -4
  21. package/dist/{gutterpress-viewer-zkv2stfy.js → gutterpress-viewer-1n793gwd.js} +5 -3
  22. package/dist/{index-c275p061.js → index-gp503ze9.js} +1622 -1332
  23. package/dist/{index-5dcj1vts.js → index-hrx0gfkj.js} +23 -684
  24. package/dist/index-ht1bcqdd.js +493 -0
  25. package/dist/index-q1xqxrh9.js +949 -0
  26. package/dist/index.js +12 -3
  27. package/dist/lib/black-text-gray.d.ts +55 -8
  28. package/dist/lib/build-fingerprint.d.ts +2 -0
  29. package/dist/lib/engine.d.ts +2 -1
  30. package/dist/lib/lint-rules.d.ts +9 -0
  31. package/dist/lib/markdown/assemble.d.ts +3 -5
  32. package/dist/lib/markdown/index.d.ts +3 -8
  33. package/dist/lib/markdown/renderer.d.ts +9 -1
  34. package/dist/lib/page-size.d.ts +66 -0
  35. package/dist/lib/pdf-inspect.d.ts +6 -0
  36. package/dist/lib/printsafe.d.ts +8 -1
  37. package/dist/lib/project-scaffold.d.ts +3 -9
  38. package/dist/lib/remote-auth/github-repos.d.ts +7 -0
  39. package/dist/lib/remote-auth/online-backup.d.ts +51 -0
  40. package/dist/lib/snippets.d.ts +3 -0
  41. package/dist/{manifest.schema-40sfq49z.json → manifest.schema-gh0jjve9.json} +14 -2
  42. package/dist/{new-m5y2wepr.js → new-bjdf7bhg.js} +5 -4
  43. package/dist/{plugin.js-m4a7m3t4.tpl → plugin.js-cswq7wvd.tpl} +4 -1
  44. package/dist/{plugin.test.js-6n8ct5e3.tpl → plugin.test.js-xgxrd8hf.tpl} +4 -1
  45. package/dist/{preflight-bwpqwwny.js → preflight-gvw01661.js} +5 -4
  46. package/dist/preview/file-watcher.d.ts +2 -4
  47. package/dist/{preview-62y7qhkp.js → preview-1cschq8s.js} +5 -4
  48. package/dist/{publish-k2zyt3x6.js → publish-ddqrb8s9.js} +5 -4
  49. package/dist/render.js +30 -5
  50. package/dist/schema/manifest.types.d.ts +17 -0
  51. package/dist/{validate-fgwwxtbn.js → validate-3hjkgxrz.js} +5 -4
  52. package/package.json +1 -1
  53. package/dist/index-eyaj6nkc.js +0 -267
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./cli-ppc0vz4b.js";
3
+ } from "./cli-pqcb2nnb.js";
4
4
  import {
5
5
  execCapture,
6
6
  findTool,
@@ -0,0 +1,493 @@
1
+ import {
2
+ __require
3
+ } from "./cli-37x76zdn.js";
4
+
5
+ // src/lib/black-text-gray.ts
6
+ var MAX_CHANNEL = 0.12;
7
+ var MAX_SPREAD = 0.04;
8
+ function isNearBlack([r, g, b]) {
9
+ const max = Math.max(r, g, b);
10
+ return max <= MAX_CHANNEL && max - Math.min(r, g, b) <= MAX_SPREAD;
11
+ }
12
+ var WS = new Set([0, 9, 10, 12, 13, 32]);
13
+ var DELIM = new Set("()<>[]{}/%".split("").map((c) => c.charCodeAt(0)));
14
+ function* tokenize(s) {
15
+ let i = 0;
16
+ const n = s.length;
17
+ while (i < n) {
18
+ const c = s.charCodeAt(i);
19
+ if (WS.has(c)) {
20
+ i++;
21
+ continue;
22
+ }
23
+ const start = i;
24
+ if (c === 37) {
25
+ while (i < n && s[i] !== `
26
+ ` && s[i] !== "\r")
27
+ i++;
28
+ continue;
29
+ }
30
+ if (c === 40) {
31
+ let depth = 0;
32
+ while (i < n) {
33
+ const d = s[i++];
34
+ if (d === "\\")
35
+ i++;
36
+ else if (d === "(")
37
+ depth++;
38
+ else if (d === ")" && --depth === 0)
39
+ break;
40
+ }
41
+ yield { text: s.slice(start, i), start, end: i, op: false };
42
+ continue;
43
+ }
44
+ if (c === 60 && s[i + 1] === "<") {
45
+ i += 2;
46
+ yield { text: "<<", start, end: i, op: false };
47
+ continue;
48
+ }
49
+ if (c === 62 && s[i + 1] === ">") {
50
+ i += 2;
51
+ yield { text: ">>", start, end: i, op: false };
52
+ continue;
53
+ }
54
+ if (c === 60) {
55
+ while (i < n && s[i] !== ">")
56
+ i++;
57
+ i++;
58
+ yield { text: s.slice(start, i), start, end: i, op: false };
59
+ continue;
60
+ }
61
+ if (c === 91 || c === 93 || c === 62 || c === 123 || c === 125 || c === 41) {
62
+ i++;
63
+ yield { text: s[start], start, end: i, op: false };
64
+ continue;
65
+ }
66
+ i++;
67
+ while (i < n && !WS.has(s.charCodeAt(i)) && !DELIM.has(s.charCodeAt(i)))
68
+ i++;
69
+ const text = s.slice(start, i);
70
+ const isOperand = c === 47 || /^[+-]?(\d+\.?\d*|\.\d+)$/.test(text);
71
+ yield { text, start, end: i, op: !isOperand };
72
+ if (text === "ID") {
73
+ const m = /\sEI(?=\s|$)/g;
74
+ m.lastIndex = i;
75
+ const hit = m.exec(s);
76
+ i = hit ? hit.index + hit[0].length : n;
77
+ }
78
+ }
79
+ }
80
+ var LARGE_TEXT_PT = 24;
81
+ var SIZE_EPS = 0.05;
82
+ var area = (m) => Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
83
+
84
+ class TextScale {
85
+ ctm;
86
+ font = 0;
87
+ tm = 1;
88
+ stack = [];
89
+ constructor(ctm) {
90
+ this.ctm = ctm;
91
+ }
92
+ get unit() {
93
+ return this.ctm;
94
+ }
95
+ get size() {
96
+ return this.font * this.tm * this.ctm;
97
+ }
98
+ op(op, nums) {
99
+ switch (op) {
100
+ case "q":
101
+ this.stack.push([this.ctm, this.font]);
102
+ return false;
103
+ case "Q": {
104
+ const p = this.stack.pop();
105
+ if (p)
106
+ [this.ctm, this.font] = p;
107
+ return true;
108
+ }
109
+ case "cm":
110
+ if (nums.length === 6)
111
+ this.ctm *= area(nums);
112
+ return true;
113
+ case "BT":
114
+ this.tm = 1;
115
+ return true;
116
+ case "Tm":
117
+ if (nums.length === 6)
118
+ this.tm = area(nums);
119
+ return true;
120
+ case "Tf":
121
+ this.font = Math.abs(nums[nums.length - 1] ?? 0) || 0;
122
+ return true;
123
+ }
124
+ return false;
125
+ }
126
+ }
127
+ function rewriteBlackText(src, ctx = {}) {
128
+ let fill = null;
129
+ let stroke = null;
130
+ const stack = [];
131
+ const scale = new TextScale(ctx.baseScale ?? 1);
132
+ let inText = false;
133
+ let fillDirty = false;
134
+ let strokeDirty = false;
135
+ const spans = [];
136
+ let lastOp = "";
137
+ let rect = null;
138
+ const edits = [];
139
+ let operands = [];
140
+ const rgbOf = () => {
141
+ if (operands.length !== 3)
142
+ return null;
143
+ const v = operands.map((t) => Number(t.text));
144
+ return v.some((x) => Number.isNaN(x)) ? null : { rgb: v, raw: operands.map((t) => t.text).join(" ") };
145
+ };
146
+ const isSmall = () => scale.size <= LARGE_TEXT_PT + SIZE_EPS;
147
+ let fillIns = null;
148
+ let strokeIns = null;
149
+ const syncOne = (colour, dirty, ins, at, gray, op) => {
150
+ if (!colour || !isNearBlack(colour.rgb))
151
+ return [dirty, ins];
152
+ const small = isSmall();
153
+ if (small && !dirty) {
154
+ const e = { start: at, end: at, text: ` ${gray}` };
155
+ edits.push(e);
156
+ return [true, e];
157
+ }
158
+ if (!small && dirty) {
159
+ if (ins)
160
+ ins.text = "";
161
+ else
162
+ edits.push({ start: at, end: at, text: ` ${colour.raw} ${op}` });
163
+ return [false, null];
164
+ }
165
+ return [dirty, ins];
166
+ };
167
+ const sync = (at) => {
168
+ [fillDirty, fillIns] = syncOne(fill, fillDirty, fillIns, at, "0 g", "rg");
169
+ [strokeDirty, strokeIns] = syncOne(stroke, strokeDirty, strokeIns, at, "0 G", "RG");
170
+ };
171
+ const flush = (s) => {
172
+ for (const r of s.rects) {
173
+ if (r.thickness > 0.2 * s.maxSmall)
174
+ continue;
175
+ edits.push({ start: r.start, end: r.start, text: "q 0 g " }, { start: r.end, end: r.end, text: " Q" });
176
+ }
177
+ };
178
+ for (const t of tokenize(src)) {
179
+ if (!t.op) {
180
+ operands.push(t);
181
+ continue;
182
+ }
183
+ const op = t.text;
184
+ const nums = operands.map((o) => Number(o.text));
185
+ const sizeMayHaveChanged = scale.op(op, nums);
186
+ switch (op) {
187
+ case "q":
188
+ stack.push([fill, stroke]);
189
+ break;
190
+ case "Q": {
191
+ const p = stack.pop();
192
+ if (p)
193
+ [fill, stroke] = p;
194
+ break;
195
+ }
196
+ case "BT":
197
+ inText = true;
198
+ fillDirty = strokeDirty = false;
199
+ fillIns = strokeIns = null;
200
+ sync(t.end);
201
+ break;
202
+ case "Tf":
203
+ case "Tm":
204
+ if (inText && sizeMayHaveChanged)
205
+ sync(t.end);
206
+ break;
207
+ case "ET":
208
+ if (inText) {
209
+ let ins = "";
210
+ if (fillDirty && fill)
211
+ ins += `${fill.raw} rg `;
212
+ if (strokeDirty && stroke)
213
+ ins += `${stroke.raw} RG `;
214
+ if (ins)
215
+ edits.push({ start: t.start, end: t.start, text: ins });
216
+ }
217
+ inText = false;
218
+ fillIns = strokeIns = null;
219
+ break;
220
+ case "rg":
221
+ case "RG": {
222
+ const c = rgbOf();
223
+ const isFill = op === "rg";
224
+ if (isFill)
225
+ fill = c;
226
+ else
227
+ stroke = c;
228
+ if (inText && c && isNearBlack(c.rgb) && isSmall()) {
229
+ edits.push({ start: operands[0].start, end: t.end, text: isFill ? "0 g" : "0 G" });
230
+ if (isFill)
231
+ fillDirty = true;
232
+ else
233
+ strokeDirty = true;
234
+ } else if (inText) {
235
+ if (isFill)
236
+ fillDirty = false;
237
+ else
238
+ strokeDirty = false;
239
+ }
240
+ break;
241
+ }
242
+ case "g":
243
+ case "k":
244
+ case "sc":
245
+ case "scn":
246
+ case "cs":
247
+ fill = null;
248
+ if (inText)
249
+ fillDirty = false;
250
+ break;
251
+ case "G":
252
+ case "K":
253
+ case "SC":
254
+ case "SCN":
255
+ case "CS":
256
+ stroke = null;
257
+ if (inText)
258
+ strokeDirty = false;
259
+ break;
260
+ case "Do": {
261
+ const name = operands[operands.length - 1]?.text;
262
+ if (name?.startsWith("/"))
263
+ ctx.onDo?.(name.slice(1), scale.unit);
264
+ break;
265
+ }
266
+ case "BDC":
267
+ case "BMC":
268
+ spans.push({ hasSmall: false, maxSmall: 0, rects: [] });
269
+ break;
270
+ case "EMC": {
271
+ const s = spans.pop();
272
+ if (!s)
273
+ break;
274
+ const parent = spans[spans.length - 1];
275
+ if (s.hasSmall)
276
+ flush(s);
277
+ else
278
+ parent?.rects.push(...s.rects);
279
+ if (parent && s.hasSmall) {
280
+ parent.hasSmall = true;
281
+ parent.maxSmall = Math.max(parent.maxSmall, s.maxSmall);
282
+ }
283
+ break;
284
+ }
285
+ case "Tj":
286
+ case "TJ":
287
+ case "'":
288
+ case '"': {
289
+ fillIns = strokeIns = null;
290
+ const span = spans[spans.length - 1];
291
+ if (span && inText && isSmall()) {
292
+ span.hasSmall = true;
293
+ span.maxSmall = Math.max(span.maxSmall, scale.size);
294
+ }
295
+ break;
296
+ }
297
+ case "re":
298
+ rect = !inText && fill && isNearBlack(fill.rgb) && operands.length === 4 && nums.every((x) => !Number.isNaN(x)) ? { start: operands[0].start, thickness: Math.min(Math.abs(nums[2]), Math.abs(nums[3])) * scale.unit } : null;
299
+ break;
300
+ case "f":
301
+ case "F":
302
+ case "f*":
303
+ if (rect && lastOp === "re")
304
+ spans[spans.length - 1]?.rects.push({ ...rect, end: t.end });
305
+ break;
306
+ }
307
+ lastOp = op;
308
+ operands = [];
309
+ }
310
+ return applyEdits(src, edits);
311
+ }
312
+ function applyEdits(s, edits) {
313
+ if (!edits.length)
314
+ return s;
315
+ edits.sort((a, b) => a.start - b.start);
316
+ let out = "";
317
+ let pos = 0;
318
+ for (const e of edits) {
319
+ out += s.slice(pos, e.start) + e.text;
320
+ pos = e.end;
321
+ }
322
+ return out + s.slice(pos);
323
+ }
324
+ function isRichBlack(c) {
325
+ const [cy, m, y, k] = c;
326
+ const lo = Math.min(cy, m, y);
327
+ return k >= 0.7 && lo >= 0.3 && Math.max(cy, m, y) - lo <= 0.25;
328
+ }
329
+ function countRichBlackText(src, ctx = {}) {
330
+ const scale = new TextScale(ctx.baseScale ?? 1);
331
+ let fill = null;
332
+ const stack = [];
333
+ let count = 0;
334
+ let operands = [];
335
+ for (const t of tokenize(src)) {
336
+ if (!t.op) {
337
+ operands.push(t);
338
+ continue;
339
+ }
340
+ const op = t.text;
341
+ const nums = operands.map((o) => Number(o.text));
342
+ scale.op(op, nums);
343
+ switch (op) {
344
+ case "q":
345
+ stack.push(fill);
346
+ break;
347
+ case "Q":
348
+ if (stack.length)
349
+ fill = stack.pop() ?? null;
350
+ break;
351
+ case "k":
352
+ fill = nums.length === 4 && !nums.some(Number.isNaN) ? nums : null;
353
+ break;
354
+ case "sc":
355
+ case "scn":
356
+ fill = nums.length === 4 && !nums.some(Number.isNaN) ? nums : null;
357
+ break;
358
+ case "g":
359
+ case "rg":
360
+ case "cs":
361
+ fill = null;
362
+ break;
363
+ case "Do": {
364
+ const name = operands[operands.length - 1]?.text;
365
+ if (name?.startsWith("/"))
366
+ ctx.onDo?.(name.slice(1), scale.unit);
367
+ break;
368
+ }
369
+ case "Tj":
370
+ case "TJ":
371
+ case "'":
372
+ case '"':
373
+ if (fill && isRichBlack(fill) && scale.size <= LARGE_TEXT_PT + SIZE_EPS)
374
+ count++;
375
+ break;
376
+ }
377
+ operands = [];
378
+ }
379
+ return count;
380
+ }
381
+ async function visitContent(doc, visit) {
382
+ const { PDFName, PDFRawStream, PDFArray, PDFRef, PDFDict, decodePDFRawStream } = await import("pdf-lib");
383
+ const ctx = doc.context;
384
+ const SKIP = ["Filter", "DecodeParms", "Length"].map((k) => PDFName.of(k));
385
+ let changed = false;
386
+ const decode = (s) => {
387
+ try {
388
+ return Buffer.from(decodePDFRawStream(s).decode()).toString("latin1");
389
+ } catch {
390
+ return null;
391
+ }
392
+ };
393
+ const replace = (ref, old, text) => {
394
+ const entries = {};
395
+ for (const [k, v] of old.dict.entries())
396
+ if (!SKIP.includes(k))
397
+ entries[k.decodeText()] = v;
398
+ ctx.assign(ref, ctx.flateStream(Buffer.from(text, "latin1"), entries));
399
+ changed = true;
400
+ };
401
+ const formScale = new Map;
402
+ const formPages = new Map;
403
+ const formMatrixScale = (form) => {
404
+ const m = form.dict.lookupMaybe(PDFName.of("Matrix"), PDFArray);
405
+ const nums = m?.asArray().map((n) => Number(n.toString()));
406
+ return nums?.length === 6 && !nums.some(Number.isNaN) ? area(nums) : 1;
407
+ };
408
+ const pages = doc.getPages();
409
+ for (let p = 0;p < pages.length; p++) {
410
+ const page = pages[p];
411
+ const contents = page.node.Contents();
412
+ const refs = [];
413
+ if (contents instanceof PDFArray) {
414
+ for (let i = 0;i < contents.size(); i++) {
415
+ const r = contents.get(i);
416
+ if (r instanceof PDFRef)
417
+ refs.push(r);
418
+ }
419
+ } else if (contents instanceof PDFRawStream) {
420
+ const r = page.node.get(PDFName.of("Contents"));
421
+ if (r instanceof PDFRef)
422
+ refs.push(r);
423
+ }
424
+ const streams = refs.map((r) => ctx.lookup(r));
425
+ if (!refs.length || !streams.every((s) => s instanceof PDFRawStream))
426
+ continue;
427
+ const parts = streams.map((s) => decode(s));
428
+ if (parts.some((q) => q === null))
429
+ continue;
430
+ const joined = parts.join(`
431
+ `);
432
+ const xobjects = page.node.Resources()?.lookupMaybe(PDFName.of("XObject"), PDFDict);
433
+ const next = visit(joined, {
434
+ baseScale: 1,
435
+ pages: [p + 1],
436
+ onDo: (name, scale) => {
437
+ const ref = xobjects?.get(PDFName.of(name));
438
+ const form = ref instanceof PDFRef ? ctx.lookup(ref) : undefined;
439
+ if (!(ref instanceof PDFRef) || !(form instanceof PDFRawStream))
440
+ return;
441
+ if (form.dict.get(PDFName.of("Subtype")) !== PDFName.of("Form"))
442
+ return;
443
+ const at = scale * formMatrixScale(form);
444
+ formScale.set(ref.tag, Math.min(formScale.get(ref.tag) ?? Infinity, at));
445
+ (formPages.get(ref.tag) ?? formPages.set(ref.tag, new Set).get(ref.tag)).add(p + 1);
446
+ }
447
+ });
448
+ if (next === joined)
449
+ continue;
450
+ replace(refs[0], streams[0], next);
451
+ page.node.set(PDFName.of("Contents"), refs[0]);
452
+ }
453
+ for (const [ref, obj] of ctx.enumerateIndirectObjects()) {
454
+ if (!(obj instanceof PDFRawStream))
455
+ continue;
456
+ if (obj.dict.get(PDFName.of("Subtype")) !== PDFName.of("Form"))
457
+ continue;
458
+ const text = decode(obj);
459
+ if (text === null)
460
+ continue;
461
+ const next = visit(text, {
462
+ baseScale: formScale.get(ref.tag) ?? 0,
463
+ pages: [...formPages.get(ref.tag) ?? []]
464
+ });
465
+ if (next !== text)
466
+ replace(ref, obj, next);
467
+ }
468
+ return changed;
469
+ }
470
+ async function blackTextToGray(pdf) {
471
+ const { PDFDocument } = await import("pdf-lib");
472
+ const doc = await PDFDocument.load(pdf, { updateMetadata: false });
473
+ const changed = await visitContent(doc, (src, info) => rewriteBlackText(src, info));
474
+ return changed ? doc.save({ updateFieldAppearances: false }) : pdf;
475
+ }
476
+ async function findRichBlackText(pdf) {
477
+ const { PDFDocument } = await import("pdf-lib");
478
+ const doc = await PDFDocument.load(pdf, { updateMetadata: false });
479
+ let runs = 0;
480
+ const pages = new Set;
481
+ await visitContent(doc, (src, info) => {
482
+ const n = countRichBlackText(src, info);
483
+ if (n) {
484
+ runs += n;
485
+ for (const p of info.pages)
486
+ pages.add(p);
487
+ }
488
+ return src;
489
+ });
490
+ return { runs, pages: [...pages].sort((a, b) => a - b) };
491
+ }
492
+
493
+ export { LARGE_TEXT_PT, rewriteBlackText, countRichBlackText, blackTextToGray, findRichBlackText };
@@ -681,10 +681,15 @@ function planRectoBlanks(sites) {
681
681
  return wrong;
682
682
  });
683
683
  }
684
- function signaturePadding(pageCount, signature = 1, reserveLastPage = false) {
684
+ function lastPageMode(print) {
685
+ return print.lastPage ?? (print.reserveLastPage ? "blank" : undefined);
686
+ }
687
+ function signaturePadding(pageCount, signature = 1, lastPage) {
685
688
  const size = signature > 1 ? signature : 1;
689
+ if (lastPage === "short-by-one")
690
+ return (size - (pageCount + 1) % size) % size;
686
691
  const padded = (size - pageCount % size) % size;
687
- return padded === 0 && reserveLastPage ? size : padded;
692
+ return padded === 0 && lastPage === "blank" ? size : padded;
688
693
  }
689
694
  var WHICH_VALUES = new Set(["first", "start", "last", "first-except"]);
690
695
  function parseWhich(raw) {
@@ -1111,7 +1116,7 @@ import { fileURLToPath } from "node:url";
1111
1116
  var favicon_default = "./favicon-wkbm9cjn.ico";
1112
1117
 
1113
1118
  // src/assets/manifest.schema.json
1114
- var manifest_schema_default = "./manifest.schema-40sfq49z.json";
1119
+ var manifest_schema_default = "./manifest.schema-gh0jjve9.json";
1115
1120
 
1116
1121
  // src/assets/preview/scripts/preview-interface.js
1117
1122
  var preview_interface_default = "./preview-interface-c44qk17f.js";
@@ -1126,7 +1131,7 @@ var preview_shell_default = "./preview-shell-xwn84kqr.js";
1126
1131
  var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
1127
1132
 
1128
1133
  // src/assets/engine/gutterpress-viewer.js
1129
- var gutterpress_viewer_default = "./gutterpress-viewer-zkv2stfy.js";
1134
+ var gutterpress_viewer_default = "./gutterpress-viewer-1n793gwd.js";
1130
1135
 
1131
1136
  // src/assets/engine/gutterpress-agent.js
1132
1137
  var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
@@ -1156,7 +1161,7 @@ var package_default = "./package-9rv69pxm.json";
1156
1161
  var README_default = "./README-vsnsc1b3.md";
1157
1162
 
1158
1163
  // src/assets/extension-templates/plugin/plugin.js.tpl
1159
- var plugin_js_default = "./plugin.js-m4a7m3t4.tpl";
1164
+ var plugin_js_default = "./plugin.js-cswq7wvd.tpl";
1160
1165
 
1161
1166
  // src/assets/extension-templates/plugin/styles/plugin.css
1162
1167
  var plugin_default = "./plugin-spbcem4j.css";
@@ -1171,7 +1176,7 @@ var fixture_default = "./fixture-2qnyqgb5.md";
1171
1176
  var expected_default = "./expected-ycmacem8.html";
1172
1177
 
1173
1178
  // src/assets/extension-templates/plugin/test/plugin.test.js.tpl
1174
- var plugin_test_js_default = "./plugin.test.js-6n8ct5e3.tpl";
1179
+ var plugin_test_js_default = "./plugin.test.js-xgxrd8hf.tpl";
1175
1180
 
1176
1181
  // src/assets/extension-templates/theme/package.json
1177
1182
  var package_default2 = "./package-aenwjew3.json";
@@ -1455,7 +1460,7 @@ async function postprocess(input, opts) {
1455
1460
  g.media.width - inset,
1456
1461
  g.media.height - inset
1457
1462
  ];
1458
- const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.reserveLastPage);
1463
+ const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.lastPage);
1459
1464
  for (let i = 0;i < padded; i++)
1460
1465
  doc.addPage([g.media.width, g.media.height]);
1461
1466
  const wantMarks = opts.marks || g.marks.includes("crop") || g.marks.includes("cross");
@@ -2232,12 +2237,12 @@ ${mapCss}`;
2232
2237
  const post = await postprocess(bytes, {
2233
2238
  geometry: tier2.geometry,
2234
2239
  signature: opts.signature,
2235
- reserveLastPage: opts.reserveLastPage,
2240
+ lastPage: opts.lastPage,
2236
2241
  marks: opts.marks,
2237
2242
  title: opts.title,
2238
2243
  author: opts.author
2239
2244
  });
2240
- log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.reserveLastPage ? "; last page reserved blank" : ""})` : ""));
2245
+ log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.lastPage ? `; last page: ${opts.lastPage}` : ""})` : ""));
2241
2246
  return {
2242
2247
  bytes: post.bytes,
2243
2248
  tier,
@@ -2597,4 +2602,4 @@ ${lines.length ? lines.join(`
2597
2602
  `);
2598
2603
  }
2599
2604
 
2600
- export { getAssetsDir, getAssetPath, MARGIN_BOX_IGNORED_PROPERTIES, build };
2605
+ export { lastPageMode, getAssetsDir, getAssetPath, MARGIN_BOX_IGNORED_PROPERTIES, build };
@@ -4,7 +4,7 @@ import {
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "gutterpress",
7
- version: "0.11.17-alpha.2",
7
+ version: "0.11.17-alpha.4",
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-ppc0vz4b.js";
9
+ } from "./cli-pqcb2nnb.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-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)
21
+ new: () => import("./new-bjdf7bhg.js").then((m) => m.default),
22
+ preview: () => import("./preview-1cschq8s.js").then((m) => m.default),
23
+ build: () => import("./build-fam0tqg6.js").then((m) => m.default),
24
+ publish: () => import("./publish-ddqrb8s9.js").then((m) => m.default),
25
+ validate: () => import("./validate-3hjkgxrz.js").then((m) => m.default),
26
+ preflight: () => import("./preflight-gvw01661.js").then((m) => m.default),
27
+ doctor: () => import("./doctor-zre5k5fg.js").then((m) => m.default),
28
+ ext: () => import("./ext-hfqcg6ax.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-m5y2wepr.js");
53
+ const { newArgs } = await import("./new-bjdf7bhg.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-bwpqwwny.js");
65
+ const { preflightArgs } = await import("./preflight-gvw01661.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-dsbfejt3.js");
85
+ const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-hfqcg6ax.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-70xgehq2.js";
4
+ } from "./cli-8apk8571.js";
5
5
  import {
6
6
  UsageError,
7
7
  rejectExtraPositionals,
8
8
  rejectUnknownFlags
9
- } from "./cli-ppc0vz4b.js";
9
+ } from "./cli-pqcb2nnb.js";
10
10
  import"./cli-46ycxe6r.js";
11
11
  import"./cli-7fkhgtfn.js";
12
12
  import"./cli-37x76zdn.js";
@@ -1,5 +1,6 @@
1
1
  import { type Browser } from "../shared/cdp.ts";
2
2
  import { type GcpmModel } from "../shared/gcpm-extract.ts";
3
+ import { type LastPageMode } from "../shared/synthesis.ts";
3
4
  import { type Tier2Output } from "./tier2.ts";
4
5
  import { type PostprocessResult } from "./postprocess.ts";
5
6
  /**
@@ -19,8 +20,8 @@ export interface BuildOptions {
19
20
  input: string;
20
21
  output?: string;
21
22
  signature?: number;
22
- /** guarantee the final page is a blank page added by postprocess */
23
- reserveLastPage?: boolean;
23
+ /** the printer-reserved last page: see `LastPageMode` in shared/synthesis.ts */
24
+ lastPage?: LastPageMode;
24
25
  marks?: boolean;
25
26
  slugPt?: number;
26
27
  bleedPt?: number;