@deepseek-ai/dsh-experimental-inspector 0.1.6-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +156 -0
  4. package/README.zh.md +156 -0
  5. package/lib/client.js +3424 -0
  6. package/lib/index.js +2406 -0
  7. package/lib/types/client/bridge/controller.d.ts +10 -0
  8. package/lib/types/client/bridge/dispatcher.d.ts +26 -0
  9. package/lib/types/client/bridge/lifecycle.d.ts +20 -0
  10. package/lib/types/client/bridge/publisher.d.ts +42 -0
  11. package/lib/types/client/bridge/rpc.d.ts +13 -0
  12. package/lib/types/client/bridge/transport.d.ts +34 -0
  13. package/lib/types/client/cdp/console.d.ts +45 -0
  14. package/lib/types/client/cdp/debugger.d.ts +8 -0
  15. package/lib/types/client/cdp/errors.d.ts +8 -0
  16. package/lib/types/client/cdp/heap-profiler.d.ts +8 -0
  17. package/lib/types/client/cdp/index.d.ts +10 -0
  18. package/lib/types/client/cdp/objects.d.ts +69 -0
  19. package/lib/types/client/cdp/profiler.d.ts +8 -0
  20. package/lib/types/client/cdp/properties.d.ts +16 -0
  21. package/lib/types/client/cdp/runtime.d.ts +79 -0
  22. package/lib/types/client/cdp/sources.d.ts +52 -0
  23. package/lib/types/client/cdp/stack.d.ts +27 -0
  24. package/lib/types/client/index.d.ts +3 -0
  25. package/lib/types/client/inspection/cordis.d.ts +3 -0
  26. package/lib/types/client/inspection/network.d.ts +4 -0
  27. package/lib/types/client/inspection/realm.d.ts +27 -0
  28. package/lib/types/client/plugin.d.ts +28 -0
  29. package/lib/types/host/bridge/controller.d.ts +108 -0
  30. package/lib/types/host/bridge/dispatcher.d.ts +16 -0
  31. package/lib/types/host/bridge/lifecycle.d.ts +42 -0
  32. package/lib/types/host/bridge/publisher.d.ts +31 -0
  33. package/lib/types/host/bridge/rpc.d.ts +15 -0
  34. package/lib/types/host/bridge/transport.d.ts +28 -0
  35. package/lib/types/host/cdp/console.d.ts +14 -0
  36. package/lib/types/host/cdp/debugger.d.ts +8 -0
  37. package/lib/types/host/cdp/errors.d.ts +6 -0
  38. package/lib/types/host/cdp/heap-profiler.d.ts +8 -0
  39. package/lib/types/host/cdp/index.d.ts +10 -0
  40. package/lib/types/host/cdp/objects.d.ts +8 -0
  41. package/lib/types/host/cdp/profiler.d.ts +8 -0
  42. package/lib/types/host/cdp/properties.d.ts +7 -0
  43. package/lib/types/host/cdp/runtime.d.ts +16 -0
  44. package/lib/types/host/cdp/sources.d.ts +14 -0
  45. package/lib/types/host/cdp/stack.d.ts +4 -0
  46. package/lib/types/host/index.d.ts +3 -0
  47. package/lib/types/host/inspection/cordis.d.ts +3 -0
  48. package/lib/types/host/inspection/network.d.ts +23 -0
  49. package/lib/types/host/inspection/realm.d.ts +9 -0
  50. package/lib/types/host/plugin.d.ts +19 -0
  51. package/lib/types/index.d.ts +50 -0
  52. package/lib/types/shared/bridge/buffer.d.ts +62 -0
  53. package/lib/types/shared/bridge/codec.d.ts +4 -0
  54. package/lib/types/shared/bridge/control-codec.d.ts +27 -0
  55. package/lib/types/shared/bridge/ids.d.ts +19 -0
  56. package/lib/types/shared/bridge/messages/control.d.ts +64 -0
  57. package/lib/types/shared/bridge/messages/cordis.d.ts +4 -0
  58. package/lib/types/shared/bridge/messages/network.d.ts +4 -0
  59. package/lib/types/shared/bridge/messages/observation.d.ts +110 -0
  60. package/lib/types/shared/bridge/messages/query/codec.d.ts +40 -0
  61. package/lib/types/shared/bridge/messages/query/commands.d.ts +35 -0
  62. package/lib/types/shared/bridge/messages/query/frames.d.ts +31 -0
  63. package/lib/types/shared/bridge/messages/query/index.d.ts +5 -0
  64. package/lib/types/shared/bridge/messages/runtime/command-codec.d.ts +9 -0
  65. package/lib/types/shared/bridge/messages/runtime/commands.d.ts +76 -0
  66. package/lib/types/shared/bridge/messages/runtime/console-frames.d.ts +52 -0
  67. package/lib/types/shared/bridge/messages/runtime/frames.d.ts +98 -0
  68. package/lib/types/shared/bridge/messages/runtime/index.d.ts +5 -0
  69. package/lib/types/shared/bridge/messages/runtime/value-codec.d.ts +28 -0
  70. package/lib/types/shared/bridge/messages/sources/codec.d.ts +15 -0
  71. package/lib/types/shared/bridge/messages/sources/commands.d.ts +42 -0
  72. package/lib/types/shared/bridge/messages/sources/frames.d.ts +67 -0
  73. package/lib/types/shared/bridge/messages/sources/index.d.ts +5 -0
  74. package/lib/types/shared/bridge/publisher.d.ts +33 -0
  75. package/lib/types/shared/bridge/query-reader.d.ts +10 -0
  76. package/lib/types/shared/bridge/rpc.d.ts +62 -0
  77. package/lib/types/shared/bridge/validation.d.ts +3 -0
  78. package/lib/types/shared/bridge/version.d.ts +3 -0
  79. package/lib/types/shared/cdp/capabilities.d.ts +17 -0
  80. package/lib/types/shared/cdp/console.d.ts +28 -0
  81. package/lib/types/shared/cdp/debugger.d.ts +69 -0
  82. package/lib/types/shared/cdp/errors.d.ts +27 -0
  83. package/lib/types/shared/cdp/ids.d.ts +9 -0
  84. package/lib/types/shared/cdp/index.d.ts +11 -0
  85. package/lib/types/shared/cdp/operations.d.ts +86 -0
  86. package/lib/types/shared/cdp/property.d.ts +28 -0
  87. package/lib/types/shared/cdp/realm.d.ts +137 -0
  88. package/lib/types/shared/cdp/remote-object.d.ts +44 -0
  89. package/lib/types/shared/cdp/sources.d.ts +18 -0
  90. package/lib/types/shared/cordis/collector.d.ts +26 -0
  91. package/lib/types/shared/cordis/ids.d.ts +7 -0
  92. package/lib/types/shared/cordis/model.d.ts +61 -0
  93. package/lib/types/shared/cordis/object-reference.d.ts +14 -0
  94. package/lib/types/shared/cordis/object-registry.d.ts +80 -0
  95. package/lib/types/shared/cordis/observer.d.ts +15 -0
  96. package/lib/types/shared/cordis/projector.d.ts +34 -0
  97. package/lib/types/shared/cordis/publisher.d.ts +13 -0
  98. package/lib/types/shared/cordis/reader.d.ts +18 -0
  99. package/lib/types/shared/cordis/snapshot.d.ts +39 -0
  100. package/lib/types/shared/identity.d.ts +12 -0
  101. package/lib/types/shared/index.d.ts +18 -0
  102. package/lib/types/shared/json.d.ts +35 -0
  103. package/lib/types/shared/network/event-source.d.ts +20 -0
  104. package/lib/types/shared/network/observation.d.ts +52 -0
  105. package/lib/types/shared/service.d.ts +23 -0
  106. package/lib/types/shared/validation.d.ts +52 -0
  107. package/lib/types/worker/bridge/endpoint.d.ts +49 -0
  108. package/lib/types/worker/bridge/hub.d.ts +108 -0
  109. package/lib/types/worker/bridge/runtime-rpc.d.ts +90 -0
  110. package/lib/types/worker/bridge/session.d.ts +15 -0
  111. package/lib/types/worker/bridge/source-rpc.d.ts +42 -0
  112. package/lib/types/worker/cdp/domains/debugger/cdp-params.d.ts +15 -0
  113. package/lib/types/worker/cdp/domains/debugger/index.d.ts +6 -0
  114. package/lib/types/worker/cdp/domains/debugger/projector.d.ts +22 -0
  115. package/lib/types/worker/cdp/domains/debugger/script-registry.d.ts +70 -0
  116. package/lib/types/worker/cdp/domains/debugger/session.d.ts +47 -0
  117. package/lib/types/worker/cdp/domains/dom/index.d.ts +4 -0
  118. package/lib/types/worker/cdp/domains/dom/model.d.ts +108 -0
  119. package/lib/types/worker/cdp/domains/dom/session.d.ts +74 -0
  120. package/lib/types/worker/cdp/domains/native.d.ts +25 -0
  121. package/lib/types/worker/cdp/domains/network/session.d.ts +46 -0
  122. package/lib/types/worker/cdp/domains/runtime/cdp-params.d.ts +82 -0
  123. package/lib/types/worker/cdp/domains/runtime/index.d.ts +3 -0
  124. package/lib/types/worker/cdp/domains/runtime/object-table.d.ts +117 -0
  125. package/lib/types/worker/cdp/domains/runtime/session.d.ts +97 -0
  126. package/lib/types/worker/cdp/ids.d.ts +37 -0
  127. package/lib/types/worker/cdp/protocol.d.ts +46 -0
  128. package/lib/types/worker/cdp/realm-sessions.d.ts +64 -0
  129. package/lib/types/worker/cdp/session.d.ts +34 -0
  130. package/lib/types/worker/cdp/target.d.ts +17 -0
  131. package/lib/types/worker/entry.d.ts +3 -0
  132. package/lib/types/worker/inspection/cordis-query.d.ts +11 -0
  133. package/lib/types/worker/inspection/cordis-store.d.ts +94 -0
  134. package/lib/types/worker/inspection/network-store.d.ts +110 -0
  135. package/lib/types/worker/inspection/query-router.d.ts +78 -0
  136. package/lib/types/worker/inspection/realm-store.d.ts +58 -0
  137. package/lib/types/worker/inspection/realm.d.ts +43 -0
  138. package/lib/types/worker/realms/client/bridge.d.ts +18 -0
  139. package/lib/types/worker/realms/client/console.d.ts +21 -0
  140. package/lib/types/worker/realms/client/debugger.d.ts +8 -0
  141. package/lib/types/worker/realms/client/index.d.ts +18 -0
  142. package/lib/types/worker/realms/client/runtime.d.ts +28 -0
  143. package/lib/types/worker/realms/client/scripts.d.ts +15 -0
  144. package/lib/types/worker/realms/client/sources.d.ts +30 -0
  145. package/lib/types/worker/realms/client/values.d.ts +55 -0
  146. package/lib/types/worker/realms/host/bridge.d.ts +49 -0
  147. package/lib/types/worker/realms/host/console.d.ts +25 -0
  148. package/lib/types/worker/realms/host/debugger.d.ts +25 -0
  149. package/lib/types/worker/realms/host/index.d.ts +13 -0
  150. package/lib/types/worker/realms/host/runtime.d.ts +54 -0
  151. package/lib/types/worker/realms/host/scripts.d.ts +9 -0
  152. package/lib/types/worker/realms/host/sources.d.ts +26 -0
  153. package/lib/types/worker/realms/host/values.d.ts +22 -0
  154. package/lib/types/worker/server.d.ts +16 -0
  155. package/lib/worker.js +7184 -0
  156. package/package.json +64 -0
package/lib/index.js ADDED
@@ -0,0 +1,2406 @@
1
+ import z from "@deepseek-ai/schemastery";
2
+ import { randomBytes, randomUUID } from "node:crypto";
3
+ import { tmpdir } from "node:os";
4
+ import { MessageChannel, Worker } from "node:worker_threads";
5
+ import { Context } from "@deepseek-ai/cordis";
6
+ import { randomUUID as randomUUID$1 } from "@deepseek-ai/dsh-util-crypto";
7
+ //#endregion
8
+ //#region lib/types/host/inspection/network.js
9
+ /** Full `globalThis.fetch` capture that publishes without delaying response delivery. */
10
+ /** Observation topics published by the Host network adapter. */
11
+ const NETWORK_TOPICS = [
12
+ "fetch/start",
13
+ "fetch/request-body-chunk",
14
+ "fetch/request-body-end",
15
+ "fetch/response",
16
+ "fetch/response-body-chunk",
17
+ "fetch/end",
18
+ "fetch/error"
19
+ ];
20
+ /**
21
+ * Install full fetch capture for every later call through `globalThis.fetch`.
22
+ * @param publisher - Host source that receives fetch lifecycle records.
23
+ * @param options - Per-body capture limits.
24
+ * @returns The owner that stops capture and awaits pending body readers.
25
+ */
26
+ function installFetchObserver(publisher, options) {
27
+ const descriptor = Object.getOwnPropertyDescriptor(globalThis, "fetch");
28
+ const original = globalThis.fetch;
29
+ if (typeof original !== "function") throw new Error("inspector: globalThis.fetch is unavailable");
30
+ if (descriptor !== void 0 && !("value" in descriptor)) throw new Error("inspector: globalThis.fetch is an accessor and cannot be observed safely");
31
+ const controller = new AbortController();
32
+ const pending = /* @__PURE__ */ new Set();
33
+ let nextRequestId = 0;
34
+ const track = (promise) => {
35
+ pending.add(promise);
36
+ promise.then(() => {
37
+ pending.delete(promise);
38
+ }, () => {
39
+ pending.delete(promise);
40
+ });
41
+ };
42
+ const observedFetch = async (input, init) => {
43
+ const request = new Request(input, init);
44
+ const requestId = `fetch-${++nextRequestId}`;
45
+ publisher.publish("fetch/start", {
46
+ requestId,
47
+ url: request.url,
48
+ method: request.method,
49
+ headers: headerEntries(request.headers),
50
+ hasBody: request.body !== null,
51
+ wallTimeMs: Date.now()
52
+ });
53
+ let requestClone;
54
+ try {
55
+ requestClone = request.clone();
56
+ } catch (error) {
57
+ publisher.publish("fetch/request-body-end", {
58
+ requestId,
59
+ capturedBytes: 0,
60
+ truncated: false,
61
+ captureError: renderError$1(error)
62
+ });
63
+ }
64
+ if (requestClone !== void 0) track(captureBody(requestClone.body, options.maxRequestBodyBytes, options.maxChunkBytes, controller.signal, (data) => {
65
+ publisher.publish("fetch/request-body-chunk", {
66
+ requestId,
67
+ data
68
+ });
69
+ }).then((outcome) => {
70
+ publisher.publish("fetch/request-body-end", compactOutcome(requestId, outcome));
71
+ }));
72
+ let response;
73
+ try {
74
+ response = await Reflect.apply(original, globalThis, [request]);
75
+ } catch (error) {
76
+ publisher.publish("fetch/error", {
77
+ requestId,
78
+ message: renderError$1(error),
79
+ canceled: request.signal.aborted || isAbortError(error)
80
+ });
81
+ throw error;
82
+ }
83
+ publisher.publish("fetch/response", {
84
+ requestId,
85
+ url: response.url || request.url,
86
+ status: response.status,
87
+ statusText: response.statusText,
88
+ headers: headerEntries(response.headers),
89
+ mimeType: response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() ?? ""
90
+ });
91
+ try {
92
+ track(captureBody(response.clone().body, options.maxResponseBodyBytes, options.maxChunkBytes, controller.signal, (data) => {
93
+ publisher.publish("fetch/response-body-chunk", {
94
+ requestId,
95
+ data
96
+ });
97
+ }).then((outcome) => {
98
+ publisher.publish("fetch/end", {
99
+ requestId,
100
+ capturedBytes: outcome.capturedBytes,
101
+ responseBodyTruncated: outcome.truncated,
102
+ ...outcome.captureError === void 0 ? {} : { responseCaptureError: outcome.captureError }
103
+ });
104
+ }));
105
+ } catch (error) {
106
+ publisher.publish("fetch/end", {
107
+ requestId,
108
+ capturedBytes: 0,
109
+ responseBodyTruncated: false,
110
+ responseCaptureError: renderError$1(error)
111
+ });
112
+ }
113
+ return response;
114
+ };
115
+ Object.defineProperty(observedFetch, "name", {
116
+ value: original.name,
117
+ configurable: true
118
+ });
119
+ Object.defineProperty(observedFetch, "length", {
120
+ value: original.length,
121
+ configurable: true
122
+ });
123
+ Object.defineProperty(globalThis, "fetch", descriptor === void 0 ? {
124
+ value: observedFetch,
125
+ writable: true,
126
+ configurable: true
127
+ } : {
128
+ ...descriptor,
129
+ value: observedFetch
130
+ });
131
+ let stopped;
132
+ return { stop() {
133
+ if (stopped !== void 0) return stopped;
134
+ stopped = (async () => {
135
+ const current = Object.getOwnPropertyDescriptor(globalThis, "fetch");
136
+ if (current !== void 0 && "value" in current && current.value === observedFetch) if (descriptor === void 0) Reflect.deleteProperty(globalThis, "fetch");
137
+ else Object.defineProperty(globalThis, "fetch", descriptor);
138
+ controller.abort();
139
+ await Promise.allSettled([...pending]);
140
+ })();
141
+ return stopped;
142
+ } };
143
+ }
144
+ async function captureBody(body, limit, chunkLimit, signal, emit) {
145
+ if (body === null) return {
146
+ capturedBytes: 0,
147
+ truncated: false
148
+ };
149
+ const reader = body.getReader();
150
+ const abort = () => {
151
+ reader.cancel(signal.reason).catch(() => void 0);
152
+ };
153
+ signal.addEventListener("abort", abort, { once: true });
154
+ let capturedBytes = 0;
155
+ let truncated = false;
156
+ try {
157
+ while (!signal.aborted) {
158
+ const item = await reader.read();
159
+ if (item.done) break;
160
+ let offset = 0;
161
+ while (offset < item.value.byteLength) {
162
+ const remaining = limit - capturedBytes;
163
+ if (remaining <= 0) {
164
+ truncated = true;
165
+ reader.cancel("inspector body capture limit reached").catch(() => void 0);
166
+ return {
167
+ capturedBytes,
168
+ truncated
169
+ };
170
+ }
171
+ const size = Math.min(chunkLimit, remaining, item.value.byteLength - offset);
172
+ const chunk = item.value.subarray(offset, offset + size);
173
+ emit(Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength).toString("base64"));
174
+ capturedBytes += size;
175
+ offset += size;
176
+ }
177
+ }
178
+ if (signal.aborted) {
179
+ reader.cancel(signal.reason).catch(() => void 0);
180
+ return {
181
+ capturedBytes,
182
+ truncated,
183
+ captureError: "inspector stopped during body capture"
184
+ };
185
+ }
186
+ return {
187
+ capturedBytes,
188
+ truncated
189
+ };
190
+ } catch (error) {
191
+ return {
192
+ capturedBytes,
193
+ truncated: true,
194
+ captureError: renderError$1(error)
195
+ };
196
+ } finally {
197
+ signal.removeEventListener("abort", abort);
198
+ reader.releaseLock();
199
+ }
200
+ }
201
+ function compactOutcome(requestId, outcome) {
202
+ return {
203
+ requestId,
204
+ capturedBytes: outcome.capturedBytes,
205
+ truncated: outcome.truncated,
206
+ ...outcome.captureError === void 0 ? {} : { captureError: outcome.captureError }
207
+ };
208
+ }
209
+ function headerEntries(headers) {
210
+ return [...headers.entries()];
211
+ }
212
+ function isAbortError(error) {
213
+ return error instanceof DOMException && error.name === "AbortError";
214
+ }
215
+ function renderError$1(error) {
216
+ if (error instanceof Error) return `${error.name}: ${error.message}`;
217
+ try {
218
+ return String(error);
219
+ } catch {
220
+ return "unrenderable fetch error";
221
+ }
222
+ }
223
+ //#endregion
224
+ //#region lib/types/shared/identity.js
225
+ /** Shared branded-identifier construction without assigning protocol ownership. */
226
+ /**
227
+ * Validate and brand a non-empty identifier received from or sent across a runtime boundary.
228
+ * @param value - Untrusted identifier text.
229
+ * @param label - Field name used in validation errors.
230
+ * @returns The role-branded identifier.
231
+ */
232
+ function inspectorId(value, label) {
233
+ if (value.length === 0 || value.length > 256) throw new Error(`inspector protocol: ${label} must contain 1 to 256 characters`);
234
+ return value;
235
+ }
236
+ //#endregion
237
+ //#region lib/types/shared/json.js
238
+ /** JSON values admitted by every Inspector cross-realm message. */
239
+ /**
240
+ * Test that a value can cross both MessagePort and JSON WebSocket carriers without coercion.
241
+ * @param value - Candidate wire value.
242
+ * @returns Whether the value is lossless JSON data.
243
+ */
244
+ function isJsonValue(value) {
245
+ return visitJson(value, /* @__PURE__ */ new Set());
246
+ }
247
+ /**
248
+ * Compute the UTF-8 byte length of a JSON wire value.
249
+ * @param value - Validated JSON value.
250
+ * @returns Its encoded byte length.
251
+ */
252
+ function jsonByteLength(value) {
253
+ return new TextEncoder().encode(JSON.stringify(value)).byteLength;
254
+ }
255
+ /**
256
+ * Test whether a value is a plain object with string own keys.
257
+ * @param value - Candidate object.
258
+ * @returns Whether the value has `Object.prototype` or a null prototype.
259
+ */
260
+ function isPlainObject(value) {
261
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
262
+ const prototype = Reflect.getPrototypeOf(value);
263
+ return prototype === Object.prototype || prototype === null;
264
+ }
265
+ function visitJson(value, ancestors) {
266
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
267
+ if (typeof value === "number") return Number.isFinite(value) && !Object.is(value, -0);
268
+ if (typeof value !== "object" || ancestors.has(value)) return false;
269
+ ancestors.add(value);
270
+ try {
271
+ if (Array.isArray(value)) {
272
+ if (Object.getPrototypeOf(value) !== Array.prototype || Reflect.ownKeys(value).length !== value.length + 1) return false;
273
+ return value.every((item) => visitJson(item, ancestors));
274
+ }
275
+ if (!isPlainObject(value)) return false;
276
+ for (const key of Reflect.ownKeys(value)) {
277
+ if (typeof key !== "string") return false;
278
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
279
+ if (descriptor?.enumerable !== true || !("value" in descriptor) || !visitJson(descriptor.value, ancestors)) return false;
280
+ }
281
+ return true;
282
+ } finally {
283
+ ancestors.delete(value);
284
+ }
285
+ }
286
+ //#endregion
287
+ //#region lib/types/shared/validation.js
288
+ /** Shared exact-object readers for versioned Inspector wire protocols. */
289
+ /**
290
+ * Require a plain object containing only the listed fields.
291
+ * @param value - Candidate object.
292
+ * @param keys - Complete field allowlist.
293
+ * @param label - Object name used in validation errors.
294
+ * @returns The validated plain object.
295
+ */
296
+ function exactObject(value, keys, label) {
297
+ if (!isPlainObject(value)) throw new Error(`inspector protocol: ${label} must be an object`);
298
+ exactKeys(value, keys, label);
299
+ return value;
300
+ }
301
+ /**
302
+ * Reject fields outside one versioned object's declared field set.
303
+ * @param value - Plain object being validated.
304
+ * @param keys - Complete field allowlist.
305
+ * @param label - Object name used in validation errors.
306
+ */
307
+ function exactKeys(value, keys, label) {
308
+ const allowed = new Set(keys);
309
+ for (const key of Reflect.ownKeys(value)) if (typeof key !== "string" || !allowed.has(key)) throw new Error(`inspector protocol: ${label} has unknown field ${JSON.stringify(String(key))}`);
310
+ }
311
+ /**
312
+ * Read one non-empty opaque identifier.
313
+ * @param value - Candidate identifier.
314
+ * @param label - Field name used in validation errors.
315
+ * @returns The role-branded identifier.
316
+ */
317
+ function wireId(value, label) {
318
+ if (typeof value !== "string") throw new Error(`inspector protocol: ${label} must be a string`);
319
+ return inspectorId(value, label);
320
+ }
321
+ /**
322
+ * Read one optional string field.
323
+ * @param value - Object containing the field.
324
+ * @param key - Field name.
325
+ * @returns An empty object or the validated field.
326
+ */
327
+ function optionalString(value, key) {
328
+ const item = value[key];
329
+ if (item === void 0) return {};
330
+ if (typeof item !== "string") throw new Error(`inspector protocol: ${key} must be a string`);
331
+ return { [key]: item };
332
+ }
333
+ /**
334
+ * Read one optional boolean field.
335
+ * @param value - Object containing the field.
336
+ * @param key - Field name.
337
+ * @returns An empty object or the validated field.
338
+ */
339
+ function optionalBoolean(value, key) {
340
+ const item = value[key];
341
+ if (item === void 0) return {};
342
+ if (typeof item !== "boolean") throw new Error(`inspector protocol: ${key} must be a boolean`);
343
+ return { [key]: item };
344
+ }
345
+ /**
346
+ * Read one optional non-negative finite number field.
347
+ * @param value - Object containing the field.
348
+ * @param key - Field name.
349
+ * @returns An empty object or the validated field.
350
+ */
351
+ function optionalNonNegativeNumber(value, key) {
352
+ const item = value[key];
353
+ if (item === void 0) return {};
354
+ if (typeof item !== "number" || !Number.isFinite(item) || item < 0) throw new Error(`inspector protocol: ${key} must be a non-negative finite number`);
355
+ return { [key]: item };
356
+ }
357
+ //#endregion
358
+ //#region lib/types/shared/bridge/messages/runtime/console-frames.js
359
+ /**
360
+ * Parse a Worker-to-Client Console lifecycle frame.
361
+ * @param value - Untrusted decoded frame.
362
+ * @returns A validated enable or disable frame.
363
+ */
364
+ function parseClientConsoleControlFrame(value) {
365
+ exactKeys(value, [
366
+ "v",
367
+ "t",
368
+ "sourceId",
369
+ "generation",
370
+ "sessionId"
371
+ ], "Client Console control frame");
372
+ if (value.v !== 0 || value.t !== "client-console/enable" && value.t !== "client-console/disable") throw new Error("inspector protocol: invalid Client Console control frame");
373
+ return {
374
+ v: 0,
375
+ t: value.t,
376
+ sourceId: wireId(value.sourceId, "sourceId"),
377
+ generation: wireId(value.generation, "generation"),
378
+ sessionId: wireId(value.sessionId, "sessionId")
379
+ };
380
+ }
381
+ //#endregion
382
+ //#region lib/types/shared/bridge/messages/runtime/command-codec.js
383
+ /** Exact wire decoder for Client Runtime commands. */
384
+ /**
385
+ * Parse and rebuild one Runtime command before it enters the Client realm.
386
+ * @param value - Untrusted command value.
387
+ * @returns The validated command union member.
388
+ */
389
+ function parseClientRuntimeCommand(value) {
390
+ if (!isPlainObject(value) || typeof value.op !== "string") throw new Error("inspector protocol: Client Runtime command must have an op");
391
+ switch (value.op) {
392
+ case "evaluate":
393
+ exactKeys(value, [
394
+ "op",
395
+ "expression",
396
+ "objectGroup",
397
+ "includeCommandLineAPI",
398
+ "silent",
399
+ "returnByValue",
400
+ "generatePreview",
401
+ "userGesture",
402
+ "awaitPromise",
403
+ "disableBreaks",
404
+ "replMode",
405
+ "allowUnsafeEvalBlockedByCSP",
406
+ "timeoutMs"
407
+ ], "evaluate command");
408
+ if (typeof value.expression !== "string") throw new Error("inspector protocol: evaluate expression must be a string");
409
+ return {
410
+ op: "evaluate",
411
+ expression: value.expression,
412
+ ...optionalString(value, "objectGroup"),
413
+ ...optionalBoolean(value, "includeCommandLineAPI"),
414
+ ...optionalBoolean(value, "silent"),
415
+ ...optionalBoolean(value, "returnByValue"),
416
+ ...optionalBoolean(value, "generatePreview"),
417
+ ...optionalBoolean(value, "userGesture"),
418
+ ...optionalBoolean(value, "awaitPromise"),
419
+ ...optionalBoolean(value, "disableBreaks"),
420
+ ...optionalBoolean(value, "replMode"),
421
+ ...optionalBoolean(value, "allowUnsafeEvalBlockedByCSP"),
422
+ ...optionalNonNegativeNumber(value, "timeoutMs")
423
+ };
424
+ case "get-properties":
425
+ exactKeys(value, [
426
+ "op",
427
+ "handle",
428
+ "ownProperties",
429
+ "accessorPropertiesOnly",
430
+ "generatePreview",
431
+ "nonIndexedPropertiesOnly"
432
+ ], "get-properties command");
433
+ return {
434
+ op: "get-properties",
435
+ handle: wireId(value.handle, "handle"),
436
+ ...optionalBoolean(value, "ownProperties"),
437
+ ...optionalBoolean(value, "accessorPropertiesOnly"),
438
+ ...optionalBoolean(value, "generatePreview"),
439
+ ...optionalBoolean(value, "nonIndexedPropertiesOnly")
440
+ };
441
+ case "call-function": return parseCallFunction(value);
442
+ case "await-promise":
443
+ exactKeys(value, [
444
+ "op",
445
+ "promise",
446
+ "returnByValue",
447
+ "generatePreview"
448
+ ], "await-promise command");
449
+ return {
450
+ op: "await-promise",
451
+ promise: wireId(value.promise, "promise"),
452
+ ...optionalBoolean(value, "returnByValue"),
453
+ ...optionalBoolean(value, "generatePreview")
454
+ };
455
+ case "release-object":
456
+ exactKeys(value, ["op", "handle"], "release-object command");
457
+ return {
458
+ op: "release-object",
459
+ handle: wireId(value.handle, "handle")
460
+ };
461
+ case "release-object-group":
462
+ exactKeys(value, ["op", "objectGroup"], "release-object-group command");
463
+ if (typeof value.objectGroup !== "string") throw new Error("inspector protocol: objectGroup must be a string");
464
+ return {
465
+ op: "release-object-group",
466
+ objectGroup: value.objectGroup
467
+ };
468
+ case "global-lexical-scope-names":
469
+ exactKeys(value, ["op"], "global-lexical-scope-names command");
470
+ return { op: "global-lexical-scope-names" };
471
+ default: throw new Error(`inspector protocol: unknown Client Runtime command ${JSON.stringify(value.op)}`);
472
+ }
473
+ }
474
+ function parseCallFunction(value) {
475
+ exactKeys(value, [
476
+ "op",
477
+ "functionDeclaration",
478
+ "receiver",
479
+ "arguments",
480
+ "objectGroup",
481
+ "silent",
482
+ "returnByValue",
483
+ "generatePreview",
484
+ "userGesture",
485
+ "awaitPromise"
486
+ ], "call-function command");
487
+ if (typeof value.functionDeclaration !== "string") throw new Error("inspector protocol: functionDeclaration must be a string");
488
+ let args;
489
+ if (value.arguments !== void 0) {
490
+ if (!Array.isArray(value.arguments)) throw new Error("inspector protocol: call arguments must be an array");
491
+ args = value.arguments.map(parseCallArgument);
492
+ }
493
+ return {
494
+ op: "call-function",
495
+ functionDeclaration: value.functionDeclaration,
496
+ ...value.receiver === void 0 ? {} : { receiver: wireId(value.receiver, "receiver") },
497
+ ...args === void 0 ? {} : { arguments: args },
498
+ ...optionalString(value, "objectGroup"),
499
+ ...optionalBoolean(value, "silent"),
500
+ ...optionalBoolean(value, "returnByValue"),
501
+ ...optionalBoolean(value, "generatePreview"),
502
+ ...optionalBoolean(value, "userGesture"),
503
+ ...optionalBoolean(value, "awaitPromise")
504
+ };
505
+ }
506
+ function parseCallArgument(value) {
507
+ if (!isPlainObject(value) || typeof value.kind !== "string") throw new Error("inspector protocol: invalid Client Runtime call argument");
508
+ switch (value.kind) {
509
+ case "value":
510
+ exactKeys(value, ["kind", "value"], "value call argument");
511
+ if (!isJsonValue(value.value)) throw new Error("inspector protocol: call argument value must be JSON");
512
+ return {
513
+ kind: "value",
514
+ value: value.value
515
+ };
516
+ case "unserializable":
517
+ exactKeys(value, ["kind", "value"], "unserializable call argument");
518
+ if (typeof value.value !== "string") throw new Error("inspector protocol: unserializable argument must be a string");
519
+ return {
520
+ kind: "unserializable",
521
+ value: value.value
522
+ };
523
+ case "object":
524
+ exactKeys(value, ["kind", "handle"], "object call argument");
525
+ return {
526
+ kind: "object",
527
+ handle: wireId(value.handle, "handle")
528
+ };
529
+ case "undefined":
530
+ exactKeys(value, ["kind"], "undefined call argument");
531
+ return { kind: "undefined" };
532
+ default: throw new Error(`inspector protocol: unknown call argument ${JSON.stringify(value.kind)}`);
533
+ }
534
+ }
535
+ //#endregion
536
+ //#region lib/types/shared/bridge/messages/runtime/frames.js
537
+ /**
538
+ * Parse and rebuild one Worker-to-Client Runtime request.
539
+ * @param value - Untrusted request frame.
540
+ * @returns The validated request frame.
541
+ */
542
+ function parseClientRuntimeRequestFrame(value) {
543
+ exactKeys(value, [
544
+ "v",
545
+ "t",
546
+ "sourceId",
547
+ "generation",
548
+ "sessionId",
549
+ "requestId",
550
+ "command"
551
+ ], "Client Runtime request");
552
+ if (value.v !== 0 || value.t !== "client-runtime/request") throw new Error("inspector protocol: invalid Client Runtime request envelope");
553
+ return {
554
+ v: 0,
555
+ t: "client-runtime/request",
556
+ sourceId: wireId(value.sourceId, "sourceId"),
557
+ generation: wireId(value.generation, "generation"),
558
+ sessionId: wireId(value.sessionId, "sessionId"),
559
+ requestId: wireId(value.requestId, "requestId"),
560
+ command: parseClientRuntimeCommand(value.command)
561
+ };
562
+ }
563
+ /**
564
+ * Parse and rebuild one Worker-to-Client Runtime cancellation.
565
+ * @param value - Untrusted cancellation frame.
566
+ * @returns The validated cancellation frame.
567
+ */
568
+ function parseClientRuntimeCancelFrame(value) {
569
+ exactKeys(value, [
570
+ "v",
571
+ "t",
572
+ "sourceId",
573
+ "generation",
574
+ "sessionId",
575
+ "requestId"
576
+ ], "Client Runtime cancellation");
577
+ if (value.v !== 0 || value.t !== "client-runtime/cancel") throw new Error("inspector protocol: invalid Client Runtime cancellation envelope");
578
+ return {
579
+ v: 0,
580
+ t: "client-runtime/cancel",
581
+ sourceId: wireId(value.sourceId, "sourceId"),
582
+ generation: wireId(value.generation, "generation"),
583
+ sessionId: wireId(value.sessionId, "sessionId"),
584
+ requestId: wireId(value.requestId, "requestId")
585
+ };
586
+ }
587
+ /**
588
+ * Parse and rebuild one Worker acknowledgement for a Client Runtime response.
589
+ * @param value - Untrusted acknowledgement frame.
590
+ * @returns The validated acknowledgement frame.
591
+ */
592
+ function parseClientRuntimeResponseAcknowledgedFrame(value) {
593
+ exactKeys(value, [
594
+ "v",
595
+ "t",
596
+ "sourceId",
597
+ "generation",
598
+ "sessionId",
599
+ "requestId"
600
+ ], "Client Runtime response acknowledgement");
601
+ if (value.v !== 0 || value.t !== "client-runtime/response-acknowledged") throw new Error("inspector protocol: invalid Client Runtime response acknowledgement envelope");
602
+ return {
603
+ v: 0,
604
+ t: "client-runtime/response-acknowledged",
605
+ sourceId: wireId(value.sourceId, "sourceId"),
606
+ generation: wireId(value.generation, "generation"),
607
+ sessionId: wireId(value.sessionId, "sessionId"),
608
+ requestId: wireId(value.requestId, "requestId")
609
+ };
610
+ }
611
+ /**
612
+ * Parse and rebuild one Runtime-session cleanup notification.
613
+ * @param value - Untrusted cleanup frame.
614
+ * @returns The validated cleanup frame.
615
+ */
616
+ function parseClientRuntimeSessionClosedFrame(value) {
617
+ exactKeys(value, [
618
+ "v",
619
+ "t",
620
+ "sourceId",
621
+ "generation",
622
+ "sessionId"
623
+ ], "Client Runtime session close");
624
+ if (value.v !== 0 || value.t !== "client-runtime/session-closed") throw new Error("inspector protocol: invalid Client Runtime session close envelope");
625
+ return {
626
+ v: 0,
627
+ t: "client-runtime/session-closed",
628
+ sourceId: wireId(value.sourceId, "sourceId"),
629
+ generation: wireId(value.generation, "generation"),
630
+ sessionId: wireId(value.sessionId, "sessionId")
631
+ };
632
+ }
633
+ //#endregion
634
+ //#region lib/types/shared/bridge/messages/sources/codec.js
635
+ /** Exact decoders for Client source catalog operations and values. */
636
+ /**
637
+ * Parse one Worker-to-Client source command.
638
+ * @param value - Untrusted decoded command.
639
+ * @returns The validated command.
640
+ */
641
+ function parseClientSourceCommand(value) {
642
+ if (!isPlainObject(value) || typeof value.op !== "string") throw new Error("inspector protocol: Client source command must have an op");
643
+ if (value.op === "list-scripts") {
644
+ exactKeys(value, ["op"], "Client source list command");
645
+ return { op: "list-scripts" };
646
+ }
647
+ if (value.op !== "get-content-chunk") throw new Error(`inspector protocol: unknown Client source command ${JSON.stringify(value.op)}`);
648
+ exactKeys(value, [
649
+ "op",
650
+ "scriptKey",
651
+ "content",
652
+ "offset",
653
+ "maxBytes"
654
+ ], "Client source chunk command");
655
+ return {
656
+ op: "get-content-chunk",
657
+ scriptKey: wireId(value.scriptKey, "scriptKey"),
658
+ content: contentKind(value.content),
659
+ offset: natural$3(value.offset, "offset", true),
660
+ maxBytes: natural$3(value.maxBytes, "maxBytes", false)
661
+ };
662
+ }
663
+ function contentKind(value) {
664
+ if (value !== "source" && value !== "source-map") throw new Error("inspector protocol: invalid Client source content kind");
665
+ return value;
666
+ }
667
+ function natural$3(value, label, zero) {
668
+ if (!Number.isSafeInteger(value) || value < (zero ? 0 : 1)) throw new Error(`inspector protocol: ${label} must be ${zero ? "a non-negative" : "a positive"} integer`);
669
+ return value;
670
+ }
671
+ //#endregion
672
+ //#region lib/types/shared/bridge/messages/sources/frames.js
673
+ /**
674
+ * Parse one Worker-to-Client source request.
675
+ * @param value - Untrusted decoded request.
676
+ * @returns The validated request frame.
677
+ */
678
+ function parseClientSourceRequestFrame(value) {
679
+ exactKeys(value, [
680
+ "v",
681
+ "t",
682
+ "sourceId",
683
+ "generation",
684
+ "sessionId",
685
+ "requestId",
686
+ "command"
687
+ ], "Client source request");
688
+ if (value.v !== 0 || value.t !== "client-sources/request") throw new Error("inspector protocol: invalid Client source request envelope");
689
+ return {
690
+ v: 0,
691
+ t: "client-sources/request",
692
+ sourceId: wireId(value.sourceId, "sourceId"),
693
+ generation: wireId(value.generation, "generation"),
694
+ sessionId: wireId(value.sessionId, "sessionId"),
695
+ requestId: wireId(value.requestId, "requestId"),
696
+ command: parseClientSourceCommand(value.command)
697
+ };
698
+ }
699
+ /**
700
+ * Parse one Client source-session cleanup notification.
701
+ * @param value - Untrusted decoded notification.
702
+ * @returns The validated cleanup frame.
703
+ */
704
+ function parseClientSourceSessionClosedFrame(value) {
705
+ exactKeys(value, [
706
+ "v",
707
+ "t",
708
+ "sourceId",
709
+ "generation",
710
+ "sessionId"
711
+ ], "Client source session close");
712
+ if (value.v !== 0 || value.t !== "client-sources/session-closed") throw new Error("inspector protocol: invalid Client source session close envelope");
713
+ return {
714
+ v: 0,
715
+ t: "client-sources/session-closed",
716
+ sourceId: wireId(value.sourceId, "sourceId"),
717
+ generation: wireId(value.generation, "generation"),
718
+ sessionId: wireId(value.sessionId, "sessionId")
719
+ };
720
+ }
721
+ //#endregion
722
+ //#region lib/types/shared/bridge/messages/observation.js
723
+ /** Versioned source lifecycle, observation, and extension frames shared by both carriers. */
724
+ /**
725
+ * Parse and rebuild one Worker control frame received by a source.
726
+ * @param value - Untrusted decoded wire value.
727
+ * @returns The validated Worker-to-source frame.
728
+ */
729
+ function parseWorkerSourceFrame(value) {
730
+ if (!isJsonValue(value) || !isPlainObject(value) || value.v !== 0 || typeof value.t !== "string") throw new Error("inspector protocol: invalid Worker source frame");
731
+ if (value.t === "source/rejected") {
732
+ exactKeys(value, [
733
+ "v",
734
+ "t",
735
+ "code",
736
+ "message"
737
+ ], "source/rejected frame");
738
+ if (value.code !== "invalid-frame" && value.code !== "version-mismatch" && value.code !== "unauthorized" || typeof value.message !== "string") throw new Error("inspector protocol: invalid source/rejected frame");
739
+ return {
740
+ v: 0,
741
+ t: "source/rejected",
742
+ code: value.code,
743
+ message: value.message
744
+ };
745
+ }
746
+ if (value.t === "client-runtime/request") return parseClientRuntimeRequestFrame(value);
747
+ if (value.t === "client-runtime/cancel") return parseClientRuntimeCancelFrame(value);
748
+ if (value.t === "client-runtime/response-acknowledged") return parseClientRuntimeResponseAcknowledgedFrame(value);
749
+ if (value.t === "client-runtime/session-closed") return parseClientRuntimeSessionClosedFrame(value);
750
+ if (value.t === "client-sources/request") return parseClientSourceRequestFrame(value);
751
+ if (value.t === "client-sources/session-closed") return parseClientSourceSessionClosedFrame(value);
752
+ if (value.t === "client-console/enable" || value.t === "client-console/disable") return parseClientConsoleControlFrame(value);
753
+ const common = {
754
+ v: 0,
755
+ sourceId: sourceId(value.sourceId),
756
+ generation: generation(value.generation)
757
+ };
758
+ if (value.t === "source/accepted") {
759
+ exactKeys(value, [
760
+ "v",
761
+ "t",
762
+ "sourceId",
763
+ "generation"
764
+ ], "source/accepted frame");
765
+ return {
766
+ ...common,
767
+ t: "source/accepted"
768
+ };
769
+ }
770
+ if (value.t === "source/append-acknowledged") {
771
+ exactKeys(value, [
772
+ "v",
773
+ "t",
774
+ "sourceId",
775
+ "generation",
776
+ "nextSequence"
777
+ ], "source append acknowledgement");
778
+ return {
779
+ ...common,
780
+ t: "source/append-acknowledged",
781
+ nextSequence: natural$2(value.nextSequence, "nextSequence")
782
+ };
783
+ }
784
+ if (value.t === "source/resnapshot" && typeof value.reason === "string") {
785
+ exactKeys(value, [
786
+ "v",
787
+ "t",
788
+ "sourceId",
789
+ "generation",
790
+ "expectedSequence",
791
+ "reason"
792
+ ], "source/resnapshot frame");
793
+ return {
794
+ ...common,
795
+ t: "source/resnapshot",
796
+ expectedSequence: natural$2(value.expectedSequence, "expectedSequence"),
797
+ reason: value.reason
798
+ };
799
+ }
800
+ throw new Error(`inspector protocol: unknown Worker source frame ${JSON.stringify(value.t)}`);
801
+ }
802
+ function sourceId(value) {
803
+ if (typeof value !== "string") throw new Error("inspector protocol: sourceId must be a string");
804
+ return inspectorId(value, "sourceId");
805
+ }
806
+ function generation(value) {
807
+ if (typeof value !== "string") throw new Error("inspector protocol: generation must be a string");
808
+ return inspectorId(value, "generation");
809
+ }
810
+ function natural$2(value, label) {
811
+ if (!Number.isSafeInteger(value) || value < 0) throw new Error(`inspector protocol: ${label} must be a non-negative safe integer`);
812
+ return value;
813
+ }
814
+ //#endregion
815
+ //#region lib/types/shared/bridge/publisher.js
816
+ /** Source-side interfaces shared by MessagePort and WebSocket bridge implementations. */
817
+ /** Shared observation and query delegation inherited by both source transports. */
818
+ var InspectorSourceConnection = class {
819
+ /** Publish one JSON observation without waiting on its carrier. */
820
+ publish(topic, payload, monotonicMs = performance.now()) {
821
+ this.publisher.publish(topic, payload, monotonicMs);
822
+ }
823
+ /** Retain and publish one state value for reconnect or replacement recovery. */
824
+ setState(topic, payload, monotonicMs = performance.now()) {
825
+ this.publisher.setState(topic, payload, monotonicMs);
826
+ }
827
+ /** Execute one non-CDP query through the active source generation. */
828
+ request(query) {
829
+ return this.queries.request(query);
830
+ }
831
+ };
832
+ /**
833
+ * Reject a Client Console control frame that was routed to the Host source.
834
+ * @param operation - Misrouted Console frame type.
835
+ * @returns This function never returns.
836
+ */
837
+ function rejectConsoleBridgeCommand(operation) {
838
+ throw new Error(`inspector protocol: ${operation} cannot use the Host source bridge`);
839
+ }
840
+ //#endregion
841
+ //#region lib/types/host/cdp/stack.js
842
+ /** Host stack and call-frame data remain owned by the Worker-side Node inspector session. */
843
+ /** Stable explanation used for Host bridge rejections. */
844
+ const HOST_CDP_BRIDGE_REASON = "Host Runtime is attached directly from the Inspector Worker";
845
+ //#endregion
846
+ //#region lib/types/host/cdp/errors.js
847
+ /** Explicit failure for Client-style CDP bridge commands misrouted to the Host. */
848
+ /** Host Runtime uses the Worker-side Node inspector session instead of source RPC. */
849
+ var HostCdpBridgeUnavailableError = class extends Error {
850
+ constructor(operation) {
851
+ super(`inspector protocol: ${operation} cannot use the Host source bridge; ${HOST_CDP_BRIDGE_REASON}`);
852
+ }
853
+ };
854
+ //#endregion
855
+ //#region lib/types/host/cdp/objects.js
856
+ /** Host RemoteObject handles never cross the Host source bridge. */
857
+ /**
858
+ * Reject an object operation that must use the Worker-owned native inspector session.
859
+ * @param operation - Misrouted object operation.
860
+ * @returns This function never returns.
861
+ */
862
+ function rejectObjectBridgeOperation(operation) {
863
+ throw new HostCdpBridgeUnavailableError(operation);
864
+ }
865
+ //#endregion
866
+ //#region lib/types/host/cdp/properties.js
867
+ /** Host property enumeration never crosses the Host source bridge. */
868
+ /**
869
+ * Reject a property request that must use the Worker-owned native inspector session.
870
+ * @returns This function never returns.
871
+ */
872
+ function rejectPropertyBridgeOperation() {
873
+ return rejectObjectBridgeOperation("client-runtime/get-properties");
874
+ }
875
+ /**
876
+ * Reject a Client Runtime command that was routed to the Host source.
877
+ * @param command - Misrouted Client Runtime operation.
878
+ * @returns This function never returns.
879
+ */
880
+ function rejectRuntimeBridgeCommand(command) {
881
+ switch (command.op) {
882
+ case "get-properties": return rejectPropertyBridgeOperation();
883
+ case "release-object":
884
+ case "release-object-group": return rejectObjectBridgeOperation(`client-runtime/${command.op}`);
885
+ case "evaluate":
886
+ case "call-function":
887
+ case "await-promise":
888
+ case "global-lexical-scope-names": throw new HostCdpBridgeUnavailableError(`client-runtime/${command.op}`);
889
+ default: return assertNever$1(command);
890
+ }
891
+ }
892
+ function assertNever$1(value) {
893
+ throw new Error(`Unexpected Host Runtime bridge command: ${JSON.stringify(value)}`);
894
+ }
895
+ /**
896
+ * Reject a Client Sources request that was routed to the Host source.
897
+ * @returns This function never returns.
898
+ */
899
+ function rejectSourcesBridgeCommand() {
900
+ throw new Error("inspector protocol: Client Sources cannot use the Host source bridge");
901
+ }
902
+ //#endregion
903
+ //#region lib/types/host/cdp/index.js
904
+ /** Source-side CDP capability declarations for the Host realm. */
905
+ const HOST_BRIDGE_CAPABILITIES = [
906
+ void 0,
907
+ void 0,
908
+ void 0,
909
+ void 0,
910
+ void 0,
911
+ void 0
912
+ ].filter((capability) => capability !== void 0);
913
+ /**
914
+ * Collect Host source-bridge capabilities.
915
+ * @param _origin - Unused Host origin supplied for parity with the Client adapter.
916
+ * @param _hasSources - Unused source availability supplied for parity with the Client adapter.
917
+ * @returns No capabilities because the Worker attaches to Host V8 directly.
918
+ */
919
+ function bridgeCapabilities(_origin, _hasSources) {
920
+ return HOST_BRIDGE_CAPABILITIES;
921
+ }
922
+ //#endregion
923
+ //#region lib/types/host/inspection/realm.js
924
+ /** Stable descriptor for the Host observation source generation. */
925
+ /**
926
+ * Create the descriptor for one Host-to-Worker MessagePort generation.
927
+ * @param label - Human-readable Host execution-context label.
928
+ * @returns The complete Host source descriptor.
929
+ */
930
+ function createHostRealmSource(label) {
931
+ return {
932
+ sourceId: inspectorId(`host-${randomUUID()}`, "sourceId"),
933
+ generation: inspectorId(randomUUID(), "generation"),
934
+ kind: "host",
935
+ label,
936
+ timeOriginMs: performance.timeOrigin,
937
+ capabilities: bridgeCapabilities("", false)
938
+ };
939
+ }
940
+ //#endregion
941
+ //#region lib/types/shared/bridge/buffer.js
942
+ /** Realm-neutral bounded buffering for Host and Client observation sources. */
943
+ const SOURCE_FRAME_OVERHEAD_BYTES = 4096;
944
+ /**
945
+ * Owns retained state, queued events, and source-local sequencing independently
946
+ * of whether frames travel over MessagePort or WebSocket.
947
+ */
948
+ var InspectorSourceBuffer = class {
949
+ options;
950
+ queue = [];
951
+ state = /* @__PURE__ */ new Map();
952
+ queuedBytes = 0;
953
+ nextSequence = 1;
954
+ expectedSequence = 1;
955
+ constructor(options) {
956
+ this.options = options;
957
+ }
958
+ /** Whether at least one observation is waiting for transport. */
959
+ get hasPending() {
960
+ return this.queue.length > 0;
961
+ }
962
+ /**
963
+ * Validate and enqueue one observation, dropping the oldest prefix as needed.
964
+ * A record larger than one transport frame is dropped after consuming its sequence number.
965
+ * @param topic - Declared domain topic.
966
+ * @param payload - Lossless JSON payload.
967
+ * @param monotonicMs - Finite source-clock timestamp.
968
+ */
969
+ publish(topic, payload, monotonicMs) {
970
+ this.enqueue(this.record(topic, payload, monotonicMs));
971
+ }
972
+ /**
973
+ * Replace one retained topic and enqueue the same observation for live delivery.
974
+ * @param topic - Declared state topic.
975
+ * @param payload - Lossless JSON payload retained for replacement frames.
976
+ * @param monotonicMs - Finite source-clock timestamp.
977
+ */
978
+ setState(topic, payload, monotonicMs) {
979
+ const record = this.record(topic, payload, monotonicMs);
980
+ const previous = this.state.get(topic);
981
+ this.state.set(topic, record);
982
+ if (!this.stateFits()) {
983
+ if (previous === void 0) this.state.delete(topic);
984
+ else this.state.set(topic, previous);
985
+ throw new Error("inspector: source state exceeds the source-frame byte limit");
986
+ }
987
+ this.enqueue(record);
988
+ }
989
+ /**
990
+ * Build a complete state replacement and absorb every preceding queue drop.
991
+ * @param sourceId - Logical source identity.
992
+ * @param generation - Current transport generation.
993
+ * @returns A replacement frame whose sequence is the next append position.
994
+ */
995
+ replacement(sourceId, generation) {
996
+ const nextSequence = this.queue[0]?.sequence ?? this.nextSequence;
997
+ this.expectedSequence = nextSequence;
998
+ return {
999
+ v: 0,
1000
+ t: "source/replace",
1001
+ sourceId,
1002
+ generation,
1003
+ nextSequence,
1004
+ records: [...this.state.values()]
1005
+ };
1006
+ }
1007
+ /**
1008
+ * Remove and sequence the next transport-sized observation batch.
1009
+ * @param sourceId - Logical source identity.
1010
+ * @param generation - Current transport generation.
1011
+ * @returns The next append frame, or `undefined` when the queue is empty.
1012
+ */
1013
+ takeBatch(sourceId, generation) {
1014
+ if (this.queue.length === 0) return void 0;
1015
+ const batch = [];
1016
+ let batchBytes = SOURCE_FRAME_OVERHEAD_BYTES;
1017
+ const first = this.queue[0];
1018
+ while (batch.length < this.options.maxRecordsPerFrame && this.queue.length > 0) {
1019
+ const candidate = this.queue[0];
1020
+ if (candidate.sequence !== first.sequence + batch.length) break;
1021
+ if (batch.length > 0 && batchBytes + candidate.bytes > this.options.maxFrameBytes) break;
1022
+ this.queue.shift();
1023
+ batch.push(candidate);
1024
+ batchBytes += candidate.bytes;
1025
+ }
1026
+ this.queuedBytes -= batch.reduce((sum, item) => sum + item.bytes, 0);
1027
+ const firstSequence = first.sequence;
1028
+ const frame = {
1029
+ v: 0,
1030
+ t: "source/append",
1031
+ sourceId,
1032
+ generation,
1033
+ firstSequence,
1034
+ droppedBefore: firstSequence - this.expectedSequence,
1035
+ records: batch.map((item) => item.record)
1036
+ };
1037
+ this.expectedSequence = firstSequence + frame.records.length;
1038
+ return frame;
1039
+ }
1040
+ /** Discard observations that have not entered a transport frame. */
1041
+ discardPending() {
1042
+ this.queue.length = 0;
1043
+ this.queuedBytes = 0;
1044
+ }
1045
+ record(topic, payload, monotonicMs) {
1046
+ if (topic.length === 0 || topic.length > 128) throw new Error("inspector: topic must contain 1 to 128 characters");
1047
+ if (!this.options.topics.includes("*") && !this.options.topics.includes(topic)) throw new Error(`inspector: source does not declare topic ${JSON.stringify(topic)}`);
1048
+ if (!isJsonValue(payload)) throw new Error("inspector: source payload must be lossless JSON data");
1049
+ if (!Number.isFinite(monotonicMs)) throw new Error("inspector: monotonicMs must be finite");
1050
+ return {
1051
+ monotonicMs,
1052
+ topic,
1053
+ payload
1054
+ };
1055
+ }
1056
+ enqueue(record) {
1057
+ const bytes = jsonByteLength(record);
1058
+ const sequence = this.nextSequence++;
1059
+ if (bytes + SOURCE_FRAME_OVERHEAD_BYTES > this.options.maxFrameBytes) return;
1060
+ this.queue.push({
1061
+ sequence,
1062
+ bytes,
1063
+ record
1064
+ });
1065
+ this.queuedBytes += bytes;
1066
+ while (this.queue.length > this.options.maxQueuedRecords || this.queuedBytes > this.options.maxQueuedBytes) {
1067
+ const dropped = this.queue.shift();
1068
+ this.queuedBytes -= dropped.bytes;
1069
+ }
1070
+ }
1071
+ stateFits() {
1072
+ return jsonByteLength([...this.state.values()]) + SOURCE_FRAME_OVERHEAD_BYTES <= this.options.maxFrameBytes;
1073
+ }
1074
+ };
1075
+ //#endregion
1076
+ //#region lib/types/host/bridge/publisher.js
1077
+ /** Buffered Host observation publication over a dedicated Worker MessagePort. */
1078
+ /** Non-blocking Host publisher with microtask-coalesced MessagePort writes. */
1079
+ var HostBridgePublisher = class {
1080
+ port;
1081
+ source;
1082
+ records;
1083
+ flushScheduled = false;
1084
+ inFlightNextSequence;
1085
+ closed = false;
1086
+ constructor(port, source, options) {
1087
+ this.port = port;
1088
+ this.source = source;
1089
+ this.records = new InspectorSourceBuffer(options);
1090
+ }
1091
+ publish(topic, payload, monotonicMs = performance.now()) {
1092
+ if (this.closed) return;
1093
+ this.records.publish(topic, payload, monotonicMs);
1094
+ this.scheduleFlush();
1095
+ }
1096
+ setState(topic, payload, monotonicMs = performance.now()) {
1097
+ if (this.closed) throw new Error("inspector: Host source is closed");
1098
+ this.records.setState(topic, payload, monotonicMs);
1099
+ this.scheduleFlush();
1100
+ }
1101
+ /** Send the retained state as a complete source replacement. */
1102
+ replace() {
1103
+ this.inFlightNextSequence = void 0;
1104
+ this.port.postMessage(this.records.replacement(this.source.sourceId, this.source.generation));
1105
+ this.scheduleFlush();
1106
+ }
1107
+ /** Send one queued batch when no earlier MessagePort batch awaits acknowledgement. */
1108
+ flush() {
1109
+ if (this.closed || this.inFlightNextSequence !== void 0) return;
1110
+ const frame = this.records.takeBatch(this.source.sourceId, this.source.generation);
1111
+ if (frame === void 0) return;
1112
+ this.port.postMessage(frame);
1113
+ this.inFlightNextSequence = frame.firstSequence + frame.records.length;
1114
+ }
1115
+ /**
1116
+ * Release one in-flight batch and schedule the next bounded transfer.
1117
+ * @param nextSequence - First sequence expected by the Worker after the accepted batch.
1118
+ */
1119
+ acknowledge(nextSequence) {
1120
+ if (this.closed || this.inFlightNextSequence === void 0) return;
1121
+ if (nextSequence !== this.inFlightNextSequence) throw new Error("inspector: Host source acknowledgement does not match the in-flight batch");
1122
+ this.inFlightNextSequence = void 0;
1123
+ this.scheduleFlush();
1124
+ }
1125
+ /** Send at most one final batch, discard later queued observations, and reject publication. */
1126
+ close() {
1127
+ if (this.closed) return;
1128
+ this.flush();
1129
+ this.closed = true;
1130
+ this.records.discardPending();
1131
+ }
1132
+ scheduleFlush() {
1133
+ if (!this.records.hasPending || this.flushScheduled) return;
1134
+ this.flushScheduled = true;
1135
+ queueMicrotask(() => {
1136
+ this.flushScheduled = false;
1137
+ this.flush();
1138
+ });
1139
+ }
1140
+ };
1141
+ /**
1142
+ * Decode a consumer-neutral tree received across an Inspector transport.
1143
+ * @param value - Untrusted query result value.
1144
+ * @returns A detached tree containing only public semantic fields.
1145
+ */
1146
+ function parseCordisRuntimeTree(value) {
1147
+ const record = exactObject(value, [
1148
+ "schemaVersion",
1149
+ "host",
1150
+ "clients"
1151
+ ], "Cordis runtime tree");
1152
+ if (record.schemaVersion !== 0 || !Array.isArray(record.clients)) throw new Error("inspector protocol: invalid Cordis runtime tree");
1153
+ const host = record.host === null ? null : parseRealm(record.host, "host");
1154
+ const clients = record.clients.map((client) => parseRealm(client, "client"));
1155
+ const sourceIds = /* @__PURE__ */ new Set();
1156
+ for (const realm of host === null ? clients : [host, ...clients]) {
1157
+ if (sourceIds.has(realm.source.sourceId)) throw new Error("inspector protocol: Cordis runtime tree repeats a sourceId");
1158
+ sourceIds.add(realm.source.sourceId);
1159
+ }
1160
+ return {
1161
+ schemaVersion: 0,
1162
+ host,
1163
+ clients
1164
+ };
1165
+ }
1166
+ function parseRealm(value, kind) {
1167
+ const record = exactObject(value, [
1168
+ "source",
1169
+ "connection",
1170
+ "revision",
1171
+ "truncated",
1172
+ "root"
1173
+ ], "Cordis runtime realm");
1174
+ const source = exactObject(record.source, [
1175
+ "sourceId",
1176
+ "kind",
1177
+ "label"
1178
+ ], "Cordis runtime source");
1179
+ if (source.kind !== kind || typeof source.label !== "string" || source.label.length === 0 || source.label.length > 256) throw new Error(`inspector protocol: invalid ${kind} Cordis runtime source`);
1180
+ if (!Number.isSafeInteger(record.revision) || record.revision < 1 || typeof record.truncated !== "boolean") throw new Error("inspector protocol: invalid Cordis runtime realm header");
1181
+ const root = parseNode(record.root, { fiberUids: /* @__PURE__ */ new Set() }, 0);
1182
+ if (root.kind !== "context") throw new Error("inspector protocol: Cordis runtime root must be a Context");
1183
+ return {
1184
+ source: {
1185
+ sourceId: wireId(source.sourceId, "sourceId"),
1186
+ kind,
1187
+ label: source.label
1188
+ },
1189
+ connection: parseConnection(record.connection),
1190
+ revision: record.revision,
1191
+ truncated: record.truncated,
1192
+ root
1193
+ };
1194
+ }
1195
+ function parseConnection(value) {
1196
+ if (!isPlainObject(value)) throw new Error("inspector protocol: Cordis runtime connection must be an object");
1197
+ if (value.state === "connected") {
1198
+ exactKeys(value, ["state"], "connected Cordis runtime connection");
1199
+ return { state: "connected" };
1200
+ }
1201
+ if (value.state === "disconnected" && typeof value.reason === "string") {
1202
+ exactKeys(value, ["state", "reason"], "disconnected Cordis runtime connection");
1203
+ return {
1204
+ state: "disconnected",
1205
+ reason: value.reason
1206
+ };
1207
+ }
1208
+ throw new Error("inspector protocol: invalid Cordis runtime connection");
1209
+ }
1210
+ function parseNode(value, state, depth) {
1211
+ if (depth > 256) throw new Error("inspector protocol: Cordis runtime tree exceeds the depth limit");
1212
+ if (!isPlainObject(value) || value.kind !== "context" && value.kind !== "fiber") throw new Error("inspector protocol: Cordis runtime node must have a known kind");
1213
+ const record = exactObject(value, value.kind === "fiber" ? [
1214
+ "kind",
1215
+ "uid",
1216
+ "children"
1217
+ ] : ["kind", "children"], "Cordis runtime node");
1218
+ if (!Array.isArray(record.children)) throw new Error("inspector protocol: Cordis runtime node children must be an array");
1219
+ if (record.kind === "context") return {
1220
+ kind: "context",
1221
+ children: record.children.map((child) => parseNode(child, state, depth + 1))
1222
+ };
1223
+ if (!Number.isSafeInteger(record.uid) || record.uid < 1 || record.children.length !== 1) throw new Error("inspector protocol: invalid Cordis runtime Fiber");
1224
+ const uid = record.uid;
1225
+ if (state.fiberUids.has(uid)) throw new Error("inspector protocol: Cordis runtime tree repeats a Fiber uid");
1226
+ state.fiberUids.add(uid);
1227
+ const context = parseNode(record.children[0], state, depth + 1);
1228
+ if (context.kind !== "context") throw new Error("inspector protocol: Cordis runtime Fiber child must be a Context");
1229
+ return {
1230
+ kind: "fiber",
1231
+ uid,
1232
+ children: [context]
1233
+ };
1234
+ }
1235
+ //#endregion
1236
+ //#region lib/types/shared/bridge/messages/query/codec.js
1237
+ /** Exact decoders for non-CDP Inspector query frames. */
1238
+ /**
1239
+ * Test whether a decoded carrier value belongs to the query response protocol.
1240
+ * @param value - Decoded carrier value.
1241
+ * @returns Whether the query response decoder owns the value.
1242
+ */
1243
+ function isInspectorQueryResponseEnvelope(value) {
1244
+ return isPlainObject(value) && value.t === "query/response";
1245
+ }
1246
+ /**
1247
+ * Decode one Worker-to-source query response.
1248
+ * @param value - Untrusted decoded carrier value.
1249
+ * @returns The detached, validated response frame.
1250
+ */
1251
+ function parseInspectorQueryResponseFrame(value) {
1252
+ const record = exactObject(value, [
1253
+ "v",
1254
+ "t",
1255
+ "sourceId",
1256
+ "generation",
1257
+ "requestId",
1258
+ "outcome"
1259
+ ], "query response");
1260
+ if (record.v !== 0 || record.t !== "query/response") throw new Error("inspector protocol: invalid query response envelope");
1261
+ return {
1262
+ v: 0,
1263
+ t: "query/response",
1264
+ sourceId: wireId(record.sourceId, "sourceId"),
1265
+ generation: wireId(record.generation, "generation"),
1266
+ requestId: wireId(record.requestId, "requestId"),
1267
+ outcome: parseOutcome(record.outcome)
1268
+ };
1269
+ }
1270
+ function parseResult(value) {
1271
+ if (!isPlainObject(value) || typeof value.op !== "string") throw new Error("inspector protocol: query result must have an op");
1272
+ switch (value.op) {
1273
+ case "cordis-tree/get":
1274
+ exactKeys(value, ["op", "tree"], "Cordis tree query result");
1275
+ return {
1276
+ op: "cordis-tree/get",
1277
+ tree: parseCordisRuntimeTree(value.tree)
1278
+ };
1279
+ default: throw new Error(`inspector protocol: unknown query result ${JSON.stringify(value.op)}`);
1280
+ }
1281
+ }
1282
+ function parseOutcome(value) {
1283
+ if (!isPlainObject(value) || typeof value.ok !== "boolean") throw new Error("inspector protocol: invalid query outcome");
1284
+ if (value.ok) {
1285
+ exactKeys(value, ["ok", "result"], "successful query outcome");
1286
+ return {
1287
+ ok: true,
1288
+ result: parseResult(value.result)
1289
+ };
1290
+ }
1291
+ exactKeys(value, ["ok", "error"], "failed query outcome");
1292
+ const error = exactObject(value.error, ["code", "message"], "query error");
1293
+ if (!QUERY_ERROR_CODES.has(error.code) || typeof error.message !== "string") throw new Error("inspector protocol: invalid query error");
1294
+ return {
1295
+ ok: false,
1296
+ error: {
1297
+ code: error.code,
1298
+ message: error.message
1299
+ }
1300
+ };
1301
+ }
1302
+ const QUERY_ERROR_CODES = new Set([
1303
+ "invalid-request",
1304
+ "stale-source",
1305
+ "result-too-large",
1306
+ "internal-error"
1307
+ ]);
1308
+ //#endregion
1309
+ //#region lib/types/shared/bridge/rpc.js
1310
+ /** Shared Host/Client owner of correlated non-CDP query requests. */
1311
+ /** Failure deliberately returned by the Worker query handler. */
1312
+ var InspectorQueryRemoteError = class extends Error {
1313
+ code;
1314
+ constructor(code, message) {
1315
+ super(message);
1316
+ this.code = code;
1317
+ }
1318
+ };
1319
+ /** Correlates requests for one reconnecting Host or Client source. */
1320
+ var InspectorQueryConnection = class {
1321
+ options;
1322
+ pending = /* @__PURE__ */ new Map();
1323
+ active;
1324
+ nextRequestId = 0;
1325
+ closed = false;
1326
+ constructor(options) {
1327
+ this.options = options;
1328
+ }
1329
+ /**
1330
+ * Admit the source generation acknowledged by the Worker.
1331
+ * @param sourceId - Stable source identity.
1332
+ * @param generation - Newly accepted transport generation.
1333
+ * @param sender - Carrier writer valid for that generation.
1334
+ */
1335
+ connect(sourceId, generation, sender) {
1336
+ if (this.closed) throw new Error("inspector query connection is closed");
1337
+ this.disconnect("Inspector source generation replaced");
1338
+ this.active = {
1339
+ sourceId,
1340
+ generation,
1341
+ sender
1342
+ };
1343
+ }
1344
+ /**
1345
+ * Execute a query against the currently accepted source generation.
1346
+ * @param query - Closed typed query command.
1347
+ * @returns The result with the same operation discriminant.
1348
+ */
1349
+ request(query) {
1350
+ const active = this.active;
1351
+ if (this.closed || active === void 0) return Promise.reject(/* @__PURE__ */ new Error("Inspector query transport is not connected"));
1352
+ const requestId = inspectorId(`query-${String(++this.nextRequestId)}`, "requestId");
1353
+ const frame = {
1354
+ v: 0,
1355
+ t: "query/request",
1356
+ sourceId: active.sourceId,
1357
+ generation: active.generation,
1358
+ requestId,
1359
+ query
1360
+ };
1361
+ if (jsonByteLength(frame) > this.options.maxFrameBytes) return Promise.reject(/* @__PURE__ */ new Error(`Inspector query request exceeds ${String(this.options.maxFrameBytes)} bytes`));
1362
+ return new Promise((resolve, reject) => {
1363
+ const timer = setTimeout(() => {
1364
+ this.pending.delete(requestId);
1365
+ reject(/* @__PURE__ */ new Error(`Inspector query ${query.op} timed out after ${String(this.options.timeoutMs)}ms`));
1366
+ }, this.options.timeoutMs);
1367
+ this.pending.set(requestId, {
1368
+ op: query.op,
1369
+ resolve,
1370
+ reject,
1371
+ timer
1372
+ });
1373
+ try {
1374
+ active.sender.send(frame);
1375
+ } catch (error) {
1376
+ this.rejectPending(requestId, renderError(error));
1377
+ }
1378
+ });
1379
+ }
1380
+ /**
1381
+ * Consume a decoded carrier value when it is a query response.
1382
+ * @param value - Untrusted Worker-to-source value.
1383
+ * @returns Whether the value belonged to the query protocol.
1384
+ */
1385
+ receive(value) {
1386
+ if (!isInspectorQueryResponseEnvelope(value)) return false;
1387
+ let frame;
1388
+ try {
1389
+ frame = parseInspectorQueryResponseFrame(value);
1390
+ if (jsonByteLength(frame) > this.options.maxFrameBytes) throw new Error(`inspector protocol: query response exceeds ${String(this.options.maxFrameBytes)} bytes`);
1391
+ } catch (error) {
1392
+ this.disconnect(`Invalid Inspector query response: ${renderError(error).message}`);
1393
+ throw error;
1394
+ }
1395
+ const pending = this.pending.get(frame.requestId);
1396
+ if (pending === void 0) return true;
1397
+ const active = this.active;
1398
+ if (active === void 0 || frame.sourceId !== active.sourceId || frame.generation !== active.generation) {
1399
+ this.rejectPending(frame.requestId, /* @__PURE__ */ new Error("Inspector query response source generation does not match"));
1400
+ return true;
1401
+ }
1402
+ if (!frame.outcome.ok) {
1403
+ this.rejectPending(frame.requestId, new InspectorQueryRemoteError(frame.outcome.error.code, frame.outcome.error.message));
1404
+ return true;
1405
+ }
1406
+ if (frame.outcome.result.op !== pending.op) {
1407
+ this.rejectPending(frame.requestId, /* @__PURE__ */ new Error(`Inspector query response op ${frame.outcome.result.op} does not match ${pending.op}`));
1408
+ return true;
1409
+ }
1410
+ clearTimeout(pending.timer);
1411
+ this.pending.delete(frame.requestId);
1412
+ pending.resolve(frame.outcome.result);
1413
+ return true;
1414
+ }
1415
+ /**
1416
+ * Reject active requests while permitting a later source generation.
1417
+ * @param reason - Failure reported to every pending caller.
1418
+ */
1419
+ disconnect(reason) {
1420
+ this.active = void 0;
1421
+ for (const requestId of [...this.pending.keys()]) this.rejectPending(requestId, new Error(reason));
1422
+ }
1423
+ /**
1424
+ * Permanently reject requests and prevent later reconnection.
1425
+ * @param reason - Failure reported to every pending caller.
1426
+ */
1427
+ close(reason = "Inspector query connection closed") {
1428
+ if (this.closed) return;
1429
+ this.closed = true;
1430
+ this.disconnect(reason);
1431
+ }
1432
+ rejectPending(requestId, error) {
1433
+ const pending = this.pending.get(requestId);
1434
+ if (pending === void 0) return;
1435
+ clearTimeout(pending.timer);
1436
+ this.pending.delete(requestId);
1437
+ pending.reject(error);
1438
+ }
1439
+ };
1440
+ function renderError(error) {
1441
+ return error instanceof Error ? error : new Error(String(error));
1442
+ }
1443
+ //#endregion
1444
+ //#region lib/types/host/bridge/rpc.js
1445
+ /** Host-side non-CDP query bridge over the Worker MessagePort. */
1446
+ /** Owns query correlation for one Host source generation. */
1447
+ var HostBridgeRpc = class extends InspectorQueryConnection {
1448
+ port;
1449
+ constructor(port, options) {
1450
+ super(options);
1451
+ this.port = port;
1452
+ }
1453
+ /**
1454
+ * Connect query writes after the Worker accepts the Host source.
1455
+ * @param source - Accepted Host source descriptor.
1456
+ */
1457
+ connectPort(source) {
1458
+ this.connect(source.sourceId, source.generation, { send: (frame) => {
1459
+ this.port.postMessage(frame);
1460
+ } });
1461
+ }
1462
+ };
1463
+ //#endregion
1464
+ //#region lib/types/host/bridge/dispatcher.js
1465
+ /** Dispatch of validated Worker frames accepted by the Host MessagePort. */
1466
+ /**
1467
+ * Dispatch one validated Worker frame and reject Client-only commands on the Host carrier.
1468
+ * @param frame - Decoded Worker-to-source frame.
1469
+ * @param handlers - Host source-lifecycle operations.
1470
+ */
1471
+ function dispatchBridgeFrame(frame, handlers) {
1472
+ switch (frame.t) {
1473
+ case "source/accepted":
1474
+ handlers.accepted(frame);
1475
+ return;
1476
+ case "source/append-acknowledged":
1477
+ handlers.acknowledged(frame);
1478
+ return;
1479
+ case "source/resnapshot":
1480
+ handlers.resnapshot(frame);
1481
+ return;
1482
+ case "source/rejected":
1483
+ handlers.rejected(frame);
1484
+ return;
1485
+ case "client-runtime/request": return rejectRuntimeBridgeCommand(frame.command);
1486
+ case "client-runtime/cancel":
1487
+ case "client-runtime/response-acknowledged": return;
1488
+ case "client-console/enable":
1489
+ case "client-console/disable": return rejectConsoleBridgeCommand(frame.t);
1490
+ case "client-sources/request": return rejectSourcesBridgeCommand();
1491
+ case "client-runtime/session-closed":
1492
+ case "client-sources/session-closed": return;
1493
+ default: return assertNever(frame);
1494
+ }
1495
+ }
1496
+ function assertNever(value) {
1497
+ throw new Error(`Unexpected Worker source frame: ${JSON.stringify(value)}`);
1498
+ }
1499
+ //#endregion
1500
+ //#region lib/types/host/bridge/transport.js
1501
+ /** Host-realm observation publisher over a dedicated MessagePort. */
1502
+ /** Non-blocking Host source; queue overflow is represented by `droppedBefore` on the next batch. */
1503
+ var HostInspectorSource = class extends InspectorSourceConnection {
1504
+ port;
1505
+ source;
1506
+ publisher;
1507
+ closed = false;
1508
+ queries;
1509
+ constructor(port, options) {
1510
+ super();
1511
+ this.port = port;
1512
+ this.source = createHostRealmSource(options.label);
1513
+ this.publisher = new HostBridgePublisher(port, this.source, options);
1514
+ this.queries = new HostBridgeRpc(port, {
1515
+ timeoutMs: options.queryTimeoutMs,
1516
+ maxFrameBytes: options.maxFrameBytes
1517
+ });
1518
+ port.on("message", (value) => {
1519
+ try {
1520
+ if (this.queries.receive(value)) return;
1521
+ this.receive(parseWorkerSourceFrame(value));
1522
+ } catch {
1523
+ this.close();
1524
+ }
1525
+ });
1526
+ port.on("close", () => {
1527
+ this.queries.disconnect("Inspector Host source disconnected");
1528
+ });
1529
+ port.start();
1530
+ const open = {
1531
+ v: 0,
1532
+ t: "source/open",
1533
+ source: this.source,
1534
+ topics: [...options.topics]
1535
+ };
1536
+ port.postMessage(open);
1537
+ this.publisher.replace();
1538
+ }
1539
+ /** Flush pending observations and close the source port. */
1540
+ close() {
1541
+ if (this.closed) return;
1542
+ this.publisher.close();
1543
+ this.closed = true;
1544
+ this.queries.close("Inspector Host source closed");
1545
+ const frame = {
1546
+ v: 0,
1547
+ t: "source/close",
1548
+ sourceId: this.source.sourceId,
1549
+ generation: this.source.generation
1550
+ };
1551
+ this.port.postMessage(frame);
1552
+ this.port.close();
1553
+ }
1554
+ receive(frame) {
1555
+ if (frame.t !== "source/rejected" && (frame.sourceId !== this.source.sourceId || frame.generation !== this.source.generation)) return;
1556
+ dispatchBridgeFrame(frame, {
1557
+ accepted: () => {
1558
+ this.queries.connectPort(this.source);
1559
+ },
1560
+ acknowledged: (acknowledged) => {
1561
+ this.publisher.acknowledge(acknowledged.nextSequence);
1562
+ },
1563
+ resnapshot: () => {
1564
+ this.publisher.replace();
1565
+ },
1566
+ rejected: (rejected) => {
1567
+ this.queries.disconnect(`Inspector Host source rejected: ${rejected.message}`);
1568
+ }
1569
+ });
1570
+ }
1571
+ };
1572
+ //#endregion
1573
+ //#region lib/types/shared/bridge/control-codec.js
1574
+ /** Exact decoders for Host, Worker, and injected Client lifecycle values. */
1575
+ /**
1576
+ * Decode one Worker-to-Host lifecycle event.
1577
+ * @param value - Untrusted control message.
1578
+ * @returns The validated Worker event.
1579
+ */
1580
+ function parseInspectorWorkerControl(value) {
1581
+ const record = exactObjectByType(value, "Worker control message");
1582
+ switch (record.type) {
1583
+ case "ready":
1584
+ exactKeys(record, [
1585
+ "type",
1586
+ "host",
1587
+ "port",
1588
+ "targetId"
1589
+ ], "Worker ready message");
1590
+ if (typeof record.host !== "string" || typeof record.targetId !== "string") throw new Error("inspector protocol: invalid Worker ready identity");
1591
+ return {
1592
+ type: "ready",
1593
+ host: record.host,
1594
+ port: natural$1(record.port, "port", true),
1595
+ targetId: record.targetId
1596
+ };
1597
+ case "failure":
1598
+ exactKeys(record, ["type", "message"], "Worker failure message");
1599
+ if (typeof record.message !== "string") throw new Error("inspector protocol: invalid Worker failure");
1600
+ return {
1601
+ type: "failure",
1602
+ message: record.message
1603
+ };
1604
+ case "stopped":
1605
+ exactKeys(record, ["type"], "Worker stopped message");
1606
+ return { type: "stopped" };
1607
+ default: throw new Error("inspector protocol: unknown Worker control message");
1608
+ }
1609
+ }
1610
+ function exactObjectByType(value, label) {
1611
+ if (!isPlainObject(value) || typeof value.type !== "string") throw new Error(`inspector protocol: ${label} must have a type`);
1612
+ return value;
1613
+ }
1614
+ function natural$1(value, label, zero = false) {
1615
+ if (!Number.isSafeInteger(value) || value < (zero ? 0 : 1)) throw new Error(`inspector protocol: ${label} must be ${zero ? "a non-negative" : "a positive"} safe integer`);
1616
+ return value;
1617
+ }
1618
+ //#endregion
1619
+ //#region lib/types/host/bridge/lifecycle.js
1620
+ /** Failure containment and shutdown coordination for the Inspector Worker. */
1621
+ /** Tracks Worker termination without removing the listener that contains runtime errors. */
1622
+ var InspectorWorkerLifecycle = class {
1623
+ worker;
1624
+ exitResolution = Promise.withResolvers();
1625
+ failureResolution = Promise.withResolvers();
1626
+ failure;
1627
+ running = false;
1628
+ expectedExit = false;
1629
+ notified = false;
1630
+ onUnexpectedExit;
1631
+ exitCodeValue;
1632
+ /** Worker exit code once its `exit` event has fired. */
1633
+ get exitCode() {
1634
+ return this.exitCodeValue;
1635
+ }
1636
+ constructor(worker) {
1637
+ this.worker = worker;
1638
+ worker.on("error", (error) => {
1639
+ this.failure ??= error;
1640
+ this.failureResolution.resolve(error);
1641
+ this.notifyUnexpectedExit();
1642
+ });
1643
+ worker.once("exit", (code) => {
1644
+ this.exitCodeValue = code;
1645
+ this.exitResolution.resolve(code);
1646
+ this.notifyUnexpectedExit();
1647
+ });
1648
+ }
1649
+ /**
1650
+ * Wait for the validated ready frame while also observing startup failure and exit.
1651
+ * @param timeoutMs - Readiness deadline in milliseconds.
1652
+ * @returns The Worker's bound endpoint fields.
1653
+ */
1654
+ async waitForReady(timeoutMs) {
1655
+ let timer;
1656
+ let onMessage;
1657
+ const message = new Promise((resolve, reject) => {
1658
+ onMessage = (value) => {
1659
+ let control;
1660
+ try {
1661
+ control = parseInspectorWorkerControl(value);
1662
+ } catch (error) {
1663
+ reject(error instanceof Error ? error : new Error(String(error)));
1664
+ return;
1665
+ }
1666
+ if (control.type === "ready") resolve(control);
1667
+ else if (control.type === "failure") reject(/* @__PURE__ */ new Error(`inspector Worker failed: ${control.message}`));
1668
+ };
1669
+ timer = setTimeout(() => {
1670
+ reject(/* @__PURE__ */ new Error(`inspector Worker did not become ready within ${String(timeoutMs)}ms`));
1671
+ }, timeoutMs);
1672
+ this.worker.on("message", onMessage);
1673
+ });
1674
+ try {
1675
+ return await Promise.race([
1676
+ message,
1677
+ this.failureResolution.promise.then((error) => {
1678
+ throw error;
1679
+ }),
1680
+ this.exitResolution.promise.then((code) => {
1681
+ throw new Error(`inspector Worker exited before readiness (code ${String(code)})`);
1682
+ })
1683
+ ]);
1684
+ } finally {
1685
+ if (timer !== void 0) clearTimeout(timer);
1686
+ if (onMessage !== void 0) this.worker.off("message", onMessage);
1687
+ }
1688
+ }
1689
+ /**
1690
+ * Begin reporting an unexpected runtime exit through one contained callback.
1691
+ * @param listener - Failure observer that must not throw.
1692
+ */
1693
+ markRunning(listener) {
1694
+ this.running = true;
1695
+ this.onUnexpectedExit = listener;
1696
+ this.notifyUnexpectedExit();
1697
+ }
1698
+ /** Mark subsequent Worker termination as owner-requested. */
1699
+ expectExit() {
1700
+ this.expectedExit = true;
1701
+ }
1702
+ /** Terminate the Worker during failed initialization. */
1703
+ async terminate() {
1704
+ this.expectExit();
1705
+ if (this.exitCodeValue === void 0) await this.worker.terminate();
1706
+ }
1707
+ /**
1708
+ * Request graceful shutdown and terminate after the deadline.
1709
+ * @param timeoutMs - Grace period before forced termination.
1710
+ */
1711
+ async stop(timeoutMs) {
1712
+ this.expectExit();
1713
+ if (this.exitCodeValue !== void 0) return;
1714
+ this.worker.postMessage({ type: "shutdown" });
1715
+ let timer;
1716
+ const timeout = new Promise((resolve) => {
1717
+ timer = setTimeout(() => {
1718
+ resolve("timeout");
1719
+ }, timeoutMs);
1720
+ });
1721
+ const outcome = await Promise.race([this.exitResolution.promise.then(() => "exited"), timeout]);
1722
+ if (timer !== void 0) clearTimeout(timer);
1723
+ if (outcome === "exited") return;
1724
+ await this.worker.terminate();
1725
+ throw new Error(`inspector Worker did not stop within ${String(timeoutMs)}ms and was terminated`);
1726
+ }
1727
+ notifyUnexpectedExit() {
1728
+ if (!this.running || this.expectedExit || this.notified || this.exitCodeValue === void 0) return;
1729
+ this.notified = true;
1730
+ this.onUnexpectedExit?.(this.failure ?? /* @__PURE__ */ new Error(`inspector Worker exited unexpectedly with code ${String(this.exitCodeValue)}`));
1731
+ }
1732
+ };
1733
+ //#endregion
1734
+ //#region lib/types/host/bridge/controller.js
1735
+ /** Host controller that owns the Inspector Worker and Host observation source. */
1736
+ const DEFAULT_MAX_REQUEST_BODY_BYTES = 8 * 1024 * 1024;
1737
+ const DEFAULT_MAX_RESPONSE_BODY_BYTES = 32 * 1024 * 1024;
1738
+ const DEFAULT_MAX_BODY_CHUNK_BYTES = 48 * 1024;
1739
+ const DEFAULT_MAX_JOURNAL_BYTES = 256 * 1024 * 1024;
1740
+ const DEFAULT_MAX_RETAINED_REQUESTS = 2e3;
1741
+ const DEFAULT_MAX_SOURCE_FRAME_BYTES = 128 * 1024;
1742
+ const DEFAULT_MAX_SOURCE_RECORDS_PER_FRAME = 128;
1743
+ const DEFAULT_MAX_QUEUED_RECORDS = 2048;
1744
+ const DEFAULT_MAX_QUEUED_BYTES = 16 * 1024 * 1024;
1745
+ const DEFAULT_STARTUP_TIMEOUT_MS = 1e4;
1746
+ const DEFAULT_STOP_TIMEOUT_MS = 5e3;
1747
+ const DEFAULT_CLIENT_RECONNECT_BASE_MS = 250;
1748
+ const DEFAULT_CLIENT_RECONNECT_MAX_MS = 5e3;
1749
+ const DEFAULT_CLIENT_RUNTIME_TIMEOUT_MS = 3e4;
1750
+ const DEFAULT_QUERY_TIMEOUT_MS = 1e4;
1751
+ const DEFAULT_MAX_CLIENT_RUNTIME_OBJECTS = 1e4;
1752
+ const DEFAULT_MAX_CLIENT_RUNTIME_PROPERTIES = 2e3;
1753
+ const DEFAULT_MAX_CLIENT_SOURCE_BYTES = 8 * 1024 * 1024;
1754
+ const DEFAULT_MAX_CORDIS_NODES = 2048;
1755
+ const DEFAULT_MAX_DISCONNECTED_CORDIS_TREES = 8;
1756
+ /**
1757
+ * Resolve and validate all deployment-varying Inspector choices.
1758
+ * @param options - Partial caller configuration.
1759
+ * @returns A complete immutable configuration.
1760
+ */
1761
+ function resolveInspectorOptions(options = {}) {
1762
+ const spec = {
1763
+ host: options.host ?? "127.0.0.1",
1764
+ port: natural(options.port ?? 0, "port", true),
1765
+ clientOrigins: [...options.clientOrigins ?? []],
1766
+ captureFetch: options.captureFetch ?? true,
1767
+ maxRequestBodyBytes: natural(options.maxRequestBodyBytes ?? DEFAULT_MAX_REQUEST_BODY_BYTES, "maxRequestBodyBytes"),
1768
+ maxResponseBodyBytes: natural(options.maxResponseBodyBytes ?? DEFAULT_MAX_RESPONSE_BODY_BYTES, "maxResponseBodyBytes"),
1769
+ maxBodyChunkBytes: natural(options.maxBodyChunkBytes ?? DEFAULT_MAX_BODY_CHUNK_BYTES, "maxBodyChunkBytes"),
1770
+ maxJournalBytes: natural(options.maxJournalBytes ?? DEFAULT_MAX_JOURNAL_BYTES, "maxJournalBytes"),
1771
+ maxRetainedRequests: natural(options.maxRetainedRequests ?? DEFAULT_MAX_RETAINED_REQUESTS, "maxRetainedRequests"),
1772
+ maxSourceFrameBytes: natural(options.maxSourceFrameBytes ?? DEFAULT_MAX_SOURCE_FRAME_BYTES, "maxSourceFrameBytes"),
1773
+ maxSourceRecordsPerFrame: natural(options.maxSourceRecordsPerFrame ?? DEFAULT_MAX_SOURCE_RECORDS_PER_FRAME, "maxSourceRecordsPerFrame"),
1774
+ maxQueuedRecords: natural(options.maxQueuedRecords ?? DEFAULT_MAX_QUEUED_RECORDS, "maxQueuedRecords"),
1775
+ maxQueuedBytes: natural(options.maxQueuedBytes ?? DEFAULT_MAX_QUEUED_BYTES, "maxQueuedBytes"),
1776
+ startupTimeoutMs: natural(options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS, "startupTimeoutMs"),
1777
+ stopTimeoutMs: natural(options.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS, "stopTimeoutMs"),
1778
+ clientReconnectBaseMs: natural(options.clientReconnectBaseMs ?? DEFAULT_CLIENT_RECONNECT_BASE_MS, "clientReconnectBaseMs"),
1779
+ clientReconnectMaxMs: natural(options.clientReconnectMaxMs ?? DEFAULT_CLIENT_RECONNECT_MAX_MS, "clientReconnectMaxMs"),
1780
+ clientRuntimeTimeoutMs: natural(options.clientRuntimeTimeoutMs ?? DEFAULT_CLIENT_RUNTIME_TIMEOUT_MS, "clientRuntimeTimeoutMs"),
1781
+ queryTimeoutMs: natural(options.queryTimeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS, "queryTimeoutMs"),
1782
+ maxClientRuntimeObjects: natural(options.maxClientRuntimeObjects ?? DEFAULT_MAX_CLIENT_RUNTIME_OBJECTS, "maxClientRuntimeObjects"),
1783
+ maxClientRuntimeProperties: natural(options.maxClientRuntimeProperties ?? DEFAULT_MAX_CLIENT_RUNTIME_PROPERTIES, "maxClientRuntimeProperties"),
1784
+ maxClientSourceBytes: natural(options.maxClientSourceBytes ?? DEFAULT_MAX_CLIENT_SOURCE_BYTES, "maxClientSourceBytes"),
1785
+ maxCordisNodes: natural(options.maxCordisNodes ?? DEFAULT_MAX_CORDIS_NODES, "maxCordisNodes"),
1786
+ maxDisconnectedCordisTrees: natural(options.maxDisconnectedCordisTrees ?? DEFAULT_MAX_DISCONNECTED_CORDIS_TREES, "maxDisconnectedCordisTrees", true)
1787
+ };
1788
+ if (spec.port > 65535) throw new Error("inspector: port must not exceed 65535");
1789
+ if (Math.ceil(spec.maxBodyChunkBytes / 3) * 4 + 4096 > spec.maxSourceFrameBytes) throw new Error("inspector: maxSourceFrameBytes cannot carry one base64 body chunk");
1790
+ if (spec.clientReconnectMaxMs < spec.clientReconnectBaseMs) throw new Error("inspector: clientReconnectMaxMs must be at least clientReconnectBaseMs");
1791
+ for (const origin of spec.clientOrigins) if (new URL(origin).origin !== origin) throw new Error(`inspector: client origin must be canonical: ${origin}`);
1792
+ return spec;
1793
+ }
1794
+ /**
1795
+ * Start the Worker, create the Host source, and install full fetch capture by default.
1796
+ * @param options - Partial caller configuration.
1797
+ * @returns The ready endpoint and its quiescent shutdown handle.
1798
+ */
1799
+ async function startInspector(options = {}) {
1800
+ const spec = resolveInspectorOptions(options);
1801
+ const channel = new MessageChannel();
1802
+ const clientProtocol = `dsh-inspector-v${String(0)}-${randomBytes(32).toString("base64url")}`;
1803
+ const lifecycle = new InspectorWorkerLifecycle(spawnWorker({
1804
+ config: {
1805
+ host: spec.host,
1806
+ startPort: spec.port,
1807
+ targetId: randomUUID(),
1808
+ clientToken: clientProtocol,
1809
+ clientOrigins: spec.clientOrigins,
1810
+ maxSourceFrameBytes: spec.maxSourceFrameBytes,
1811
+ maxSourceRecordsPerFrame: spec.maxSourceRecordsPerFrame,
1812
+ maxRetainedRequests: spec.maxRetainedRequests,
1813
+ maxJournalBytes: spec.maxJournalBytes,
1814
+ clientRuntimeTimeoutMs: spec.clientRuntimeTimeoutMs,
1815
+ maxClientSourceBytes: spec.maxClientSourceBytes,
1816
+ maxCordisNodes: spec.maxCordisNodes,
1817
+ maxDisconnectedCordisTrees: spec.maxDisconnectedCordisTrees
1818
+ },
1819
+ hostSourcePort: channel.port2
1820
+ }));
1821
+ let source;
1822
+ try {
1823
+ source = new HostInspectorSource(channel.port1, {
1824
+ label: "Host",
1825
+ topics: ["*", ...NETWORK_TOPICS],
1826
+ maxQueuedRecords: spec.maxQueuedRecords,
1827
+ maxQueuedBytes: spec.maxQueuedBytes,
1828
+ maxRecordsPerFrame: spec.maxSourceRecordsPerFrame,
1829
+ maxFrameBytes: spec.maxSourceFrameBytes,
1830
+ queryTimeoutMs: spec.queryTimeoutMs
1831
+ });
1832
+ } catch (error) {
1833
+ channel.port1.close();
1834
+ await lifecycle.terminate();
1835
+ throw error;
1836
+ }
1837
+ const ready = await lifecycle.waitForReady(spec.startupTimeoutMs).catch(async (error) => {
1838
+ source.close();
1839
+ await lifecycle.terminate();
1840
+ throw error;
1841
+ });
1842
+ const authority = `${ready.host}:${String(ready.port)}`;
1843
+ const endpoint = {
1844
+ httpUrl: `http://${authority}/`,
1845
+ webSocketDebuggerUrl: `ws://${authority}/devtools/page/${ready.targetId}`,
1846
+ devtoolsFrontendUrl: `devtools://devtools/bundled/devtools_app.html?ws=${authority}/devtools/page/${ready.targetId}&panel=elements&noJavaScriptCompletion=true`,
1847
+ client: {
1848
+ endpoint: `ws://${authority}/ingest`,
1849
+ protocol: clientProtocol,
1850
+ maxQueuedRecords: spec.maxQueuedRecords,
1851
+ maxQueuedBytes: spec.maxQueuedBytes,
1852
+ maxRecordsPerFrame: spec.maxSourceRecordsPerFrame,
1853
+ maxFrameBytes: spec.maxSourceFrameBytes,
1854
+ reconnectBaseMs: spec.clientReconnectBaseMs,
1855
+ reconnectMaxMs: spec.clientReconnectMaxMs,
1856
+ queryTimeoutMs: spec.queryTimeoutMs,
1857
+ maxRuntimeObjectsPerSession: spec.maxClientRuntimeObjects,
1858
+ maxRuntimePropertiesPerResult: spec.maxClientRuntimeProperties,
1859
+ maxClientSourceBytes: spec.maxClientSourceBytes,
1860
+ maxCordisNodes: spec.maxCordisNodes
1861
+ }
1862
+ };
1863
+ let fetchObserver;
1864
+ try {
1865
+ fetchObserver = spec.captureFetch ? installFetchObserver(source, {
1866
+ maxRequestBodyBytes: spec.maxRequestBodyBytes,
1867
+ maxResponseBodyBytes: spec.maxResponseBodyBytes,
1868
+ maxChunkBytes: spec.maxBodyChunkBytes
1869
+ }) : void 0;
1870
+ } catch (error) {
1871
+ source.close();
1872
+ await lifecycle.terminate();
1873
+ throw error;
1874
+ }
1875
+ lifecycle.markRunning((error) => {
1876
+ try {
1877
+ source.close();
1878
+ } catch (closeError) {
1879
+ console.error("dsh inspector: Host source cleanup after Worker failure failed", closeError);
1880
+ }
1881
+ fetchObserver?.stop().catch((stopError) => {
1882
+ console.error("dsh inspector: fetch cleanup after Worker failure failed", stopError);
1883
+ });
1884
+ console.error("dsh inspector: Worker stopped unexpectedly", error);
1885
+ });
1886
+ let closing;
1887
+ return {
1888
+ endpoint,
1889
+ source,
1890
+ close() {
1891
+ closing ??= closeInspector(lifecycle, source, fetchObserver, spec.stopTimeoutMs);
1892
+ return closing;
1893
+ }
1894
+ };
1895
+ }
1896
+ function spawnWorker(boot) {
1897
+ const options = {
1898
+ workerData: boot,
1899
+ transferList: [boot.hostSourcePort],
1900
+ execArgv: []
1901
+ };
1902
+ if (!import.meta.url.endsWith(".ts")) return new Worker(new URL("./worker.js", import.meta.url), options);
1903
+ const workerEntry = new URL("../../worker/entry.ts", import.meta.url);
1904
+ const tsxEsmApiEntry = import.meta.resolve("tsx/esm/api");
1905
+ const bootstrap = [
1906
+ `import { register } from ${JSON.stringify(tsxEsmApiEntry)}`,
1907
+ "register()",
1908
+ `await import(${JSON.stringify(workerEntry.href)})`
1909
+ ].join("\n");
1910
+ return new Worker(new URL(`data:text/javascript,${encodeURIComponent(bootstrap)}`), {
1911
+ ...options,
1912
+ env: sourceWorkerEnv()
1913
+ });
1914
+ }
1915
+ function sourceWorkerEnv() {
1916
+ const env = {};
1917
+ if (process.platform === "win32") {
1918
+ env.TMP = tmpdir();
1919
+ env.TEMP = tmpdir();
1920
+ }
1921
+ if (process.env.TSX_TSCONFIG_PATH !== void 0) env.TSX_TSCONFIG_PATH = process.env.TSX_TSCONFIG_PATH;
1922
+ return env;
1923
+ }
1924
+ async function closeInspector(lifecycle, source, fetchObserver, timeoutMs) {
1925
+ const failures = [];
1926
+ try {
1927
+ await fetchObserver?.stop();
1928
+ } catch (error) {
1929
+ failures.push(error);
1930
+ }
1931
+ try {
1932
+ source.close();
1933
+ } catch (error) {
1934
+ failures.push(error);
1935
+ }
1936
+ try {
1937
+ await lifecycle.stop(timeoutMs);
1938
+ } catch (error) {
1939
+ failures.push(error);
1940
+ }
1941
+ if (failures.length > 0) throw new AggregateError(failures, "inspector: shutdown failed");
1942
+ }
1943
+ function natural(value, name, zero = false) {
1944
+ if (!Number.isSafeInteger(value) || value < (zero ? 0 : 1)) throw new Error(`inspector: ${name} must be ${zero ? "a non-negative" : "a positive"} safe integer`);
1945
+ return value;
1946
+ }
1947
+ //#endregion
1948
+ //#region lib/types/shared/bridge/query-reader.js
1949
+ /** Query-backed adapter for the transport-independent Cordis tree reader. */
1950
+ /**
1951
+ * Create a reader that obtains the tree through the typed Inspector query protocol.
1952
+ * @param requester - Active Host or Client query connection.
1953
+ * @returns A non-CDP Cordis tree reader.
1954
+ */
1955
+ function createQueryCordisRuntimeTreeReader(requester) {
1956
+ return { async getTree() {
1957
+ return (await requester.request({ op: "cordis-tree/get" })).tree;
1958
+ } };
1959
+ }
1960
+ //#endregion
1961
+ //#region lib/types/shared/service.js
1962
+ /** Cordis service API shared by the Host and Client plugin faces. */
1963
+ /**
1964
+ * Create the shared service façade without exposing the carrier implementation.
1965
+ * @param connection - Realm-local observation and query transport.
1966
+ * @returns The Cordis service value.
1967
+ */
1968
+ function createInspectorService(connection) {
1969
+ return {
1970
+ publish: (topic, payload, monotonicMs) => {
1971
+ connection.publish(topic, payload, monotonicMs);
1972
+ },
1973
+ cordis: createQueryCordisRuntimeTreeReader(connection)
1974
+ };
1975
+ }
1976
+ //#endregion
1977
+ //#region lib/types/shared/bridge/messages/cordis.js
1978
+ /** Bridge message metadata for Cordis runtime-tree snapshots. */
1979
+ /** Observation topic carrying the latest complete Cordis tree. */
1980
+ const CORDIS_TREE_TOPIC = "cordis/tree";
1981
+ //#endregion
1982
+ //#region lib/types/shared/cordis/object-registry.js
1983
+ /** Realm-local retention and identity for live objects referenced by Inspector snapshots. */
1984
+ const REGISTRIES_SYMBOL = "dsh.inspector.realm-object-registries";
1985
+ const MAX_FIBER_WRAPPER_DEPTH = 8;
1986
+ `${JSON.stringify(REGISTRIES_SYMBOL)}`;
1987
+ /** One realm's bounded table of objects retained by its latest semantic snapshot. */
1988
+ var RealmObjectRegistry = class {
1989
+ /** Realm-unique id carried by every reference from this registry. */
1990
+ id = inspectorId(randomUUID$1(), "registryId");
1991
+ known = /* @__PURE__ */ new WeakMap();
1992
+ retained = /* @__PURE__ */ new Map();
1993
+ nextHandle = 1;
1994
+ disposed = false;
1995
+ constructor() {
1996
+ registries().set(this.id, this);
1997
+ }
1998
+ /**
1999
+ * Start one replacement generation.
2000
+ * @returns A collector that atomically installs exactly the retained objects on commit.
2001
+ */
2002
+ begin() {
2003
+ if (this.disposed) throw new Error("inspector: realm object registry is disposed");
2004
+ return new RealmObjectGeneration(this);
2005
+ }
2006
+ /**
2007
+ * Resolve one current opaque handle.
2008
+ * @param handle - Handle from the latest committed snapshot.
2009
+ * @returns The live object, when it remains retained.
2010
+ */
2011
+ resolve(handle) {
2012
+ return this.retained.get(handle);
2013
+ }
2014
+ /**
2015
+ * Identify one object retained by the latest snapshot. Cordis plugin calls may return nested thenable facades;
2016
+ * only objects whose prototype path consists exclusively of those `then` wrappers resolve to the retained Fiber.
2017
+ * @param value - Candidate live value.
2018
+ * @returns Its wire reference, when present in this registry.
2019
+ */
2020
+ identify(value) {
2021
+ if ((typeof value !== "object" || value === null) && typeof value !== "function") return void 0;
2022
+ let candidate = value;
2023
+ for (let depth = 0; candidate !== null && depth <= MAX_FIBER_WRAPPER_DEPTH; depth++) {
2024
+ const handle = this.known.get(candidate);
2025
+ if (handle !== void 0 && this.retained.get(handle) === candidate) return {
2026
+ registryId: this.id,
2027
+ handle
2028
+ };
2029
+ try {
2030
+ const keys = Reflect.ownKeys(candidate);
2031
+ if (keys.length !== 1 || keys[0] !== "then") return void 0;
2032
+ candidate = Object.getPrototypeOf(candidate);
2033
+ } catch {
2034
+ return;
2035
+ }
2036
+ }
2037
+ }
2038
+ /** Remove this registry from the realm and release all strong references. */
2039
+ close() {
2040
+ if (this.disposed) return;
2041
+ this.disposed = true;
2042
+ registries().delete(this.id);
2043
+ this.retained.clear();
2044
+ }
2045
+ /**
2046
+ * Assign a stable handle and retain a value in one pending generation.
2047
+ * @param value - Object represented by the pending snapshot.
2048
+ * @param next - Pending generation's strong-reference table.
2049
+ * @returns The registry id and stable object handle.
2050
+ */
2051
+ retain(value, next) {
2052
+ let handle = this.known.get(value);
2053
+ if (handle === void 0) {
2054
+ handle = inspectorId(`object-${String(this.nextHandle++)}`, "objectHandle");
2055
+ this.known.set(value, handle);
2056
+ }
2057
+ next.set(handle, value);
2058
+ return {
2059
+ registryId: this.id,
2060
+ handle
2061
+ };
2062
+ }
2063
+ /**
2064
+ * Replace the current strong-reference set with one completed generation.
2065
+ * @param next - Complete object table for the committed snapshot.
2066
+ */
2067
+ commit(next) {
2068
+ this.retained = next;
2069
+ }
2070
+ };
2071
+ /** Mutable object set assembled before one snapshot becomes visible. */
2072
+ var RealmObjectGeneration = class {
2073
+ owner;
2074
+ retained = /* @__PURE__ */ new Map();
2075
+ committed = false;
2076
+ constructor(owner) {
2077
+ this.owner = owner;
2078
+ }
2079
+ /**
2080
+ * Retain one object and obtain its stable opaque reference.
2081
+ * @param value - Context or Fiber represented in the snapshot.
2082
+ * @returns Source-local wire reference.
2083
+ */
2084
+ retain(value) {
2085
+ if (this.committed) throw new Error("inspector: realm object generation is already committed");
2086
+ return this.owner.retain(value, this.retained);
2087
+ }
2088
+ /**
2089
+ * Stop retaining an object omitted while bounding the pending snapshot.
2090
+ * @param handle - Opaque handle removed from this pending generation.
2091
+ */
2092
+ release(handle) {
2093
+ if (this.committed) throw new Error("inspector: realm object generation is already committed");
2094
+ this.retained.delete(handle);
2095
+ }
2096
+ /** Atomically replace the registry's retained set. */
2097
+ commit() {
2098
+ if (this.committed) return;
2099
+ this.committed = true;
2100
+ this.owner.commit(this.retained);
2101
+ }
2102
+ };
2103
+ function registries() {
2104
+ const key = Symbol.for(REGISTRIES_SYMBOL);
2105
+ const existing = Reflect.get(globalThis, key);
2106
+ if (existing instanceof Map) return existing;
2107
+ const value = /* @__PURE__ */ new Map();
2108
+ Reflect.set(globalThis, key, value);
2109
+ return value;
2110
+ }
2111
+ //#endregion
2112
+ //#region lib/types/shared/cordis/collector.js
2113
+ /** Shared Host/Client projection from live Cordis objects to a bounded semantic tree. */
2114
+ const SHADOW = Symbol.for("cordis.shadow");
2115
+ /** Realm-local collector with a current live-object table. */
2116
+ var CordisTreeCollector = class {
2117
+ root;
2118
+ limits;
2119
+ /** Live-object table replaced atomically with each emitted snapshot. */
2120
+ objects = new RealmObjectRegistry();
2121
+ revision = 0;
2122
+ constructor(root, limits) {
2123
+ this.root = root;
2124
+ this.limits = limits;
2125
+ }
2126
+ /**
2127
+ * Capture the current reachable Context/Fiber tree.
2128
+ * @returns A detached JSON snapshot whose retained objects replace the prior generation atomically.
2129
+ */
2130
+ snapshot() {
2131
+ const collected = collectContexts(this.root);
2132
+ const tree = collected.root;
2133
+ const objects = this.objects.begin();
2134
+ let nodeCount = 0;
2135
+ let truncated = collected.truncated;
2136
+ const contextNode = (info) => {
2137
+ if (nodeCount >= this.limits.maxNodes) {
2138
+ truncated = true;
2139
+ return;
2140
+ }
2141
+ nodeCount++;
2142
+ const node = {
2143
+ kind: "context",
2144
+ objectHandle: objects.retain(info.value).handle,
2145
+ children: []
2146
+ };
2147
+ for (const child of info.children) if (child.fiber !== void 0 && child.fiber.ctx === child.value) {
2148
+ const projected = fiberNode(child.fiber, child);
2149
+ if (projected !== void 0) node.children.push(projected);
2150
+ } else {
2151
+ const projected = contextNode(child);
2152
+ if (projected !== void 0) node.children.push(projected);
2153
+ }
2154
+ return node;
2155
+ };
2156
+ const fiberNode = (fiber, owned) => {
2157
+ if (fiber.uid === null) return void 0;
2158
+ if (nodeCount + 2 > this.limits.maxNodes) {
2159
+ truncated = true;
2160
+ return;
2161
+ }
2162
+ nodeCount++;
2163
+ const context = contextNode(owned);
2164
+ return {
2165
+ kind: "fiber",
2166
+ objectHandle: objects.retain(fiber).handle,
2167
+ uid: fiber.uid,
2168
+ children: [context]
2169
+ };
2170
+ };
2171
+ const root = contextNode(tree);
2172
+ if (root === void 0) throw new Error("inspector: maxNodes cannot retain the root Context");
2173
+ let snapshot = {
2174
+ schemaVersion: 0,
2175
+ revision: ++this.revision,
2176
+ objectRegistryId: this.objects.id,
2177
+ root,
2178
+ truncated
2179
+ };
2180
+ while (jsonByteLength(snapshot) > this.limits.maxBytes) {
2181
+ const removed = pruneLast(root);
2182
+ if (removed.length === 0) break;
2183
+ for (const handle of removed) objects.release(handle);
2184
+ snapshot = {
2185
+ ...snapshot,
2186
+ truncated: true
2187
+ };
2188
+ }
2189
+ if (jsonByteLength(snapshot) > this.limits.maxBytes) throw new Error("inspector: Cordis root exceeds the source-frame byte limit");
2190
+ objects.commit();
2191
+ return snapshot;
2192
+ }
2193
+ /** Release the realm-global resolver and every retained object. */
2194
+ close() {
2195
+ this.objects.close();
2196
+ }
2197
+ };
2198
+ function collectContexts(root) {
2199
+ const contexts = /* @__PURE__ */ new Map();
2200
+ let truncated = false;
2201
+ const ensure = (candidate, depth = 0) => {
2202
+ if (depth > 100) {
2203
+ truncated = true;
2204
+ return;
2205
+ }
2206
+ const value = unwrapContext(candidate);
2207
+ if (!Context.is(value)) return void 0;
2208
+ const existing = contexts.get(value);
2209
+ if (existing !== void 0) return existing;
2210
+ if (value === root) {
2211
+ const info = describeContext(value);
2212
+ contexts.set(value, info);
2213
+ return info;
2214
+ }
2215
+ const parent = ensure(unwrapContext(Object.getPrototypeOf(value)), depth + 1);
2216
+ if (parent === void 0) return void 0;
2217
+ const info = describeContext(value);
2218
+ contexts.set(value, info);
2219
+ parent.children.push(info);
2220
+ return info;
2221
+ };
2222
+ const rootInfo = ensure(root);
2223
+ for (const runtime of root.registry.values()) for (const fiber of runtime.fibers) {
2224
+ if (fiber.uid === null) continue;
2225
+ ensure(fiber.parent);
2226
+ ensure(fiber.ctx);
2227
+ }
2228
+ for (const key of Reflect.ownKeys(root.events._hooks)) for (const hook of root.events._hooks[key] ?? []) ensure(hook.ctx);
2229
+ const order = (info) => info.fiber?.uid ?? Number.MAX_SAFE_INTEGER;
2230
+ for (const info of contexts.values()) info.children.sort((left, right) => order(left) - order(right));
2231
+ return {
2232
+ root: rootInfo,
2233
+ truncated
2234
+ };
2235
+ }
2236
+ function describeContext(value) {
2237
+ return {
2238
+ value,
2239
+ children: [],
2240
+ fiber: ownValue(value, "fiber")
2241
+ };
2242
+ }
2243
+ function ownValue(value, key) {
2244
+ return Reflect.getOwnPropertyDescriptor(value, key)?.value;
2245
+ }
2246
+ function unwrapContext(value) {
2247
+ let current = value;
2248
+ while (typeof current === "object" && current !== null && Object.hasOwn(current, SHADOW)) current = Object.getPrototypeOf(current);
2249
+ return current;
2250
+ }
2251
+ function pruneLast(context) {
2252
+ const child = context.children.at(-1);
2253
+ if (child === void 0) return [];
2254
+ if (child.kind === "context") {
2255
+ const nested = pruneLast(child);
2256
+ if (nested.length > 0) return nested;
2257
+ context.children.pop();
2258
+ return [child.objectHandle];
2259
+ }
2260
+ const owned = child.children[0];
2261
+ const nested = pruneLast(owned);
2262
+ if (nested.length > 0) return nested;
2263
+ context.children.pop();
2264
+ return [child.objectHandle, owned.objectHandle];
2265
+ }
2266
+ //#endregion
2267
+ //#region lib/types/shared/cordis/observer.js
2268
+ /** Lifecycle-driven Cordis tree publication shared by Host and Client plugin faces. */
2269
+ /**
2270
+ * Observe one Cordis realm and publish immutable tree replacements.
2271
+ * @param ctx - Plugin context whose root is inspected and whose effects own listeners.
2272
+ * @param listener - Consumer of complete snapshots in the inspected realm.
2273
+ * @param limits - Snapshot node and encoded-byte limits.
2274
+ * @returns A disposer that unregisters listeners and releases retained objects.
2275
+ */
2276
+ function observeCordisTree(ctx, listener, limits) {
2277
+ const collector = new CordisTreeCollector(ctx.root, limits);
2278
+ let scheduled = false;
2279
+ let closed = false;
2280
+ const publish = () => {
2281
+ scheduled = false;
2282
+ if (closed) return;
2283
+ listener(collector.snapshot());
2284
+ };
2285
+ const schedule = () => {
2286
+ if (scheduled || closed) return;
2287
+ scheduled = true;
2288
+ queueMicrotask(publish);
2289
+ };
2290
+ const disposers = [ctx.on("internal/plugin", schedule, { global: true }), ctx.on("internal/status", schedule, { global: true })];
2291
+ publish();
2292
+ return () => {
2293
+ if (closed) return;
2294
+ closed = true;
2295
+ for (const dispose of disposers) dispose();
2296
+ collector.close();
2297
+ };
2298
+ }
2299
+ //#endregion
2300
+ //#region lib/types/shared/cordis/publisher.js
2301
+ /** Shared Host/Client publication of browser-safe Cordis snapshots. */
2302
+ /**
2303
+ * Observe one Cordis runtime and retain its latest source snapshot.
2304
+ * @param ctx - Plugin context whose root is inspected.
2305
+ * @param publisher - Active Host or Client source publisher.
2306
+ * @param limits - Snapshot node and encoded-byte limits.
2307
+ * @returns A disposer that stops observation and releases retained objects.
2308
+ */
2309
+ function publishCordisTree(ctx, publisher, limits) {
2310
+ return observeCordisTree(ctx, (snapshot) => {
2311
+ publisher.setState(CORDIS_TREE_TOPIC, snapshot);
2312
+ }, limits);
2313
+ }
2314
+ //#endregion
2315
+ //#region lib/types/host/plugin.js
2316
+ /** Host Cordis plugin for the cross-realm Inspector Worker and full fetch capture. */
2317
+ /** Start the Worker, expose `ctx.inspector`, and inject the matching Client bootstrap. */
2318
+ async function apply$1(ctx, config) {
2319
+ await ctx.effect(async () => {
2320
+ const spec = resolveInspectorOptions(config);
2321
+ const handle = await startInspector(spec);
2322
+ const disposers = [];
2323
+ try {
2324
+ disposers.push(publishCordisTree(ctx, handle.source, {
2325
+ maxNodes: spec.maxCordisNodes,
2326
+ maxBytes: spec.maxSourceFrameBytes - 4096
2327
+ }));
2328
+ disposers.push(ctx.provide("inspector", createInspectorService(handle.source)));
2329
+ disposers.push(ctx.on("webserver/index-inject", (table) => {
2330
+ table.push({
2331
+ kind: "global",
2332
+ name: "__DSH_INSPECTOR__",
2333
+ value: handle.endpoint.client
2334
+ });
2335
+ }));
2336
+ console.log(`dsh inspector: ${handle.endpoint.devtoolsFrontendUrl}`);
2337
+ } catch (error) {
2338
+ await disposeInspector(handle, disposers).catch((cleanupError) => {
2339
+ ctx.logger.error("experimental-inspector: initialization rollback failed", cleanupError);
2340
+ });
2341
+ throw error;
2342
+ }
2343
+ return async () => {
2344
+ await disposeInspector(handle, disposers);
2345
+ };
2346
+ }, "experimental-inspector: Host Worker");
2347
+ }
2348
+ async function disposeInspector(handle, disposers) {
2349
+ const failures = [];
2350
+ for (const dispose of [...disposers].reverse()) try {
2351
+ await dispose();
2352
+ } catch (error) {
2353
+ failures.push(error);
2354
+ }
2355
+ try {
2356
+ await handle.close();
2357
+ } catch (error) {
2358
+ failures.push(error);
2359
+ }
2360
+ if (failures.length > 0) throw new AggregateError(failures, "experimental-inspector: disposal failed");
2361
+ }
2362
+ //#endregion
2363
+ //#region lib/types/index.js
2364
+ /** Repository-facing Host package entry over the mirrored implementation tree. */
2365
+ /** Cordis plugin name shared with the Client face. */
2366
+ const name = "experimental-inspector";
2367
+ /** Host service required to inject the Client connection bootstrap into index.html. */
2368
+ const inject = ["webServer"];
2369
+ const libraryDefaults = resolveInspectorOptions();
2370
+ /** Runtime validation for {@link Config}. */
2371
+ const Config = z.object({
2372
+ host: z.const("127.0.0.1").default("127.0.0.1"),
2373
+ port: z.natural().max(65535).default(9230),
2374
+ clientOrigins: z.array(z.string()).default([]),
2375
+ captureFetch: z.boolean().default(true),
2376
+ maxRequestBodyBytes: z.natural().min(1).default(libraryDefaults.maxRequestBodyBytes),
2377
+ maxResponseBodyBytes: z.natural().min(1).default(libraryDefaults.maxResponseBodyBytes),
2378
+ maxBodyChunkBytes: z.natural().min(1).default(libraryDefaults.maxBodyChunkBytes),
2379
+ maxJournalBytes: z.natural().min(1).default(libraryDefaults.maxJournalBytes),
2380
+ maxRetainedRequests: z.natural().min(1).default(libraryDefaults.maxRetainedRequests),
2381
+ maxSourceFrameBytes: z.natural().min(1).default(libraryDefaults.maxSourceFrameBytes),
2382
+ maxSourceRecordsPerFrame: z.natural().min(1).default(libraryDefaults.maxSourceRecordsPerFrame),
2383
+ maxQueuedRecords: z.natural().min(1).default(libraryDefaults.maxQueuedRecords),
2384
+ maxQueuedBytes: z.natural().min(1).default(libraryDefaults.maxQueuedBytes),
2385
+ startupTimeoutMs: z.natural().min(1).default(libraryDefaults.startupTimeoutMs),
2386
+ stopTimeoutMs: z.natural().min(1).default(libraryDefaults.stopTimeoutMs),
2387
+ clientReconnectBaseMs: z.natural().min(1).default(libraryDefaults.clientReconnectBaseMs),
2388
+ clientReconnectMaxMs: z.natural().min(1).default(libraryDefaults.clientReconnectMaxMs),
2389
+ clientRuntimeTimeoutMs: z.natural().min(1).default(libraryDefaults.clientRuntimeTimeoutMs),
2390
+ queryTimeoutMs: z.natural().min(1).default(libraryDefaults.queryTimeoutMs),
2391
+ maxClientRuntimeObjects: z.natural().min(1).default(libraryDefaults.maxClientRuntimeObjects),
2392
+ maxClientRuntimeProperties: z.natural().min(1).default(libraryDefaults.maxClientRuntimeProperties),
2393
+ maxClientSourceBytes: z.natural().min(1).default(libraryDefaults.maxClientSourceBytes),
2394
+ maxCordisNodes: z.natural().min(1).default(libraryDefaults.maxCordisNodes),
2395
+ maxDisconnectedCordisTrees: z.natural().default(libraryDefaults.maxDisconnectedCordisTrees)
2396
+ });
2397
+ /**
2398
+ * Apply the Host implementation from the repository-standard package entry.
2399
+ * @param ctx - Host Cordis plugin context.
2400
+ * @param config - Validated Inspector configuration.
2401
+ */
2402
+ async function apply(ctx, config) {
2403
+ await apply$1(ctx, config);
2404
+ }
2405
+ //#endregion
2406
+ export { Config, apply, inject, name, resolveInspectorOptions, startInspector };