@danielsimonjr/sciengjs 0.2.0 → 0.3.1

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 (76) hide show
  1. package/README.md +10 -5
  2. package/THIRD_PARTY_NOTICES.md +16 -0
  3. package/assets/licenses/MIT-mermaid.txt +21 -0
  4. package/assets/licenses/mermaid-bundle.txt +2128 -0
  5. package/assets/mermaid.min.js +3636 -0
  6. package/dist/browser/backend-pdf.d.ts +3 -0
  7. package/dist/browser/backend-pdf.js +15 -0
  8. package/dist/browser/backend-pdf.js.map +1 -0
  9. package/dist/browser/backend-png.d.ts +3 -0
  10. package/dist/browser/backend-png.js +18 -0
  11. package/dist/browser/backend-png.js.map +1 -0
  12. package/dist/browser/cdp.d.ts +37 -0
  13. package/dist/browser/cdp.js +161 -0
  14. package/dist/browser/cdp.js.map +1 -0
  15. package/dist/browser/flags.d.ts +10 -0
  16. package/dist/browser/flags.js +33 -0
  17. package/dist/browser/flags.js.map +1 -0
  18. package/dist/browser/index.d.ts +5 -0
  19. package/dist/browser/index.js +6 -0
  20. package/dist/browser/index.js.map +1 -0
  21. package/dist/browser/input.d.ts +38 -0
  22. package/dist/browser/input.js +97 -0
  23. package/dist/browser/input.js.map +1 -0
  24. package/dist/browser/page.d.ts +10 -0
  25. package/dist/browser/page.js +33 -0
  26. package/dist/browser/page.js.map +1 -0
  27. package/dist/browser/pinned.d.ts +16 -0
  28. package/dist/browser/pinned.js +13 -0
  29. package/dist/browser/pinned.js.map +1 -0
  30. package/dist/browser/profile.d.ts +9 -0
  31. package/dist/browser/profile.js +33 -0
  32. package/dist/browser/profile.js.map +1 -0
  33. package/dist/browser/proxy.d.ts +14 -0
  34. package/dist/browser/proxy.js +64 -0
  35. package/dist/browser/proxy.js.map +1 -0
  36. package/dist/browser/render.d.ts +58 -0
  37. package/dist/browser/render.js +421 -0
  38. package/dist/browser/render.js.map +1 -0
  39. package/dist/core.js +10 -2
  40. package/dist/core.js.map +1 -1
  41. package/dist/graph/backend-pdf.d.ts +3 -0
  42. package/dist/graph/backend-pdf.js +14 -0
  43. package/dist/graph/backend-pdf.js.map +1 -0
  44. package/dist/graph/backend-png.d.ts +4 -2
  45. package/dist/graph/backend-png.js +13 -13
  46. package/dist/graph/backend-png.js.map +1 -1
  47. package/dist/mermaid/backend-pdf.d.ts +6 -0
  48. package/dist/mermaid/backend-pdf.js +19 -0
  49. package/dist/mermaid/backend-pdf.js.map +1 -0
  50. package/dist/mermaid/backend-png.d.ts +3 -2
  51. package/dist/mermaid/backend-png.js +20 -6
  52. package/dist/mermaid/backend-png.js.map +1 -1
  53. package/dist/mermaid/backend-svg.d.ts +4 -1
  54. package/dist/mermaid/backend-svg.js +13 -3
  55. package/dist/mermaid/backend-svg.js.map +1 -1
  56. package/dist/mermaid/browser.d.ts +30 -0
  57. package/dist/mermaid/browser.js +52 -0
  58. package/dist/mermaid/browser.js.map +1 -0
  59. package/dist/mermaid/common.d.ts +7 -0
  60. package/dist/mermaid/common.js +34 -2
  61. package/dist/mermaid/common.js.map +1 -1
  62. package/dist/pairs.d.ts +2 -1
  63. package/dist/pairs.js +8 -6
  64. package/dist/pairs.js.map +1 -1
  65. package/dist/registry.js +4 -0
  66. package/dist/registry.js.map +1 -1
  67. package/dist/types.d.ts +2 -0
  68. package/dist/version.d.ts +1 -1
  69. package/dist/version.js +1 -1
  70. package/dist/worker/entry.js +1 -1
  71. package/dist/worker/entry.js.map +1 -1
  72. package/dist/worker/protocol.d.ts +7 -0
  73. package/dist/worker/run.d.ts +7 -0
  74. package/dist/worker/run.js +36 -1
  75. package/dist/worker/run.js.map +1 -1
  76. package/package.json +7 -2
@@ -0,0 +1,64 @@
1
+ import { once } from "node:events";
2
+ import { createServer as createHttpServer } from "node:http";
3
+ /**
4
+ * The host of an absolute URL, or of the authority of a CONNECT request ("host:port"). A value that is
5
+ * neither is recorded as it was sent, so that no attempt is lost.
6
+ */
7
+ function hostOf(target) {
8
+ if (/^https?:\/\//i.test(target)) {
9
+ try {
10
+ return new URL(target).hostname;
11
+ }
12
+ catch {
13
+ // A URL that does not parse is recorded as it was sent. A throw here would crash the engine process.
14
+ return target;
15
+ }
16
+ }
17
+ const colon = target.lastIndexOf(":");
18
+ return colon > 0 ? target.slice(0, colon) : target;
19
+ }
20
+ const REFUSED = "HTTP/1.1 403 Forbidden\r\nConnection: close\r\nContent-Length: 0\r\n\r\n";
21
+ /**
22
+ * Starts a proxy on 127.0.0.1 with an ephemeral port. It answers 403 to each request and to each CONNECT,
23
+ * and forwards nothing. The browser sends its connection attempts here, so the route off the host is closed.
24
+ */
25
+ export async function startRefusingProxy() {
26
+ const log = [];
27
+ const sockets = new Set();
28
+ const server = createHttpServer((req, res) => {
29
+ log.push(hostOf(req.url ?? ""));
30
+ res.writeHead(403, { Connection: "close", "Content-Length": "0" });
31
+ res.end();
32
+ });
33
+ server.on("connection", (socket) => {
34
+ sockets.add(socket);
35
+ // The browser resets its connections while it closes. An unhandled error on a socket would end the process.
36
+ socket.on("error", () => { });
37
+ socket.on("close", () => sockets.delete(socket));
38
+ });
39
+ server.on("connect", (req, socket) => {
40
+ log.push(hostOf(req.url ?? ""));
41
+ socket.on("error", () => { });
42
+ socket.end(REFUSED);
43
+ });
44
+ server.listen(0, "127.0.0.1");
45
+ await once(server, "listening");
46
+ const address = server.address();
47
+ if (address === null || typeof address === "string") {
48
+ throw new Error("the refusing proxy has no TCP address");
49
+ }
50
+ return {
51
+ port: address.port,
52
+ attempts: () => [...log],
53
+ close: () => closeServer(server, sockets),
54
+ };
55
+ }
56
+ /** Ends every open connection, then closes the server. */
57
+ function closeServer(server, sockets) {
58
+ for (const socket of sockets)
59
+ socket.destroy();
60
+ return new Promise((resolve, reject) => {
61
+ server.close((err) => (err ? reject(err) : resolve()));
62
+ });
63
+ }
64
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/browser/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { CdpConnection } from "./cdp.ts";
2
+ /** The address of the page that the client loads. The client answers it from memory, so it names no host. */
3
+ export declare const PAGE_URL = "http://sciengjs-page.invalid/";
4
+ /** The output of the browser stage for a page. The svg format returns the SVG that the page reports. */
5
+ export type HtmlFormat = "png" | "pdf" | "svg";
6
+ /** A pinned file that the client fulfils for one exact URL, with its bytes read before the browser starts. */
7
+ export interface PinnedBytes {
8
+ bytes: Uint8Array;
9
+ mime: string;
10
+ }
11
+ interface HtmlPageBase {
12
+ html: string;
13
+ /** Path of the browser executable. */
14
+ browser: string;
15
+ /** The time limit of the render, in milliseconds. */
16
+ timeoutMs: number;
17
+ /** Called with the profile folder of this render once the folder exists. A test uses it to find leaks. */
18
+ onProfile?: (profile: string) => void;
19
+ /** The exact pinned URLs that the client fulfils from memory. Every other request is refused. */
20
+ pinned?: ReadonlyMap<string, PinnedBytes>;
21
+ /**
22
+ * The page sets window.__sciengDone to {ok, svg} or {ok, message}. The capture waits for that value. A page
23
+ * that reports ok false rejects with E_INPUT. A png or pdf then draws the diagram in the element sciengjs-diagram.
24
+ */
25
+ awaitDone?: boolean;
26
+ }
27
+ /** One page to draw. A png has a size and a device scale. A pdf has neither. An svg needs awaitDone. */
28
+ export type HtmlPageRequest = (HtmlPageBase & {
29
+ format: "png";
30
+ width: number;
31
+ height: number;
32
+ scale: number;
33
+ }) | (HtmlPageBase & {
34
+ format: "pdf";
35
+ }) | (HtmlPageBase & {
36
+ format: "svg";
37
+ awaitDone: true;
38
+ });
39
+ /** The bytes that the browser drew, and the requests that it asked for and the client refused. */
40
+ export interface HtmlPageResult {
41
+ bytes: Uint8Array;
42
+ /** Each URL that the page asked for and the client refused, in order. */
43
+ blocked: string[];
44
+ }
45
+ /**
46
+ * Loads the page in a new target, refuses every request that is not the page, then captures it. Every request
47
+ * to the browser carries the deadline, and the whole capture runs under it. The load wait keys on the loader of
48
+ * the navigation, so a load event of an earlier document does not count.
49
+ */
50
+ export declare function capturePage(cdp: CdpConnection, req: HtmlPageRequest, deadline: number): Promise<HtmlPageResult>;
51
+ /**
52
+ * Draws one HTML page in a new headless browser and returns the bytes of a PNG or a PDF.
53
+ * The browser runs with a new profile, the forced flags and a refusing proxy. The browser sandbox stays on.
54
+ * The profile, the proxy and the browser are removed on every path before the function returns. One deadline
55
+ * covers the whole cleanup.
56
+ */
57
+ export declare function renderHtmlPage(req: HtmlPageRequest): Promise<HtmlPageResult>;
58
+ export {};
@@ -0,0 +1,421 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { RenderError } from "../errors.js";
5
+ import { CdpConnection, connectCdp } from "./cdp.js";
6
+ import { forcedBrowserFlags } from "./flags.js";
7
+ import { MAX_DEVICE_PIXELS } from "./input.js";
8
+ import { makeProfile, removeProfile } from "./profile.js";
9
+ import { startRefusingProxy } from "./proxy.js";
10
+ /** The address of the page that the client loads. The client answers it from memory, so it names no host. */
11
+ export const PAGE_URL = "http://sciengjs-page.invalid/";
12
+ /** The icon address of the page host. The client answers it locally, as the browser asks for it on its own. */
13
+ const FAVICON_URL = "http://sciengjs-page.invalid/favicon.ico";
14
+ /**
15
+ * The share of the render time that the page work may use. The rest is the budget for stopping the browser
16
+ * and removing the profile. The budget comes from the worker time limit, so the cleanup runs before the worker ends.
17
+ */
18
+ const PAGE_SHARE = 0.8;
19
+ const POLL_MS = 100;
20
+ const PORT_FILE = "DevToolsActivePort";
21
+ /** Codes of a read that Windows holds while the browser writes the port file. Such a read is polled again. */
22
+ const HELD_READ_CODES = new Set(["EBUSY", "EPERM", "ENOENT"]);
23
+ const IS_WINDOWS = process.platform === "win32";
24
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
25
+ function watchChild(child, browser) {
26
+ const state = { browser, exited: false, code: null, signal: null };
27
+ child.once("error", (err) => {
28
+ state.error = err;
29
+ });
30
+ child.once("exit", (code, signal) => {
31
+ state.exited = true;
32
+ state.code = code;
33
+ state.signal = signal;
34
+ });
35
+ return state;
36
+ }
37
+ /** Waits for the DevTools port file. Returns the WebSocket address of the browser. */
38
+ async function waitForBrowser(profile, state, deadline) {
39
+ const file = join(profile, PORT_FILE);
40
+ for (;;) {
41
+ if (state.error !== undefined) {
42
+ throw new RenderError("E_STAGE_MISSING", `cannot start the browser at ${state.browser}: ${state.error.message}`);
43
+ }
44
+ if (state.exited) {
45
+ throw new RenderError("E_STAGE_MISSING", `the browser exited with ${state.code ?? state.signal} before it published its DevTools port`);
46
+ }
47
+ if (existsSync(file)) {
48
+ try {
49
+ const lines = readFileSync(file, "utf8").split(/\r?\n/);
50
+ const port = Number(lines[0]);
51
+ if (Number.isInteger(port) && port > 0 && (lines[1] ?? "") !== "") {
52
+ return `ws://127.0.0.1:${port}${lines[1]}`;
53
+ }
54
+ }
55
+ catch (err) {
56
+ if (!HELD_READ_CODES.has(err.code ?? ""))
57
+ throw err;
58
+ }
59
+ }
60
+ if (Date.now() >= deadline) {
61
+ throw new RenderError("E_TIMEOUT", "the browser did not publish its DevTools port in time");
62
+ }
63
+ await sleep(POLL_MS);
64
+ }
65
+ }
66
+ /** Rejects when the promise does not settle before the deadline. */
67
+ async function withDeadline(work, deadline, message) {
68
+ let timer;
69
+ const expired = new Promise((_, reject) => {
70
+ timer = setTimeout(() => reject(new RenderError("E_TIMEOUT", message)), Math.max(0, deadline - Date.now()));
71
+ });
72
+ try {
73
+ return await Promise.race([work, expired]);
74
+ }
75
+ finally {
76
+ clearTimeout(timer);
77
+ }
78
+ }
79
+ /** The request interception of one page. It answers the page and the icon, and refuses every other request. */
80
+ class Interceptor {
81
+ cdp;
82
+ html;
83
+ pinned;
84
+ blocked = [];
85
+ faults = [];
86
+ guarded = new Set();
87
+ sessions = new Map();
88
+ sessionWaiters = new Map();
89
+ constructor(cdp, html, pinned) {
90
+ this.cdp = cdp;
91
+ this.html = html;
92
+ this.pinned = pinned;
93
+ }
94
+ record = (err) => {
95
+ this.faults.push(err instanceof Error ? err : new Error(String(err)));
96
+ };
97
+ /**
98
+ * Intercepts every request of the session and auto-attaches its child targets (frames in another process,
99
+ * workers, pop-ups) paused, so that each child is guarded the same way before it runs. A dedicated worker has no
100
+ * Fetch domain: the session of its page intercepts its requests.
101
+ */
102
+ async guard(sessionId, type = "page") {
103
+ if (this.guarded.has(sessionId))
104
+ return;
105
+ this.guarded.add(sessionId);
106
+ const cdp = this.cdp;
107
+ cdp.on("Fetch.requestPaused", sessionId, (params) => this.paused(sessionId, params));
108
+ cdp.on("Target.attachedToTarget", sessionId, (params) => this.attached(params));
109
+ if (type !== "worker")
110
+ await cdp.send("Fetch.enable", { patterns: [{ urlPattern: "*" }] }, sessionId);
111
+ await cdp.send("Target.setAutoAttach", { autoAttach: true, waitForDebuggerOnStart: true, flatten: true }, sessionId);
112
+ }
113
+ /** Guards a new child target, then lets it run. A child that cannot be guarded fails the render. */
114
+ attached(params) {
115
+ const { sessionId, targetInfo } = params;
116
+ this.guard(sessionId, targetInfo.type)
117
+ .then(() => {
118
+ this.sessions.set(targetInfo.targetId, sessionId);
119
+ this.sessionWaiters.get(targetInfo.targetId)?.(sessionId);
120
+ return this.cdp.send("Runtime.runIfWaitingForDebugger", {}, sessionId);
121
+ })
122
+ .catch(this.record);
123
+ }
124
+ /** The session of a target, once the target is attached and guarded. */
125
+ sessionOf(targetId) {
126
+ const known = this.sessions.get(targetId);
127
+ if (known !== undefined)
128
+ return Promise.resolve(known);
129
+ return new Promise((resolve) => this.sessionWaiters.set(targetId, resolve));
130
+ }
131
+ paused(sessionId, params) {
132
+ const cdp = this.cdp;
133
+ const paused = params;
134
+ if (paused.request.url === FAVICON_URL) {
135
+ // The browser asks for an icon of the page host by itself. The client answers it with no content, so no
136
+ // request leaves the process and the icon is not counted as a request of the page.
137
+ cdp
138
+ .send("Fetch.fulfillRequest", { requestId: paused.requestId, responseCode: 204, responseHeaders: [], body: "" }, sessionId)
139
+ .catch(this.record);
140
+ return;
141
+ }
142
+ if (paused.request.url === PAGE_URL) {
143
+ cdp
144
+ .send("Fetch.fulfillRequest", {
145
+ requestId: paused.requestId,
146
+ responseCode: 200,
147
+ responseHeaders: [{ name: "Content-Type", value: "text/html; charset=utf-8" }],
148
+ body: Buffer.from(this.html, "utf8").toString("base64"),
149
+ }, sessionId)
150
+ .catch(this.record);
151
+ return;
152
+ }
153
+ const asset = this.pinned.get(paused.request.url);
154
+ if (asset !== undefined) {
155
+ // A pinned build is fulfilled from the bytes that the caller read from the engine package. No request leaves the process.
156
+ cdp
157
+ .send("Fetch.fulfillRequest", {
158
+ requestId: paused.requestId,
159
+ responseCode: 200,
160
+ responseHeaders: [{ name: "Content-Type", value: asset.mime }],
161
+ body: Buffer.from(asset.bytes).toString("base64"),
162
+ }, sessionId)
163
+ .catch(this.record);
164
+ return;
165
+ }
166
+ this.blocked.push(paused.request.url);
167
+ cdp.send("Fetch.failRequest", { requestId: paused.requestId, errorReason: "BlockedByClient" }, sessionId).catch(this.record);
168
+ }
169
+ }
170
+ /**
171
+ * Loads the page in a new target, refuses every request that is not the page, then captures it. Every request
172
+ * to the browser carries the deadline, and the whole capture runs under it. The load wait keys on the loader of
173
+ * the navigation, so a load event of an earlier document does not count.
174
+ */
175
+ export async function capturePage(cdp, req, deadline) {
176
+ return withDeadline(capture(cdp, req), deadline, "the page did not load in time");
177
+ }
178
+ async function capture(cdp, req) {
179
+ const guard = new Interceptor(cdp, req.html, req.pinned ?? new Map());
180
+ // A new page that the page opens (window.open) is a new target of the browser. The browser-level auto-attach
181
+ // pauses it until it is guarded. A target of the browser itself (for example a built-in extension) is not a
182
+ // target of the page: the client lets it run, and the forced flags keep its connections on the proxy.
183
+ cdp.on("Target.attachedToTarget", undefined, (params) => {
184
+ const { sessionId, targetInfo } = params;
185
+ if (targetInfo.type === "page") {
186
+ guard.attached(params);
187
+ }
188
+ else {
189
+ cdp.send("Runtime.runIfWaitingForDebugger", {}, sessionId).catch(guard.record);
190
+ }
191
+ });
192
+ await cdp.send("Target.setAutoAttach", { autoAttach: true, waitForDebuggerOnStart: true, flatten: true });
193
+ const target = (await cdp.send("Target.createTarget", { url: "about:blank" }));
194
+ // The browser-level auto-attach attaches the new target and guards it. The client waits for that session.
195
+ const s = await guard.sessionOf(target.targetId);
196
+ const loads = new Set();
197
+ let onLoad;
198
+ cdp.on("Page.lifecycleEvent", s, (params) => {
199
+ const event = params;
200
+ if (event.name === "load") {
201
+ loads.add(event.loaderId);
202
+ onLoad?.();
203
+ }
204
+ });
205
+ await cdp.send("Page.enable", {}, s);
206
+ await cdp.send("Page.setLifecycleEventsEnabled", { enabled: true }, s);
207
+ if (req.format === "png" && req.awaitDone !== true) {
208
+ await cdp.send("Emulation.setDeviceMetricsOverride", { width: req.width, height: req.height, deviceScaleFactor: req.scale, mobile: false }, s);
209
+ }
210
+ const nav = (await cdp.send("Page.navigate", { url: PAGE_URL }, s));
211
+ if (nav.errorText !== undefined && nav.errorText !== "") {
212
+ throw new RenderError("E_INTERNAL", `the browser did not load the page: ${nav.errorText}`);
213
+ }
214
+ const loaderId = nav.loaderId ?? "";
215
+ // The load event can come before the reply of Page.navigate, so the seen loaders are checked first.
216
+ if (!loads.has(loaderId)) {
217
+ await new Promise((resolve) => {
218
+ onLoad = () => {
219
+ if (loads.has(loaderId))
220
+ resolve();
221
+ };
222
+ });
223
+ }
224
+ let bytes;
225
+ if (req.awaitDone === true) {
226
+ const done = await awaitDoneReport(cdp, s);
227
+ // A page that cannot run the pinned build is a fault of the engine, not of the source.
228
+ if (!done.ok)
229
+ throw new RenderError(done.internal === true ? "E_INTERNAL" : "E_INPUT", done.message);
230
+ if (req.format === "svg") {
231
+ bytes = new TextEncoder().encode(done.svg);
232
+ }
233
+ else {
234
+ bytes = await drawDiagram(cdp, s, req);
235
+ }
236
+ }
237
+ else if (req.format === "pdf") {
238
+ await fitPageToDiagram(cdp, s);
239
+ bytes = await printPdf(cdp, s);
240
+ }
241
+ else if (req.format === "png") {
242
+ const data = (await cdp.send("Page.captureScreenshot", { format: "png", captureBeyondViewport: false }, s));
243
+ bytes = Buffer.from(data.data, "base64");
244
+ }
245
+ else {
246
+ throw new RenderError("E_INTERNAL", "the page format is not drawn by this stage");
247
+ }
248
+ if (guard.faults.length > 0) {
249
+ throw new RenderError("E_INTERNAL", `the browser rejected a page request: ${guard.faults[0]?.message ?? "unknown"}`);
250
+ }
251
+ return { bytes, blocked: guard.blocked };
252
+ }
253
+ /** Waits until the page sets window.__sciengDone. The wait is one promise that the browser resolves. */
254
+ async function awaitDoneReport(cdp, s) {
255
+ const expression = "new Promise((resolve) => { const poll = () => (window.__sciengDone ? resolve(window.__sciengDone) : setTimeout(poll, 50)); poll(); })";
256
+ const reply = (await cdp.send("Runtime.evaluate", { expression, awaitPromise: true, returnByValue: true }, s));
257
+ const value = reply.result?.value;
258
+ if (reply.exceptionDetails !== undefined || value === undefined) {
259
+ throw new RenderError("E_INTERNAL", "the page did not report a result");
260
+ }
261
+ return value;
262
+ }
263
+ /** Reads the box of the first SVG of the diagram element, or undefined when the page has no diagram. */
264
+ async function diagramBox(cdp, s) {
265
+ const expression = '(() => { const e = document.querySelector("#sciengjs-diagram svg"); if (!e) return null; const r = e.getBoundingClientRect(); ' +
266
+ "return { x: r.x, y: r.y, width: Math.ceil(r.width), height: Math.ceil(r.height) }; })()";
267
+ const reply = (await cdp.send("Runtime.evaluate", { expression, returnByValue: true }, s));
268
+ const box = reply.result?.value;
269
+ return box === null || box === undefined || box.width <= 0 || box.height <= 0 ? undefined : box;
270
+ }
271
+ /** Draws the diagram of a page that reports done: a png clipped to the diagram box. */
272
+ async function drawDiagram(cdp, s, req) {
273
+ if (req.format === "svg")
274
+ throw new RenderError("E_INTERNAL", "an svg is not drawn from a box");
275
+ const box = await diagramBox(cdp, s);
276
+ if (box === undefined)
277
+ throw new RenderError("E_INPUT", "the diagram has no drawable size");
278
+ if (req.format === "pdf") {
279
+ await fitPageToDiagram(cdp, s);
280
+ return printPdf(cdp, s);
281
+ }
282
+ if (box.width * req.scale * (box.height * req.scale) > MAX_DEVICE_PIXELS) {
283
+ throw new RenderError("E_INPUT", `the png must not have more than ${MAX_DEVICE_PIXELS} device pixels`);
284
+ }
285
+ // The viewport takes the size of the diagram and the device scale of the request, so a wide diagram is not
286
+ // clipped and its pixel width is its CSS width times the scale.
287
+ await cdp.send("Emulation.setDeviceMetricsOverride", { width: Math.ceil(box.x + box.width), height: Math.ceil(box.y + box.height), deviceScaleFactor: req.scale, mobile: false }, s);
288
+ const fitted = (await diagramBox(cdp, s)) ?? box;
289
+ const data = (await cdp.send("Page.captureScreenshot", {
290
+ format: "png",
291
+ captureBeyondViewport: false,
292
+ clip: { x: fitted.x, y: fitted.y, width: fitted.width, height: fitted.height, scale: 1 },
293
+ }, s));
294
+ return Buffer.from(data.data, "base64");
295
+ }
296
+ /** Sets the pdf page size to the diagram box, so that the pdf holds one page of the diagram. A page with no diagram keeps its size. */
297
+ async function fitPageToDiagram(cdp, s) {
298
+ const box = await diagramBox(cdp, s);
299
+ if (box === undefined)
300
+ return;
301
+ const css = `@page { size: ${box.width}px ${box.height}px; margin: 0 }`;
302
+ await cdp.send("Runtime.evaluate", { expression: `(() => { const st = document.createElement("style"); st.textContent = ${JSON.stringify(css)}; document.head.appendChild(st); })()` }, s);
303
+ }
304
+ async function printPdf(cdp, s) {
305
+ const data = (await cdp.send("Page.printToPDF", { printBackground: true, preferCSSPageSize: true }, s));
306
+ return Buffer.from(data.data, "base64");
307
+ }
308
+ function hasExited(child) {
309
+ return child.exitCode !== null || child.signalCode !== null;
310
+ }
311
+ /** Waits for the browser to exit. Returns false when it is still running at the deadline. */
312
+ async function waitForExit(child, deadline) {
313
+ if (hasExited(child))
314
+ return true;
315
+ let timer;
316
+ const exited = new Promise((resolve) => {
317
+ child.once("exit", () => resolve(true));
318
+ timer = setTimeout(() => resolve(hasExited(child)), Math.max(0, deadline - Date.now()));
319
+ });
320
+ const result = await exited;
321
+ clearTimeout(timer);
322
+ return result;
323
+ }
324
+ /**
325
+ * Kills the browser and every process that it started. On POSIX the browser leads its own process group, so the
326
+ * group dies with one signal, also after the browser itself exited. On Windows `taskkill /T` walks the tree of a
327
+ * live process id. After the browser exited, Windows can give its id to an unrelated process, so the call is
328
+ * skipped then. A process that is already gone is not an error.
329
+ */
330
+ function killTree(child) {
331
+ const pid = child.pid;
332
+ if (pid === undefined)
333
+ return;
334
+ if (IS_WINDOWS) {
335
+ if (hasExited(child))
336
+ return;
337
+ spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
338
+ return;
339
+ }
340
+ try {
341
+ process.kill(-pid, "SIGKILL");
342
+ }
343
+ catch (err) {
344
+ if (err.code !== "ESRCH")
345
+ throw err;
346
+ }
347
+ }
348
+ /**
349
+ * Asks the browser to close, then waits for its exit. A browser still running at the deadline is killed with its
350
+ * process tree. The tree kill also runs after a clean close, so that no helper process stays.
351
+ */
352
+ async function stopBrowser(cdp, child, deadline) {
353
+ if (cdp !== undefined) {
354
+ // The exit wait below decides whether the browser stopped. A failed close request is not an error by itself.
355
+ await cdp.send("Browser.close", {}, undefined, deadline).catch(() => undefined);
356
+ cdp.close();
357
+ }
358
+ const closed = await waitForExit(child, deadline);
359
+ killTree(child);
360
+ if (closed)
361
+ return;
362
+ // The kill is sure to end the process, but its exit event needs a moment. The wait gets a short floor.
363
+ if (!(await waitForExit(child, Math.max(deadline, Date.now() + 1000)))) {
364
+ throw new RenderError("E_INTERNAL", "the browser did not stop after it was killed");
365
+ }
366
+ }
367
+ /**
368
+ * Draws one HTML page in a new headless browser and returns the bytes of a PNG or a PDF.
369
+ * The browser runs with a new profile, the forced flags and a refusing proxy. The browser sandbox stays on.
370
+ * The profile, the proxy and the browser are removed on every path before the function returns. One deadline
371
+ * covers the whole cleanup.
372
+ */
373
+ export async function renderHtmlPage(req) {
374
+ const pageBudgetMs = Math.floor(req.timeoutMs * PAGE_SHARE);
375
+ const cleanupBudgetMs = req.timeoutMs - pageBudgetMs;
376
+ const deadline = Date.now() + pageBudgetMs;
377
+ let proxy;
378
+ let profile;
379
+ let child;
380
+ let state;
381
+ let cdp;
382
+ try {
383
+ proxy = await startRefusingProxy();
384
+ profile = makeProfile();
385
+ req.onProfile?.(profile);
386
+ try {
387
+ child = spawn(req.browser, [...forcedBrowserFlags({ profileDir: profile, proxyPort: proxy.port }), "about:blank"], {
388
+ stdio: "ignore",
389
+ windowsHide: true,
390
+ // On POSIX the browser leads a new process group, so that the cleanup can kill the whole tree.
391
+ detached: !IS_WINDOWS,
392
+ });
393
+ }
394
+ catch (err) {
395
+ // Bun and Node on Windows throw at the spawn call for a file that cannot run.
396
+ throw new RenderError("E_STAGE_MISSING", `cannot start the browser at ${req.browser}: ${err.message}`);
397
+ }
398
+ state = watchChild(child, req.browser);
399
+ const address = await waitForBrowser(profile, state, deadline);
400
+ cdp = await connectCdp(address, deadline);
401
+ cdp.setDeadline(deadline);
402
+ return await capturePage(cdp, req, deadline);
403
+ }
404
+ finally {
405
+ const cleanupDeadline = Date.now() + cleanupBudgetMs;
406
+ try {
407
+ if (child !== undefined && state?.error === undefined)
408
+ await stopBrowser(cdp, child, cleanupDeadline);
409
+ }
410
+ finally {
411
+ try {
412
+ await proxy?.close();
413
+ }
414
+ finally {
415
+ if (profile !== undefined)
416
+ await removeProfile(profile, cleanupDeadline);
417
+ }
418
+ }
419
+ }
420
+ }
421
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/browser/render.ts"],"names":[],"mappings":"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"}
package/dist/core.js CHANGED
@@ -57,13 +57,19 @@ export async function renderWithRegistry(req, options, registry, configDeps) {
57
57
  format: req.format,
58
58
  source: req.source,
59
59
  options: (req.options ?? {}),
60
- settings: { maxMemoryMb: cfg.maxMemoryMb, rasterFont: cfg.rasterFont, assetsUrl: cfg.assetsUrl },
60
+ settings: {
61
+ maxMemoryMb: cfg.maxMemoryMb,
62
+ rasterFont: cfg.rasterFont,
63
+ assetsUrl: cfg.assetsUrl,
64
+ browser: cfg.browser,
65
+ timeoutMs: cfg.timeoutMs,
66
+ },
61
67
  },
62
68
  }, { timeoutMs: cfg.timeoutMs, maxMemoryMb: cfg.maxMemoryMb });
63
69
  return {
64
70
  bytes: out.bytes,
65
71
  mime: MIME[req.format],
66
- backend: entry.backend,
72
+ backend: out.backend ?? entry.backend,
67
73
  warnings: out.warnings ?? [],
68
74
  };
69
75
  }
@@ -75,6 +81,8 @@ export async function capabilitiesWithRegistry(options, registry, configDeps) {
75
81
  const browserReady = pair.stage !== "browser" || cfg.browser !== undefined;
76
82
  const ready = registered && browserReady;
77
83
  const cap = { type: pair.type, format: pair.format, stage: pair.stage, ready };
84
+ if (pair.note !== undefined)
85
+ cap.note = pair.note;
78
86
  if (!registered)
79
87
  cap.reason = "no backend is built in this release";
80
88
  else if (!browserReady)
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { BackendOutput, WorkerJob } from "../worker/protocol.ts";
2
+ /** Renders dot to pdf: the SVG of the graph, then the pdf of that SVG in the browser stage. The backend takes no options. */
3
+ export declare function render(request: WorkerJob["request"]): Promise<BackendOutput>;
@@ -0,0 +1,14 @@
1
+ import { RenderError } from "../errors.js";
2
+ import { drawSvgToPdf } from "../mermaid/browser.js";
3
+ import { dotSourceText, dotToSvg } from "./dot.js";
4
+ /** Renders dot to pdf: the SVG of the graph, then the pdf of that SVG in the browser stage. The backend takes no options. */
5
+ export async function render(request) {
6
+ const names = Object.keys(request.options ?? {});
7
+ if (names.length > 0) {
8
+ throw new RenderError("E_INPUT", `dot to pdf takes no options; got ${names.join(", ")}`);
9
+ }
10
+ const dot = await dotToSvg(dotSourceText(request.source));
11
+ const draw = await drawSvgToPdf(dot.svg, request.settings);
12
+ return { bytes: draw.bytes, warnings: [...dot.warnings, ...draw.warnings], backend: "graph/viz+browser/chromium" };
13
+ }
14
+ //# sourceMappingURL=backend-pdf.js.map