@sanoma-ai/workflows 0.11.17 → 0.11.18

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 (94) hide show
  1. package/README.md +13 -9
  2. package/dist/call.d.ts +35 -4
  3. package/dist/call.js +128 -40
  4. package/dist/call.js.map +1 -1
  5. package/dist/client.d.ts +17 -8
  6. package/dist/client.js +90 -51
  7. package/dist/client.js.map +1 -1
  8. package/dist/collection.d.ts +25 -7
  9. package/dist/collection.js +236 -91
  10. package/dist/collection.js.map +1 -1
  11. package/dist/config.d.ts +8 -5
  12. package/dist/config.js +10 -10
  13. package/dist/config.js.map +1 -1
  14. package/dist/db/company.d.ts +20 -0
  15. package/dist/db/company.js +9 -1
  16. package/dist/db/company.js.map +1 -1
  17. package/dist/describe.js +1 -1
  18. package/dist/describe.js.map +1 -1
  19. package/dist/description.js +1 -1
  20. package/dist/description.js.map +1 -1
  21. package/dist/errors.d.ts +2 -1
  22. package/dist/errors.js +3 -2
  23. package/dist/errors.js.map +1 -1
  24. package/dist/grid.js +3 -2
  25. package/dist/grid.js.map +1 -1
  26. package/dist/host-derive.d.ts +13 -8
  27. package/dist/host-derive.js +26 -13
  28. package/dist/host-derive.js.map +1 -1
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/ledger.d.ts +7 -0
  33. package/dist/ledger.js +32 -2
  34. package/dist/ledger.js.map +1 -1
  35. package/dist/local-sandbox.d.ts +8 -1
  36. package/dist/local-sandbox.js +3 -2
  37. package/dist/local-sandbox.js.map +1 -1
  38. package/dist/op.d.ts +3 -2
  39. package/dist/op.js.map +1 -1
  40. package/dist/resources.d.ts +1 -1
  41. package/dist/resources.js +9 -6
  42. package/dist/resources.js.map +1 -1
  43. package/dist/runner-box.d.ts +23 -0
  44. package/dist/runner-box.js +181 -0
  45. package/dist/runner-box.js.map +1 -0
  46. package/dist/runner-protocol.d.ts +73 -0
  47. package/dist/runner-protocol.js +34 -0
  48. package/dist/runner-protocol.js.map +1 -0
  49. package/dist/sandbox-contract.d.ts +14 -5
  50. package/dist/sandbox-contract.js.map +1 -1
  51. package/dist/sandbox-runner.cjs +7 -0
  52. package/dist/scenario.js +16 -7
  53. package/dist/scenario.js.map +1 -1
  54. package/dist/schema.js +6 -3
  55. package/dist/schema.js.map +1 -1
  56. package/dist/secret.d.ts +2 -1
  57. package/dist/secret.js +3 -2
  58. package/dist/secret.js.map +1 -1
  59. package/dist/shared.d.ts +39 -5
  60. package/dist/shared.js +13 -1
  61. package/dist/shared.js.map +1 -1
  62. package/dist/sites.js +10 -8
  63. package/dist/sites.js.map +1 -1
  64. package/dist/source.d.ts +21 -0
  65. package/dist/source.js.map +1 -1
  66. package/drizzle/company/0003_ledger_target.sql +2 -0
  67. package/drizzle/company/meta/0003_snapshot.json +845 -0
  68. package/drizzle/company/meta/_journal.json +7 -0
  69. package/package.json +5 -2
  70. package/src/call.ts +181 -60
  71. package/src/client.ts +118 -67
  72. package/src/collection.ts +265 -97
  73. package/src/config.ts +20 -20
  74. package/src/db/company.ts +9 -1
  75. package/src/describe.ts +1 -1
  76. package/src/description.ts +1 -1
  77. package/src/errors.ts +3 -2
  78. package/src/grid.ts +3 -1
  79. package/src/host-derive.ts +38 -18
  80. package/src/index.ts +2 -0
  81. package/src/ledger.ts +42 -2
  82. package/src/local-sandbox.ts +3 -2
  83. package/src/op.ts +3 -2
  84. package/src/resources.ts +8 -6
  85. package/src/runner-box.ts +218 -0
  86. package/src/runner-protocol.ts +61 -0
  87. package/src/sandbox-contract.ts +11 -4
  88. package/src/sandbox-runner.ts +187 -0
  89. package/src/scenario.ts +16 -6
  90. package/src/schema.ts +14 -3
  91. package/src/secret.ts +6 -2
  92. package/src/shared.ts +40 -4
  93. package/src/sites.ts +11 -7
  94. package/src/source.ts +14 -0
@@ -0,0 +1,23 @@
1
+ import { type RunnerHealth } from "./runner-protocol.ts";
2
+ import type { Box } from "./sandbox-contract.ts";
3
+ /**
4
+ * The runner as one file (`dist/sandbox-runner.cjs`, its dependencies bundled in), which a
5
+ * backend writes into a box and starts with the box's `node` (22 or later).
6
+ */
7
+ export declare function runnerScript(): Promise<Uint8Array>;
8
+ /**
9
+ * What the runner at `url` (asked with `headers`) answers at `RUNNER_HEALTH`, or undefined when nothing
10
+ * answers as a runner: a backend starts one then, and replaces one of another `protocol`.
11
+ */
12
+ export declare const runnerHealth: (url: string, headers?: Record<string, string>) => Promise<RunnerHealth | undefined>;
13
+ /**
14
+ * The box `id` whose runner is at `url` (`http(s)://`, the WebSocket's upgrade sent with
15
+ * `headers`): its commands, files and `stop` (which kills every command in it and closes the
16
+ * connection). Connects at the first call, and again at the next call after a drop or a `stop`.
17
+ * How its ports are reached is the vendor's, so the backend adds `expose`.
18
+ */
19
+ export declare function runnerBox({ url, headers, id, }: {
20
+ url: string;
21
+ headers?: Record<string, string>;
22
+ id: string;
23
+ }): Omit<Box, "expose">;
@@ -0,0 +1,181 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { fileURLToPath } from "node:url";
3
+ import { FILE, frame, RUNNER_HEALTH, STDERR, STDIN, unframe, } from "./runner-protocol.js";
4
+ // A box whose commands and files go through the runner (`sandbox-runner.ts`), a small server of
5
+ // ours a backend starts inside a remote box, over one WebSocket: so every vendor's backend is
6
+ // "open the box, start the runner, talk to it", whatever the vendor's own exec can or cannot
7
+ // stream. The protocol is in `runner-protocol.ts`. One connection carries many processes; a
8
+ // dropped one ends them here (exit 255) but kills nothing in the box.
9
+ /**
10
+ * The runner as one file (`dist/sandbox-runner.cjs`, its dependencies bundled in), which a
11
+ * backend writes into a box and starts with the box's `node` (22 or later).
12
+ */
13
+ export async function runnerScript() {
14
+ // `../dist/` from `src/` (the tests) and from `dist/` alike.
15
+ const at = new URL("../dist/sandbox-runner.cjs", import.meta.url);
16
+ return readFile(at).catch(() => {
17
+ throw new Error(`${fileURLToPath(at)} is missing: build @sanoma-ai/workflows`);
18
+ });
19
+ }
20
+ /**
21
+ * What the runner at `url` (asked with `headers`) answers at `RUNNER_HEALTH`, or undefined when nothing
22
+ * answers as a runner: a backend starts one then, and replaces one of another `protocol`.
23
+ */
24
+ export const runnerHealth = (url, headers) => fetch(`${url}${RUNNER_HEALTH}`, { headers, signal: AbortSignal.timeout(5_000) })
25
+ .then(async (res) => {
26
+ const health = res.ok ? (await res.json()) : null;
27
+ return typeof health?.protocol === "number" && typeof health.pid === "number"
28
+ ? { protocol: health.protocol, pid: health.pid }
29
+ : undefined;
30
+ })
31
+ .catch(() => undefined);
32
+ const encoder = new TextEncoder();
33
+ /** Drops a write or close the reader no longer wants (it cancelled). */
34
+ const ignore = () => { };
35
+ /** How long the runner's WebSocket may take to open, in ms. */
36
+ const OPEN_MS = 30_000;
37
+ /**
38
+ * The box `id` whose runner is at `url` (`http(s)://`, the WebSocket's upgrade sent with
39
+ * `headers`): its commands, files and `stop` (which kills every command in it and closes the
40
+ * connection). Connects at the first call, and again at the next call after a drop or a `stop`.
41
+ * How its ports are reached is the vendor's, so the backend adds `expose`.
42
+ */
43
+ export function runnerBox({ url, headers, id, }) {
44
+ const where = `the runner at ${new URL(url).host}`;
45
+ let current;
46
+ let last = 0;
47
+ const connect = () => (current ??= open());
48
+ function open() {
49
+ const opening = new Promise((resolve, reject) => {
50
+ // Node's WebSocket (undici) takes `headers` beside the standard's protocols.
51
+ const ws = new WebSocket(url.replace(/^http/, "ws"), { headers });
52
+ ws.binaryType = "arraybuffer";
53
+ const connection = { ws, waiting: new Map() };
54
+ const late = setTimeout(() => ws.close(), OPEN_MS);
55
+ ws.addEventListener("open", () => {
56
+ clearTimeout(late);
57
+ resolve(connection);
58
+ });
59
+ ws.addEventListener("message", ({ data }) => {
60
+ try {
61
+ if (typeof data !== "string") {
62
+ const { id: of, stream, bytes } = unframe(new Uint8Array(data));
63
+ return connection.waiting.get(of)?.bytes(stream, bytes);
64
+ }
65
+ const answer = JSON.parse(data);
66
+ if (answer.id !== undefined)
67
+ connection.waiting.get(answer.id)?.answer(answer);
68
+ }
69
+ catch {
70
+ // A frame that is not the protocol's (another runner's) is dropped.
71
+ }
72
+ });
73
+ ws.addEventListener("close", ({ code, reason }) => {
74
+ clearTimeout(late);
75
+ if (current === opening)
76
+ current = undefined;
77
+ reject(new Error(`${where} closed the connection (${reason || code})`));
78
+ for (const waiter of connection.waiting.values())
79
+ waiter.lost();
80
+ connection.waiting.clear();
81
+ });
82
+ });
83
+ return opening;
84
+ }
85
+ /** Sends `request` (and `bytes` after it): resolves with the file it answers, null for none, or nothing for `ok`. */
86
+ async function ask(request, bytes) {
87
+ const { ws, waiting } = await connect();
88
+ const n = ++last;
89
+ return new Promise((resolve, reject) => {
90
+ const settle = (done) => {
91
+ waiting.delete(n);
92
+ done();
93
+ };
94
+ waiting.set(n, {
95
+ bytes: (_, file) => settle(() => resolve(file)),
96
+ answer: (answer) => settle(() => answer.op === "error"
97
+ ? reject(new Error(`${where}: ${answer.message}`))
98
+ : resolve(answer.op === "absent" ? null : undefined)),
99
+ lost: () => reject(new Error(`${where} closed the connection`)),
100
+ });
101
+ ws.send(JSON.stringify({ ...request, id: n }));
102
+ if (bytes)
103
+ ws.send(frame(n, FILE, bytes));
104
+ });
105
+ }
106
+ return {
107
+ id,
108
+ async run(command, { cwd, env, stdin = false, signal } = {}) {
109
+ const { ws, waiting } = await connect();
110
+ const n = ++last;
111
+ const stdout = new TransformStream();
112
+ const stderr = new TransformStream();
113
+ const out = stdout.writable.getWriter();
114
+ const err = stderr.writable.getWriter();
115
+ const exited = new Promise((done) => {
116
+ const end = (exitCode) => {
117
+ waiting.delete(n);
118
+ out.close().catch(ignore);
119
+ err.close().catch(ignore);
120
+ done({ exitCode });
121
+ };
122
+ waiting.set(n, {
123
+ bytes: (stream, bytes) => void (stream === STDERR ? err : out).write(bytes).catch(ignore),
124
+ answer(answer) {
125
+ if (answer.op === "exit")
126
+ return end(answer.code);
127
+ if (answer.op !== "error")
128
+ return;
129
+ err.write(encoder.encode(`${where}: ${answer.message}\n`)).catch(ignore);
130
+ end(127);
131
+ },
132
+ lost: () => end(255),
133
+ });
134
+ });
135
+ ws.send(JSON.stringify({ op: "run", id: n, command, cwd, env, stdin }));
136
+ const kill = (sig = "SIGKILL") => {
137
+ if (waiting.has(n))
138
+ ws.send(JSON.stringify({ op: "kill", id: n, signal: sig }));
139
+ };
140
+ const onAbort = () => kill();
141
+ if (signal?.aborted)
142
+ onAbort();
143
+ signal?.addEventListener("abort", onAbort, { once: true });
144
+ void exited.then(() => signal?.removeEventListener("abort", onAbort));
145
+ const endInput = () => void ws.send(JSON.stringify({ op: "stdin-end", id: n }));
146
+ return {
147
+ stdin: new WritableStream({
148
+ write(bytes) {
149
+ if (!stdin)
150
+ throw new Error("its stdin is closed: run it with stdin: true");
151
+ ws.send(frame(n, STDIN, bytes));
152
+ },
153
+ close: endInput,
154
+ abort: endInput,
155
+ }),
156
+ stdout: stdout.readable,
157
+ stderr: stderr.readable,
158
+ wait: () => exited,
159
+ kill,
160
+ };
161
+ },
162
+ read: async (path) => (await ask({ op: "read", path })) ?? null,
163
+ async write(path, bytes, { mode } = {}) {
164
+ await ask({ op: "write", path, mode }, bytes);
165
+ },
166
+ async stop() {
167
+ // This connection, not one a call opens meanwhile after a drop.
168
+ const closing = connect();
169
+ try {
170
+ await ask({ op: "stop" });
171
+ }
172
+ finally {
173
+ // The next call opens a new connection, not this closing one.
174
+ if (current === closing)
175
+ current = undefined;
176
+ (await closing.catch(() => undefined))?.ws.close();
177
+ }
178
+ },
179
+ };
180
+ }
181
+ //# sourceMappingURL=runner-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-box.js","sourceRoot":"","sources":["../src/runner-box.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /** The port the runner listens on in a box. */
2
+ export declare const RUNNER_PORT = 7700;
3
+ /**
4
+ * Where the runner answers its health: not `/health`, which Agent37's edge answers itself on
5
+ * every port, so that path never reaches what listens there.
6
+ */
7
+ export declare const RUNNER_HEALTH = "/runner/health";
8
+ /**
9
+ * The protocol's version, which the runner's health answers: a backend replaces a runner
10
+ * that answers another, one an earlier release started in a box that slept.
11
+ */
12
+ export declare const RUNNER_PROTOCOL = 2;
13
+ /** What the runner's health (`RUNNER_HEALTH`) answers: its protocol, and its pid, which a backend replacing it ends. */
14
+ export interface RunnerHealth {
15
+ protocol: number;
16
+ pid: number;
17
+ }
18
+ /** What a binary frame's bytes are: a process's stdin, stdout or stderr, or a file read or written. */
19
+ export declare const STDIN = 0;
20
+ export declare const STDOUT = 1;
21
+ export declare const STDERR = 2;
22
+ export declare const FILE = 3;
23
+ /** What the client says, as text. A `write`'s bytes follow it as the frame `(id, FILE)`. */
24
+ export type RunnerRequest = {
25
+ op: "run";
26
+ id: number;
27
+ command: string;
28
+ cwd?: string;
29
+ env?: Record<string, string>;
30
+ stdin: boolean;
31
+ } | {
32
+ op: "stdin-end";
33
+ id: number;
34
+ } | {
35
+ op: "kill";
36
+ id: number;
37
+ signal: NodeJS.Signals;
38
+ } | {
39
+ op: "read";
40
+ id: number;
41
+ path: string;
42
+ } | {
43
+ op: "write";
44
+ id: number;
45
+ path: string;
46
+ mode?: number;
47
+ } | {
48
+ op: "stop";
49
+ id: number;
50
+ };
51
+ /** What the runner answers, as text. A `read` that finds a file answers the frame `(id, FILE)`. */
52
+ export type RunnerAnswer = {
53
+ op: "exit";
54
+ id: number;
55
+ code: number;
56
+ } | {
57
+ op: "absent";
58
+ id: number;
59
+ } | {
60
+ op: "ok";
61
+ id: number;
62
+ } | {
63
+ op: "error";
64
+ id?: number;
65
+ message: string;
66
+ };
67
+ /** A binary frame: `id` (4 bytes), `stream` (1 byte), then `bytes`. */
68
+ export declare function frame(id: number, stream: number, bytes: Uint8Array): Uint8Array<ArrayBuffer>;
69
+ export declare const unframe: (framed: Uint8Array) => {
70
+ id: number;
71
+ stream: number;
72
+ bytes: Uint8Array<ArrayBufferLike>;
73
+ };
@@ -0,0 +1,34 @@
1
+ // The runner's protocol, over one WebSocket per box, shared by the runner (`sandbox-runner.ts`)
2
+ // and its client (`runner-box.ts`): text frames for control, as JSON, each carrying the `id` of
3
+ // the process or the request it is about; binary frames for bytes, `frame(id, stream, bytes)`.
4
+ /** The port the runner listens on in a box. */
5
+ export const RUNNER_PORT = 7700;
6
+ /**
7
+ * Where the runner answers its health: not `/health`, which Agent37's edge answers itself on
8
+ * every port, so that path never reaches what listens there.
9
+ */
10
+ export const RUNNER_HEALTH = "/runner/health";
11
+ /**
12
+ * The protocol's version, which the runner's health answers: a backend replaces a runner
13
+ * that answers another, one an earlier release started in a box that slept.
14
+ */
15
+ export const RUNNER_PROTOCOL = 2;
16
+ /** What a binary frame's bytes are: a process's stdin, stdout or stderr, or a file read or written. */
17
+ export const STDIN = 0;
18
+ export const STDOUT = 1;
19
+ export const STDERR = 2;
20
+ export const FILE = 3;
21
+ /** A binary frame: `id` (4 bytes), `stream` (1 byte), then `bytes`. */
22
+ export function frame(id, stream, bytes) {
23
+ const framed = new Uint8Array(5 + bytes.length);
24
+ new DataView(framed.buffer).setUint32(0, id);
25
+ framed[4] = stream;
26
+ framed.set(bytes, 5);
27
+ return framed;
28
+ }
29
+ export const unframe = (framed) => ({
30
+ id: new DataView(framed.buffer, framed.byteOffset, framed.byteLength).getUint32(0),
31
+ stream: framed[4],
32
+ bytes: framed.subarray(5),
33
+ });
34
+ //# sourceMappingURL=runner-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-protocol.js","sourceRoot":"","sources":["../src/runner-protocol.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,gGAAgG;AAChG,+FAA+F;AAE/F,+CAA+C;AAC/C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC;AAEhC;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAQjC,uGAAuG;AACvG,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC;AACvB,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC;AACxB,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC;AACxB,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;AAkBtB,uEAAuE;AACvE,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAc,EAAE,KAAiB;IACjE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;IACnB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAkB,EAAE,EAAE,CAAC,CAAC;IAC9C,EAAE,EAAE,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAClF,MAAM,EAAE,MAAM,CAAC,CAAC,CAAE;IAClB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;CAC1B,CAAC,CAAC"}
@@ -76,19 +76,28 @@ export interface Box {
76
76
  * vendor keeps its state, so no snapshot handle crosses the contract.
77
77
  */
78
78
  export interface SandboxBackend {
79
- /** The box `name`, made from `image` with `size` vCPUs when there is none, woken or started when stopped. */
79
+ /**
80
+ * The box `name`, made from `image` with `size` vCPUs when there is none (left out, the backend's
81
+ * own), woken or started when stopped.
82
+ */
80
83
  open(opts: {
81
84
  name: string;
82
- image: string;
83
- size: number;
85
+ image?: string;
86
+ size?: number;
84
87
  }): Promise<Box>;
85
88
  /** Deletes the box `name` and whatever the vendor kept of it: the next `open` finds it empty. */
86
89
  discard(opts: {
87
90
  name: string;
88
91
  }): Promise<void>;
89
92
  }
90
- /** What the app gives a connector's sandbox half (`ConnectorSetup.sandbox`): the secrets, as a model half reads them. */
91
- export type SandboxContext = Pick<LoginContext, "secrets">;
93
+ /**
94
+ * What the app gives a connector's sandbox half (`ConnectorSetup.sandbox`): the secrets, as a model
95
+ * half reads them, and the declared fields of the resource whose boxes it opens, which hold the
96
+ * vendor's facts (its region, its type of machine) beside the image and size `open` takes.
97
+ */
98
+ export type SandboxContext = Pick<LoginContext, "secrets"> & {
99
+ declared: Record<string, unknown>;
100
+ };
92
101
  /**
93
102
  * Throws what is wrong with a resource type's `sandbox`: a type apply cannot change (not
94
103
  * `writable`), a capability that is not a boolean, an input that names no field, `outputs` that
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox-contract.js","sourceRoot":"","sources":["../src/sandbox-contract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0FpC;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,OAAoB,EACpB,IAAiD;IAEjD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI,CAAC,QAAQ;QAAE,QAAQ,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IAC5F,MAAM,YAAY,GAAiC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;IAC9E,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAU,EAAE,CAAC;QAC1D,IAAI,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,IAAI,wBAAwB,CAAC,CAAC;IAC3G,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,MAAM,CAAU,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAY,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,oBAAoB,IAAI,GAAG,CAAC,CAAC;IAClH,CAAC;IACD,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,UAAU;QAAE,QAAQ,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACpG,IAAI,QAAQ,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,kBAAkB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvF,CAAC"}
1
+ {"version":3,"file":"sandbox-contract.js","sourceRoot":"","sources":["../src/sandbox-contract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiGpC;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,OAAoB,EACpB,IAAiD;IAEjD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI,CAAC,QAAQ;QAAE,QAAQ,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IAC5F,MAAM,YAAY,GAAiC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;IAC9E,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAU,EAAE,CAAC;QAC1D,IAAI,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,IAAI,wBAAwB,CAAC,CAAC;IAC3G,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,MAAM,CAAU,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAY,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,oBAAoB,IAAI,GAAG,CAAC,CAAC;IAClH,CAAC;IACD,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,UAAU;QAAE,QAAQ,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACpG,IAAI,QAAQ,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,kBAAkB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvF,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use strict";var dr=Object.create;var Xe=Object.defineProperty;var hr=Object.getOwnPropertyDescriptor;var pr=Object.getOwnPropertyNames;var _r=Object.getPrototypeOf,mr=Object.prototype.hasOwnProperty;var S=(t,e)=>()=>{try{return e||t((e={exports:{}}).exports,e),e.exports}catch(r){throw e=0,r}};var gr=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of pr(e))!mr.call(t,n)&&n!==r&&Xe(t,n,{get:()=>e[n],enumerable:!(s=hr(e,n))||s.enumerable});return t};var I=(t,e,r)=>(r=t!=null?dr(_r(t)):{},gr(e||!t||!t.__esModule?Xe(r,"default",{value:t,enumerable:!0}):r,t));var k=S((ln,et)=>{"use strict";var Je=["nodebuffer","arraybuffer","fragments"],Qe=typeof Blob<"u";Qe&&Je.push("blob");et.exports={BINARY_TYPES:Je,CLOSE_TIMEOUT:3e4,EMPTY_BUFFER:Buffer.alloc(0),GUID:"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",hasBlob:Qe,kForOnEventAttribute:Symbol("kIsForOnEventAttribute"),kListener:Symbol("kListener"),kStatusCode:Symbol("status-code"),kWebSocket:Symbol("websocket"),NOOP:()=>{}}});var J=S((fn,oe)=>{"use strict";var{EMPTY_BUFFER:yr}=k(),we=Buffer[Symbol.species];function xr(t,e){if(t.length===0)return yr;if(t.length===1)return t[0];let r=Buffer.allocUnsafe(e),s=0;for(let n=0;n<t.length;n++){let i=t[n];r.set(i,s),s+=i.length}return s<e?new we(r.buffer,r.byteOffset,s):r}function tt(t,e,r,s,n){for(let i=0;i<n;i++)r[s+i]=t[i]^e[i&3]}function rt(t,e){for(let r=0;r<t.length;r++)t[r]^=e[r&3]}function Sr(t){return t.length===t.buffer.byteLength?t.buffer:t.buffer.slice(t.byteOffset,t.byteOffset+t.length)}function Oe(t){if(Oe.readOnly=!0,Buffer.isBuffer(t))return t;let e;return t instanceof ArrayBuffer?e=new we(t):ArrayBuffer.isView(t)?e=new we(t.buffer,t.byteOffset,t.byteLength):(e=Buffer.from(t),Oe.readOnly=!1),e}oe.exports={concat:xr,mask:tt,toArrayBuffer:Sr,toBuffer:Oe,unmask:rt};if(!process.env.WS_NO_BUFFER_UTIL)try{let t=require("bufferutil");oe.exports.mask=function(e,r,s,n,i){i<48?tt(e,r,s,n,i):t.mask(e,r,s,n,i)},oe.exports.unmask=function(e,r){e.length<32?rt(e,r):t.unmask(e,r)}}catch{}});var it=S((un,nt)=>{"use strict";var st=Symbol("kDone"),ve=Symbol("kRun"),Re=class{constructor(e){this[st]=()=>{this.pending--,this[ve]()},this.concurrency=e||1/0,this.jobs=[],this.pending=0}add(e){this.jobs.push(e),this[ve]()}[ve](){if(this.pending!==this.concurrency&&this.jobs.length){let e=this.jobs.shift();this.pending++,e(this[st])}}};nt.exports=Re});var V=S((dn,lt)=>{"use strict";var Q=require("zlib"),ot=J(),Er=it(),{kStatusCode:at}=k(),br=Buffer[Symbol.species],wr=Buffer.from([0,0,255,255]),ce=Symbol("permessage-deflate"),N=Symbol("total-length"),j=Symbol("callback"),D=Symbol("buffers"),q=Symbol("error"),ae,Te=class{constructor(e){if(this._options=e||{},this._threshold=this._options.threshold!==void 0?this._options.threshold:1024,this._maxPayload=this._options.maxPayload|0,this._isServer=!!this._options.isServer,this._deflate=null,this._inflate=null,this.params=null,!ae){let r=this._options.concurrencyLimit!==void 0?this._options.concurrencyLimit:10;ae=new Er(r)}}static get extensionName(){return"permessage-deflate"}offer(){let e={};return this._options.serverNoContextTakeover&&(e.server_no_context_takeover=!0),this._options.clientNoContextTakeover&&(e.client_no_context_takeover=!0),this._options.serverMaxWindowBits&&(e.server_max_window_bits=this._options.serverMaxWindowBits),this._options.clientMaxWindowBits?e.client_max_window_bits=this._options.clientMaxWindowBits:this._options.clientMaxWindowBits==null&&(e.client_max_window_bits=!0),e}accept(e){return e=this.normalizeParams(e),this.params=this._isServer?this.acceptAsServer(e):this.acceptAsClient(e),this.params}cleanup(){if(this._inflate&&(this._inflate.close(),this._inflate=null),this._deflate){let e=this._deflate[j];this._deflate.close(),this._deflate=null,e&&e(new Error("The deflate stream was closed while data was being processed"))}}acceptAsServer(e){let r=this._options,s=e.find(n=>!(r.serverNoContextTakeover===!1&&n.server_no_context_takeover||n.server_max_window_bits&&(r.serverMaxWindowBits===!1||typeof r.serverMaxWindowBits=="number"&&r.serverMaxWindowBits>n.server_max_window_bits)||typeof r.clientMaxWindowBits=="number"&&(typeof n.client_max_window_bits=="number"?r.clientMaxWindowBits>n.client_max_window_bits:!n.client_max_window_bits)));if(!s)throw new Error("None of the extension offers can be accepted");return r.serverNoContextTakeover&&(s.server_no_context_takeover=!0),r.clientNoContextTakeover&&(s.client_no_context_takeover=!0),typeof r.serverMaxWindowBits=="number"&&(s.server_max_window_bits=r.serverMaxWindowBits),typeof r.clientMaxWindowBits=="number"?s.client_max_window_bits=r.clientMaxWindowBits:(s.client_max_window_bits===!0||r.clientMaxWindowBits===!1)&&delete s.client_max_window_bits,s}acceptAsClient(e){let r=e[0];if(this._options.clientNoContextTakeover===!1&&r.client_no_context_takeover)throw new Error('Unexpected parameter "client_no_context_takeover"');if(!r.client_max_window_bits)typeof this._options.clientMaxWindowBits=="number"&&(r.client_max_window_bits=this._options.clientMaxWindowBits);else if(this._options.clientMaxWindowBits===!1||typeof this._options.clientMaxWindowBits=="number"&&r.client_max_window_bits>this._options.clientMaxWindowBits)throw new Error('Unexpected or invalid parameter "client_max_window_bits"');return r}normalizeParams(e){return e.forEach(r=>{Object.keys(r).forEach(s=>{let n=r[s];if(n.length>1)throw new Error(`Parameter "${s}" must have only a single value`);if(n=n[0],s==="client_max_window_bits"){if(n!==!0){let i=+n;if(!Number.isInteger(i)||i<8||i>15)throw new TypeError(`Invalid value for parameter "${s}": ${n}`);n=i}else if(!this._isServer)throw new TypeError(`Invalid value for parameter "${s}": ${n}`)}else if(s==="server_max_window_bits"){let i=+n;if(!Number.isInteger(i)||i<8||i>15)throw new TypeError(`Invalid value for parameter "${s}": ${n}`);n=i}else if(s==="client_no_context_takeover"||s==="server_no_context_takeover"){if(n!==!0)throw new TypeError(`Invalid value for parameter "${s}": ${n}`)}else throw new Error(`Unknown parameter "${s}"`);r[s]=n})}),e}decompress(e,r,s){ae.add(n=>{this._decompress(e,r,(i,o)=>{n(),s(i,o)})})}compress(e,r,s){ae.add(n=>{this._compress(e,r,(i,o)=>{n(),s(i,o)})})}_decompress(e,r,s){let n=this._isServer?"client":"server";if(!this._inflate){let i=`${n}_max_window_bits`,o=typeof this.params[i]!="number"?Q.Z_DEFAULT_WINDOWBITS:this.params[i];this._inflate=Q.createInflateRaw({...this._options.zlibInflateOptions,windowBits:o}),this._inflate[ce]=this,this._inflate[N]=0,this._inflate[D]=[],this._inflate.on("error",vr),this._inflate.on("data",ct)}this._inflate[j]=s,this._inflate.write(e),r&&this._inflate.write(wr),this._inflate.flush(()=>{let i=this._inflate[q];if(i){this._inflate.close(),this._inflate=null,s(i);return}let o=ot.concat(this._inflate[D],this._inflate[N]);this._inflate._readableState.endEmitted?(this._inflate.close(),this._inflate=null):(this._inflate[N]=0,this._inflate[D]=[],r&&this.params[`${n}_no_context_takeover`]&&this._inflate.reset()),s(null,o)})}_compress(e,r,s){let n=this._isServer?"server":"client";if(!this._deflate){let i=`${n}_max_window_bits`,o=typeof this.params[i]!="number"?Q.Z_DEFAULT_WINDOWBITS:this.params[i];this._deflate=Q.createDeflateRaw({...this._options.zlibDeflateOptions,windowBits:o}),this._deflate[N]=0,this._deflate[D]=[],this._deflate.on("data",Or)}this._deflate[j]=s,this._deflate.write(e),this._deflate.flush(Q.Z_SYNC_FLUSH,()=>{if(!this._deflate)return;let i=ot.concat(this._deflate[D],this._deflate[N]);r&&(i=new br(i.buffer,i.byteOffset,i.length-4)),this._deflate[j]=null,this._deflate[N]=0,this._deflate[D]=[],r&&this.params[`${n}_no_context_takeover`]&&this._deflate.reset(),s(null,i)})}};lt.exports=Te;function Or(t){this[D].push(t),this[N]+=t.length}function ct(t){if(this[N]+=t.length,this[ce]._maxPayload<1||this[N]<=this[ce]._maxPayload){this[D].push(t);return}this[q]=new RangeError("Max payload size exceeded"),this[q].code="WS_ERR_UNSUPPORTED_MESSAGE_LENGTH",this[q][at]=1009,this.removeListener("data",ct),this.reset()}function vr(t){if(this[ce]._inflate=null,this[q]){this[j](this[q]);return}t[at]=1007,this[j](t)}});var H=S((hn,le)=>{"use strict";var{isUtf8:ft}=require("buffer"),{hasBlob:Rr}=k(),Tr=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0];function kr(t){return t>=1e3&&t<=1014&&t!==1004&&t!==1005&&t!==1006||t>=3e3&&t<=4999}function ke(t){let e=t.length,r=0;for(;r<e;)if((t[r]&128)===0)r++;else if((t[r]&224)===192){if(r+1===e||(t[r+1]&192)!==128||(t[r]&254)===192)return!1;r+=2}else if((t[r]&240)===224){if(r+2>=e||(t[r+1]&192)!==128||(t[r+2]&192)!==128||t[r]===224&&(t[r+1]&224)===128||t[r]===237&&(t[r+1]&224)===160)return!1;r+=3}else if((t[r]&248)===240){if(r+3>=e||(t[r+1]&192)!==128||(t[r+2]&192)!==128||(t[r+3]&192)!==128||t[r]===240&&(t[r+1]&240)===128||t[r]===244&&t[r+1]>143||t[r]>244)return!1;r+=4}else return!1;return!0}function Nr(t){return Rr&&typeof t=="object"&&typeof t.arrayBuffer=="function"&&typeof t.type=="string"&&typeof t.stream=="function"&&(t[Symbol.toStringTag]==="Blob"||t[Symbol.toStringTag]==="File")}le.exports={isBlob:Nr,isValidStatusCode:kr,isValidUTF8:ke,tokenChars:Tr};if(ft)le.exports.isValidUTF8=function(t){return t.length<24?ke(t):ft(t)};else if(!process.env.WS_NO_UTF_8_VALIDATE)try{let t=require("utf-8-validate");le.exports.isValidUTF8=function(e){return e.length<32?ke(e):t(e)}}catch{}});var Ae=S((pn,gt)=>{"use strict";var{Writable:Pr}=require("stream"),ut=V(),{BINARY_TYPES:Cr,EMPTY_BUFFER:dt,kStatusCode:Lr,kWebSocket:Ar}=k(),{concat:Ne,toArrayBuffer:Ir,unmask:Dr}=J(),{isValidStatusCode:Br,isValidUTF8:ht}=H(),fe=Buffer[Symbol.species],w=0,pt=1,_t=2,mt=3,Pe=4,Ce=5,ue=6,Le=class extends Pr{constructor(e={}){super(),this._allowSynchronousEvents=e.allowSynchronousEvents!==void 0?e.allowSynchronousEvents:!0,this._binaryType=e.binaryType||Cr[0],this._extensions=e.extensions||{},this._isServer=!!e.isServer,this._maxBufferedChunks=e.maxBufferedChunks|0,this._maxFragments=e.maxFragments|0,this._maxPayload=e.maxPayload|0,this._skipUTF8Validation=!!e.skipUTF8Validation,this[Ar]=void 0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._numFragments=0,this._fragments=[],this._errored=!1,this._loop=!1,this._state=w}_write(e,r,s){if(this._opcode===8&&this._state==w)return s();if(this._maxBufferedChunks>0&&this._buffers.length>=this._maxBufferedChunks){s(this.createError(RangeError,"Too many buffered chunks",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS"));return}this._bufferedBytes+=e.length,this._buffers.push(e),this.startLoop(s)}consume(e){if(this._bufferedBytes-=e,e===this._buffers[0].length)return this._buffers.shift();if(e<this._buffers[0].length){let s=this._buffers[0];return this._buffers[0]=new fe(s.buffer,s.byteOffset+e,s.length-e),new fe(s.buffer,s.byteOffset,e)}let r=Buffer.allocUnsafe(e);do{let s=this._buffers[0],n=r.length-e;e>=s.length?r.set(this._buffers.shift(),n):(r.set(new Uint8Array(s.buffer,s.byteOffset,e),n),this._buffers[0]=new fe(s.buffer,s.byteOffset+e,s.length-e)),e-=s.length}while(e>0);return r}startLoop(e){this._loop=!0;do switch(this._state){case w:this.getInfo(e);break;case pt:this.getPayloadLength16(e);break;case _t:this.getPayloadLength64(e);break;case mt:this.getMask();break;case Pe:this.getData(e);break;case Ce:case ue:this._loop=!1;return}while(this._loop);this._errored||e()}getInfo(e){if(this._bufferedBytes<2){this._loop=!1;return}let r=this.consume(2);if((r[0]&48)!==0){let n=this.createError(RangeError,"RSV2 and RSV3 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_2_3");e(n);return}let s=(r[0]&64)===64;if(s&&!this._extensions[ut.extensionName]){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(n);return}if(this._fin=(r[0]&128)===128,this._opcode=r[0]&15,this._payloadLength=r[1]&127,this._opcode===0){if(s){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(n);return}if(!this._fragmented){let n=this.createError(RangeError,"invalid opcode 0",!0,1002,"WS_ERR_INVALID_OPCODE");e(n);return}this._opcode=this._fragmented}else if(this._opcode===1||this._opcode===2){if(this._fragmented){let n=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");e(n);return}this._compressed=s}else if(this._opcode>7&&this._opcode<11){if(!this._fin){let n=this.createError(RangeError,"FIN must be set",!0,1002,"WS_ERR_EXPECTED_FIN");e(n);return}if(s){let n=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(n);return}if(this._payloadLength>125||this._opcode===8&&this._payloadLength===1){let n=this.createError(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002,"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH");e(n);return}}else{let n=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");e(n);return}if(!this._fin&&!this._fragmented&&(this._fragmented=this._opcode),this._masked=(r[1]&128)===128,this._isServer){if(!this._masked){let n=this.createError(RangeError,"MASK must be set",!0,1002,"WS_ERR_EXPECTED_MASK");e(n);return}}else if(this._masked){let n=this.createError(RangeError,"MASK must be clear",!0,1002,"WS_ERR_UNEXPECTED_MASK");e(n);return}this._payloadLength===126?this._state=pt:this._payloadLength===127?this._state=_t:this.haveLength(e)}getPayloadLength16(e){if(this._bufferedBytes<2){this._loop=!1;return}this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength(e)}getPayloadLength64(e){if(this._bufferedBytes<8){this._loop=!1;return}let r=this.consume(8),s=r.readUInt32BE(0);if(s>Math.pow(2,21)-1){let n=this.createError(RangeError,"Unsupported WebSocket frame: payload length > 2^53 - 1",!1,1009,"WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH");e(n);return}this._payloadLength=s*Math.pow(2,32)+r.readUInt32BE(4),this.haveLength(e)}haveLength(e){if(this._payloadLength&&this._opcode<8&&(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0)){let r=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");e(r);return}this._masked?this._state=mt:this._state=Pe}getMask(){if(this._bufferedBytes<4){this._loop=!1;return}this._mask=this.consume(4),this._state=Pe}getData(e){let r=dt;if(this._payloadLength){if(this._bufferedBytes<this._payloadLength){this._loop=!1;return}r=this.consume(this._payloadLength),this._masked&&(this._mask[0]|this._mask[1]|this._mask[2]|this._mask[3])!==0&&Dr(r,this._mask)}if(this._opcode>7){this.controlMessage(r,e);return}if(this._maxFragments>0&&++this._numFragments>this._maxFragments){let s=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");e(s);return}if(this._compressed){this._state=Ce,this.decompress(r,e);return}r.length&&(this._messageLength=this._totalPayloadLength,this._fragments.push(r)),this.dataMessage(e)}decompress(e,r){this._extensions[ut.extensionName].decompress(e,this._fin,(n,i)=>{if(n)return r(n);if(i.length){if(this._messageLength+=i.length,this._messageLength>this._maxPayload&&this._maxPayload>0){let o=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");r(o);return}this._fragments.push(i)}this.dataMessage(r),this._state===w&&this.startLoop(r)})}dataMessage(e){if(!this._fin){this._state=w;return}let r=this._messageLength,s=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._numFragments=0,this._fragments=[],this._opcode===2){let n;this._binaryType==="nodebuffer"?n=Ne(s,r):this._binaryType==="arraybuffer"?n=Ir(Ne(s,r)):this._binaryType==="blob"?n=new Blob(s):n=s,this._allowSynchronousEvents?(this.emit("message",n,!0),this._state=w):(this._state=ue,setImmediate(()=>{this.emit("message",n,!0),this._state=w,this.startLoop(e)}))}else{let n=Ne(s,r);if(!this._skipUTF8Validation&&!ht(n)){let i=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");e(i);return}this._state===Ce||this._allowSynchronousEvents?(this.emit("message",n,!1),this._state=w):(this._state=ue,setImmediate(()=>{this.emit("message",n,!1),this._state=w,this.startLoop(e)}))}}controlMessage(e,r){if(this._opcode===8){if(e.length===0)this._loop=!1,this.emit("conclude",1005,dt),this.end();else{let s=e.readUInt16BE(0);if(!Br(s)){let i=this.createError(RangeError,`invalid status code ${s}`,!0,1002,"WS_ERR_INVALID_CLOSE_CODE");r(i);return}let n=new fe(e.buffer,e.byteOffset+2,e.length-2);if(!this._skipUTF8Validation&&!ht(n)){let i=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");r(i);return}this._loop=!1,this.emit("conclude",s,n),this.end()}this._state=w;return}this._allowSynchronousEvents?(this.emit(this._opcode===9?"ping":"pong",e),this._state=w):(this._state=ue,setImmediate(()=>{this.emit(this._opcode===9?"ping":"pong",e),this._state=w,this.startLoop(r)}))}createError(e,r,s,n,i){this._loop=!1,this._errored=!0;let o=new e(s?`Invalid WebSocket frame: ${r}`:r);return Error.captureStackTrace(o,this.createError),o.code=i,o[Lr]=n,o}};gt.exports=Le});var Be=S((mn,St)=>{"use strict";var{Duplex:_n}=require("stream"),{randomFillSync:Ur}=require("crypto"),{types:{isUint8Array:Fr}}=require("util"),yt=V(),{EMPTY_BUFFER:Wr,kWebSocket:Mr,NOOP:$r}=k(),{isBlob:z,isValidStatusCode:Gr}=H(),{mask:xt,toBuffer:F}=J(),O=Symbol("kByteLength"),jr=Buffer.alloc(4),de=8*1024,W,K=de,R=0,qr=1,Vr=2,Ie=class t{constructor(e,r,s){this._extensions=r||{},s&&(this._generateMask=s,this._maskBuffer=Buffer.alloc(4)),this._socket=e,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._queue=[],this._state=R,this.onerror=$r,this[Mr]=void 0}static frame(e,r){let s,n=!1,i=2,o=!1;r.mask&&(s=r.maskBuffer||jr,r.generateMask?r.generateMask(s):(K===de&&(W===void 0&&(W=Buffer.alloc(de)),Ur(W,0,de),K=0),s[0]=W[K++],s[1]=W[K++],s[2]=W[K++],s[3]=W[K++]),o=(s[0]|s[1]|s[2]|s[3])===0,i=6);let l;typeof e=="string"?(!r.mask||o)&&r[O]!==void 0?l=r[O]:(e=Buffer.from(e),l=e.length):(l=e.length,n=r.mask&&r.readOnly&&!o);let f=l;l>=65536?(i+=8,f=127):l>125&&(i+=2,f=126);let c=Buffer.allocUnsafe(n?l+i:i);return c[0]=r.fin?r.opcode|128:r.opcode,r.rsv1&&(c[0]|=64),c[1]=f,f===126?c.writeUInt16BE(l,2):f===127&&(c[2]=c[3]=0,c.writeUIntBE(l,4,6)),r.mask?(c[1]|=128,c[i-4]=s[0],c[i-3]=s[1],c[i-2]=s[2],c[i-1]=s[3],o?[c,e]:n?(xt(e,s,c,i,l),[c]):(xt(e,s,e,0,l),[c,e])):[c,e]}close(e,r,s,n){let i;if(e===void 0)i=Wr;else{if(typeof e!="number"||!Gr(e))throw new TypeError("First argument must be a valid error code number");if(r===void 0||!r.length)i=Buffer.allocUnsafe(2),i.writeUInt16BE(e,0);else{let l=Buffer.byteLength(r);if(l>123)throw new RangeError("The message must not be greater than 123 bytes");if(i=Buffer.allocUnsafe(2+l),i.writeUInt16BE(e,0),typeof r=="string")i.write(r,2);else if(Fr(r))i.set(r,2);else throw new TypeError("Second argument must be a string or a Uint8Array")}}let o={[O]:i.length,fin:!0,generateMask:this._generateMask,mask:s,maskBuffer:this._maskBuffer,opcode:8,readOnly:!1,rsv1:!1};this._state!==R?this.enqueue([this.dispatch,i,!1,o,n]):this.sendFrame(t.frame(i,o),n)}ping(e,r,s){let n,i;if(typeof e=="string"?(n=Buffer.byteLength(e),i=!1):z(e)?(n=e.size,i=!1):(e=F(e),n=e.length,i=F.readOnly),n>125)throw new RangeError("The data size must not be greater than 125 bytes");let o={[O]:n,fin:!0,generateMask:this._generateMask,mask:r,maskBuffer:this._maskBuffer,opcode:9,readOnly:i,rsv1:!1};z(e)?this._state!==R?this.enqueue([this.getBlobData,e,!1,o,s]):this.getBlobData(e,!1,o,s):this._state!==R?this.enqueue([this.dispatch,e,!1,o,s]):this.sendFrame(t.frame(e,o),s)}pong(e,r,s){let n,i;if(typeof e=="string"?(n=Buffer.byteLength(e),i=!1):z(e)?(n=e.size,i=!1):(e=F(e),n=e.length,i=F.readOnly),n>125)throw new RangeError("The data size must not be greater than 125 bytes");let o={[O]:n,fin:!0,generateMask:this._generateMask,mask:r,maskBuffer:this._maskBuffer,opcode:10,readOnly:i,rsv1:!1};z(e)?this._state!==R?this.enqueue([this.getBlobData,e,!1,o,s]):this.getBlobData(e,!1,o,s):this._state!==R?this.enqueue([this.dispatch,e,!1,o,s]):this.sendFrame(t.frame(e,o),s)}send(e,r,s){let n=this._extensions[yt.extensionName],i=r.binary?2:1,o=r.compress,l,f;typeof e=="string"?(l=Buffer.byteLength(e),f=!1):z(e)?(l=e.size,f=!1):(e=F(e),l=e.length,f=F.readOnly),this._firstFragment?(this._firstFragment=!1,o&&n&&n.params[n._isServer?"server_no_context_takeover":"client_no_context_takeover"]&&(o=l>=n._threshold),this._compress=o):(o=!1,i=0),r.fin&&(this._firstFragment=!0);let c={[O]:l,fin:r.fin,generateMask:this._generateMask,mask:r.mask,maskBuffer:this._maskBuffer,opcode:i,readOnly:f,rsv1:o};z(e)?this._state!==R?this.enqueue([this.getBlobData,e,this._compress,c,s]):this.getBlobData(e,this._compress,c,s):this._state!==R?this.enqueue([this.dispatch,e,this._compress,c,s]):this.dispatch(e,this._compress,c,s)}getBlobData(e,r,s,n){this._bufferedBytes+=s[O],this._state=Vr,e.arrayBuffer().then(i=>{if(this._socket.destroyed){let l=new Error("The socket was closed while the blob was being read");process.nextTick(De,this,l,n);return}this._bufferedBytes-=s[O];let o=F(i);r?this.dispatch(o,r,s,n):(this._state=R,this.sendFrame(t.frame(o,s),n),this.dequeue())}).catch(i=>{process.nextTick(Hr,this,i,n)})}dispatch(e,r,s,n){if(!r){this.sendFrame(t.frame(e,s),n);return}let i=this._extensions[yt.extensionName];this._bufferedBytes+=s[O],this._state=qr,i.compress(e,s.fin,(o,l)=>{if(this._socket.destroyed){let f=new Error("The socket was closed while data was being compressed");De(this,f,n);return}this._bufferedBytes-=s[O],this._state=R,s.readOnly=!1,this.sendFrame(t.frame(l,s),n),this.dequeue()})}dequeue(){for(;this._state===R&&this._queue.length;){let e=this._queue.shift();this._bufferedBytes-=e[3][O],Reflect.apply(e[0],this,e.slice(1))}}enqueue(e){this._bufferedBytes+=e[3][O],this._queue.push(e)}sendFrame(e,r){e.length===2?(this._socket.cork(),this._socket.write(e[0]),this._socket.write(e[1],r),this._socket.uncork()):this._socket.write(e[0],r)}};St.exports=Ie;function De(t,e,r){typeof r=="function"&&r(e);for(let s=0;s<t._queue.length;s++){let n=t._queue[s],i=n[n.length-1];typeof i=="function"&&i(e)}}function Hr(t,e,r){De(t,e,r),t.onerror(e)}});var Nt=S((gn,kt)=>{"use strict";var{kForOnEventAttribute:ee,kListener:Ue}=k(),Et=Symbol("kCode"),bt=Symbol("kData"),wt=Symbol("kError"),Ot=Symbol("kMessage"),vt=Symbol("kReason"),Y=Symbol("kTarget"),Rt=Symbol("kType"),Tt=Symbol("kWasClean"),P=class{constructor(e){this[Y]=null,this[Rt]=e}get target(){return this[Y]}get type(){return this[Rt]}};Object.defineProperty(P.prototype,"target",{enumerable:!0});Object.defineProperty(P.prototype,"type",{enumerable:!0});var M=class extends P{constructor(e,r={}){super(e),this[Et]=r.code===void 0?0:r.code,this[vt]=r.reason===void 0?"":r.reason,this[Tt]=r.wasClean===void 0?!1:r.wasClean}get code(){return this[Et]}get reason(){return this[vt]}get wasClean(){return this[Tt]}};Object.defineProperty(M.prototype,"code",{enumerable:!0});Object.defineProperty(M.prototype,"reason",{enumerable:!0});Object.defineProperty(M.prototype,"wasClean",{enumerable:!0});var Z=class extends P{constructor(e,r={}){super(e),this[wt]=r.error===void 0?null:r.error,this[Ot]=r.message===void 0?"":r.message}get error(){return this[wt]}get message(){return this[Ot]}};Object.defineProperty(Z.prototype,"error",{enumerable:!0});Object.defineProperty(Z.prototype,"message",{enumerable:!0});var te=class extends P{constructor(e,r={}){super(e),this[bt]=r.data===void 0?null:r.data}get data(){return this[bt]}};Object.defineProperty(te.prototype,"data",{enumerable:!0});var zr={addEventListener(t,e,r={}){for(let n of this.listeners(t))if(!r[ee]&&n[Ue]===e&&!n[ee])return;let s;if(t==="message")s=function(i,o){let l=new te("message",{data:o?i:i.toString()});l[Y]=this,he(e,this,l)};else if(t==="close")s=function(i,o){let l=new M("close",{code:i,reason:o.toString(),wasClean:this._closeFrameReceived&&this._closeFrameSent});l[Y]=this,he(e,this,l)};else if(t==="error")s=function(i){let o=new Z("error",{error:i,message:i.message});o[Y]=this,he(e,this,o)};else if(t==="open")s=function(){let i=new P("open");i[Y]=this,he(e,this,i)};else return;s[ee]=!!r[ee],s[Ue]=e,r.once?this.once(t,s):this.on(t,s)},removeEventListener(t,e){for(let r of this.listeners(t))if(r[Ue]===e&&!r[ee]){this.removeListener(t,r);break}}};kt.exports={CloseEvent:M,ErrorEvent:Z,Event:P,EventTarget:zr,MessageEvent:te};function he(t,e,r){typeof t=="object"&&t.handleEvent?t.handleEvent.call(t,r):t.call(e,r)}});var pe=S((yn,Pt)=>{"use strict";var{tokenChars:re}=H();function T(t,e,r){t[e]===void 0?t[e]=[r]:t[e].push(r)}function Kr(t){let e=Object.create(null),r=Object.create(null),s=!1,n=!1,i=!1,o,l,f=-1,c=-1,u=-1,a=0;for(;a<t.length;a++)if(c=t.charCodeAt(a),o===void 0)if(u===-1&&re[c]===1)f===-1&&(f=a);else if(a!==0&&(c===32||c===9))u===-1&&f!==-1&&(u=a);else if(c===59||c===44){if(f===-1)throw new SyntaxError(`Unexpected character at index ${a}`);u===-1&&(u=a);let p=t.slice(f,u);c===44?(T(e,p,r),r=Object.create(null)):o=p,f=u=-1}else throw new SyntaxError(`Unexpected character at index ${a}`);else if(l===void 0)if(u===-1&&re[c]===1)f===-1&&(f=a);else if(c===32||c===9)u===-1&&f!==-1&&(u=a);else if(c===59||c===44){if(f===-1)throw new SyntaxError(`Unexpected character at index ${a}`);u===-1&&(u=a),T(r,t.slice(f,u),!0),c===44&&(T(e,o,r),r=Object.create(null),o=void 0),f=u=-1}else if(c===61&&f!==-1&&u===-1)l=t.slice(f,a),f=u=-1;else throw new SyntaxError(`Unexpected character at index ${a}`);else if(n){if(re[c]!==1)throw new SyntaxError(`Unexpected character at index ${a}`);f===-1?f=a:s||(s=!0),n=!1}else if(i)if(re[c]===1)f===-1&&(f=a);else if(c===34&&f!==-1)i=!1,u=a;else if(c===92)n=!0;else throw new SyntaxError(`Unexpected character at index ${a}`);else if(c===34&&t.charCodeAt(a-1)===61)i=!0;else if(u===-1&&re[c]===1)f===-1&&(f=a);else if(f!==-1&&(c===32||c===9))u===-1&&(u=a);else if(c===59||c===44){if(f===-1)throw new SyntaxError(`Unexpected character at index ${a}`);u===-1&&(u=a);let p=t.slice(f,u);s&&(p=p.replace(/\\/g,""),s=!1),T(r,l,p),c===44&&(T(e,o,r),r=Object.create(null),o=void 0),l=void 0,f=u=-1}else throw new SyntaxError(`Unexpected character at index ${a}`);if(f===-1||i||c===32||c===9)throw new SyntaxError("Unexpected end of input");u===-1&&(u=a);let d=t.slice(f,u);return o===void 0?T(e,d,r):(l===void 0?T(r,d,!0):s?T(r,l,d.replace(/\\/g,"")):T(r,l,d),T(e,o,r)),e}function Yr(t){return Object.keys(t).map(e=>{let r=t[e];return Array.isArray(r)||(r=[r]),r.map(s=>[e].concat(Object.keys(s).map(n=>{let i=s[n];return Array.isArray(i)||(i=[i]),i.map(o=>o===!0?n:`${n}=${o}`).join("; ")})).join("; ")).join(", ")}).join(", ")}Pt.exports={format:Yr,parse:Kr}});var ye=S((En,Gt)=>{"use strict";var Zr=require("events"),Xr=require("https"),Jr=require("http"),At=require("net"),Qr=require("tls"),{randomBytes:es,createHash:ts}=require("crypto"),{Duplex:xn,Readable:Sn}=require("stream"),{URL:Fe}=require("url"),B=V(),rs=Ae(),ss=Be(),{isBlob:ns}=H(),{BINARY_TYPES:Ct,CLOSE_TIMEOUT:is,EMPTY_BUFFER:_e,GUID:os,kForOnEventAttribute:We,kListener:as,kStatusCode:cs,kWebSocket:y,NOOP:It}=k(),{EventTarget:{addEventListener:ls,removeEventListener:fs}}=Nt(),{format:us,parse:ds}=pe(),{toBuffer:hs}=J(),Dt=Symbol("kAborted"),Me=[8,13],C=["CONNECTING","OPEN","CLOSING","CLOSED"],ps=/^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/,g=class t extends Zr{constructor(e,r,s){super(),this._binaryType=Ct[0],this._closeCode=1006,this._closeFrameReceived=!1,this._closeFrameSent=!1,this._closeMessage=_e,this._closeTimer=null,this._errorEmitted=!1,this._extensions={},this._paused=!1,this._protocol="",this._readyState=t.CONNECTING,this._receiver=null,this._sender=null,this._socket=null,e!==null?(this._bufferedAmount=0,this._isServer=!1,this._redirects=0,r===void 0?!s||s.protocols===void 0?r=[]:Array.isArray(s.protocols)?r=s.protocols:r=[s.protocols]:Array.isArray(r)||(typeof r=="object"&&r!==null?(s=r,s.protocols===void 0?r=[]:Array.isArray(s.protocols)?r=s.protocols:r=[s.protocols]):r=[r]),Bt(this,e,r,s)):(this._autoPong=s.autoPong,this._closeTimeout=s.closeTimeout,this._isServer=!0)}get binaryType(){return this._binaryType}set binaryType(e){Ct.includes(e)&&(this._binaryType=e,this._receiver&&(this._receiver._binaryType=e))}get bufferedAmount(){return this._socket?this._socket._writableState.length+this._sender._bufferedBytes:this._bufferedAmount}get extensions(){return Object.keys(this._extensions).join()}get isPaused(){return this._paused}get onclose(){return null}get onerror(){return null}get onopen(){return null}get onmessage(){return null}get protocol(){return this._protocol}get readyState(){return this._readyState}get url(){return this._url}setSocket(e,r,s){let n=new rs({allowSynchronousEvents:s.allowSynchronousEvents,binaryType:this.binaryType,extensions:this._extensions,isServer:this._isServer,maxBufferedChunks:s.maxBufferedChunks,maxFragments:s.maxFragments,maxPayload:s.maxPayload,skipUTF8Validation:s.skipUTF8Validation}),i=new ss(e,this._extensions,s.generateMask);this._receiver=n,this._sender=i,this._socket=e,n[y]=this,i[y]=this,e[y]=this,n.on("conclude",gs),n.on("drain",ys),n.on("error",xs),n.on("message",Ss),n.on("ping",Es),n.on("pong",bs),i.onerror=ws,e.setTimeout&&e.setTimeout(0),e.setNoDelay&&e.setNoDelay(),r.length>0&&e.unshift(r),e.on("close",Wt),e.on("data",ge),e.on("end",Mt),e.on("error",$t),this._readyState=t.OPEN,this.emit("open")}emitClose(){if(!this._socket){this._readyState=t.CLOSED,this.emit("close",this._closeCode,this._closeMessage);return}this._extensions[B.extensionName]&&this._extensions[B.extensionName].cleanup(),this._receiver.removeAllListeners(),this._readyState=t.CLOSED,this.emit("close",this._closeCode,this._closeMessage)}close(e,r){if(this.readyState!==t.CLOSED){if(this.readyState===t.CONNECTING){E(this,this._req,"WebSocket was closed before the connection was established");return}if(this.readyState===t.CLOSING){this._closeFrameSent&&(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end();return}this._sender.close(e,r,!this._isServer,s=>{s||(this._closeFrameSent=!0,(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end())}),this._readyState=t.CLOSING,Ft(this)}}pause(){this.readyState===t.CONNECTING||this.readyState===t.CLOSED||(this._paused=!0,this._socket.pause())}ping(e,r,s){if(this.readyState===t.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof e=="function"?(s=e,e=r=void 0):typeof r=="function"&&(s=r,r=void 0),typeof e=="number"&&(e=e.toString()),this.readyState!==t.OPEN){$e(this,e,s);return}r===void 0&&(r=!this._isServer),this._sender.ping(e||_e,r,s)}pong(e,r,s){if(this.readyState===t.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof e=="function"?(s=e,e=r=void 0):typeof r=="function"&&(s=r,r=void 0),typeof e=="number"&&(e=e.toString()),this.readyState!==t.OPEN){$e(this,e,s);return}r===void 0&&(r=!this._isServer),this._sender.pong(e||_e,r,s)}resume(){this.readyState===t.CONNECTING||this.readyState===t.CLOSED||(this._paused=!1,this._receiver._writableState.needDrain||this._socket.resume())}send(e,r,s){if(this.readyState===t.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof r=="function"&&(s=r,r={}),typeof e=="number"&&(e=e.toString()),this.readyState!==t.OPEN){$e(this,e,s);return}let n={binary:typeof e!="string",mask:!this._isServer,compress:!0,fin:!0,...r};this._extensions[B.extensionName]||(n.compress=!1),this._sender.send(e||_e,n,s)}terminate(){if(this.readyState!==t.CLOSED){if(this.readyState===t.CONNECTING){E(this,this._req,"WebSocket was closed before the connection was established");return}this._socket&&(this._readyState=t.CLOSING,this._socket.destroy())}}};Object.defineProperty(g,"CONNECTING",{enumerable:!0,value:C.indexOf("CONNECTING")});Object.defineProperty(g.prototype,"CONNECTING",{enumerable:!0,value:C.indexOf("CONNECTING")});Object.defineProperty(g,"OPEN",{enumerable:!0,value:C.indexOf("OPEN")});Object.defineProperty(g.prototype,"OPEN",{enumerable:!0,value:C.indexOf("OPEN")});Object.defineProperty(g,"CLOSING",{enumerable:!0,value:C.indexOf("CLOSING")});Object.defineProperty(g.prototype,"CLOSING",{enumerable:!0,value:C.indexOf("CLOSING")});Object.defineProperty(g,"CLOSED",{enumerable:!0,value:C.indexOf("CLOSED")});Object.defineProperty(g.prototype,"CLOSED",{enumerable:!0,value:C.indexOf("CLOSED")});["binaryType","bufferedAmount","extensions","isPaused","protocol","readyState","url"].forEach(t=>{Object.defineProperty(g.prototype,t,{enumerable:!0})});["open","error","close","message"].forEach(t=>{Object.defineProperty(g.prototype,`on${t}`,{enumerable:!0,get(){for(let e of this.listeners(t))if(e[We])return e[as];return null},set(e){for(let r of this.listeners(t))if(r[We]){this.removeListener(t,r);break}typeof e=="function"&&this.addEventListener(t,e,{[We]:!0})}})});g.prototype.addEventListener=ls;g.prototype.removeEventListener=fs;Gt.exports=g;function Bt(t,e,r,s){let n={allowSynchronousEvents:!0,autoPong:!0,closeTimeout:is,protocolVersion:Me[1],maxBufferedChunks:262144,maxFragments:16384,maxPayload:104857600,skipUTF8Validation:!1,perMessageDeflate:!0,followRedirects:!1,maxRedirects:10,...s,socketPath:void 0,hostname:void 0,protocol:void 0,protocols:void 0,timeout:void 0,method:"GET",host:void 0,path:void 0,port:void 0};if(t._autoPong=n.autoPong,t._closeTimeout=n.closeTimeout,!Me.includes(n.protocolVersion))throw new RangeError(`Unsupported protocol version: ${n.protocolVersion} (supported versions: ${Me.join(", ")})`);let i;if(e instanceof Fe)i=e;else try{i=new Fe(e)}catch{throw new SyntaxError(`Invalid URL: ${e}`)}i.protocol==="http:"?i.protocol="ws:":i.protocol==="https:"&&(i.protocol="wss:"),t._url=i.href;let o=i.protocol==="wss:",l=i.protocol==="ws+unix:",f;if(i.protocol!=="ws:"&&!o&&!l?f=`The URL's protocol must be one of "ws:", "wss:", "http:", "https:", or "ws+unix:"`:l&&!i.pathname?f="The URL's pathname is empty":i.hash&&(f="The URL contains a fragment identifier"),f){let h=new SyntaxError(f);if(t._redirects===0)throw h;me(t,h);return}let c=o?443:80,u=es(16).toString("base64"),a=o?Xr.request:Jr.request,d=new Set,p;if(n.createConnection=n.createConnection||(o?ms:_s),n.defaultPort=n.defaultPort||c,n.port=i.port||c,n.host=i.hostname.startsWith("[")?i.hostname.slice(1,-1):i.hostname,n.headers={...n.headers,"Sec-WebSocket-Version":n.protocolVersion,"Sec-WebSocket-Key":u,Connection:"Upgrade",Upgrade:"websocket"},n.path=i.pathname+i.search,n.timeout=n.handshakeTimeout,n.perMessageDeflate&&(p=new B({...n.perMessageDeflate,isServer:!1,maxPayload:n.maxPayload}),n.headers["Sec-WebSocket-Extensions"]=us({[B.extensionName]:p.offer()})),r.length){for(let h of r){if(typeof h!="string"||!ps.test(h)||d.has(h))throw new SyntaxError("An invalid or duplicated subprotocol was specified");d.add(h)}n.headers["Sec-WebSocket-Protocol"]=r.join(",")}if(n.origin&&(n.protocolVersion<13?n.headers["Sec-WebSocket-Origin"]=n.origin:n.headers.Origin=n.origin),(i.username||i.password)&&(n.auth=`${i.username}:${i.password}`),l){let h=n.path.split(":");n.socketPath=h[0],n.path=h[1]}let _;if(n.followRedirects){if(t._redirects===0){t._originalIpc=l,t._originalSecure=o,t._originalHostOrSocketPath=l?n.socketPath:i.host;let h=s&&s.headers;if(s={...s,headers:{}},h)for(let[m,b]of Object.entries(h))s.headers[m.toLowerCase()]=b}else if(t.listenerCount("redirect")===0){let h=l?t._originalIpc?n.socketPath===t._originalHostOrSocketPath:!1:t._originalIpc?!1:i.host===t._originalHostOrSocketPath;(!h||t._originalSecure&&!o)&&(delete n.headers.authorization,delete n.headers.cookie,h||delete n.headers.host,n.auth=void 0)}n.auth&&!s.headers.authorization&&(s.headers.authorization="Basic "+Buffer.from(n.auth).toString("base64")),_=t._req=a(n),t._redirects&&t.emit("redirect",t.url,_)}else _=t._req=a(n);n.timeout&&_.on("timeout",()=>{E(t,_,"Opening handshake has timed out")}),_.on("error",h=>{_===null||_[Dt]||(_=t._req=null,me(t,h))}),_.on("response",h=>{let m=h.headers.location,b=h.statusCode;if(m&&n.followRedirects&&b>=300&&b<400){if(++t._redirects>n.maxRedirects){E(t,_,"Maximum redirects exceeded");return}_.abort();let x;try{x=new Fe(m,e)}catch{let A=new SyntaxError(`Invalid URL: ${m}`);me(t,A);return}Bt(t,x,r,s)}else t.emit("unexpected-response",_,h)||E(t,_,`Unexpected server response: ${h.statusCode}`)}),_.on("upgrade",(h,m,b)=>{if(t.emit("upgrade",h),t.readyState!==g.CONNECTING)return;_=t._req=null;let x=h.headers.upgrade;if(x===void 0||x.toLowerCase()!=="websocket"){E(t,m,"Invalid Upgrade header");return}let v=ts("sha1").update(u+os).digest("base64");if(h.headers["sec-websocket-accept"]!==v){E(t,m,"Invalid Sec-WebSocket-Accept header");return}let A=h.headers["sec-websocket-protocol"],U;if(A!==void 0?d.size?d.has(A)||(U="Server sent an invalid subprotocol"):U="Server sent a subprotocol but none was requested":d.size&&(U="Server sent no subprotocol"),U){E(t,m,U);return}A&&(t._protocol=A);let Ye=h.headers["sec-websocket-extensions"];if(Ye!==void 0){if(!p){E(t,m,"Server sent a Sec-WebSocket-Extensions header but no extension was requested");return}let Ee;try{Ee=ds(Ye)}catch{E(t,m,"Invalid Sec-WebSocket-Extensions header");return}let Ze=Object.keys(Ee);if(Ze.length!==1||Ze[0]!==B.extensionName){E(t,m,"Server indicated an extension that was not requested");return}try{p.accept(Ee[B.extensionName])}catch{E(t,m,"Invalid Sec-WebSocket-Extensions header");return}t._extensions[B.extensionName]=p}t.setSocket(m,b,{allowSynchronousEvents:n.allowSynchronousEvents,generateMask:n.generateMask,maxBufferedChunks:n.maxBufferedChunks,maxFragments:n.maxFragments,maxPayload:n.maxPayload,skipUTF8Validation:n.skipUTF8Validation})}),n.finishRequest?n.finishRequest(_,t):_.end()}function me(t,e){t._readyState=g.CLOSING,t._errorEmitted=!0,t.emit("error",e),t.emitClose()}function _s(t){return t.path=t.socketPath,At.connect(t)}function ms(t){return t.path=void 0,!t.servername&&t.servername!==""&&(t.servername=At.isIP(t.host)?"":t.host),Qr.connect(t)}function E(t,e,r){t._readyState=g.CLOSING;let s=new Error(r);Error.captureStackTrace(s,E),e.setHeader?(e[Dt]=!0,e.abort(),e.socket&&!e.socket.destroyed&&e.socket.destroy(),process.nextTick(me,t,s)):(e.destroy(s),e.once("error",t.emit.bind(t,"error")),e.once("close",t.emitClose.bind(t)))}function $e(t,e,r){if(e){let s=ns(e)?e.size:hs(e).length;t._socket?t._sender._bufferedBytes+=s:t._bufferedAmount+=s}if(r){let s=new Error(`WebSocket is not open: readyState ${t.readyState} (${C[t.readyState]})`);process.nextTick(r,s)}}function gs(t,e){let r=this[y];r._closeFrameReceived=!0,r._closeMessage=e,r._closeCode=t,r._socket[y]!==void 0&&(r._socket.removeListener("data",ge),process.nextTick(Ut,r._socket),t===1005?r.close():r.close(t,e))}function ys(){let t=this[y];t.isPaused||t._socket.resume()}function xs(t){let e=this[y];e._socket[y]!==void 0&&(e._socket.removeListener("data",ge),process.nextTick(Ut,e._socket),e.close(t[cs])),e._errorEmitted||(e._errorEmitted=!0,e.emit("error",t))}function Lt(){this[y].emitClose()}function Ss(t,e){this[y].emit("message",t,e)}function Es(t){let e=this[y];e._autoPong&&e.pong(t,!this._isServer,It),e.emit("ping",t)}function bs(t){this[y].emit("pong",t)}function Ut(t){t.resume()}function ws(t){let e=this[y];e.readyState!==g.CLOSED&&(e.readyState===g.OPEN&&(e._readyState=g.CLOSING,Ft(e)),this._socket.end(),e._errorEmitted||(e._errorEmitted=!0,e.emit("error",t)))}function Ft(t){t._closeTimer=setTimeout(t._socket.destroy.bind(t._socket),t._closeTimeout)}function Wt(){let t=this[y];if(this.removeListener("close",Wt),this.removeListener("data",ge),this.removeListener("end",Mt),t._readyState=g.CLOSING,!this._readableState.endEmitted&&!t._closeFrameReceived&&!t._receiver._writableState.errorEmitted&&this._readableState.length!==0){let e=this.read(this._readableState.length);t._receiver.write(e)}t._receiver.end(),this[y]=void 0,clearTimeout(t._closeTimer),t._receiver._writableState.finished||t._receiver._writableState.errorEmitted?t.emitClose():(t._receiver.on("error",Lt),t._receiver.on("finish",Lt))}function ge(t){this[y]._receiver.write(t)||this.pause()}function Mt(){let t=this[y];t._readyState=g.CLOSING,t._receiver.end(),this.end()}function $t(){let t=this[y];this.removeListener("error",$t),this.on("error",It),t&&(t._readyState=g.CLOSING,this.destroy())}});var Ht=S((wn,Vt)=>{"use strict";var bn=ye(),{Duplex:Os}=require("stream");function jt(t){t.emit("close")}function vs(){!this.destroyed&&this._writableState.finished&&this.destroy()}function qt(t){this.removeListener("error",qt),this.destroy(),this.listenerCount("error")===0&&this.emit("error",t)}function Rs(t,e){let r=!0,s=new Os({...e,autoDestroy:!1,emitClose:!1,objectMode:!1,writableObjectMode:!1});return t.on("message",function(i,o){let l=!o&&s._readableState.objectMode?i.toString():i;s.push(l)||t.pause()}),t.once("error",function(i){s.destroyed||(r=!1,s.destroy(i))}),t.once("close",function(){s.destroyed||s.push(null)}),s._destroy=function(n,i){if(t.readyState===t.CLOSED){i(n),process.nextTick(jt,s);return}let o=!1;t.once("error",function(f){o=!0,i(f)}),t.once("close",function(){o||i(n),process.nextTick(jt,s)}),r&&t.terminate()},s._final=function(n){if(t.readyState===t.CONNECTING){t.once("open",function(){s._final(n)});return}t._socket!==null&&(t._socket._writableState.finished?(n(),s._readableState.endEmitted&&s.destroy()):(t._socket.once("finish",function(){n()}),t.close()))},s._read=function(){t.isPaused&&t.resume()},s._write=function(n,i,o){if(t.readyState===t.CONNECTING){t.once("open",function(){s._write(n,i,o)});return}t.send(n,o)},s.on("end",vs),s.on("error",qt),s}Vt.exports=Rs});var Ge=S((On,zt)=>{"use strict";var{tokenChars:Ts}=H();function ks(t){let e=new Set,r=-1,s=-1,n=0;for(n;n<t.length;n++){let o=t.charCodeAt(n);if(s===-1&&Ts[o]===1)r===-1&&(r=n);else if(n!==0&&(o===32||o===9))s===-1&&r!==-1&&(s=n);else if(o===44){if(r===-1)throw new SyntaxError(`Unexpected character at index ${n}`);s===-1&&(s=n);let l=t.slice(r,s);if(e.has(l))throw new SyntaxError(`The "${l}" subprotocol is duplicated`);e.add(l),r=s=-1}else throw new SyntaxError(`Unexpected character at index ${n}`)}if(r===-1||s!==-1)throw new SyntaxError("Unexpected end of input");let i=t.slice(r,n);if(e.has(i))throw new SyntaxError(`The "${i}" subprotocol is duplicated`);return e.add(i),e}zt.exports={parse:ks}});var er=S((Rn,Qt)=>{"use strict";var Ns=require("events"),xe=require("http"),{Duplex:vn}=require("stream"),{createHash:Ps}=require("crypto"),Kt=pe(),$=V(),Cs=Ge(),Ls=ye(),{CLOSE_TIMEOUT:As,GUID:Is,kWebSocket:Ds}=k(),Bs=/^[+/0-9A-Za-z]{22}==$/,Yt=0,Zt=1,Jt=2,je=class extends Ns{constructor(e,r){if(super(),e={allowSynchronousEvents:!0,autoPong:!0,maxBufferedChunks:256*1024,maxFragments:16*1024,maxPayload:100*1024*1024,skipUTF8Validation:!1,perMessageDeflate:!1,handleProtocols:null,clientTracking:!0,closeTimeout:As,verifyClient:null,noServer:!1,backlog:null,server:null,host:null,path:null,port:null,WebSocket:Ls,...e},e.port==null&&!e.server&&!e.noServer||e.port!=null&&(e.server||e.noServer)||e.server&&e.noServer)throw new TypeError('One and only one of the "port", "server", or "noServer" options must be specified');if(e.port!=null?(this._server=xe.createServer((s,n)=>{let i=xe.STATUS_CODES[426];n.writeHead(426,{"Content-Length":i.length,"Content-Type":"text/plain"}),n.end(i)}),this._server.listen(e.port,e.host,e.backlog,r)):e.server&&(this._server=e.server),this._server){let s=this.emit.bind(this,"connection");this._removeListeners=Us(this._server,{listening:this.emit.bind(this,"listening"),error:this.emit.bind(this,"error"),upgrade:(n,i,o)=>{this.handleUpgrade(n,i,o,s)}})}e.perMessageDeflate===!0&&(e.perMessageDeflate={}),e.clientTracking&&(this.clients=new Set,this._shouldEmitClose=!1),this.options=e,this._state=Yt}address(){if(this.options.noServer)throw new Error('The server is operating in "noServer" mode');return this._server?this._server.address():null}close(e){if(this._state===Jt){e&&this.once("close",()=>{e(new Error("The server is not running"))}),process.nextTick(se,this);return}if(e&&this.once("close",e),this._state!==Zt)if(this._state=Zt,this.options.noServer||this.options.server)this._server&&(this._removeListeners(),this._removeListeners=this._server=null),this.clients?this.clients.size?this._shouldEmitClose=!0:process.nextTick(se,this):process.nextTick(se,this);else{let r=this._server;this._removeListeners(),this._removeListeners=this._server=null,r.close(()=>{se(this)})}}shouldHandle(e){if(this.options.path){let r=e.url.indexOf("?");if((r!==-1?e.url.slice(0,r):e.url)!==this.options.path)return!1}return!0}handleUpgrade(e,r,s,n){r.on("error",Xt);let i=e.headers["sec-websocket-key"],o=e.headers.upgrade,l=+e.headers["sec-websocket-version"];if(e.method!=="GET"){G(this,e,r,405,"Invalid HTTP method");return}if(o===void 0||o.toLowerCase()!=="websocket"){G(this,e,r,400,"Invalid Upgrade header");return}if(i===void 0||!Bs.test(i)){G(this,e,r,400,"Missing or invalid Sec-WebSocket-Key header");return}if(l!==13&&l!==8){G(this,e,r,400,"Missing or invalid Sec-WebSocket-Version header",{"Sec-WebSocket-Version":"13, 8"});return}if(!this.shouldHandle(e)){ne(r,400);return}let f=e.headers["sec-websocket-protocol"],c=new Set;if(f!==void 0)try{c=Cs.parse(f)}catch{G(this,e,r,400,"Invalid Sec-WebSocket-Protocol header");return}let u=e.headers["sec-websocket-extensions"],a={};if(this.options.perMessageDeflate&&u!==void 0){let d=new $({...this.options.perMessageDeflate,isServer:!0,maxPayload:this.options.maxPayload});try{let p=Kt.parse(u);p[$.extensionName]&&(d.accept(p[$.extensionName]),a[$.extensionName]=d)}catch{G(this,e,r,400,"Invalid or unacceptable Sec-WebSocket-Extensions header");return}}if(this.options.verifyClient){let d={origin:e.headers[`${l===8?"sec-websocket-origin":"origin"}`],secure:!!(e.socket.authorized||e.socket.encrypted),req:e};if(this.options.verifyClient.length===2){this.options.verifyClient(d,(p,_,h,m)=>{if(!p)return ne(r,_||401,h,m);this.completeUpgrade(a,i,c,e,r,s,n)});return}if(!this.options.verifyClient(d))return ne(r,401)}this.completeUpgrade(a,i,c,e,r,s,n)}completeUpgrade(e,r,s,n,i,o,l){if(!i.readable||!i.writable)return i.destroy();if(i[Ds])throw new Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");if(this._state>Yt)return ne(i,503);let c=["HTTP/1.1 101 Switching Protocols","Upgrade: websocket","Connection: Upgrade",`Sec-WebSocket-Accept: ${Ps("sha1").update(r+Is).digest("base64")}`],u=new this.options.WebSocket(null,void 0,this.options);if(s.size){let a=this.options.handleProtocols?this.options.handleProtocols(s,n):s.values().next().value;a&&(c.push(`Sec-WebSocket-Protocol: ${a}`),u._protocol=a)}if(e[$.extensionName]){let a=e[$.extensionName].params,d=Kt.format({[$.extensionName]:[a]});c.push(`Sec-WebSocket-Extensions: ${d}`),u._extensions=e}this.emit("headers",c,n),i.write(c.concat(`\r
2
+ `).join(`\r
3
+ `)),i.removeListener("error",Xt),u.setSocket(i,o,{allowSynchronousEvents:this.options.allowSynchronousEvents,maxBufferedChunks:this.options.maxBufferedChunks,maxFragments:this.options.maxFragments,maxPayload:this.options.maxPayload,skipUTF8Validation:this.options.skipUTF8Validation}),this.clients&&(this.clients.add(u),u.on("close",()=>{this.clients.delete(u),this._shouldEmitClose&&!this.clients.size&&process.nextTick(se,this)})),l(u,n)}};Qt.exports=je;function Us(t,e){for(let r of Object.keys(e))t.on(r,e[r]);return function(){for(let s of Object.keys(e))t.removeListener(s,e[s])}}function se(t){t._state=Jt,t.emit("close")}function Xt(){this.destroy()}function ne(t,e,r,s){r=r||xe.STATUS_CODES[e],s={Connection:"close","Content-Type":"text/html","Content-Length":Buffer.byteLength(r),...s},t.once("finish",t.destroy),t.end(`HTTP/1.1 ${e} ${xe.STATUS_CODES[e]}\r
4
+ `+Object.keys(s).map(n=>`${n}: ${s[n]}`).join(`\r
5
+ `)+`\r
6
+ \r
7
+ `+r)}function G(t,e,r,s,n,i){if(t.listenerCount("wsClientError")){let o=new Error(n);Error.captureStackTrace(o,G),t.emit("wsClientError",o,r,e)}else ne(r,s,n,i)}});var lr=require("node:http"),fr=require("node:os"),ze=require("node:timers/promises");var Fs=I(Ht(),1),Ws=I(pe(),1),Ms=I(V(),1),$s=I(Ae(),1),Gs=I(Be(),1),js=I(Ge(),1),qs=I(ye(),1),qe=I(er(),1);var nr=require("node:child_process"),L=require("node:fs/promises"),X=require("node:path"),Se=require("node:stream");function ir(t,e,r){let s=new Set,n=i=>(0,X.resolve)(e,i);return{id:t,async run(i,{cwd:o,env:l,stdin:f,signal:c}={}){let u=(0,nr.spawn)("bash",["-c",i],{cwd:n(o??"."),env:{...r,...l},stdio:"pipe",detached:!0}),a=u.pid;a!==void 0&&s.add(a),u.stdin.on("error",()=>{}),f||u.stdin.end();let d=!1,p=new Promise(m=>{u.on("error",()=>m({exitCode:127})),u.on("exit",b=>{d=!0,a!==void 0&&!rr(a)&&s.delete(a);let x=()=>m({exitCode:b??1});u.on("close",x),setTimeout(x,Vs).unref()})}),_=(m="SIGKILL")=>{a!==void 0&&(!d||rr(a))&&sr(a,m)},h=()=>_();return c?.aborted&&h(),c?.addEventListener("abort",h,{once:!0}),p.then(()=>c?.removeEventListener("abort",h)),{stdin:Se.Writable.toWeb(u.stdin),stdout:tr(u.stdout),stderr:tr(u.stderr),wait:()=>p,kill:_}},read:i=>(0,L.readFile)(n(i)).catch(()=>null),async write(i,o,{mode:l}={}){await(0,L.mkdir)((0,X.dirname)(n(i)),{recursive:!0}),await(0,L.writeFile)(n(i),o),l!==void 0&&await(0,L.chmod)(n(i),l)},expose:async i=>({url:`http://127.0.0.1:${i}`}),async stop(){for(let i of s)sr(i);s.clear()}}}var Vs=200,tr=t=>Se.Readable.toWeb(t);function rr(t){try{return process.kill(-t,0),!0}catch{return!1}}function sr(t,e="SIGKILL"){try{process.kill(-t,e)}catch{}}var or="/runner/health";function Ve(t,e,r){let s=new Uint8Array(5+r.length);return new DataView(s.buffer).setUint32(0,t),s[4]=e,s.set(r,5),s}var ar=t=>({id:new DataView(t.buffer,t.byteOffset,t.byteLength).getUint32(0),stream:t[4],bytes:t.subarray(5)});var Hs=["text","number","boolean","date","person"];var Pn=`${Hs.map(t=>`"${t}"`).join(", ")}, { type, optional: true } or { enum: [...] }`;var zs=/^[\w-]{1,64}$/,Cn=new RegExp(`^change:(${zs.source.slice(1,-1)})(?:~\\d+)?$`);var Ks="anonymous";var Ln=Object.freeze({id:Ks,groups:[]});var He=t=>t instanceof Error?t.message:String(t);var en=Number(process.env.SANOMA_RUNNER_PORT??7700),tn=process.env.SANOMA_RUNNER_HOST??"0.0.0.0",rn=50,sn=1<<20,nn=3e4,{SANOMA_RUNNER_PORT:Wn,SANOMA_RUNNER_HOST:Mn,...on}=process.env,ie=ir("runner",(0,fr.homedir)(),on),Ke=(0,lr.createServer)((t,e)=>{if(t.url!==or)return void e.writeHead(404).end();e.writeHead(200,{"content-type":"application/json"}).end(JSON.stringify({protocol:2,pid:process.pid}))});new qe.default({server:Ke}).on("connection",an).on("error",t=>console.error(`the runner's WebSocket server: ${t.message}`));Ke.listen(en,tn,()=>{let{address:t,port:e}=Ke.address();console.log(`sanoma runner listening on ${t}:${e}`)});process.on("SIGTERM",()=>{ie.stop().finally(()=>process.exit(0))});function an(t){let e=new Map,r=new Map,s=new Map,n=a=>t.readyState===t.OPEN&&t.send(a),i=a=>n(JSON.stringify(a)),o=setInterval(()=>t.ping(),nn);t.on("error",a=>console.error(`a connection: ${a.message}`)),t.on("close",()=>{clearInterval(o);for(let a of r.keys())c(a)}),t.on("message",(a,d)=>{if(d)return a.length<5?i({op:"error",message:"a binary frame is an id, a stream and bytes"}):f(ar(a));let p;try{p=JSON.parse(String(a))}catch{return i({op:"error",message:"a text frame is JSON"})}if(typeof p!="object"||p===null)return i({op:"error",message:"a request is an object"});l(p).catch(_=>i({op:"error",id:p.id,message:He(_)}))});async function l(a){switch(a.op){case"run":{let{id:d,command:p,cwd:_,env:h,stdin:m}=a,b=ie.run(p,{cwd:_,env:h,stdin:m});if(e.set(d,b),m){let x=b.then(v=>v.stdin.getWriter());x.catch(()=>{}),r.set(d,x)}try{let x=await b,v={at:Date.now(),done:!1},A=Promise.all([u(d,1,x.stdout,v),u(d,2,x.stderr,v)]).finally(()=>v.done=!0),{exitCode:U}=await x.wait();for(v.at=Date.now();!v.done&&Date.now()-v.at<rn;)await Promise.race([A,(0,ze.setTimeout)(10)]);return i({op:"exit",id:d,code:U})}finally{e.delete(d),r.delete(d)}}case"stdin-end":return c(a.id);case"kill":return e.get(a.id)?.then(d=>d.kill(a.signal));case"read":{let d=await ie.read(a.path);return d?n(Ve(a.id,3,d)):i({op:"absent",id:a.id})}case"write":return s.set(a.id,a);case"stop":return await ie.stop(),i({op:"ok",id:a.id});default:throw new Error(`no such request: ${a.op}`)}}function f({id:a,stream:d,bytes:p}){if(d===0)return void r.get(a)?.then(h=>h.write(p)).catch(()=>{});let _=s.get(a);d!==3||!_||(s.delete(a),ie.write(_.path,p,{mode:_.mode}).then(()=>i({op:"ok",id:a}),h=>i({op:"error",id:a,message:He(h)})))}function c(a){let d=r.get(a);return r.delete(a),d?.then(p=>p.close()).catch(()=>{})}async function u(a,d,p,_){try{for await(let h of p){for(;t.readyState===t.OPEN&&t.bufferedAmount>sn;)_.at=Date.now(),await(0,ze.setTimeout)(10);n(Ve(a,d,h)),_.at=Date.now()}}catch{}}}
package/dist/scenario.js CHANGED
@@ -4,6 +4,7 @@ import { setTimeout as delay } from "node:timers/promises";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { ParameterTypeRegistry } from "@cucumber/cucumber-expressions";
6
6
  import { PickleStepType, } from "@cucumber/messages";
7
+ import { targetOf } from "./call.js";
7
8
  import { buildLibrary, lineOf, runFeatures, stepResults, StepStatus, } from "./cucumber.js";
8
9
  import { errorCode, errorInfo, SanomaError } from "./errors.js";
9
10
  import { contains, detailOf, isCall } from "./expectations.js";
@@ -13,7 +14,7 @@ import { isDirectory, kindDirs, SCENARIOS_DIR } from "./paths.js";
13
14
  import { AFTER_CREATE_MS, callAfterCreate, isObject } from "./resource.js";
14
15
  import { admit, readPeople } from "./resources.js";
15
16
  import { memorySecrets } from "./secret.js";
16
- import { APPLY_WORKFLOW, BUILT_IN_WORKFLOWS, DATA_VENDOR, declaresPeople, DRIFT_WORKFLOW, errorMessage, fitsOp, flatten, groupNamesOf, isEnded, principalIdsOf, problemLine, RUNTIME_AGENTS, visitorPrincipal, } from "./shared.js";
17
+ import { APPLY_WORKFLOW, BUILT_IN_WORKFLOWS, DATA_VENDOR, declaresPeople, DRIFT_WORKFLOW, entryOpsOf, errorMessage, fitsOp, flatten, groupNamesOf, isBatch, isEnded, principalIdsOf, problemLine, RUNTIME_AGENTS, visitorPrincipal, } from "./shared.js";
17
18
  const KINDS = {
18
19
  [PickleStepType.CONTEXT]: "given",
19
20
  [PickleStepType.ACTION]: "when",
@@ -177,6 +178,13 @@ function rulesOf(scope) {
177
178
  { name: "field", regexp: /\S+/, transformer: (s) => s },
178
179
  ];
179
180
  const opOf = (id) => scope.ops.get(id);
181
+ /** An operation a `Then` step reads the ledger for: never a batch, which the ledger records as its entries. */
182
+ const recordedOp = (id) => {
183
+ const op = opOf(id);
184
+ if (isBatch(op))
185
+ throw new Error(`${op.id} is recorded as its entries: name ${entryOpsOf(op).join(" or ")}`);
186
+ return op.id;
187
+ };
180
188
  const workflowOf = (name) => scope.workflows.get(name);
181
189
  // The people as the root's data files declare them when a step names one (`readPeople`, read
182
190
  // again only once a file changed): while they declare no one, any id and any group go.
@@ -323,32 +331,32 @@ function rulesOf(scope) {
323
331
  kind: "then",
324
332
  source: "{op} was called with",
325
333
  takes: TAKES_OBJECT,
326
- read: ([op], pickle) => expecting({ op: op, input: fieldsFrom(pickle, opOf(op).input, inputOf(op), true), called: true }),
334
+ read: ([op], pickle) => expecting({ op: recordedOp(op), input: fieldsFrom(pickle, opOf(op).input, inputOf(op), true), called: true }),
327
335
  },
328
336
  ...[true, false].map((called) => ({
329
337
  kind: "then",
330
338
  source: `{op} was ${called ? "" : "not "}called`,
331
- read: ([op]) => expecting({ op: op, called }),
339
+ read: ([op]) => expecting({ op: recordedOp(op), called }),
332
340
  })),
333
341
  {
334
342
  kind: "then",
335
343
  source: "{op} was denied",
336
- read: ([op]) => expecting({ op: op, decision: "denied" }),
344
+ read: ([op]) => expecting({ op: recordedOp(op), decision: "denied" }),
337
345
  },
338
346
  {
339
347
  kind: "then",
340
348
  source: "{op} was denied with {string}",
341
- read: ([op, reason]) => expecting({ op: op, decision: "denied", reason: reason }),
349
+ read: ([op, reason]) => expecting({ op: recordedOp(op), decision: "denied", reason: reason }),
342
350
  },
343
351
  {
344
352
  kind: "then",
345
353
  source: "{op} was held for {who}",
346
- read: ([op, who]) => expecting({ op: op, decision: "held", approver: who }),
354
+ read: ([op, who]) => expecting({ op: recordedOp(op), decision: "held", approver: who }),
347
355
  },
348
356
  {
349
357
  kind: "then",
350
358
  source: "{op} was held for group {string}",
351
- read: ([op, group]) => expecting({ op: op, decision: "held", approver: { group: groupNamed(group) } }),
359
+ read: ([op, group]) => expecting({ op: recordedOp(op), decision: "held", approver: { group: groupNamed(group) } }),
352
360
  },
353
361
  {
354
362
  kind: "then",
@@ -887,6 +895,7 @@ function testWorld(built, { driver, fake, live }) {
887
895
  record({
888
896
  type: "op.called",
889
897
  op: op.id,
898
+ ...targetOf(op, input),
890
899
  effect: op.effect,
891
900
  input,
892
901
  decision: { kind: "allow" },