gutterpress 0.9.0-alpha.2 → 0.10.0-alpha.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 (138) hide show
  1. package/README.md +18 -4
  2. package/dist/api/index.d.ts +11 -5
  3. package/dist/api/index.js +20 -15
  4. package/dist/assets/preview/scripts/preview-bridge.d.ts +1 -0
  5. package/dist/assets/preview/scripts/preview-interface.d.ts +1 -0
  6. package/dist/{audit-nhn2pjz3.js → audit-xxegv0t0.js} +10 -7
  7. package/dist/{build-san7fv2z.js → build-w0vb6mgq.js} +14 -8
  8. package/dist/checks/source/index.d.ts +1 -0
  9. package/dist/checks/source/layout-markers.d.ts +3 -0
  10. package/dist/checks/source/local-ref-parser.d.ts +28 -0
  11. package/dist/cli-46ycxe6r.js +18 -0
  12. package/dist/{cli-k4bd06sd.js → cli-5czby0dd.js} +4986 -5889
  13. package/dist/cli-c41yr7he.js +241 -0
  14. package/dist/{cli-e5zhb0xs.js → cli-f4rcbt2t.js} +17 -24
  15. package/dist/{cli-najycadg.js → cli-gk3wsdpb.js} +69 -253
  16. package/dist/{index-yzrh708h.js → cli-k1065rkg.js} +2 -5
  17. package/dist/{cli-506tg37g.js → cli-revgt4pr.js} +2 -1
  18. package/dist/{cli-wchtvxvw.js → cli-v5mp7a6q.js} +14 -1
  19. package/dist/cli-yp3p0sf2.js +2343 -0
  20. package/dist/cli.js +20 -18
  21. package/dist/{doctor-hrk0kxxz.js → doctor-ctgn1dnt.js} +4 -2
  22. package/dist/engine/compiler/build.d.ts +139 -0
  23. package/dist/engine/compiler/postprocess.d.ts +23 -0
  24. package/dist/engine/compiler/tier2.d.ts +78 -0
  25. package/dist/engine/shared/cdp.d.ts +104 -0
  26. package/dist/engine/shared/content-value.d.ts +64 -0
  27. package/dist/engine/shared/gcpm-extract.d.ts +119 -0
  28. package/dist/engine/shared/margin-box-support.d.ts +12 -0
  29. package/dist/engine/shared/pdf-inspect.d.ts +24 -0
  30. package/dist/engine/shared/synthesis.d.ts +155 -0
  31. package/dist/engine-eng4xh2q.js +41 -0
  32. package/dist/engine-q5skhgms.js +40 -0
  33. package/dist/gutterpress-agent-1ctgfz92.js +576 -0
  34. package/dist/gutterpress-viewer-cem7dmr5.js +2349 -0
  35. package/dist/index-a4kr77td.js +1907 -0
  36. package/dist/{cli-yzrh708h.js → index-mdefp0y5.js} +1 -1
  37. package/dist/index-mvehxh0e.js +708 -0
  38. package/dist/{index-bynn850m.js → index-s416qpdv.js} +3049 -4015
  39. package/dist/{index-wchtvxvw.js → index-v5mp7a6q.js} +14 -1
  40. package/dist/index.d.ts +3 -1
  41. package/dist/index.js +24 -17
  42. package/dist/lib/asset-inline.d.ts +36 -0
  43. package/dist/lib/browser-pool.d.ts +18 -0
  44. package/dist/lib/build-error.d.ts +1 -1
  45. package/dist/lib/build-preflight.d.ts +35 -2
  46. package/dist/lib/build-runner.d.ts +45 -17
  47. package/dist/lib/build-staging.d.ts +9 -55
  48. package/dist/lib/cli-args.d.ts +8 -0
  49. package/dist/lib/desktop.d.ts +2 -2
  50. package/dist/lib/embedded-assets.d.ts +1 -1
  51. package/dist/lib/engine.d.ts +33 -0
  52. package/dist/lib/ghostscript.d.ts +46 -1
  53. package/dist/lib/markdown/assemble.d.ts +18 -10
  54. package/dist/lib/markdown/gp-pin-scope.d.ts +1 -0
  55. package/dist/lib/markdown/gutterpress-css.d.ts +125 -0
  56. package/dist/lib/markdown/images.d.ts +26 -0
  57. package/dist/lib/markdown/index.d.ts +4 -2
  58. package/dist/lib/markdown/inline-source.d.ts +10 -0
  59. package/dist/lib/markdown/markers.d.ts +32 -0
  60. package/dist/lib/markdown/renderer.d.ts +8 -3
  61. package/dist/lib/markdown/source-range.d.ts +61 -0
  62. package/dist/lib/missing-asset-placeholder.d.ts +52 -0
  63. package/dist/lib/presets.d.ts +1 -1
  64. package/dist/lib/printsafe.d.ts +2 -3
  65. package/dist/lib/remote-auth/converge-merge.d.ts +48 -0
  66. package/dist/lib/remote-auth/image-clash.d.ts +17 -0
  67. package/dist/lib/remote-auth/recovery/classify.d.ts +55 -67
  68. package/dist/lib/remote-auth/recovery/inspect.d.ts +14 -13
  69. package/dist/lib/remote-auth/recovery/locks.d.ts +20 -0
  70. package/dist/lib/remote-auth/recovery/repair.d.ts +29 -0
  71. package/dist/lib/remote-auth/recovery/types.d.ts +8 -204
  72. package/dist/lib/remote-auth/sync-messages.d.ts +2 -3
  73. package/dist/lib/remote-auth/sync-types.d.ts +35 -63
  74. package/dist/lib/remote-auth/sync.d.ts +11 -18
  75. package/dist/lib/remote-auth/transport.d.ts +14 -7
  76. package/dist/lib/theme-import.d.ts +4 -5
  77. package/dist/{lint-96j9hrj4.js → lint-gsh6qwrq.js} +10 -7
  78. package/dist/{manifest.schema-z61rzw44.json → manifest.schema-zxgxnbg7.json} +21 -0
  79. package/dist/{new-8p38wavc.js → new-nkhycqy4.js} +12 -8
  80. package/dist/{plugin-ees6nhkc.js → plugin-129wcs93.js} +10 -7
  81. package/dist/{preflight-1q6c2edh.js → preflight-41hcejg9.js} +10 -7
  82. package/dist/preview/file-watcher.d.ts +13 -17
  83. package/dist/preview/lifecycle.d.ts +1 -1
  84. package/dist/{pagedjs-bridge-vn4hk9fx.js → preview-bridge-fz7vpk8m.js} +8 -0
  85. package/dist/preview-interface-fnqb2y4v.js +1015 -0
  86. package/dist/{preview-y5a2zen1.js → preview-pftsvr9z.js} +16 -9
  87. package/dist/preview-shell-c5mfa3q0.js +346 -0
  88. package/dist/{project-source-p0gn1wd5.js → project-source-ekcyp63q.js} +1 -1
  89. package/dist/{publish-rm9yb3wh.js → publish-dnjvb4jg.js} +10 -7
  90. package/dist/render.d.ts +3 -4
  91. package/dist/render.js +728 -64
  92. package/dist/{repair-zgq7q2g6.js → repair-a3enjttn.js} +45 -79
  93. package/dist/schema/manifest.types.d.ts +38 -0
  94. package/dist/{source-provider-c1rjm2c0.js → source-provider-3tcj6qg2.js} +2 -2
  95. package/dist/source-provider-vanafrt9.js +40 -0
  96. package/dist/{theme-zz2ktzqs.css → theme-h5recz6c.css} +8 -7
  97. package/dist/{theme-570zmh2t.css → theme-j2bagrfx.css} +8 -7
  98. package/dist/{theme-nya4nqh6.css → theme-nn6d53zy.css} +8 -7
  99. package/dist/types.d.ts +7 -0
  100. package/dist/{validate-nr0xa6sa.js → validate-ph1xffqy.js} +10 -7
  101. package/package.json +6 -6
  102. package/dist/cli-yja077f6.js +0 -92
  103. package/dist/git-http-yrb4ag6z.js +0 -17
  104. package/dist/index-yja077f6.js +0 -92
  105. package/dist/lib/markdown/markdown-it-paged.d.ts +0 -30
  106. package/dist/lib/pagedjs-marker.d.ts +0 -42
  107. package/dist/lib/pagedjs.d.ts +0 -26
  108. package/dist/lib/pagination.d.ts +0 -149
  109. package/dist/lib/remote-auth/conflict-resolution.d.ts +0 -29
  110. package/dist/lib/remote-auth/recovery/abort-interrupted-operation.d.ts +0 -103
  111. package/dist/lib/remote-auth/recovery/backup.d.ts +0 -113
  112. package/dist/lib/remote-auth/recovery/context.d.ts +0 -47
  113. package/dist/lib/remote-auth/recovery/dispatch.d.ts +0 -28
  114. package/dist/lib/remote-auth/recovery/failsafe.d.ts +0 -33
  115. package/dist/lib/remote-auth/recovery/manual-guidance.d.ts +0 -28
  116. package/dist/lib/remote-auth/recovery/outcome-mapping.d.ts +0 -59
  117. package/dist/lib/remote-auth/recovery/policy.d.ts +0 -47
  118. package/dist/lib/remote-auth/recovery/recover-auth.d.ts +0 -42
  119. package/dist/lib/remote-auth/recovery/recover-binary-conflict.d.ts +0 -37
  120. package/dist/lib/remote-auth/recovery/recover-corrupt-index.d.ts +0 -40
  121. package/dist/lib/remote-auth/recovery/recover-detached-head.d.ts +0 -70
  122. package/dist/lib/remote-auth/recovery/recover-interrupted-cherry-pick.d.ts +0 -23
  123. package/dist/lib/remote-auth/recovery/recover-interrupted-merge.d.ts +0 -28
  124. package/dist/lib/remote-auth/recovery/recover-interrupted-rebase.d.ts +0 -39
  125. package/dist/lib/remote-auth/recovery/recover-merge-conflict.d.ts +0 -34
  126. package/dist/lib/remote-auth/recovery/recover-missing-git-dir.d.ts +0 -37
  127. package/dist/lib/remote-auth/recovery/recover-missing-objects.d.ts +0 -56
  128. package/dist/lib/remote-auth/recovery/recover-network.d.ts +0 -34
  129. package/dist/lib/remote-auth/recovery/recover-non-fast-forward.d.ts +0 -27
  130. package/dist/lib/remote-auth/recovery/recover-stale-lock.d.ts +0 -68
  131. package/dist/lib/remote-auth/recovery/recover-unrelated-histories.d.ts +0 -44
  132. package/dist/lib/remote-auth/recovery/recover-wrong-remote.d.ts +0 -35
  133. package/dist/lib/remote-auth/resolution-plan.d.ts +0 -64
  134. package/dist/paged.polyfill-n95pbxfn.js +0 -33288
  135. package/dist/pagedjs-interface-qxvzgwd7.js +0 -557
  136. package/dist/preview-shell-6dqexx1m.js +0 -581
  137. /package/dist/assets/{preview/scripts/pagedjs-bridge.d.ts → engine/gutterpress-agent.d.ts} +0 -0
  138. /package/dist/assets/{preview/scripts/pagedjs-interface.d.ts → engine/gutterpress-viewer.d.ts} +0 -0
@@ -0,0 +1,708 @@
1
+ import {
2
+ __require
3
+ } from "./index-37x76zdn.js";
4
+
5
+ // src/lib/build-error.ts
6
+ var EXIT_CODES = {
7
+ OK: 0,
8
+ FINDINGS: 1,
9
+ USAGE: 2,
10
+ PIPELINE: 3
11
+ };
12
+
13
+ class BuildError extends Error {
14
+ exitCode;
15
+ constructor(message, exitCode = EXIT_CODES.PIPELINE, options) {
16
+ super(message, options);
17
+ this.name = "BuildError";
18
+ this.exitCode = exitCode;
19
+ }
20
+ }
21
+
22
+ // src/lib/chromium.ts
23
+ import { existsSync } from "node:fs";
24
+
25
+ // src/lib/tool-probe.ts
26
+ import { platform } from "node:os";
27
+
28
+ // src/lib/exec.ts
29
+ import { spawn } from "node:child_process";
30
+ import { join, resolve as resolvePath, delimiter } from "node:path";
31
+ function buildEnhancedPath(dir, existingPath, sep = delimiter) {
32
+ return `${dir}${sep}${existingPath}`;
33
+ }
34
+ var localBin = resolvePath(join(import.meta.dirname, "..", "..", "node_modules", ".bin"));
35
+ var enhancedPath = buildEnhancedPath(localBin, process.env.PATH ?? "");
36
+ function enhancedEnv() {
37
+ return { ...process.env, PATH: enhancedPath };
38
+ }
39
+ function run(cmd, args, opts = {}) {
40
+ return new Promise((resolve, reject) => {
41
+ const p = spawn(cmd, args, { stdio: "inherit", cwd: opts.cwd, env: enhancedEnv() });
42
+ p.on("error", reject);
43
+ p.on("exit", (code) => {
44
+ if (code === 0)
45
+ return resolve();
46
+ const cwd = opts.cwd ?? process.cwd();
47
+ reject(new Error(`${cmd} ${args.join(" ")} (cwd=${cwd}) exited ${code}`));
48
+ });
49
+ });
50
+ }
51
+ var EXIT_FLUSH_GRACE_MS = 2000;
52
+ function keepTail(buffer, chunk, limit) {
53
+ const joined = buffer + chunk;
54
+ return limit !== undefined && joined.length > limit ? joined.slice(-limit) : joined;
55
+ }
56
+ function spawnCapture(cmd, args, opts = {}) {
57
+ return new Promise((resolve, reject) => {
58
+ const p = spawn(cmd, args, {
59
+ stdio: ["ignore", "pipe", "pipe"],
60
+ cwd: opts.cwd,
61
+ env: opts.env
62
+ });
63
+ let stdout = "";
64
+ let stderr = "";
65
+ let settled = false;
66
+ let exited = false;
67
+ let exitCode = null;
68
+ let exitSignal = null;
69
+ let killTimer;
70
+ let graceTimer;
71
+ const settle = (fn) => {
72
+ if (settled)
73
+ return;
74
+ settled = true;
75
+ if (killTimer)
76
+ clearTimeout(killTimer);
77
+ if (graceTimer)
78
+ clearTimeout(graceTimer);
79
+ fn();
80
+ };
81
+ const armKill = () => {
82
+ if (!opts.timeoutMs)
83
+ return;
84
+ if (killTimer)
85
+ clearTimeout(killTimer);
86
+ killTimer = setTimeout(() => {
87
+ settle(() => {
88
+ p.kill("SIGKILL");
89
+ reject(new Error(opts.timeoutMode === "idle" ? `${cmd} produced no output for ${opts.timeoutMs}ms and was stopped` : `${cmd} ${args.join(" ")} timed out after ${opts.timeoutMs}ms`));
90
+ });
91
+ }, opts.timeoutMs);
92
+ killTimer.unref();
93
+ };
94
+ armKill();
95
+ const finish = () => settle(() => resolve({ code: exitCode, signal: exitSignal, stdout, stderr }));
96
+ const armGrace = () => {
97
+ if (graceTimer)
98
+ clearTimeout(graceTimer);
99
+ graceTimer = setTimeout(finish, opts.exitGraceMs ?? EXIT_FLUSH_GRACE_MS);
100
+ graceTimer.unref();
101
+ };
102
+ const onData = (stream) => (d) => {
103
+ const text = d.toString();
104
+ if (stream === "stdout")
105
+ stdout = keepTail(stdout, text, opts.captureLimit);
106
+ else
107
+ stderr = keepTail(stderr, text, opts.captureLimit);
108
+ opts.onChunk?.(stream, text);
109
+ if (exited)
110
+ armGrace();
111
+ else if (opts.timeoutMode === "idle")
112
+ armKill();
113
+ };
114
+ p.stdout.on("data", onData("stdout"));
115
+ p.stderr.on("data", onData("stderr"));
116
+ p.on("error", (err) => settle(() => reject(err)));
117
+ p.on("exit", (code, signal) => {
118
+ exited = true;
119
+ exitCode = code;
120
+ exitSignal = signal;
121
+ if (killTimer) {
122
+ clearTimeout(killTimer);
123
+ killTimer = undefined;
124
+ }
125
+ armGrace();
126
+ });
127
+ p.on("close", finish);
128
+ });
129
+ }
130
+ async function execCapture(cmd, args, opts = {}) {
131
+ const { code, signal, stdout, stderr } = await spawnCapture(cmd, args, {
132
+ cwd: opts.cwd,
133
+ env: enhancedEnv(),
134
+ timeoutMs: opts.timeoutMs
135
+ });
136
+ if (code === 0)
137
+ return { stdout, stderr };
138
+ throw new Error(code === null ? `${cmd} was killed by signal ${signal}
139
+ ${stderr}` : `${cmd} exited ${code}
140
+ ${stderr}`);
141
+ }
142
+
143
+ // src/lib/tool-probe.ts
144
+ var IS_WINDOWS = platform() === "win32";
145
+ var PROBE_CMD = IS_WINDOWS ? "where.exe" : "which";
146
+ async function isToolAvailable(tool) {
147
+ try {
148
+ await execCapture(PROBE_CMD, [tool]);
149
+ return true;
150
+ } catch {
151
+ return false;
152
+ }
153
+ }
154
+ async function findTool(tool) {
155
+ try {
156
+ const { stdout } = await execCapture(PROBE_CMD, [tool]);
157
+ const firstLine = stdout.split(/\r?\n/).find((line) => line.trim().length > 0);
158
+ return firstLine?.trim() || undefined;
159
+ } catch {
160
+ return;
161
+ }
162
+ }
163
+
164
+ // src/lib/install-hints.ts
165
+ var INSTALL_HINTS = {
166
+ chromium: {
167
+ label: "Google Chrome, Chromium, or Microsoft Edge",
168
+ body: ` macOS: brew install --cask google-chrome
169
+ ` + ` Ubuntu: sudo apt install -y chromium-browser
170
+ ` + " Windows: https://www.google.com/chrome/ (Edge is auto-detected if pre-installed)"
171
+ },
172
+ gs: {
173
+ label: "Ghostscript",
174
+ body: ` macOS: brew install ghostscript
175
+ ` + ` Ubuntu: sudo apt install -y ghostscript
176
+ ` + " Windows: https://www.ghostscript.com/releases/gsdnld.html (standard installs are auto-detected; or: choco install ghostscript)"
177
+ },
178
+ qpdf: {
179
+ label: "qpdf",
180
+ body: ` macOS: brew install qpdf
181
+ ` + ` Ubuntu: sudo apt install -y qpdf
182
+ ` + " Windows: choco install qpdf (or: https://github.com/qpdf/qpdf/releases)"
183
+ }
184
+ };
185
+ function fullInstallHint(tool) {
186
+ const hint = INSTALL_HINTS[tool];
187
+ return `Install ${hint.label}:
188
+ ${hint.body}`;
189
+ }
190
+
191
+ // src/lib/chromium.ts
192
+ var SYSTEM_PATHS = [
193
+ process.env.CHROMIUM_PATH,
194
+ process.env.PUPPETEER_EXECUTABLE_PATH,
195
+ "/usr/bin/google-chrome",
196
+ "/usr/bin/google-chrome-stable",
197
+ "/usr/bin/chromium",
198
+ "/usr/bin/chromium-browser",
199
+ "/snap/bin/chromium",
200
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
201
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
202
+ "/opt/homebrew/bin/chromium",
203
+ "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
204
+ "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
205
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
206
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
207
+ process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe` : undefined,
208
+ "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
209
+ "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
210
+ process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\Microsoft\\Edge\\Application\\msedge.exe` : undefined,
211
+ process.env.LOCALAPPDATA ? `${process.env.LOCALAPPDATA}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe` : undefined
212
+ ].filter(Boolean);
213
+ var PATH_CANDIDATES = [
214
+ "google-chrome",
215
+ "google-chrome-stable",
216
+ "chromium",
217
+ "chromium-browser",
218
+ "chrome",
219
+ "chrome.exe",
220
+ "msedge",
221
+ "msedge.exe",
222
+ "brave",
223
+ "brave-browser",
224
+ "brave.exe",
225
+ "vivaldi",
226
+ "vivaldi-stable",
227
+ "vivaldi.exe",
228
+ "opera",
229
+ "opera-stable",
230
+ "opera.exe"
231
+ ];
232
+ async function resolveChromiumExecutable() {
233
+ for (const candidate of SYSTEM_PATHS) {
234
+ if (existsSync(candidate))
235
+ return candidate;
236
+ }
237
+ for (const candidate of PATH_CANDIDATES) {
238
+ const found = await findTool(candidate);
239
+ if (found)
240
+ return found;
241
+ }
242
+ return;
243
+ }
244
+ async function requireChromiumExecutable() {
245
+ const found = await resolveChromiumExecutable();
246
+ if (found)
247
+ return found;
248
+ throw new Error([
249
+ "No Chrome / Chromium / Edge binary found. Gutterpress needs a Chromium-based browser to render PDFs.",
250
+ "",
251
+ "Install one of:",
252
+ INSTALL_HINTS.chromium.body,
253
+ "",
254
+ "Or point to an existing install:",
255
+ " CHROMIUM_PATH=/path/to/chrome gutterpress build ...",
256
+ "",
257
+ "The Gutterpress desktop app uses its own bundled browser for BOTH",
258
+ "PDF export and needs no separate install.",
259
+ "This message is about the CLI, which does need one."
260
+ ].join(`
261
+ `));
262
+ }
263
+
264
+ // src/lib/browser-pool.ts
265
+ var RENDER_TIMEOUT_MS = 60 * 60 * 1000;
266
+ var browserPromise = null;
267
+ async function launchBrowser(timeoutMs) {
268
+ const executablePath = await requireChromiumExecutable();
269
+ const puppeteer = (await import("puppeteer-core")).default;
270
+ const extraChromiumArgs = (process.env.GUTTERPRESS_CHROMIUM_ARGS ?? "").split(/\s+/).filter(Boolean);
271
+ return puppeteer.launch({
272
+ headless: true,
273
+ executablePath,
274
+ args: extraChromiumArgs,
275
+ protocolTimeout: timeoutMs
276
+ });
277
+ }
278
+ function prewarmBrowser(timeoutMs) {
279
+ if (browserPromise)
280
+ return;
281
+ const p = launchBrowser(timeoutMs);
282
+ browserPromise = p;
283
+ p.then((browser) => {
284
+ browser.on("disconnected", () => {
285
+ if (browserPromise === p)
286
+ browserPromise = null;
287
+ });
288
+ }).catch(() => {
289
+ if (browserPromise === p)
290
+ browserPromise = null;
291
+ });
292
+ }
293
+ async function getBrowser(timeoutMs) {
294
+ if (!browserPromise)
295
+ prewarmBrowser(timeoutMs);
296
+ return browserPromise;
297
+ }
298
+ async function closeBrowser() {
299
+ const p = browserPromise;
300
+ browserPromise = null;
301
+ if (!p)
302
+ return;
303
+ try {
304
+ const b = await p;
305
+ await b.close();
306
+ } catch {}
307
+ }
308
+
309
+ // src/engine/shared/cdp.ts
310
+ import { spawn as spawn2 } from "node:child_process";
311
+ import { existsSync as existsSync2, mkdtempSync, rmSync } from "node:fs";
312
+ import { tmpdir } from "node:os";
313
+ import { join as join2 } from "node:path";
314
+ import WebSocket from "ws";
315
+ var CANDIDATES = [
316
+ process.env.GUTTERPRESS_CHROMIUM,
317
+ process.env.PUPPETEER_EXECUTABLE_PATH,
318
+ "/opt/pw-browsers/chromium",
319
+ "/usr/bin/chromium",
320
+ "/usr/bin/chromium-browser",
321
+ "/usr/bin/google-chrome",
322
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
323
+ ].filter(Boolean);
324
+ function findChromium() {
325
+ for (const c of CANDIDATES)
326
+ if (existsSync2(c))
327
+ return c;
328
+ throw new Error(`No Chromium found. Set GUTTERPRESS_CHROMIUM. Looked in:
329
+ ${CANDIDATES.join(`
330
+ `)}`);
331
+ }
332
+ var REQUIRED_MILESTONE = 148;
333
+ function assertMilestone(product, origin, hint = "") {
334
+ const milestone = Number(/Chrome\/(\d+)/.exec(product)?.[1] ?? 0);
335
+ if (milestone < REQUIRED_MILESTONE) {
336
+ throw new Error(`The Gutterpress engine requires Chromium ${REQUIRED_MILESTONE}+; found ${product} ${origin}.` + (hint ? `
337
+ ${hint}` : ""));
338
+ }
339
+ }
340
+ function readyProbeExpr(timeoutMs) {
341
+ return `(async () => {
342
+ await document.fonts.ready;
343
+ if (window.__gpReadyPending) {
344
+ await new Promise((res) => {
345
+ const t = setTimeout(res, ${timeoutMs});
346
+ document.addEventListener('gp:ready', () => { clearTimeout(t); res(); }, { once: true });
347
+ });
348
+ }
349
+ // two rAFs: let layout settle after fonts swap
350
+ await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
351
+ return true;
352
+ })()`;
353
+ }
354
+ var DEFAULT_PRINT_OPTS = {
355
+ printBackground: true,
356
+ preferCSSPageSize: true,
357
+ generateTaggedPDF: true,
358
+ generateDocumentOutline: true
359
+ };
360
+ async function launchChromium(opts = {}) {
361
+ const bin = findChromium();
362
+ const userDataDir = mkdtempSync(join2(tmpdir(), "gp-cdp-"));
363
+ const args = [
364
+ "--remote-debugging-port=0",
365
+ `--user-data-dir=${userDataDir}`,
366
+ "--no-first-run",
367
+ "--no-default-browser-check",
368
+ "--disable-gpu",
369
+ "--no-sandbox",
370
+ "--hide-scrollbars",
371
+ "--allow-file-access-from-files",
372
+ "--font-render-hinting=none",
373
+ ...opts.headless === false ? [] : ["--headless=new"],
374
+ ...opts.args ?? [],
375
+ "about:blank"
376
+ ];
377
+ const proc = spawn2(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
378
+ const wsUrl = await readDevToolsUrl(proc);
379
+ const conn = await Connection.open(wsUrl);
380
+ const teardown = async () => {
381
+ const exited = new Promise((r) => proc.once("exit", () => r()));
382
+ try {
383
+ await Promise.race([
384
+ conn.send("Browser.close").then(() => exited),
385
+ new Promise((_, rej) => setTimeout(() => rej(new Error("Browser.close timed out")), 5000))
386
+ ]);
387
+ } catch {
388
+ proc.kill("SIGKILL");
389
+ await exited;
390
+ }
391
+ conn.close();
392
+ rmSync(userDataDir, { recursive: true, force: true });
393
+ };
394
+ return checkMilestoneAndWrap(conn, wsUrl, `at ${bin}`, teardown);
395
+ }
396
+ async function connectChromium(wsUrl) {
397
+ const conn = await Connection.open(wsUrl);
398
+ return checkMilestoneAndWrap(conn, wsUrl, "via connected browser", async () => {
399
+ conn.close();
400
+ }, `Set CHROMIUM_PATH (or PUPPETEER_EXECUTABLE_PATH) to a ${REQUIRED_MILESTONE}+ binary.`);
401
+ }
402
+ async function checkMilestoneAndWrap(conn, wsUrl, origin, teardown, overrideHint = `Set GUTTERPRESS_CHROMIUM to a ${REQUIRED_MILESTONE}+ binary.`) {
403
+ const version = await conn.send("Browser.getVersion", {});
404
+ try {
405
+ assertMilestone(version.product, origin, overrideHint);
406
+ } catch (e) {
407
+ await teardown();
408
+ throw e;
409
+ }
410
+ const milestone = Number(/Chrome\/(\d+)/.exec(version.product)?.[1] ?? 0);
411
+ return {
412
+ wsUrl,
413
+ version: version.product,
414
+ milestone,
415
+ async newPage() {
416
+ const { targetId } = await conn.send("Target.createTarget", { url: "about:blank" });
417
+ const { sessionId } = await conn.send("Target.attachToTarget", { targetId, flatten: true });
418
+ const s = new SessionImpl(conn, sessionId, targetId);
419
+ await s.send("Page.enable");
420
+ await s.send("Runtime.enable");
421
+ return s;
422
+ },
423
+ close: teardown
424
+ };
425
+ }
426
+ function readDevToolsUrl(proc) {
427
+ return new Promise((resolve, reject) => {
428
+ let buf = "";
429
+ const timer = setTimeout(() => reject(new Error(`Chromium did not report a DevTools URL:
430
+ ${buf}`)), 20000);
431
+ proc.stderr.on("data", (d) => {
432
+ buf += String(d);
433
+ const m = /ws:\/\/[^\s]+/.exec(buf);
434
+ if (m) {
435
+ clearTimeout(timer);
436
+ resolve(m[0]);
437
+ }
438
+ });
439
+ proc.once("exit", (code) => {
440
+ clearTimeout(timer);
441
+ reject(new Error(`Chromium exited (${code}) before listening:
442
+ ${buf}`));
443
+ });
444
+ });
445
+ }
446
+
447
+ class Connection {
448
+ ws;
449
+ id = 0;
450
+ pending = new Map;
451
+ listeners = new Map;
452
+ constructor(ws) {
453
+ this.ws = ws;
454
+ ws.on("message", (raw) => this.dispatch(JSON.parse(String(raw))));
455
+ }
456
+ static async open(url) {
457
+ const ws = new WebSocket(url, { maxPayload: 512 * 1024 * 1024 });
458
+ await new Promise((res, rej) => {
459
+ ws.once("open", () => res());
460
+ ws.once("error", rej);
461
+ });
462
+ return new Connection(ws);
463
+ }
464
+ dispatch(msg) {
465
+ if (msg.id !== undefined) {
466
+ const p = this.pending.get(msg.id);
467
+ if (!p)
468
+ return;
469
+ this.pending.delete(msg.id);
470
+ if (msg.error)
471
+ p.reject(new Error(`${msg.error.message} (${msg.error.code})`));
472
+ else
473
+ p.resolve(msg.result);
474
+ return;
475
+ }
476
+ const key = msg.sessionId ? `${msg.sessionId}:${msg.method}` : msg.method;
477
+ for (const fn of this.listeners.get(key) ?? [])
478
+ fn(msg.params);
479
+ for (const fn of this.listeners.get(msg.method) ?? [])
480
+ fn(msg.params);
481
+ }
482
+ send(method, params = {}, sessionId) {
483
+ const id = ++this.id;
484
+ const payload = { id, method, params };
485
+ if (sessionId)
486
+ payload.sessionId = sessionId;
487
+ return new Promise((resolve, reject) => {
488
+ this.pending.set(id, { resolve, reject });
489
+ this.ws.send(JSON.stringify(payload));
490
+ });
491
+ }
492
+ on(key, fn) {
493
+ let set = this.listeners.get(key);
494
+ if (!set)
495
+ this.listeners.set(key, set = new Set);
496
+ set.add(fn);
497
+ return () => set.delete(fn);
498
+ }
499
+ close() {
500
+ this.ws.close();
501
+ }
502
+ }
503
+
504
+ class SessionImpl {
505
+ conn;
506
+ sessionId;
507
+ targetId;
508
+ constructor(conn, sessionId, targetId) {
509
+ this.conn = conn;
510
+ this.sessionId = sessionId;
511
+ this.targetId = targetId;
512
+ }
513
+ send(method, params = {}) {
514
+ return this.conn.send(method, params, this.sessionId);
515
+ }
516
+ on(event, fn) {
517
+ return this.conn.on(`${this.sessionId}:${event}`, fn);
518
+ }
519
+ async evaluate(expression) {
520
+ const res = await this.send("Runtime.evaluate", {
521
+ expression,
522
+ returnByValue: true,
523
+ awaitPromise: true
524
+ });
525
+ if (res.exceptionDetails) {
526
+ const e = res.exceptionDetails;
527
+ throw new Error(`evaluate failed: ${e.exception?.description ?? e.text}`);
528
+ }
529
+ return res.result.value;
530
+ }
531
+ async waitForLoad(fn) {
532
+ const done = new Promise((resolve) => {
533
+ const off = this.on("Page.loadEventFired", () => {
534
+ off();
535
+ resolve();
536
+ });
537
+ });
538
+ await fn();
539
+ await done;
540
+ }
541
+ async setContent(html, baseUrl = "http://gutterpress.spike/") {
542
+ await this.waitForLoad(async () => {
543
+ const { frameTree } = await this.send("Page.getFrameTree");
544
+ await this.send("Page.setDocumentContent", {
545
+ frameId: frameTree.frame.id,
546
+ html
547
+ });
548
+ });
549
+ }
550
+ async navigate(url) {
551
+ await this.waitForLoad(async () => {
552
+ await this.send("Page.navigate", { url });
553
+ });
554
+ }
555
+ async waitForReady(timeoutMs = 15000) {
556
+ await this.evaluate(readyProbeExpr(timeoutMs));
557
+ }
558
+ async printToPDF(opts = {}) {
559
+ const res = await this.send("Page.printToPDF", {
560
+ ...DEFAULT_PRINT_OPTS,
561
+ transferMode: "ReturnAsStream",
562
+ ...opts
563
+ });
564
+ if (!res.stream)
565
+ return Uint8Array.from(Buffer.from(res.data, "base64"));
566
+ const chunks = [];
567
+ try {
568
+ for (;; ) {
569
+ const c = await this.send("IO.read", { handle: res.stream, size: 8 * 1024 * 1024 });
570
+ if (c.data)
571
+ chunks.push(Buffer.from(c.data, c.base64Encoded ? "base64" : "binary"));
572
+ if (c.eof)
573
+ break;
574
+ }
575
+ } finally {
576
+ await this.send("IO.close", { handle: res.stream }).catch(() => {});
577
+ }
578
+ return new Uint8Array(Buffer.concat(chunks));
579
+ }
580
+ async close() {
581
+ await this.conn.send("Target.closeTarget", { targetId: this.targetId });
582
+ }
583
+ }
584
+
585
+ // src/lib/embedded-assets.ts
586
+ import { existsSync as existsSync3 } from "node:fs";
587
+ import { mkdtemp, mkdir, writeFile, readFile } from "node:fs/promises";
588
+ import { tmpdir as tmpdir2 } from "node:os";
589
+ import { dirname, join as join3, resolve } from "node:path";
590
+ import { fileURLToPath } from "node:url";
591
+
592
+ // src/assets/favicon.ico
593
+ var favicon_default = "./favicon-wkbm9cjn.ico";
594
+
595
+ // src/assets/manifest.schema.json
596
+ var manifest_schema_default = "./manifest.schema-zxgxnbg7.json";
597
+
598
+ // src/assets/preview/scripts/preview-interface.js
599
+ var preview_interface_default = "./preview-interface-fnqb2y4v.js";
600
+
601
+ // src/assets/preview/scripts/preview-bridge.js
602
+ var preview_bridge_default = "./preview-bridge-fz7vpk8m.js";
603
+
604
+ // src/assets/preview/scripts/preview-shell.js
605
+ var preview_shell_default = "./preview-shell-c5mfa3q0.js";
606
+
607
+ // profiles/CGATS21_CRPC1.icc
608
+ var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
609
+
610
+ // src/assets/engine/gutterpress-viewer.js
611
+ var gutterpress_viewer_default = "./gutterpress-viewer-cem7dmr5.js";
612
+
613
+ // src/assets/engine/gutterpress-agent.js
614
+ var gutterpress_agent_default = "./gutterpress-agent-1ctgfz92.js";
615
+
616
+ // src/assets/templates/book/manifest.yaml
617
+ var manifest_default = "./manifest-n1gh3qw5.yaml";
618
+
619
+ // src/assets/templates/book/chapter-01.md
620
+ var chapter_01_default = "./chapter-01-rkpyvjna.md";
621
+
622
+ // src/assets/templates/zine/manifest.yaml
623
+ var manifest_default2 = "./manifest-n1gh3qw5.yaml";
624
+
625
+ // src/assets/templates/zine/chapter-01.md
626
+ var chapter_01_default2 = "./chapter-01-7jwqg1ct.md";
627
+
628
+ // src/assets/templates/technical/manifest.yaml
629
+ var manifest_default3 = "./manifest-n1gh3qw5.yaml";
630
+
631
+ // src/assets/templates/technical/chapter-01.md
632
+ var chapter_01_default3 = "./chapter-01-6fn9pvd0.md";
633
+
634
+ // src/assets/themes/clean-book/theme.css
635
+ var theme_default = "./theme-j2bagrfx.css";
636
+
637
+ // src/assets/themes/clean-book/theme.json
638
+ var theme_default2 = "./theme-xt0hjb1b.json";
639
+
640
+ // src/assets/themes/zine/theme.css
641
+ var theme_default3 = "./theme-h5recz6c.css";
642
+
643
+ // src/assets/themes/zine/theme.json
644
+ var theme_default4 = "./theme-cd6efzjw.json";
645
+
646
+ // src/assets/themes/technical-doc/theme.css
647
+ var theme_default5 = "./theme-nn6d53zy.css";
648
+
649
+ // src/assets/themes/technical-doc/theme.json
650
+ var theme_default6 = "./theme-tqfypc1w.json";
651
+
652
+ // src/lib/embedded-assets.ts
653
+ var __libdir = dirname(fileURLToPath(import.meta.url));
654
+ var abs = (p) => resolve(__libdir, p);
655
+ var filePath = (v) => v;
656
+ var EMBEDDED_ASSETS = {
657
+ "favicon.ico": abs(favicon_default),
658
+ "manifest.schema.json": abs(filePath(manifest_schema_default)),
659
+ "preview/scripts/preview-interface.js": abs(filePath(preview_interface_default)),
660
+ "preview/scripts/preview-bridge.js": abs(filePath(preview_bridge_default)),
661
+ "preview/scripts/preview-shell.js": abs(filePath(preview_shell_default)),
662
+ "profiles/CGATS21_CRPC1.icc": abs(filePath(CGATS21_CRPC1_default)),
663
+ "engine/gutterpress-viewer.js": abs(filePath(gutterpress_viewer_default)),
664
+ "engine/gutterpress-agent.js": abs(filePath(gutterpress_agent_default)),
665
+ "templates/book/manifest.yaml": abs(filePath(manifest_default)),
666
+ "templates/book/chapter-01.md": abs(filePath(chapter_01_default)),
667
+ "templates/zine/manifest.yaml": abs(filePath(manifest_default2)),
668
+ "templates/zine/chapter-01.md": abs(filePath(chapter_01_default2)),
669
+ "templates/technical/manifest.yaml": abs(filePath(manifest_default3)),
670
+ "templates/technical/chapter-01.md": abs(filePath(chapter_01_default3)),
671
+ "themes/clean-book/theme.css": abs(filePath(theme_default)),
672
+ "themes/clean-book/theme.json": abs(filePath(theme_default2)),
673
+ "themes/zine/theme.css": abs(filePath(theme_default3)),
674
+ "themes/zine/theme.json": abs(filePath(theme_default4)),
675
+ "themes/technical-doc/theme.css": abs(filePath(theme_default5)),
676
+ "themes/technical-doc/theme.json": abs(filePath(theme_default6))
677
+ };
678
+ var extractPromise = null;
679
+ async function extractAssets() {
680
+ const root = await mkdtemp(join3(tmpdir2(), "gutterpress-assets-"));
681
+ for (const [relPath, srcPath] of Object.entries(EMBEDDED_ASSETS)) {
682
+ const dest = join3(root, relPath);
683
+ await mkdir(dirname(dest), { recursive: true });
684
+ const bytes = await readFile(srcPath);
685
+ await writeFile(dest, bytes);
686
+ }
687
+ return root;
688
+ }
689
+ var SENTINEL_ASSET = "engine/gutterpress-viewer.js";
690
+ async function getAssetsDir() {
691
+ if (extractPromise) {
692
+ try {
693
+ const root = await extractPromise;
694
+ if (existsSync3(join3(root, SENTINEL_ASSET))) {
695
+ return root;
696
+ }
697
+ } catch {}
698
+ extractPromise = null;
699
+ }
700
+ extractPromise = extractAssets();
701
+ return extractPromise;
702
+ }
703
+ async function getAssetPath(relPath) {
704
+ const root = await getAssetsDir();
705
+ return join3(root, relPath);
706
+ }
707
+
708
+ export { EXIT_CODES, BuildError, run, spawnCapture, execCapture, isToolAvailable, findTool, INSTALL_HINTS, fullInstallHint, resolveChromiumExecutable, requireChromiumExecutable, RENDER_TIMEOUT_MS, prewarmBrowser, getBrowser, closeBrowser, getAssetPath, REQUIRED_MILESTONE, assertMilestone, readyProbeExpr, DEFAULT_PRINT_OPTS, launchChromium, connectChromium };