@shadow-js/devtools 0.0.0-stage → 1.0.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 (112) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +576 -2
  4. package/dist/dev/agent.d.ts +239 -0
  5. package/dist/dev/agent.js +626 -0
  6. package/dist/dev/agent.js.map +1 -0
  7. package/dist/dev/backend.d.ts +53 -0
  8. package/dist/dev/backend.js +53 -0
  9. package/dist/dev/backend.js.map +1 -0
  10. package/dist/dev/hook.d.ts +83 -0
  11. package/dist/dev/hook.js +136 -0
  12. package/dist/dev/hook.js.map +1 -0
  13. package/dist/dev/index.d.ts +17 -0
  14. package/dist/dev/index.js +17 -0
  15. package/dist/dev/inspection.d.ts +226 -0
  16. package/dist/dev/inspection.js +263 -0
  17. package/dist/dev/inspection.js.map +1 -0
  18. package/dist/dev/inspector.d.ts +331 -0
  19. package/dist/dev/inspector.js +429 -0
  20. package/dist/dev/inspector.js.map +1 -0
  21. package/dist/dev/model.d.ts +418 -0
  22. package/dist/dev/model.js +559 -0
  23. package/dist/dev/model.js.map +1 -0
  24. package/dist/dev/mount.d.ts +207 -0
  25. package/dist/dev/mount.js +256 -0
  26. package/dist/dev/mount.js.map +1 -0
  27. package/dist/dev/overlay.d.ts +102 -0
  28. package/dist/dev/overlay.js +176 -0
  29. package/dist/dev/overlay.js.map +1 -0
  30. package/dist/dev/preview.d.ts +74 -0
  31. package/dist/dev/preview.js +122 -0
  32. package/dist/dev/preview.js.map +1 -0
  33. package/dist/dev/protocol.d.ts +288 -0
  34. package/dist/dev/protocol.js +109 -0
  35. package/dist/dev/protocol.js.map +1 -0
  36. package/dist/dev/ring.d.ts +50 -0
  37. package/dist/dev/ring.js +94 -0
  38. package/dist/dev/ring.js.map +1 -0
  39. package/dist/dev/transport.d.ts +347 -0
  40. package/dist/dev/transport.js +394 -0
  41. package/dist/dev/transport.js.map +1 -0
  42. package/dist/dev/ui/details.js +294 -0
  43. package/dist/dev/ui/details.js.map +1 -0
  44. package/dist/dev/ui/inspection-state.d.ts +43 -0
  45. package/dist/dev/ui/inspection-state.js +62 -0
  46. package/dist/dev/ui/inspection-state.js.map +1 -0
  47. package/dist/dev/ui/issues.js +85 -0
  48. package/dist/dev/ui/issues.js.map +1 -0
  49. package/dist/dev/ui/panel.d.ts +55 -0
  50. package/dist/dev/ui/panel.js +160 -0
  51. package/dist/dev/ui/panel.js.map +1 -0
  52. package/dist/dev/ui/rows.d.ts +44 -0
  53. package/dist/dev/ui/rows.js +132 -0
  54. package/dist/dev/ui/rows.js.map +1 -0
  55. package/dist/dev/ui/state-tab.js +88 -0
  56. package/dist/dev/ui/state-tab.js.map +1 -0
  57. package/dist/dev/ui/state.d.ts +192 -0
  58. package/dist/dev/ui/state.js +147 -0
  59. package/dist/dev/ui/state.js.map +1 -0
  60. package/dist/dev/ui/styles.d.ts +31 -0
  61. package/dist/dev/ui/styles.js +113 -0
  62. package/dist/dev/ui/styles.js.map +1 -0
  63. package/dist/dev/ui/timeline.js +135 -0
  64. package/dist/dev/ui/timeline.js.map +1 -0
  65. package/dist/dev/ui/tree.js +186 -0
  66. package/dist/dev/ui/tree.js.map +1 -0
  67. package/dist/prod/agent.js +2 -0
  68. package/dist/prod/agent.js.map +1 -0
  69. package/dist/prod/backend.js +2 -0
  70. package/dist/prod/backend.js.map +1 -0
  71. package/dist/prod/hook.js +2 -0
  72. package/dist/prod/hook.js.map +1 -0
  73. package/dist/prod/index.js +1 -0
  74. package/dist/prod/inspection.js +2 -0
  75. package/dist/prod/inspection.js.map +1 -0
  76. package/dist/prod/inspector.js +2 -0
  77. package/dist/prod/inspector.js.map +1 -0
  78. package/dist/prod/model.js +2 -0
  79. package/dist/prod/model.js.map +1 -0
  80. package/dist/prod/mount.js +2 -0
  81. package/dist/prod/mount.js.map +1 -0
  82. package/dist/prod/overlay.js +11 -0
  83. package/dist/prod/overlay.js.map +1 -0
  84. package/dist/prod/preview.js +2 -0
  85. package/dist/prod/preview.js.map +1 -0
  86. package/dist/prod/protocol.js +2 -0
  87. package/dist/prod/protocol.js.map +1 -0
  88. package/dist/prod/ring.js +2 -0
  89. package/dist/prod/ring.js.map +1 -0
  90. package/dist/prod/transport.js +2 -0
  91. package/dist/prod/transport.js.map +1 -0
  92. package/dist/prod/ui/details.js +2 -0
  93. package/dist/prod/ui/details.js.map +1 -0
  94. package/dist/prod/ui/inspection-state.js +2 -0
  95. package/dist/prod/ui/inspection-state.js.map +1 -0
  96. package/dist/prod/ui/issues.js +2 -0
  97. package/dist/prod/ui/issues.js.map +1 -0
  98. package/dist/prod/ui/panel.js +2 -0
  99. package/dist/prod/ui/panel.js.map +1 -0
  100. package/dist/prod/ui/rows.js +2 -0
  101. package/dist/prod/ui/rows.js.map +1 -0
  102. package/dist/prod/ui/state-tab.js +2 -0
  103. package/dist/prod/ui/state-tab.js.map +1 -0
  104. package/dist/prod/ui/state.js +2 -0
  105. package/dist/prod/ui/state.js.map +1 -0
  106. package/dist/prod/ui/styles.js +82 -0
  107. package/dist/prod/ui/styles.js.map +1 -0
  108. package/dist/prod/ui/timeline.js +2 -0
  109. package/dist/prod/ui/timeline.js.map +1 -0
  110. package/dist/prod/ui/tree.js +2 -0
  111. package/dist/prod/ui/tree.js.map +1 -0
  112. package/package.json +69 -4
@@ -0,0 +1,626 @@
1
+ import { EVENT } from "./protocol.js";
2
+ import { errorMessage, parseEditableText, preview, toEditableText } from "./preview.js";
3
+ import { readInspections } from "./inspection.js";
4
+ import { snapshotOf } from "./inspector.js";
5
+ import { RingBuffer } from "./ring.js";
6
+ import { InspectorModel } from "./model.js";
7
+ //#region src/agent.ts
8
+ function now() {
9
+ return typeof performance !== "undefined" ? performance.now() : Date.now();
10
+ }
11
+ function isObject(value) {
12
+ return typeof value === "object" && value !== null || typeof value === "function";
13
+ }
14
+ function toNumber(value) {
15
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
16
+ }
17
+ function describeSide(value) {
18
+ if (typeof value === "string") return value.length > 200 ? `${value.slice(0, 199)}…` : value;
19
+ if (typeof Node !== "undefined" && value instanceof Node) {
20
+ if (value instanceof Element) {
21
+ const html = value.outerHTML;
22
+ return html.length > 200 ? `${html.slice(0, 199)}…` : html;
23
+ }
24
+ return `#${value.nodeName}`;
25
+ }
26
+ return preview(value, 200);
27
+ }
28
+ /**
29
+ * Creates an agent that records the runtime's events. Attach it to a hook with `agent.attach(hook)`.
30
+ * A development tool: the events come only from development builds, where the hook is installed.
31
+ *
32
+ * @param options Buffer sizes, clock and the signal writer. Every field is optional.
33
+ * @returns The agent.
34
+ * @example
35
+ * import { createAgent, installHook } from "@shadow-js/devtools";
36
+ * import { writeSignal } from "@shadow-js/core/extend";
37
+ *
38
+ * const hook = installHook();
39
+ * const agent = createAgent({ writeSignal });
40
+ * if (hook !== undefined) agent.attach(hook);
41
+ * agent.snapshot().counts.nodes;
42
+ * @since 1.0.0
43
+ */
44
+ function createAgent(options = {}) {
45
+ const clock = options.now ?? now;
46
+ const previewLength = options.previewLength ?? 80;
47
+ const maxPending = options.maxPending ?? 1e4;
48
+ const model = new InspectorModel(options.limits);
49
+ const events = new RingBuffer(options.events ?? 1e4);
50
+ const stats = {
51
+ received: 0,
52
+ recorded: 0,
53
+ ignored: 0,
54
+ unknown: 0
55
+ };
56
+ const ids = /* @__PURE__ */ new WeakMap();
57
+ const ignored = /* @__PURE__ */ new WeakSet();
58
+ const signals = /* @__PURE__ */ new Map();
59
+ const components = /* @__PURE__ */ new Map();
60
+ const stores = /* @__PURE__ */ new Map();
61
+ let nextId = 1;
62
+ let seq = 0;
63
+ let paused = false;
64
+ let quietDepth = 0;
65
+ /** The hook the agent listens to: its registry of inspection sources answers `inspect`. */
66
+ let inspectionHook;
67
+ let pending = [];
68
+ let scheduled = false;
69
+ /** A flush that started but has not recorded any run yet: empty flushes are not worth a record. */
70
+ let queuedFlush = null;
71
+ let flushOpen = false;
72
+ const listeners = /* @__PURE__ */ new Set();
73
+ const detachers = /* @__PURE__ */ new Set();
74
+ const finalizer = typeof FinalizationRegistry === "function" ? new FinalizationRegistry((id) => {
75
+ signals.delete(id);
76
+ stores.delete(id);
77
+ if (model.nodes.has(id)) emit({
78
+ k: "owner-",
79
+ seq: 0,
80
+ t: 0,
81
+ id
82
+ });
83
+ }) : void 0;
84
+ model.onBury = (record) => {
85
+ signals.delete(record.id);
86
+ components.delete(record.id);
87
+ stores.delete(record.id);
88
+ };
89
+ const deliver = () => {
90
+ scheduled = false;
91
+ if (pending.length === 0) return;
92
+ const batch = pending;
93
+ pending = [];
94
+ for (const listener of listeners) listener(batch);
95
+ };
96
+ /** Stamps, records and fans out one event. */
97
+ function emit(event, at) {
98
+ seq += 1;
99
+ event.seq = seq;
100
+ event.t = at ?? clock();
101
+ stats.recorded += 1;
102
+ events.push(event);
103
+ model.apply(event);
104
+ if (listeners.size === 0) return;
105
+ pending.push(event);
106
+ if (pending.length >= maxPending) deliver();
107
+ else if (!scheduled) {
108
+ scheduled = true;
109
+ queueMicrotask(deliver);
110
+ }
111
+ }
112
+ /** Emits the held-back flush start before the first event that belongs to it. */
113
+ const openFlush = () => {
114
+ if (queuedFlush === null) return;
115
+ const held = queuedFlush;
116
+ queuedFlush = null;
117
+ flushOpen = true;
118
+ emit({
119
+ k: "flush+",
120
+ seq: 0,
121
+ t: 0,
122
+ render: held.render,
123
+ user: held.user
124
+ }, held.t);
125
+ };
126
+ const lookup = (value) => {
127
+ if (!isObject(value)) return 0;
128
+ return ids.get(value) ?? 0;
129
+ };
130
+ const register = (value) => {
131
+ const existing = ids.get(value);
132
+ if (existing !== void 0) return existing;
133
+ const id = nextId;
134
+ nextId += 1;
135
+ ids.set(value, id);
136
+ return id;
137
+ };
138
+ /**
139
+ * Like `register`, for a leaf node (signal, store, resource): the finalizer retires it once the runtime
140
+ * has collected the object. Owners and computations are not registered: an owner can be unreachable
141
+ * while its signals are still in use, and retiring it would bury them too.
142
+ */
143
+ const registerLeaf = (value) => {
144
+ const existing = ids.get(value);
145
+ if (existing !== void 0) return existing;
146
+ const id = register(value);
147
+ finalizer?.register(value, id);
148
+ return id;
149
+ };
150
+ /** True (and remembered) when the object belongs to the tools' own UI. */
151
+ const isIgnored = (value, parent) => {
152
+ if (!isObject(value)) return false;
153
+ if (quietDepth > 0 || isObject(parent) && ignored.has(parent)) {
154
+ ignored.add(value);
155
+ return true;
156
+ }
157
+ return ignored.has(value);
158
+ };
159
+ const mapIds = (values) => {
160
+ const out = [];
161
+ if (!Array.isArray(values)) return out;
162
+ for (let i = 0; i < values.length; i += 1) {
163
+ const id = lookup(values[i]);
164
+ if (id !== 0) out.push(id);
165
+ }
166
+ return out;
167
+ };
168
+ const nodesIn = (value) => {
169
+ const out = [];
170
+ if (typeof Node === "undefined") return out;
171
+ const push = (candidate) => {
172
+ if (candidate instanceof DocumentFragment) for (const child of Array.from(candidate.childNodes)) out.push(new WeakRef(child));
173
+ else if (candidate instanceof Node) out.push(new WeakRef(candidate));
174
+ };
175
+ if (Array.isArray(value)) for (const entry of value) push(entry);
176
+ else push(value);
177
+ return out;
178
+ };
179
+ function receive(kind, a, b, c, d, e) {
180
+ if (paused) return;
181
+ stats.received += 1;
182
+ switch (kind) {
183
+ case EVENT.OWNER_CREATED: {
184
+ if (!isObject(a) || isIgnored(a, b)) {
185
+ stats.ignored += 1;
186
+ return;
187
+ }
188
+ const name = typeof d === "string" ? d : void 0;
189
+ emit({
190
+ k: "owner+",
191
+ seq: 0,
192
+ t: 0,
193
+ id: register(a),
194
+ parent: lookup(b),
195
+ label: typeof c === "string" ? c : "owner",
196
+ ...name === void 0 ? {} : { name }
197
+ });
198
+ return;
199
+ }
200
+ case EVENT.OWNER_DISPOSED: {
201
+ const id = lookup(a);
202
+ if (id === 0) {
203
+ stats.ignored += 1;
204
+ return;
205
+ }
206
+ emit({
207
+ k: "owner-",
208
+ seq: 0,
209
+ t: 0,
210
+ id
211
+ });
212
+ return;
213
+ }
214
+ case EVENT.SIGNAL_CREATED: {
215
+ if (!isObject(a) || isIgnored(a, b)) {
216
+ stats.ignored += 1;
217
+ return;
218
+ }
219
+ const id = registerLeaf(a);
220
+ signals.set(id, new WeakRef(a));
221
+ const name = typeof c === "string" ? c : void 0;
222
+ emit({
223
+ k: "signal+",
224
+ seq: 0,
225
+ t: 0,
226
+ id,
227
+ owner: lookup(b),
228
+ preview: preview(d, previewLength),
229
+ ...name === void 0 ? {} : { name }
230
+ });
231
+ return;
232
+ }
233
+ case EVENT.SIGNAL_WRITTEN: {
234
+ const id = lookup(a);
235
+ if (id === 0) {
236
+ if (isObject(a) && ignored.has(a)) stats.ignored += 1;
237
+ else stats.unknown += 1;
238
+ return;
239
+ }
240
+ emit({
241
+ k: "write",
242
+ seq: 0,
243
+ t: 0,
244
+ id,
245
+ preview: preview(b, previewLength),
246
+ writer: lookup(c),
247
+ observers: mapIds(d)
248
+ });
249
+ return;
250
+ }
251
+ case EVENT.COMPUTATION_CREATED: {
252
+ if (!isObject(a) || isIgnored(a, b)) {
253
+ stats.ignored += 1;
254
+ return;
255
+ }
256
+ const name = typeof d === "string" ? d : void 0;
257
+ emit({
258
+ k: "comp+",
259
+ seq: 0,
260
+ t: 0,
261
+ id: register(a),
262
+ owner: lookup(b),
263
+ kind: c === "memo" ? "memo" : "effect",
264
+ render: e === true,
265
+ ...name === void 0 ? {} : { name }
266
+ });
267
+ return;
268
+ }
269
+ case EVENT.COMPUTATION_RUN: {
270
+ const id = lookup(a);
271
+ if (id === 0) {
272
+ if (isObject(a) && ignored.has(a)) stats.ignored += 1;
273
+ else stats.unknown += 1;
274
+ return;
275
+ }
276
+ openFlush();
277
+ emit({
278
+ k: "run",
279
+ seq: 0,
280
+ t: 0,
281
+ id,
282
+ start: toNumber(b),
283
+ duration: toNumber(c),
284
+ changed: d === true,
285
+ sources: mapIds(e)
286
+ });
287
+ return;
288
+ }
289
+ case EVENT.COMPUTATION_DISPOSED: {
290
+ const id = lookup(a);
291
+ if (id === 0) {
292
+ stats.ignored += 1;
293
+ return;
294
+ }
295
+ emit({
296
+ k: "comp-",
297
+ seq: 0,
298
+ t: 0,
299
+ id
300
+ });
301
+ return;
302
+ }
303
+ case EVENT.COMPONENT_MOUNTED: {
304
+ const id = lookup(a);
305
+ if (id === 0) {
306
+ if (isObject(a) && ignored.has(a)) stats.ignored += 1;
307
+ else stats.unknown += 1;
308
+ return;
309
+ }
310
+ const refs = nodesIn(c);
311
+ if (refs.length > 0) components.set(id, refs);
312
+ emit({
313
+ k: "mount",
314
+ seq: 0,
315
+ t: 0,
316
+ id,
317
+ name: typeof b === "string" ? b : "Component"
318
+ });
319
+ if (!model.nodes.has(id)) components.delete(id);
320
+ return;
321
+ }
322
+ case EVENT.COMPONENT_UNMOUNTED: {
323
+ const id = lookup(a);
324
+ if (id === 0) {
325
+ stats.ignored += 1;
326
+ return;
327
+ }
328
+ components.delete(id);
329
+ emit({
330
+ k: "unmount",
331
+ seq: 0,
332
+ t: 0,
333
+ id
334
+ });
335
+ return;
336
+ }
337
+ case EVENT.RESOURCE_STATE: {
338
+ if (!isObject(a) || isIgnored(a, d)) {
339
+ stats.ignored += 1;
340
+ return;
341
+ }
342
+ const name = typeof c === "string" ? c : void 0;
343
+ emit({
344
+ k: "resource",
345
+ seq: 0,
346
+ t: 0,
347
+ id: registerLeaf(a),
348
+ owner: lookup(d),
349
+ state: typeof b === "string" ? b : String(b),
350
+ ...name === void 0 ? {} : { name }
351
+ });
352
+ return;
353
+ }
354
+ case EVENT.ERROR: {
355
+ const code = typeof c === "string" ? c : void 0;
356
+ emit({
357
+ k: "error",
358
+ seq: 0,
359
+ t: 0,
360
+ id: lookup(a),
361
+ message: errorMessage(b),
362
+ ...code === void 0 ? {} : { code }
363
+ });
364
+ return;
365
+ }
366
+ case EVENT.HYDRATION_MISMATCH:
367
+ emit({
368
+ k: "hydration",
369
+ seq: 0,
370
+ t: 0,
371
+ message: typeof a === "string" ? a : errorMessage(a),
372
+ expected: describeSide(b),
373
+ actual: describeSide(c)
374
+ });
375
+ return;
376
+ case EVENT.FLUSH_START:
377
+ queuedFlush = {
378
+ render: toNumber(a),
379
+ user: toNumber(b),
380
+ t: clock()
381
+ };
382
+ return;
383
+ case EVENT.FLUSH_END:
384
+ queuedFlush = null;
385
+ if (flushOpen) {
386
+ flushOpen = false;
387
+ emit({
388
+ k: "flush-",
389
+ seq: 0,
390
+ t: 0,
391
+ runs: toNumber(a)
392
+ });
393
+ }
394
+ return;
395
+ case EVENT.STORE_CREATED: {
396
+ if (!isObject(a) || isIgnored(a, b)) {
397
+ stats.ignored += 1;
398
+ return;
399
+ }
400
+ const handle = readStoreHandle(a);
401
+ if (handle === null) {
402
+ stats.ignored += 1;
403
+ return;
404
+ }
405
+ const id = registerLeaf(a);
406
+ stores.set(id, new WeakRef(handle));
407
+ emit({
408
+ k: "store+",
409
+ seq: 0,
410
+ t: 0,
411
+ id,
412
+ owner: lookup(b),
413
+ name: handle.name
414
+ });
415
+ if (!model.nodes.has(id)) stores.delete(id);
416
+ return;
417
+ }
418
+ default: stats.ignored += 1;
419
+ }
420
+ }
421
+ const readStoreHandle = (value) => {
422
+ const name = Reflect.get(value, "name");
423
+ const snapshot = Reflect.get(value, "snapshot");
424
+ const set = Reflect.get(value, "set");
425
+ if (typeof name !== "string" || typeof snapshot !== "function" || typeof set !== "function") return null;
426
+ return value;
427
+ };
428
+ const signalValue = (id) => {
429
+ const node = signals.get(id)?.deref();
430
+ if (node === void 0) return { found: false };
431
+ return {
432
+ found: true,
433
+ value: Reflect.get(node, "value")
434
+ };
435
+ };
436
+ const fail = (error) => ({
437
+ ok: false,
438
+ error
439
+ });
440
+ function handle(request) {
441
+ try {
442
+ switch (request.type) {
443
+ case "snapshot": return {
444
+ ok: true,
445
+ result: model.exportState()
446
+ };
447
+ case "stats": return {
448
+ ok: true,
449
+ result: {
450
+ ...stats,
451
+ events: events.size,
452
+ dropped: events.dropped
453
+ }
454
+ };
455
+ case "value": {
456
+ const read = signalValue(request.id);
457
+ if (!read.found) return fail("The signal is gone.");
458
+ return {
459
+ ok: true,
460
+ result: {
461
+ id: request.id,
462
+ kind: "signal",
463
+ text: toEditableText(read.value),
464
+ editable: options.writeSignal !== void 0
465
+ }
466
+ };
467
+ }
468
+ case "write": {
469
+ const node = signals.get(request.id)?.deref();
470
+ if (node === void 0) return fail("The signal is gone.");
471
+ if (options.writeSignal === void 0) return fail("Editing is not enabled.");
472
+ const parsed = parseEditableText(request.text);
473
+ if (!parsed.ok) return fail(parsed.error);
474
+ const write = options.writeSignal;
475
+ write(node, parsed.value);
476
+ return {
477
+ ok: true,
478
+ result: null
479
+ };
480
+ }
481
+ case "store": {
482
+ const store = stores.get(request.id)?.deref();
483
+ if (store === void 0) return fail("The store is gone.");
484
+ return {
485
+ ok: true,
486
+ result: {
487
+ id: request.id,
488
+ kind: "store",
489
+ text: toEditableText(store.snapshot()),
490
+ editable: true
491
+ }
492
+ };
493
+ }
494
+ case "store-set": {
495
+ const store = stores.get(request.id)?.deref();
496
+ if (store === void 0) return fail("The store is gone.");
497
+ const parsed = parseEditableText(request.text);
498
+ if (!parsed.ok) return fail(parsed.error);
499
+ store.set(request.path, parsed.value);
500
+ return {
501
+ ok: true,
502
+ result: null
503
+ };
504
+ }
505
+ case "pause":
506
+ paused = true;
507
+ return {
508
+ ok: true,
509
+ result: null
510
+ };
511
+ case "resume":
512
+ paused = false;
513
+ return {
514
+ ok: true,
515
+ result: null
516
+ };
517
+ case "clear":
518
+ clear();
519
+ return {
520
+ ok: true,
521
+ result: null
522
+ };
523
+ case "highlight": return {
524
+ ok: true,
525
+ result: null
526
+ };
527
+ case "inspect": return {
528
+ ok: true,
529
+ result: { sources: readInspections(inspectionHook?.inspections?.() ?? []) }
530
+ };
531
+ default: return fail("Unknown command.");
532
+ }
533
+ } catch (error) {
534
+ return fail(errorMessage(error));
535
+ }
536
+ }
537
+ function clear() {
538
+ model.importState({
539
+ lastSeq: model.lastSeq,
540
+ overflow: 0,
541
+ unknown: 0,
542
+ nodes: [],
543
+ graveyard: [],
544
+ runs: [],
545
+ writes: [],
546
+ flushes: [],
547
+ errors: [],
548
+ hydration: []
549
+ });
550
+ events.clear();
551
+ pending = [];
552
+ queuedFlush = null;
553
+ flushOpen = false;
554
+ signals.clear();
555
+ components.clear();
556
+ stores.clear();
557
+ }
558
+ const agent = {
559
+ model,
560
+ events,
561
+ stats,
562
+ get paused() {
563
+ return paused;
564
+ },
565
+ receive,
566
+ attach(hook) {
567
+ inspectionHook = hook;
568
+ const detach = hook.attach(agent);
569
+ detachers.add(detach);
570
+ return () => {
571
+ detachers.delete(detach);
572
+ detach();
573
+ };
574
+ },
575
+ subscribe(listener) {
576
+ listeners.add(listener);
577
+ return () => {
578
+ listeners.delete(listener);
579
+ };
580
+ },
581
+ flush: deliver,
582
+ quiet(fn) {
583
+ quietDepth += 1;
584
+ try {
585
+ return fn();
586
+ } finally {
587
+ quietDepth -= 1;
588
+ }
589
+ },
590
+ pause() {
591
+ paused = true;
592
+ },
593
+ resume() {
594
+ paused = false;
595
+ },
596
+ clear,
597
+ snapshot: () => snapshotOf(model),
598
+ state: () => model.exportState(),
599
+ handle,
600
+ nodesOf(id) {
601
+ const out = [];
602
+ const own = components.get(id);
603
+ if (own !== void 0) for (const ref of own) {
604
+ const node = ref.deref();
605
+ if (node?.isConnected === true) out.push(node);
606
+ }
607
+ return out;
608
+ },
609
+ dispose() {
610
+ for (const detach of detachers) detach();
611
+ detachers.clear();
612
+ inspectionHook = void 0;
613
+ listeners.clear();
614
+ pending = [];
615
+ signals.clear();
616
+ components.clear();
617
+ stores.clear();
618
+ model.onBury = void 0;
619
+ }
620
+ };
621
+ return agent;
622
+ }
623
+ //#endregion
624
+ export { createAgent };
625
+
626
+ //# sourceMappingURL=agent.js.map