@danielsimonjr/sciengjs 0.2.0 → 0.3.0

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 (75) 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.js +1 -1
  74. package/dist/worker/run.js.map +1 -1
  75. package/package.json +6 -1
@@ -0,0 +1,3 @@
1
+ import type { BackendOutput, WorkerJob } from "../worker/protocol.ts";
2
+ /** Renders html to pdf through Page.printToPDF in the headless browser. The worker calls this function. */
3
+ export declare function render(request: WorkerJob["request"]): Promise<BackendOutput>;
@@ -0,0 +1,15 @@
1
+ import { blockedWarnings, browserPathOf, htmlSource, parsePdfOptions } from "./input.js";
2
+ import { renderHtmlPage } from "./render.js";
3
+ /** Renders html to pdf through Page.printToPDF in the headless browser. The worker calls this function. */
4
+ export async function render(request) {
5
+ parsePdfOptions(request.options);
6
+ const browser = browserPathOf(request.settings.browser);
7
+ const out = await renderHtmlPage({
8
+ html: htmlSource(request.source),
9
+ format: "pdf",
10
+ browser,
11
+ timeoutMs: request.settings.timeoutMs,
12
+ });
13
+ return { bytes: out.bytes, warnings: blockedWarnings(out.blocked) };
14
+ }
15
+ //# sourceMappingURL=backend-pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend-pdf.js","sourceRoot":"","sources":["../../src/browser/backend-pdf.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAA6B;IACxD,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC;QAC/B,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;QAChC,MAAM,EAAE,KAAK;QACb,OAAO;QACP,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;KACtC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;AACtE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { BackendOutput, WorkerJob } from "../worker/protocol.ts";
2
+ /** Renders html to png: a screenshot of the page in the headless browser. The worker calls this function. */
3
+ export declare function render(request: WorkerJob["request"]): Promise<BackendOutput>;
@@ -0,0 +1,18 @@
1
+ import { blockedWarnings, browserPathOf, htmlSource, parsePngOptions } from "./input.js";
2
+ import { renderHtmlPage } from "./render.js";
3
+ /** Renders html to png: a screenshot of the page in the headless browser. The worker calls this function. */
4
+ export async function render(request) {
5
+ const options = parsePngOptions(request.options);
6
+ const browser = browserPathOf(request.settings.browser);
7
+ const out = await renderHtmlPage({
8
+ html: htmlSource(request.source),
9
+ format: "png",
10
+ width: options.width,
11
+ height: options.height,
12
+ scale: options.scale,
13
+ browser,
14
+ timeoutMs: request.settings.timeoutMs,
15
+ });
16
+ return { bytes: out.bytes, warnings: blockedWarnings(out.blocked) };
17
+ }
18
+ //# sourceMappingURL=backend-png.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend-png.js","sourceRoot":"","sources":["../../src/browser/backend-png.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,6GAA6G;AAC7G,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAA6B;IACxD,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC;QAC/B,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;QAChC,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,OAAO;QACP,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;KACtC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;AACtE,CAAC"}
@@ -0,0 +1,37 @@
1
+ /** The part of a WebSocket that the client uses. The global WebSocket of Node 22 and Bun meets it. */
2
+ export interface CdpSocket {
3
+ send(text: string): void;
4
+ close(): void;
5
+ addEventListener(type: string, listener: (ev: {
6
+ data?: unknown;
7
+ }) => void): void;
8
+ }
9
+ /** One Chrome DevTools Protocol connection. It matches each reply to its request and routes each event. */
10
+ export declare class CdpConnection {
11
+ private readonly socket;
12
+ private closed;
13
+ private nextId;
14
+ private readonly pending;
15
+ private readonly eventHandlers;
16
+ private deadline;
17
+ constructor(socket: CdpSocket);
18
+ /** Sets the default deadline (a Date.now() time) of each later request that names no deadline of its own. */
19
+ setDeadline(deadline: number | undefined): void;
20
+ /** The count of requests that wait for a reply. */
21
+ pendingCount(): number;
22
+ /**
23
+ * Sends one request. A request with no reply before its deadline rejects with E_TIMEOUT, and its pending entry
24
+ * is removed, so that a late reply is ignored.
25
+ */
26
+ send(method: string, params?: Record<string, unknown>, sessionId?: string, deadline?: number | undefined): Promise<unknown>;
27
+ on(method: string, sessionId: string | undefined, handler: (params: unknown) => void): void;
28
+ close(): void;
29
+ private handleMessageData;
30
+ private handleSocketClose;
31
+ private rejectAllPending;
32
+ }
33
+ /**
34
+ * Opens a DevTools socket and returns a connection on it. An error event, or a close before the open, rejects with
35
+ * E_STAGE_MISSING. No open before the deadline closes the socket and rejects with E_TIMEOUT.
36
+ */
37
+ export declare function connectCdp(address: string, deadline: number, makeSocket?: (address: string) => CdpSocket): Promise<CdpConnection>;
@@ -0,0 +1,161 @@
1
+ import { RenderError } from "../errors.js";
2
+ const SOCKET_CLOSED_MESSAGE = "the DevTools socket closed";
3
+ function safeJsonParse(text) {
4
+ try {
5
+ return JSON.parse(text);
6
+ }
7
+ catch {
8
+ return undefined;
9
+ }
10
+ }
11
+ function errorText(error) {
12
+ if (typeof error === "object" && error !== null) {
13
+ const message = error.message;
14
+ if (typeof message === "string") {
15
+ return message;
16
+ }
17
+ }
18
+ return JSON.stringify(error);
19
+ }
20
+ /** One Chrome DevTools Protocol connection. It matches each reply to its request and routes each event. */
21
+ export class CdpConnection {
22
+ socket;
23
+ closed = false;
24
+ nextId = 1;
25
+ pending = new Map();
26
+ eventHandlers = [];
27
+ deadline;
28
+ constructor(socket) {
29
+ this.socket = socket;
30
+ socket.addEventListener("message", (ev) => {
31
+ this.handleMessageData(ev.data);
32
+ });
33
+ socket.addEventListener("close", () => {
34
+ this.handleSocketClose();
35
+ });
36
+ }
37
+ /** Sets the default deadline (a Date.now() time) of each later request that names no deadline of its own. */
38
+ setDeadline(deadline) {
39
+ this.deadline = deadline;
40
+ }
41
+ /** The count of requests that wait for a reply. */
42
+ pendingCount() {
43
+ return this.pending.size;
44
+ }
45
+ /**
46
+ * Sends one request. A request with no reply before its deadline rejects with E_TIMEOUT, and its pending entry
47
+ * is removed, so that a late reply is ignored.
48
+ */
49
+ send(method, params, sessionId, deadline = this.deadline) {
50
+ if (this.closed) {
51
+ return Promise.reject(new Error(SOCKET_CLOSED_MESSAGE));
52
+ }
53
+ const id = this.nextId++;
54
+ const payload = {
55
+ id,
56
+ method,
57
+ params: params ?? {},
58
+ };
59
+ if (sessionId !== undefined) {
60
+ payload.sessionId = sessionId;
61
+ }
62
+ return new Promise((resolve, reject) => {
63
+ const timer = deadline === undefined
64
+ ? undefined
65
+ : setTimeout(() => {
66
+ this.pending.delete(id);
67
+ reject(new RenderError("E_TIMEOUT", `the browser did not answer ${method} in time`));
68
+ }, Math.max(0, deadline - Date.now()));
69
+ this.pending.set(id, { resolve, reject, timer });
70
+ this.socket.send(JSON.stringify(payload));
71
+ });
72
+ }
73
+ on(method, sessionId, handler) {
74
+ this.eventHandlers.push({ method, sessionId, handler });
75
+ }
76
+ close() {
77
+ if (this.closed) {
78
+ return;
79
+ }
80
+ this.closed = true;
81
+ this.rejectAllPending();
82
+ this.socket.close();
83
+ }
84
+ handleMessageData(data) {
85
+ if (typeof data !== "string") {
86
+ return;
87
+ }
88
+ const parsed = safeJsonParse(data);
89
+ if (parsed === null || typeof parsed !== "object") {
90
+ return;
91
+ }
92
+ const message = parsed;
93
+ if (typeof message.id === "number") {
94
+ const pending = this.pending.get(message.id);
95
+ if (pending === undefined) {
96
+ return;
97
+ }
98
+ this.pending.delete(message.id);
99
+ clearTimeout(pending.timer);
100
+ if (message.error !== undefined && message.error !== null) {
101
+ pending.reject(new Error(errorText(message.error)));
102
+ }
103
+ else {
104
+ pending.resolve(message.result);
105
+ }
106
+ return;
107
+ }
108
+ if (typeof message.method !== "string") {
109
+ return;
110
+ }
111
+ const eventSessionId = typeof message.sessionId === "string" ? message.sessionId : undefined;
112
+ for (const entry of this.eventHandlers) {
113
+ if (entry.method === message.method && entry.sessionId === eventSessionId) {
114
+ entry.handler(message.params);
115
+ }
116
+ }
117
+ }
118
+ handleSocketClose() {
119
+ this.closed = true;
120
+ this.rejectAllPending();
121
+ }
122
+ rejectAllPending() {
123
+ for (const pending of Array.from(this.pending.values())) {
124
+ clearTimeout(pending.timer);
125
+ pending.reject(new Error(SOCKET_CLOSED_MESSAGE));
126
+ }
127
+ this.pending.clear();
128
+ }
129
+ }
130
+ /** The WebSocket of the runtime as a CdpSocket. */
131
+ function runtimeSocket(address) {
132
+ return new WebSocket(address);
133
+ }
134
+ /**
135
+ * Opens a DevTools socket and returns a connection on it. An error event, or a close before the open, rejects with
136
+ * E_STAGE_MISSING. No open before the deadline closes the socket and rejects with E_TIMEOUT.
137
+ */
138
+ export function connectCdp(address, deadline, makeSocket = runtimeSocket) {
139
+ const socket = makeSocket(address);
140
+ return new Promise((resolve, reject) => {
141
+ let settled = false;
142
+ const settle = (fn) => {
143
+ if (settled)
144
+ return;
145
+ settled = true;
146
+ clearTimeout(timer);
147
+ fn();
148
+ };
149
+ const timer = setTimeout(() => {
150
+ settle(() => {
151
+ socket.close();
152
+ reject(new RenderError("E_TIMEOUT", `the DevTools socket ${address} did not open in time`));
153
+ });
154
+ }, Math.max(0, deadline - Date.now()));
155
+ socket.addEventListener("open", () => settle(() => resolve(new CdpConnection(socket))));
156
+ const fail = () => settle(() => reject(new RenderError("E_STAGE_MISSING", `cannot open the DevTools socket ${address}`)));
157
+ socket.addEventListener("error", fail);
158
+ socket.addEventListener("close", fail);
159
+ });
160
+ }
161
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../../src/browser/cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /** The values that the forced flags need: the profile folder and the port of the refusing proxy. */
2
+ export interface FlagInputs {
3
+ profileDir: string;
4
+ proxyPort: number;
5
+ }
6
+ /**
7
+ * The flags of every browser start. Each flag closes one route off the host. The client never adds
8
+ * `--no-sandbox`. The renderer keeps the Chrome sandbox on.
9
+ */
10
+ export declare function forcedBrowserFlags(input: FlagInputs): string[];
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The flags of every browser start. Each flag closes one route off the host. The client never adds
3
+ * `--no-sandbox`. The renderer keeps the Chrome sandbox on.
4
+ */
5
+ export function forcedBrowserFlags(input) {
6
+ return [
7
+ "--headless=new",
8
+ // The DevTools port is an ephemeral loopback port. Another local process of the same user can reach it while the
9
+ // render runs. A pipe (--remote-debugging-pipe) closes that route, but it needs extra file descriptors and
10
+ // replaces the port file, so the client keeps the port. The port lives only for one render.
11
+ "--remote-debugging-port=0",
12
+ `--user-data-dir=${input.profileDir}`,
13
+ "--no-first-run",
14
+ "--no-default-browser-check",
15
+ "--disable-extensions",
16
+ "--do-not-de-elevate",
17
+ "--disable-breakpad",
18
+ "--disable-crash-reporter",
19
+ `--proxy-server=http://127.0.0.1:${input.proxyPort}`,
20
+ "--proxy-bypass-list=<-loopback>",
21
+ "--host-resolver-rules=MAP * ~NOTFOUND, EXCLUDE 127.0.0.1",
22
+ "--force-webrtc-ip-handling-policy=disable_non_proxied_udp",
23
+ // The browser makes no request of its own: no background service, no component update, no sync, no ping.
24
+ "--disable-background-networking",
25
+ "--disable-component-update",
26
+ "--disable-sync",
27
+ "--no-pings",
28
+ "--disable-component-extensions-with-background-pages",
29
+ // Linux containers often have a small /dev/shm. The browser then writes its shared memory to the temp folder.
30
+ "--disable-dev-shm-usage",
31
+ ];
32
+ }
33
+ //# sourceMappingURL=flags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/browser/flags.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAiB;IAClD,OAAO;QACL,gBAAgB;QAChB,iHAAiH;QACjH,2GAA2G;QAC3G,4FAA4F;QAC5F,2BAA2B;QAC3B,mBAAmB,KAAK,CAAC,UAAU,EAAE;QACrC,gBAAgB;QAChB,4BAA4B;QAC5B,sBAAsB;QACtB,qBAAqB;QACrB,oBAAoB;QACpB,0BAA0B;QAC1B,mCAAmC,KAAK,CAAC,SAAS,EAAE;QACpD,iCAAiC;QACjC,0DAA0D;QAC1D,2DAA2D;QAC3D,yGAAyG;QACzG,iCAAiC;QACjC,4BAA4B;QAC5B,gBAAgB;QAChB,YAAY;QACZ,sDAAsD;QACtD,8GAA8G;QAC9G,yBAAyB;KAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ /** The Chrome DevTools Protocol client of the browser stage. It has no npm dependency. */
2
+ export { CdpConnection, type CdpSocket } from "./cdp.ts";
3
+ export { forcedBrowserFlags, type FlagInputs } from "./flags.ts";
4
+ export { startRefusingProxy, type RefusingProxy } from "./proxy.ts";
5
+ export { renderHtmlPage, type HtmlPageRequest, type HtmlPageResult, type HtmlFormat } from "./render.ts";
@@ -0,0 +1,6 @@
1
+ /** The Chrome DevTools Protocol client of the browser stage. It has no npm dependency. */
2
+ export { CdpConnection } from "./cdp.js";
3
+ export { forcedBrowserFlags } from "./flags.js";
4
+ export { startRefusingProxy } from "./proxy.js";
5
+ export { renderHtmlPage } from "./render.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAmB,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAsB,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,cAAc,EAA8D,MAAM,aAAa,CAAC"}
@@ -0,0 +1,38 @@
1
+ /** The default page width of a png, in CSS pixels. */
2
+ export declare const DEFAULT_WIDTH = 800;
3
+ /** The default page height of a png, in CSS pixels. */
4
+ export declare const DEFAULT_HEIGHT = 600;
5
+ /** The default device scale of a png. */
6
+ export declare const DEFAULT_SCALE = 1;
7
+ /** The largest width or height of a png, in CSS pixels. */
8
+ export declare const MAX_SIDE = 16384;
9
+ /** The largest device scale of a png. */
10
+ export declare const MAX_SCALE = 8;
11
+ /** The largest count of device pixels of a png: (width * scale) * (height * scale). */
12
+ export declare const MAX_DEVICE_PIXELS: number;
13
+ /** The largest count of refused URLs that get one warning each. */
14
+ export declare const MAX_BLOCKED_WARNINGS = 50;
15
+ /** The largest count of URL characters in one warning. */
16
+ export declare const MAX_WARNING_URL_CHARS = 200;
17
+ /** The options of html to png. */
18
+ export interface PngOptions {
19
+ width: number;
20
+ height: number;
21
+ scale: number;
22
+ }
23
+ /**
24
+ * Checks the options of html to png. An unknown key, a bad value, a side over MAX_SIDE, a scale over MAX_SCALE
25
+ * or a device pixel count over MAX_DEVICE_PIXELS rejects with E_INPUT.
26
+ */
27
+ export declare function parsePngOptions(options: Record<string, unknown>): PngOptions;
28
+ /** Checks the options of html to pdf. The pdf takes no option. */
29
+ export declare function parsePdfOptions(options: Record<string, unknown>): void;
30
+ /** The HTML text of a source. A source that is bytes rejects with E_INPUT. */
31
+ export declare function htmlSource(source: string | Uint8Array): string;
32
+ /** The browser path of the settings. A missing path rejects with E_STAGE_MISSING. */
33
+ export declare function browserPathOf(browser: string | undefined): string;
34
+ /**
35
+ * One warning for each request that the page made and the client refused, up to MAX_BLOCKED_WARNINGS. A URL is cut
36
+ * to MAX_WARNING_URL_CHARS and its control characters are escaped. One last warning counts the requests over the cap.
37
+ */
38
+ export declare function blockedWarnings(blocked: readonly string[]): string[];
@@ -0,0 +1,97 @@
1
+ import { RenderError } from "../errors.js";
2
+ /** The default page width of a png, in CSS pixels. */
3
+ export const DEFAULT_WIDTH = 800;
4
+ /** The default page height of a png, in CSS pixels. */
5
+ export const DEFAULT_HEIGHT = 600;
6
+ /** The default device scale of a png. */
7
+ export const DEFAULT_SCALE = 1;
8
+ /** The largest width or height of a png, in CSS pixels. */
9
+ export const MAX_SIDE = 16384;
10
+ /** The largest device scale of a png. */
11
+ export const MAX_SCALE = 8;
12
+ /** The largest count of device pixels of a png: (width * scale) * (height * scale). */
13
+ export const MAX_DEVICE_PIXELS = 64 * 1024 * 1024;
14
+ /** The largest count of refused URLs that get one warning each. */
15
+ export const MAX_BLOCKED_WARNINGS = 50;
16
+ /** The largest count of URL characters in one warning. */
17
+ export const MAX_WARNING_URL_CHARS = 200;
18
+ function rejectUnknownKeys(options, allowed, pair) {
19
+ for (const key of Object.keys(options)) {
20
+ if (!allowed.includes(key)) {
21
+ throw new RenderError("E_INPUT", `${pair} takes no option ${key}`);
22
+ }
23
+ }
24
+ }
25
+ function positiveInteger(options, key, fallback) {
26
+ if (!(key in options))
27
+ return fallback;
28
+ const value = options[key];
29
+ if (typeof value === "number" && Number.isInteger(value) && value > 0)
30
+ return value;
31
+ throw new RenderError("E_INPUT", `option ${key} must be a whole number greater than 0`);
32
+ }
33
+ function positiveNumber(options, key, fallback) {
34
+ if (!(key in options))
35
+ return fallback;
36
+ const value = options[key];
37
+ if (typeof value === "number" && Number.isFinite(value) && value > 0)
38
+ return value;
39
+ throw new RenderError("E_INPUT", `option ${key} must be a finite number greater than 0`);
40
+ }
41
+ /**
42
+ * Checks the options of html to png. An unknown key, a bad value, a side over MAX_SIDE, a scale over MAX_SCALE
43
+ * or a device pixel count over MAX_DEVICE_PIXELS rejects with E_INPUT.
44
+ */
45
+ export function parsePngOptions(options) {
46
+ rejectUnknownKeys(options, ["width", "height", "scale"], "html to png");
47
+ const width = positiveInteger(options, "width", DEFAULT_WIDTH);
48
+ const height = positiveInteger(options, "height", DEFAULT_HEIGHT);
49
+ const scale = positiveNumber(options, "scale", DEFAULT_SCALE);
50
+ if (width > MAX_SIDE || height > MAX_SIDE) {
51
+ throw new RenderError("E_INPUT", `options width and height must not be more than ${MAX_SIDE}`);
52
+ }
53
+ if (scale > MAX_SCALE) {
54
+ throw new RenderError("E_INPUT", `option scale must not be more than ${MAX_SCALE}`);
55
+ }
56
+ if (width * scale * (height * scale) > MAX_DEVICE_PIXELS) {
57
+ throw new RenderError("E_INPUT", `the png must not have more than ${MAX_DEVICE_PIXELS} device pixels`);
58
+ }
59
+ return { width, height, scale };
60
+ }
61
+ /** Checks the options of html to pdf. The pdf takes no option. */
62
+ export function parsePdfOptions(options) {
63
+ rejectUnknownKeys(options, [], "html to pdf");
64
+ }
65
+ /** The HTML text of a source. A source that is bytes rejects with E_INPUT. */
66
+ export function htmlSource(source) {
67
+ if (typeof source !== "string") {
68
+ throw new RenderError("E_INPUT", "html takes text, not bytes");
69
+ }
70
+ return source;
71
+ }
72
+ /** The browser path of the settings. A missing path rejects with E_STAGE_MISSING. */
73
+ export function browserPathOf(browser) {
74
+ if (browser === undefined || browser === "") {
75
+ throw new RenderError("E_STAGE_MISSING", "the browser stage needs SCIENG_BROWSER or the browser configuration key");
76
+ }
77
+ return browser;
78
+ }
79
+ /** Writes each control character, and U+2028 and U+2029, as a \uXXXX escape. */
80
+ function escapeControls(text) {
81
+ return text.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g, (ch) => `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`);
82
+ }
83
+ /**
84
+ * One warning for each request that the page made and the client refused, up to MAX_BLOCKED_WARNINGS. A URL is cut
85
+ * to MAX_WARNING_URL_CHARS and its control characters are escaped. One last warning counts the requests over the cap.
86
+ */
87
+ export function blockedWarnings(blocked) {
88
+ const warnings = blocked.slice(0, MAX_BLOCKED_WARNINGS).map((url) => {
89
+ const cut = url.length > MAX_WARNING_URL_CHARS ? `${url.slice(0, MAX_WARNING_URL_CHARS)}...` : url;
90
+ return `the page requested ${escapeControls(cut)}; the browser stage refused the request`;
91
+ });
92
+ if (blocked.length > MAX_BLOCKED_WARNINGS) {
93
+ warnings.push(`the browser stage refused ${blocked.length - MAX_BLOCKED_WARNINGS} more requests`);
94
+ }
95
+ return warnings;
96
+ }
97
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/browser/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /** Writes a value as a JavaScript literal that cannot end a script element or break a line. */
2
+ export declare function scriptJson(text: string): string;
3
+ /** A page that shows one SVG document. The SVG text comes from the engine, not from the caller. */
4
+ export declare function svgPageHtml(svg: string): string;
5
+ /**
6
+ * A page that loads the pinned Mermaid build and renders one source. The result is stored in window.__sciengDone:
7
+ * `{ok: true, svg}` after the SVG is shown, `{ok: false, message}` when Mermaid rejects the source, or
8
+ * `{ok: false, internal: true, message}` when the pinned build did not load.
9
+ */
10
+ export declare function mermaidPageHtml(source: string, cdnUrl: string): string;
@@ -0,0 +1,33 @@
1
+ const PAGE_STYLE = "html,body{margin:0;background:#fff}";
2
+ /** Writes a value as a JavaScript literal that cannot end a script element or break a line. */
3
+ export function scriptJson(text) {
4
+ return JSON.stringify(text).replace(/[<>&\u2028\u2029]/g, (ch) => "\\u" + ch.charCodeAt(0).toString(16).padStart(4, "0"));
5
+ }
6
+ /** A page that shows one SVG document. The SVG text comes from the engine, not from the caller. */
7
+ export function svgPageHtml(svg) {
8
+ return `<!DOCTYPE html><html><head><meta charset="utf-8"><style>${PAGE_STYLE}</style></head><body><div id="sciengjs-diagram">${svg}</div></body></html>`;
9
+ }
10
+ /**
11
+ * A page that loads the pinned Mermaid build and renders one source. The result is stored in window.__sciengDone:
12
+ * `{ok: true, svg}` after the SVG is shown, `{ok: false, message}` when Mermaid rejects the source, or
13
+ * `{ok: false, internal: true, message}` when the pinned build did not load.
14
+ */
15
+ export function mermaidPageHtml(source, cdnUrl) {
16
+ const render = 'if (typeof mermaid === "undefined") { window.__sciengDone = { ok: false, internal: true, message: "the pinned Mermaid build did not load" }; return; } ' +
17
+ 'try { mermaid.initialize({ startOnLoad: false, securityLevel: "strict" }); ' +
18
+ `const { svg } = await mermaid.render("sciengjs-render", ${scriptJson(source)}); ` +
19
+ 'const host = document.getElementById("sciengjs-diagram"); host.innerHTML = svg; ' +
20
+ // The diagram gets the explicit size of its viewBox, so that the svg and the screenshot do not follow the page width.
21
+ 'const el = host.querySelector("svg"); const vb = el && el.viewBox && el.viewBox.baseVal; ' +
22
+ "if (vb && vb.width > 0 && vb.height > 0) { " +
23
+ 'el.setAttribute("width", String(Math.ceil(vb.width))); el.setAttribute("height", String(Math.ceil(vb.height))); ' +
24
+ 'el.style.removeProperty("max-width"); } ' +
25
+ "const out = el ? new XMLSerializer().serializeToString(el) : svg; " +
26
+ "window.__sciengDone = { ok: true, svg: out }; " +
27
+ "} catch (err) { window.__sciengDone = { ok: false, message: String((err && err.message) || err) }; }";
28
+ return (`<!DOCTYPE html><html><head><meta charset="utf-8"><style>${PAGE_STYLE}</style></head><body>` +
29
+ '<div id="sciengjs-diagram"></div>' +
30
+ `<script src="${cdnUrl}"></script>` +
31
+ `<script>(async () => { ${render} })();</script></body></html>`);
32
+ }
33
+ //# sourceMappingURL=page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/browser/page.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAAG,qCAAqC,CAAC;AAEzD,+FAA+F;AAC/F,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CACjC,oBAAoB,EACpB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAC/D,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,2DAA2D,UAAU,mDAAmD,GAAG,sBAAsB,CAAC;AAC3J,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,MAAc;IAC5D,MAAM,MAAM,GACV,yJAAyJ;QACzJ,6EAA6E;QAC7E,2DAA2D,UAAU,CAAC,MAAM,CAAC,KAAK;QAClF,kFAAkF;QAClF,sHAAsH;QACtH,2FAA2F;QAC3F,6CAA6C;QAC7C,kHAAkH;QAClH,0CAA0C;QAC1C,oEAAoE;QACpE,gDAAgD;QAChD,sGAAsG,CAAC;IACzG,OAAO,CACL,2DAA2D,UAAU,uBAAuB;QAC5F,mCAAmC;QACnC,gBAAgB,MAAM,aAAa;QACnC,0BAA0B,MAAM,+BAA+B,CAChE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ /** The pinned Mermaid version. It equals the exact devDependency of the repository. */
2
+ export declare const MERMAID_VERSION = "11.17.2";
3
+ /** The SHA-256 of the pinned Mermaid build. The client refuses a local copy with other bytes. */
4
+ export declare const MERMAID_SHA256 = "581ed7d74bd9048d0e3a91363927d72ef22942d7722546b27f7cc29e35390eb8";
5
+ /** The file of the pinned Mermaid build inside the assets folder. The build copies it there. */
6
+ export declare const MERMAID_FILE = "mermaid.min.js";
7
+ /** The address that a page names for the pinned Mermaid build. The client answers it from the assets folder. */
8
+ export declare const MERMAID_CDN_URL = "https://cdn.jsdelivr.net/npm/mermaid@11.17.2/dist/mermaid.min.js";
9
+ /** One pinned build that a page may name. The client fulfils its exact URL from the local file. */
10
+ export interface PinnedAsset {
11
+ url: string;
12
+ file: string;
13
+ mime: string;
14
+ }
15
+ /** The pinned builds of the engine. Each entry names the URL of the CDN and the local file. */
16
+ export declare const PINNED_ASSETS: readonly PinnedAsset[];
@@ -0,0 +1,13 @@
1
+ /** The pinned Mermaid version. It equals the exact devDependency of the repository. */
2
+ export const MERMAID_VERSION = "11.17.2";
3
+ /** The SHA-256 of the pinned Mermaid build. The client refuses a local copy with other bytes. */
4
+ export const MERMAID_SHA256 = "581ed7d74bd9048d0e3a91363927d72ef22942d7722546b27f7cc29e35390eb8";
5
+ /** The file of the pinned Mermaid build inside the assets folder. The build copies it there. */
6
+ export const MERMAID_FILE = "mermaid.min.js";
7
+ /** The address that a page names for the pinned Mermaid build. The client answers it from the assets folder. */
8
+ export const MERMAID_CDN_URL = `https://cdn.jsdelivr.net/npm/mermaid@${MERMAID_VERSION}/dist/mermaid.min.js`;
9
+ /** The pinned builds of the engine. Each entry names the URL of the CDN and the local file. */
10
+ export const PINNED_ASSETS = [
11
+ { url: MERMAID_CDN_URL, file: MERMAID_FILE, mime: "application/javascript" },
12
+ ];
13
+ //# sourceMappingURL=pinned.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned.js","sourceRoot":"","sources":["../../src/browser/pinned.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC;AACzC,iGAAiG;AACjG,MAAM,CAAC,MAAM,cAAc,GAAG,kEAAkE,CAAC;AACjG,gGAAgG;AAChG,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAC7C,gHAAgH;AAChH,MAAM,CAAC,MAAM,eAAe,GAAG,wCAAwC,eAAe,sBAAsB,CAAC;AAS7G,+FAA+F;AAC/F,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,EAAE,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,wBAAwB,EAAE;CAC7E,CAAC"}
@@ -0,0 +1,9 @@
1
+ /** The prefix of every profile folder that a render creates. A test looks for it to find leaks. */
2
+ export declare const PROFILE_PREFIX = "sciengjs-browser-";
3
+ /** Creates a new empty profile folder in the temporary folder of the system. */
4
+ export declare function makeProfile(): string;
5
+ /**
6
+ * Removes the profile. A held file is retried until the deadline, a Date.now() time. Any other error, or a deadline with the
7
+ * folder still held, rejects with E_INTERNAL, so that a leak is never reported as clean.
8
+ */
9
+ export declare function removeProfile(profile: string, deadline: number): Promise<void>;
@@ -0,0 +1,33 @@
1
+ import { mkdtempSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { RenderError } from "../errors.js";
5
+ /** The prefix of every profile folder that a render creates. A test looks for it to find leaks. */
6
+ export const PROFILE_PREFIX = "sciengjs-browser-";
7
+ /** The codes that Windows gives while the browser still holds a file of the profile. */
8
+ const HOLD_CODES = new Set(["EBUSY", "EPERM", "ENOTEMPTY"]);
9
+ const RETRY_MS = 250;
10
+ /** Creates a new empty profile folder in the temporary folder of the system. */
11
+ export function makeProfile() {
12
+ return mkdtempSync(join(tmpdir(), PROFILE_PREFIX));
13
+ }
14
+ /**
15
+ * Removes the profile. A held file is retried until the deadline, a Date.now() time. Any other error, or a deadline with the
16
+ * folder still held, rejects with E_INTERNAL, so that a leak is never reported as clean.
17
+ */
18
+ export async function removeProfile(profile, deadline) {
19
+ for (;;) {
20
+ try {
21
+ rmSync(profile, { recursive: true, force: true });
22
+ return;
23
+ }
24
+ catch (err) {
25
+ const code = err.code;
26
+ if (code === undefined || !HOLD_CODES.has(code) || Date.now() >= deadline) {
27
+ throw new RenderError("E_INTERNAL", `cannot remove the browser profile ${profile}: ${err.message}`);
28
+ }
29
+ await new Promise((resolve) => setTimeout(resolve, RETRY_MS));
30
+ }
31
+ }
32
+ }
33
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/browser/profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,mGAAmG;AACnG,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAElD,wFAAwF;AACxF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;AAC5D,MAAM,QAAQ,GAAG,GAAG,CAAC;AAErB,gFAAgF;AAChF,MAAM,UAAU,WAAW;IACzB,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,QAAgB;IACnE,SAAS,CAAC;QACR,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,OAAO;QACT,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;YACjD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC1E,MAAM,IAAI,WAAW,CAAC,YAAY,EAAE,qCAAqC,OAAO,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YACjH,CAAC;YACD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ /** A proxy that refuses every request and records the host of each attempt. */
2
+ export interface RefusingProxy {
3
+ /** The loopback port of the proxy. */
4
+ port: number;
5
+ /** The host name of each attempt, in order. */
6
+ attempts(): string[];
7
+ /** Stops the proxy. Resolves once no connection is open. */
8
+ close(): Promise<void>;
9
+ }
10
+ /**
11
+ * Starts a proxy on 127.0.0.1 with an ephemeral port. It answers 403 to each request and to each CONNECT,
12
+ * and forwards nothing. The browser sends its connection attempts here, so the route off the host is closed.
13
+ */
14
+ export declare function startRefusingProxy(): Promise<RefusingProxy>;