@lifeart/async-dom 2.0.0-alpha.3

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 (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +623 -0
  3. package/dist/base.d.cts +398 -0
  4. package/dist/base.d.cts.map +1 -0
  5. package/dist/base.d.ts +398 -0
  6. package/dist/base.d.ts.map +1 -0
  7. package/dist/cli.cjs +528 -0
  8. package/dist/cli.cjs.map +1 -0
  9. package/dist/cli.d.cts +1 -0
  10. package/dist/cli.d.ts +1 -0
  11. package/dist/cli.js +493 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/debug.d.cts +145 -0
  14. package/dist/debug.d.cts.map +1 -0
  15. package/dist/debug.d.ts +145 -0
  16. package/dist/debug.d.ts.map +1 -0
  17. package/dist/index.cjs +26 -0
  18. package/dist/index.d.cts +560 -0
  19. package/dist/index.d.cts.map +1 -0
  20. package/dist/index.d.ts +560 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +5 -0
  23. package/dist/index2.d.cts +5 -0
  24. package/dist/index2.d.ts +5 -0
  25. package/dist/index3.d.cts +882 -0
  26. package/dist/index3.d.cts.map +1 -0
  27. package/dist/index3.d.ts +882 -0
  28. package/dist/index3.d.ts.map +1 -0
  29. package/dist/main-thread.cjs +5459 -0
  30. package/dist/main-thread.cjs.map +1 -0
  31. package/dist/main-thread.js +5429 -0
  32. package/dist/main-thread.js.map +1 -0
  33. package/dist/react.cjs +116 -0
  34. package/dist/react.cjs.map +1 -0
  35. package/dist/react.d.cts +91 -0
  36. package/dist/react.d.cts.map +1 -0
  37. package/dist/react.d.ts +91 -0
  38. package/dist/react.d.ts.map +1 -0
  39. package/dist/react.js +113 -0
  40. package/dist/react.js.map +1 -0
  41. package/dist/resolve-debug.cjs +24 -0
  42. package/dist/resolve-debug.cjs.map +1 -0
  43. package/dist/resolve-debug.js +19 -0
  44. package/dist/resolve-debug.js.map +1 -0
  45. package/dist/server.cjs +250 -0
  46. package/dist/server.cjs.map +1 -0
  47. package/dist/server.d.cts +127 -0
  48. package/dist/server.d.cts.map +1 -0
  49. package/dist/server.d.ts +127 -0
  50. package/dist/server.d.ts.map +1 -0
  51. package/dist/server.js +245 -0
  52. package/dist/server.js.map +1 -0
  53. package/dist/svelte.cjs +48 -0
  54. package/dist/svelte.cjs.map +1 -0
  55. package/dist/svelte.d.cts +38 -0
  56. package/dist/svelte.d.cts.map +1 -0
  57. package/dist/svelte.d.ts +38 -0
  58. package/dist/svelte.d.ts.map +1 -0
  59. package/dist/svelte.js +47 -0
  60. package/dist/svelte.js.map +1 -0
  61. package/dist/sync-channel.cjs +532 -0
  62. package/dist/sync-channel.cjs.map +1 -0
  63. package/dist/sync-channel.js +425 -0
  64. package/dist/sync-channel.js.map +1 -0
  65. package/dist/transport.cjs +213 -0
  66. package/dist/transport.cjs.map +1 -0
  67. package/dist/transport.d.cts +79 -0
  68. package/dist/transport.d.cts.map +1 -0
  69. package/dist/transport.d.ts +79 -0
  70. package/dist/transport.d.ts.map +1 -0
  71. package/dist/transport.js +202 -0
  72. package/dist/transport.js.map +1 -0
  73. package/dist/vite-plugin.cjs +112 -0
  74. package/dist/vite-plugin.cjs.map +1 -0
  75. package/dist/vite-plugin.d.cts +39 -0
  76. package/dist/vite-plugin.d.cts.map +1 -0
  77. package/dist/vite-plugin.d.ts +39 -0
  78. package/dist/vite-plugin.d.ts.map +1 -0
  79. package/dist/vite-plugin.js +107 -0
  80. package/dist/vite-plugin.js.map +1 -0
  81. package/dist/vue.cjs +123 -0
  82. package/dist/vue.cjs.map +1 -0
  83. package/dist/vue.d.cts +126 -0
  84. package/dist/vue.d.cts.map +1 -0
  85. package/dist/vue.d.ts +126 -0
  86. package/dist/vue.d.ts.map +1 -0
  87. package/dist/vue.js +120 -0
  88. package/dist/vue.js.map +1 -0
  89. package/dist/worker-thread.cjs +2751 -0
  90. package/dist/worker-thread.cjs.map +1 -0
  91. package/dist/worker-thread.js +2692 -0
  92. package/dist/worker-thread.js.map +1 -0
  93. package/dist/worker-transport.cjs +136 -0
  94. package/dist/worker-transport.cjs.map +1 -0
  95. package/dist/worker-transport.d.cts +162 -0
  96. package/dist/worker-transport.d.cts.map +1 -0
  97. package/dist/worker-transport.d.ts +162 -0
  98. package/dist/worker-transport.d.ts.map +1 -0
  99. package/dist/worker-transport.js +125 -0
  100. package/dist/worker-transport.js.map +1 -0
  101. package/dist/worker.cjs +12 -0
  102. package/dist/worker.d.cts +2 -0
  103. package/dist/worker.d.ts +2 -0
  104. package/dist/worker.js +2 -0
  105. package/dist/ws-server-transport.cjs +147 -0
  106. package/dist/ws-server-transport.cjs.map +1 -0
  107. package/dist/ws-server-transport.d.cts +64 -0
  108. package/dist/ws-server-transport.d.cts.map +1 -0
  109. package/dist/ws-server-transport.d.ts +64 -0
  110. package/dist/ws-server-transport.d.ts.map +1 -0
  111. package/dist/ws-server-transport.js +142 -0
  112. package/dist/ws-server-transport.js.map +1 -0
  113. package/dist/ws-transport.cjs +954 -0
  114. package/dist/ws-transport.cjs.map +1 -0
  115. package/dist/ws-transport.js +913 -0
  116. package/dist/ws-transport.js.map +1 -0
  117. package/package.json +145 -0
@@ -0,0 +1,532 @@
1
+ //#region src/core/debug.ts
2
+ const WarningCode = {
3
+ MISSING_NODE: "ASYNC_DOM_MISSING_NODE",
4
+ SYNC_TIMEOUT: "ASYNC_DOM_SYNC_TIMEOUT",
5
+ LISTENER_NOT_FOUND: "ASYNC_DOM_LISTENER_NOT_FOUND",
6
+ EVENT_ATTACH_FAILED: "ASYNC_DOM_EVENT_ATTACH_FAILED",
7
+ TRANSPORT_NOT_OPEN: "ASYNC_DOM_TRANSPORT_NOT_OPEN",
8
+ BLOCKED_PROPERTY: "ASYNC_DOM_BLOCKED_PROPERTY",
9
+ WORKER_ERROR: "WORKER_ERROR",
10
+ WORKER_UNHANDLED_REJECTION: "WORKER_UNHANDLED_REJECTION"
11
+ };
12
+ const WarningDescriptions = {
13
+ ASYNC_DOM_MISSING_NODE: {
14
+ description: "A DOM mutation referenced a node ID that doesn't exist in the node cache.",
15
+ suggestion: "Ensure nodes are created before being referenced. Check for race conditions between create and update mutations."
16
+ },
17
+ ASYNC_DOM_SYNC_TIMEOUT: {
18
+ description: "A synchronous read (getBoundingClientRect, computedStyle) timed out waiting for the main thread response.",
19
+ suggestion: "Reduce sync read frequency, increase timeout, or use cached values when possible."
20
+ },
21
+ ASYNC_DOM_LISTENER_NOT_FOUND: {
22
+ description: "An event was received for a listener ID that is not registered.",
23
+ suggestion: "This may indicate a timing issue where a listener was removed before its event was processed."
24
+ },
25
+ ASYNC_DOM_EVENT_ATTACH_FAILED: {
26
+ description: "Failed to attach an event listener to a DOM node.",
27
+ suggestion: "Verify the target node exists in the DOM when the listener is being attached."
28
+ },
29
+ ASYNC_DOM_TRANSPORT_NOT_OPEN: {
30
+ description: "Attempted to send a message through a closed or connecting transport.",
31
+ suggestion: "Ensure the transport connection is established before sending mutations."
32
+ },
33
+ ASYNC_DOM_BLOCKED_PROPERTY: {
34
+ description: "A setProperty call was blocked because the property is not in the allowed list.",
35
+ suggestion: "Add the property to additionalAllowedProperties in the renderer permissions if it's safe."
36
+ },
37
+ WORKER_ERROR: {
38
+ description: "An unhandled error occurred in the worker thread.",
39
+ suggestion: "Check the stack trace for the error source. Add error handling in your worker code."
40
+ },
41
+ WORKER_UNHANDLED_REJECTION: {
42
+ description: "An unhandled promise rejection occurred in the worker thread.",
43
+ suggestion: "Add .catch() handlers to promises or use try/catch with async/await in your worker code."
44
+ }
45
+ };
46
+ const defaultLogger = {
47
+ warning(entry) {
48
+ console.warn(`[async-dom] ${entry.code}: ${entry.message}`, entry.context);
49
+ },
50
+ mutation(entry) {
51
+ console.log(`[async-dom:${entry.side}] mutation:${entry.action}`, entry.mutation);
52
+ },
53
+ event(entry) {
54
+ console.log(`[async-dom:${entry.side}] event:${entry.phase} ${entry.eventType} listenerId=${entry.listenerId}`);
55
+ },
56
+ syncRead(entry) {
57
+ console.log(`[async-dom] sync:${entry.queryType} node=${entry.nodeId} ${entry.result} (${entry.latencyMs.toFixed(1)}ms)`);
58
+ },
59
+ scheduler(entry) {
60
+ console.log(`[async-dom] frame:${entry.frameId} actions=${entry.actionsProcessed} time=${entry.frameTimeMs.toFixed(1)}ms queue=${entry.queueDepth}`);
61
+ }
62
+ };
63
+ var DebugStats = class {
64
+ mutationsAdded = 0;
65
+ mutationsCoalesced = 0;
66
+ mutationsFlushed = 0;
67
+ mutationsApplied = 0;
68
+ eventsForwarded = 0;
69
+ eventsDispatched = 0;
70
+ syncReadRequests = 0;
71
+ syncReadTimeouts = 0;
72
+ snapshot() {
73
+ return {
74
+ mutationsAdded: this.mutationsAdded,
75
+ mutationsCoalesced: this.mutationsCoalesced,
76
+ mutationsFlushed: this.mutationsFlushed,
77
+ mutationsApplied: this.mutationsApplied,
78
+ eventsForwarded: this.eventsForwarded,
79
+ eventsDispatched: this.eventsDispatched,
80
+ syncReadRequests: this.syncReadRequests,
81
+ syncReadTimeouts: this.syncReadTimeouts
82
+ };
83
+ }
84
+ reset() {
85
+ this.mutationsAdded = 0;
86
+ this.mutationsCoalesced = 0;
87
+ this.mutationsFlushed = 0;
88
+ this.mutationsApplied = 0;
89
+ this.eventsForwarded = 0;
90
+ this.eventsDispatched = 0;
91
+ this.syncReadRequests = 0;
92
+ this.syncReadTimeouts = 0;
93
+ }
94
+ };
95
+ /**
96
+ * Mutation-to-event correlation index (Feature 19: "Why Was This Node Updated?").
97
+ *
98
+ * Indexes mutations by nodeId and links them to their batch and causal event,
99
+ * allowing reverse lookups: given a nodeId, find why it was updated.
100
+ */
101
+ var MutationEventCorrelation = class {
102
+ /** Map from nodeId -> list of { batchUid, action, timestamp, causalEvent } */
103
+ nodeIndex = /* @__PURE__ */ new Map();
104
+ maxEntriesPerNode = 20;
105
+ batchEventMap = /* @__PURE__ */ new Map();
106
+ /** Register a batch's causal event for later correlation. */
107
+ registerBatchEvent(batchUid, causalEvent) {
108
+ this.batchEventMap.set(batchUid, causalEvent);
109
+ if (this.batchEventMap.size > 500) {
110
+ const firstKey = this.batchEventMap.keys().next().value;
111
+ if (firstKey !== void 0) this.batchEventMap.delete(firstKey);
112
+ }
113
+ }
114
+ /** Index a mutation entry for a specific node. */
115
+ indexMutation(entry) {
116
+ const nodeId = entry.mutation.id;
117
+ if (nodeId == null) return;
118
+ const causalEvent = entry.batchUid != null ? this.batchEventMap.get(entry.batchUid) ?? null : null;
119
+ let list = this.nodeIndex.get(nodeId);
120
+ if (!list) {
121
+ list = [];
122
+ this.nodeIndex.set(nodeId, list);
123
+ }
124
+ list.push({
125
+ batchUid: entry.batchUid,
126
+ action: entry.action,
127
+ timestamp: entry.timestamp,
128
+ causalEvent
129
+ });
130
+ if (list.length > this.maxEntriesPerNode) list.shift();
131
+ }
132
+ /** Look up the chain: mutation -> batch -> event for a given nodeId. */
133
+ getWhyUpdated(nodeId) {
134
+ return this.nodeIndex.get(nodeId) ?? [];
135
+ }
136
+ /** Clear all data. */
137
+ clear() {
138
+ this.nodeIndex.clear();
139
+ this.batchEventMap.clear();
140
+ }
141
+ };
142
+ function resolveDebugHooks(options) {
143
+ if (!options) return {
144
+ onMutation: null,
145
+ onEvent: null,
146
+ onSyncRead: null,
147
+ onScheduler: null,
148
+ onWarning: null
149
+ };
150
+ const logger = {
151
+ ...defaultLogger,
152
+ ...options.logger
153
+ };
154
+ return {
155
+ onMutation: options.logMutations ? (e) => logger.mutation(e) : null,
156
+ onEvent: options.logEvents ? (e) => logger.event(e) : null,
157
+ onSyncRead: options.logSyncReads ? (e) => logger.syncRead(e) : null,
158
+ onScheduler: options.logScheduler ? (e) => logger.scheduler(e) : null,
159
+ onWarning: options.logWarnings ? (e) => logger.warning(e) : null
160
+ };
161
+ }
162
+ //#endregion
163
+ //#region src/core/protocol.ts
164
+ /**
165
+ * Reserved structural node IDs.
166
+ * These correspond to the well-known DOM nodes that always exist.
167
+ * Dynamic node IDs start at 11 to avoid collisions.
168
+ */
169
+ const BODY_NODE_ID = 1;
170
+ const HEAD_NODE_ID = 2;
171
+ const HTML_NODE_ID = 3;
172
+ const DOCUMENT_NODE_ID = 4;
173
+ let _nodeIdCounter = 10;
174
+ /**
175
+ * Create a new unique numeric NodeId (auto-incremented).
176
+ */
177
+ function createNodeId() {
178
+ return ++_nodeIdCounter;
179
+ }
180
+ /** Cast a plain string to a branded AppId. */
181
+ function createAppId(id) {
182
+ return id;
183
+ }
184
+ /** Cast a plain string to a branded ClientId. */
185
+ function createClientId(id) {
186
+ return id;
187
+ }
188
+ /** Type guard: narrows a Message to MutationMessage. */
189
+ function isMutationMessage(msg) {
190
+ return msg.type === "mutation";
191
+ }
192
+ /** Type guard: narrows a Message to EventMessage. */
193
+ function isEventMessage(msg) {
194
+ return msg.type === "event";
195
+ }
196
+ /** Type guard: narrows a Message to SystemMessage. */
197
+ function isSystemMessage(msg) {
198
+ return !isMutationMessage(msg) && !isEventMessage(msg);
199
+ }
200
+ //#endregion
201
+ //#region src/core/sync-channel.ts
202
+ /**
203
+ * SharedArrayBuffer-based synchronous communication channel.
204
+ *
205
+ * Allows a worker thread to make blocking reads from the main thread
206
+ * using Atomics.wait/notify. Inspired by Partytown's approach.
207
+ *
208
+ * Buffer layout (SharedArrayBuffer):
209
+ * Int32Array view:
210
+ * [0] — signal: 0=idle, 1=request-pending, 2=response-ready
211
+ * [1] — query type enum
212
+ * [2] — request data length (bytes)
213
+ * [3] — response data length (bytes)
214
+ * Uint8Array view at offset 16: request data (JSON-encoded)
215
+ * Uint8Array view at offset 16+REQUEST_REGION_SIZE: response data (JSON-encoded)
216
+ */
217
+ const HEADER_SIZE = 16;
218
+ const REQUEST_REGION_SIZE = 4096;
219
+ const DEFAULT_BUFFER_SIZE = 65536;
220
+ const SIGNAL_IDLE = 0;
221
+ const SIGNAL_REQUEST = 1;
222
+ const SIGNAL_RESPONSE = 2;
223
+ const MAX_RETRIES = 5;
224
+ const WAIT_TIMEOUT_MS = 100;
225
+ /** Type of synchronous query that a worker can make to the main thread. */
226
+ let QueryType = /* @__PURE__ */ function(QueryType) {
227
+ /** Request element.getBoundingClientRect() result. */
228
+ QueryType[QueryType["BoundingRect"] = 0] = "BoundingRect";
229
+ /** Request window.getComputedStyle() result for a property. */
230
+ QueryType[QueryType["ComputedStyle"] = 1] = "ComputedStyle";
231
+ /** Request a DOM node property (e.g., clientWidth, scrollTop). */
232
+ QueryType[QueryType["NodeProperty"] = 2] = "NodeProperty";
233
+ /** Request a window property (e.g., innerWidth). */
234
+ QueryType[QueryType["WindowProperty"] = 3] = "WindowProperty";
235
+ return QueryType;
236
+ }({});
237
+ /**
238
+ * Worker-side synchronous channel.
239
+ * Uses Atomics.wait to block until the main thread responds.
240
+ */
241
+ var SyncChannel = class SyncChannel {
242
+ signal;
243
+ meta;
244
+ requestRegion;
245
+ responseRegion;
246
+ encoder = new TextEncoder();
247
+ decoder = new TextDecoder();
248
+ constructor(buffer) {
249
+ this.signal = new Int32Array(buffer, 0, 4);
250
+ this.meta = this.signal;
251
+ this.requestRegion = new Uint8Array(buffer, HEADER_SIZE, REQUEST_REGION_SIZE);
252
+ this.responseRegion = new Uint8Array(buffer, HEADER_SIZE + REQUEST_REGION_SIZE, buffer.byteLength - HEADER_SIZE - REQUEST_REGION_SIZE);
253
+ }
254
+ /**
255
+ * Create a new SyncChannel with a fresh SharedArrayBuffer.
256
+ * The returned buffer must be transferred to the worker via postMessage.
257
+ * @param size - Total buffer size in bytes (default: 64KB)
258
+ */
259
+ static create(size = DEFAULT_BUFFER_SIZE) {
260
+ const buffer = new SharedArrayBuffer(size);
261
+ return {
262
+ channel: new SyncChannel(buffer),
263
+ buffer
264
+ };
265
+ }
266
+ /** Attach to an existing SharedArrayBuffer received from the main thread. */
267
+ static fromBuffer(sab) {
268
+ return new SyncChannel(sab);
269
+ }
270
+ /**
271
+ * Send a synchronous request to the main thread and block until response.
272
+ *
273
+ * Protocol:
274
+ * 1. Write JSON-encoded request data to the request region
275
+ * 2. Set query type and data length in the header via Atomics.store (memory fence)
276
+ * 3. Set signal to SIGNAL_REQUEST and notify the main thread
277
+ * 4. Block with Atomics.wait until signal changes or timeout (100ms per retry, 5 retries max)
278
+ * 5. Read JSON-encoded response from the response region
279
+ *
280
+ * @param queryType - The type of DOM query to execute
281
+ * @param data - JSON-encoded request payload
282
+ * @returns Parsed response object, or null on timeout or parse failure
283
+ */
284
+ request(queryType, data) {
285
+ const encoded = this.encoder.encode(data);
286
+ if (encoded.byteLength > REQUEST_REGION_SIZE) return null;
287
+ this.requestRegion.set(encoded);
288
+ Atomics.store(this.meta, 1, queryType);
289
+ Atomics.store(this.meta, 2, encoded.byteLength);
290
+ Atomics.store(this.meta, 3, 0);
291
+ Atomics.store(this.signal, 0, SIGNAL_REQUEST);
292
+ Atomics.notify(this.signal, 0);
293
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
294
+ const result = Atomics.wait(this.signal, 0, SIGNAL_REQUEST, WAIT_TIMEOUT_MS);
295
+ if (result === "not-equal") break;
296
+ if (result === "ok") break;
297
+ }
298
+ if (Atomics.load(this.signal, 0) !== SIGNAL_RESPONSE) {
299
+ Atomics.store(this.signal, 0, SIGNAL_IDLE);
300
+ return null;
301
+ }
302
+ const responseLength = Atomics.load(this.meta, 3);
303
+ if (responseLength === 0) {
304
+ Atomics.store(this.signal, 0, SIGNAL_IDLE);
305
+ return null;
306
+ }
307
+ const responseBytes = this.responseRegion.slice(0, responseLength);
308
+ const responseStr = this.decoder.decode(responseBytes);
309
+ Atomics.store(this.signal, 0, SIGNAL_IDLE);
310
+ try {
311
+ return JSON.parse(responseStr);
312
+ } catch {
313
+ return null;
314
+ }
315
+ }
316
+ };
317
+ /**
318
+ * Main-thread host for the sync channel.
319
+ * Polls for pending requests and writes responses.
320
+ */
321
+ var SyncChannelHost = class {
322
+ signal;
323
+ meta;
324
+ requestRegion;
325
+ responseRegion;
326
+ encoder = new TextEncoder();
327
+ decoder = new TextDecoder();
328
+ polling = false;
329
+ pollChannel = null;
330
+ constructor(buffer) {
331
+ this.signal = new Int32Array(buffer, 0, 4);
332
+ this.meta = this.signal;
333
+ this.requestRegion = new Uint8Array(buffer, HEADER_SIZE, REQUEST_REGION_SIZE);
334
+ this.responseRegion = new Uint8Array(buffer, HEADER_SIZE + REQUEST_REGION_SIZE, buffer.byteLength - HEADER_SIZE - REQUEST_REGION_SIZE);
335
+ }
336
+ /**
337
+ * Non-blocking check for a pending query.
338
+ */
339
+ poll() {
340
+ if (Atomics.load(this.signal, 0) !== SIGNAL_REQUEST) return null;
341
+ const queryType = Atomics.load(this.meta, 1);
342
+ const dataLength = Atomics.load(this.meta, 2);
343
+ const dataBytes = this.requestRegion.slice(0, dataLength);
344
+ return {
345
+ queryType,
346
+ data: this.decoder.decode(dataBytes)
347
+ };
348
+ }
349
+ /**
350
+ * Write a response and wake the worker.
351
+ */
352
+ respond(data) {
353
+ const json = JSON.stringify(data);
354
+ const encoded = this.encoder.encode(json);
355
+ this.responseRegion.set(encoded);
356
+ Atomics.store(this.meta, 3, encoded.byteLength);
357
+ Atomics.store(this.signal, 0, SIGNAL_RESPONSE);
358
+ Atomics.notify(this.signal, 0);
359
+ }
360
+ /**
361
+ * Start polling for requests using a MessageChannel for lowest-latency scheduling.
362
+ *
363
+ * Uses MessageChannel.postMessage for microtask-level poll frequency when active,
364
+ * with exponential backoff (up to 16ms) when idle to reduce CPU usage.
365
+ * Falls back to setInterval(4ms) when MessageChannel is unavailable.
366
+ *
367
+ * @param handler - Synchronous function that executes the query and returns the result
368
+ */
369
+ startPolling(handler) {
370
+ if (this.polling) return;
371
+ this.polling = true;
372
+ if (typeof MessageChannel !== "undefined") {
373
+ this.pollChannel = new MessageChannel();
374
+ let idleCount = 0;
375
+ const pollOnce = () => {
376
+ if (!this.polling) return;
377
+ const query = this.poll();
378
+ if (query) {
379
+ idleCount = 0;
380
+ const result = handler(query);
381
+ this.respond(result);
382
+ this.pollChannel?.port2.postMessage(null);
383
+ } else {
384
+ idleCount++;
385
+ if (idleCount <= 2) this.pollChannel?.port2.postMessage(null);
386
+ else {
387
+ const delay = Math.min(1 << idleCount - 3, 16);
388
+ setTimeout(() => {
389
+ if (this.polling) this.pollChannel?.port2.postMessage(null);
390
+ }, delay);
391
+ }
392
+ }
393
+ };
394
+ this.pollChannel.port1.onmessage = pollOnce;
395
+ this.pollChannel.port2.postMessage(null);
396
+ } else {
397
+ const intervalId = setInterval(() => {
398
+ if (!this.polling) {
399
+ clearInterval(intervalId);
400
+ return;
401
+ }
402
+ const query = this.poll();
403
+ if (query) {
404
+ const result = handler(query);
405
+ this.respond(result);
406
+ }
407
+ }, 4);
408
+ }
409
+ }
410
+ /**
411
+ * Stop polling for requests.
412
+ */
413
+ stopPolling() {
414
+ this.polling = false;
415
+ if (this.pollChannel) {
416
+ this.pollChannel.port1.close();
417
+ this.pollChannel.port2.close();
418
+ this.pollChannel = null;
419
+ }
420
+ }
421
+ };
422
+ //#endregion
423
+ Object.defineProperty(exports, "BODY_NODE_ID", {
424
+ enumerable: true,
425
+ get: function() {
426
+ return BODY_NODE_ID;
427
+ }
428
+ });
429
+ Object.defineProperty(exports, "DOCUMENT_NODE_ID", {
430
+ enumerable: true,
431
+ get: function() {
432
+ return DOCUMENT_NODE_ID;
433
+ }
434
+ });
435
+ Object.defineProperty(exports, "DebugStats", {
436
+ enumerable: true,
437
+ get: function() {
438
+ return DebugStats;
439
+ }
440
+ });
441
+ Object.defineProperty(exports, "HEAD_NODE_ID", {
442
+ enumerable: true,
443
+ get: function() {
444
+ return HEAD_NODE_ID;
445
+ }
446
+ });
447
+ Object.defineProperty(exports, "HTML_NODE_ID", {
448
+ enumerable: true,
449
+ get: function() {
450
+ return HTML_NODE_ID;
451
+ }
452
+ });
453
+ Object.defineProperty(exports, "MutationEventCorrelation", {
454
+ enumerable: true,
455
+ get: function() {
456
+ return MutationEventCorrelation;
457
+ }
458
+ });
459
+ Object.defineProperty(exports, "QueryType", {
460
+ enumerable: true,
461
+ get: function() {
462
+ return QueryType;
463
+ }
464
+ });
465
+ Object.defineProperty(exports, "SyncChannel", {
466
+ enumerable: true,
467
+ get: function() {
468
+ return SyncChannel;
469
+ }
470
+ });
471
+ Object.defineProperty(exports, "SyncChannelHost", {
472
+ enumerable: true,
473
+ get: function() {
474
+ return SyncChannelHost;
475
+ }
476
+ });
477
+ Object.defineProperty(exports, "WarningCode", {
478
+ enumerable: true,
479
+ get: function() {
480
+ return WarningCode;
481
+ }
482
+ });
483
+ Object.defineProperty(exports, "WarningDescriptions", {
484
+ enumerable: true,
485
+ get: function() {
486
+ return WarningDescriptions;
487
+ }
488
+ });
489
+ Object.defineProperty(exports, "createAppId", {
490
+ enumerable: true,
491
+ get: function() {
492
+ return createAppId;
493
+ }
494
+ });
495
+ Object.defineProperty(exports, "createClientId", {
496
+ enumerable: true,
497
+ get: function() {
498
+ return createClientId;
499
+ }
500
+ });
501
+ Object.defineProperty(exports, "createNodeId", {
502
+ enumerable: true,
503
+ get: function() {
504
+ return createNodeId;
505
+ }
506
+ });
507
+ Object.defineProperty(exports, "isEventMessage", {
508
+ enumerable: true,
509
+ get: function() {
510
+ return isEventMessage;
511
+ }
512
+ });
513
+ Object.defineProperty(exports, "isMutationMessage", {
514
+ enumerable: true,
515
+ get: function() {
516
+ return isMutationMessage;
517
+ }
518
+ });
519
+ Object.defineProperty(exports, "isSystemMessage", {
520
+ enumerable: true,
521
+ get: function() {
522
+ return isSystemMessage;
523
+ }
524
+ });
525
+ Object.defineProperty(exports, "resolveDebugHooks", {
526
+ enumerable: true,
527
+ get: function() {
528
+ return resolveDebugHooks;
529
+ }
530
+ });
531
+
532
+ //# sourceMappingURL=sync-channel.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-channel.cjs","names":[],"sources":["../src/core/debug.ts","../src/core/protocol.ts","../src/core/sync-channel.ts"],"sourcesContent":["import type { DomMutation } from \"./protocol.ts\";\n\n/**\n * Options for enabling debug logging and the in-page devtools panel.\n *\n * Each `log*` flag enables a category of structured log output. Provide a\n * custom `logger` to redirect output (e.g. to a remote telemetry service).\n */\nexport interface DebugOptions {\n\t/** Log every DOM mutation applied by the renderer. */\n\tlogMutations?: boolean;\n\t/** Log event serialization and dispatch timing. */\n\tlogEvents?: boolean;\n\t/** Log synchronous DOM read requests (getBoundingClientRect, computedStyle, etc.). */\n\tlogSyncReads?: boolean;\n\t/** Log per-frame scheduler statistics (actions processed, frame time, queue depth). */\n\tlogScheduler?: boolean;\n\t/** Log warnings such as missing nodes, sync timeouts, and blocked properties. */\n\tlogWarnings?: boolean;\n\t/** Custom logger implementation. Unset methods fall back to `console.*`. */\n\tlogger?: Partial<DebugLogger>;\n\t/** Expose `__ASYNC_DOM_DEVTOOLS__` on `globalThis` and inject the in-page devtools panel. */\n\texposeDevtools?: boolean;\n}\n\n/**\n * Custom logger that receives structured debug entries.\n *\n * Implement any subset of these methods and pass via `DebugOptions.logger`.\n */\nexport interface DebugLogger {\n\t/** Called for each DOM mutation applied on the main thread. */\n\tmutation(entry: MutationLogEntry): void;\n\t/** Called for event serialization and dispatch timing. */\n\tevent(entry: EventLogEntry): void;\n\t/** Called for each synchronous DOM read request. */\n\tsyncRead(entry: SyncReadLogEntry): void;\n\t/** Called once per scheduler frame with aggregate statistics. */\n\tscheduler(entry: SchedulerLogEntry): void;\n\t/** Called for async-dom warnings (missing nodes, timeouts, etc.). */\n\twarning(entry: WarningLogEntry): void;\n}\n\n/** A single DOM mutation log entry emitted by the debug system. */\nexport interface MutationLogEntry {\n\t/** Which thread generated this entry. */\n\tside: \"worker\" | \"main\";\n\t/** The mutation action name (e.g. \"createElement\", \"setAttribute\"). */\n\taction: string;\n\t/** The full mutation payload. */\n\tmutation: DomMutation;\n\t/** High-resolution timestamp (via `performance.now()`). */\n\ttimestamp: number;\n\t/** Batch UID that groups related mutations from a single flush. */\n\tbatchUid?: number;\n}\n\n/** A single event timing log entry emitted by the debug system. */\nexport interface EventLogEntry {\n\t/** Which thread generated this entry. */\n\tside: \"worker\" | \"main\";\n\t/** Whether this captures serialization or dispatch timing. */\n\tphase: \"serialize\" | \"dispatch\";\n\t/** The DOM event type (e.g. \"click\", \"input\"). */\n\teventType: string;\n\t/** Unique listener identifier. */\n\tlistenerId: string;\n\t/** Node ID of the event target, or `null` if unavailable. */\n\ttargetId: string | null;\n\t/** High-resolution timestamp (via `performance.now()`). */\n\ttimestamp: number;\n\t/** Time in ms the event spent in transport between threads. */\n\ttransportMs?: number;\n\t/** Time in ms the worker spent dispatching the event handler. */\n\tdispatchMs?: number;\n\t/** Number of DOM mutations produced by the event handler. */\n\tmutationCount?: number;\n}\n\n/** A single synchronous DOM read log entry. */\nexport interface SyncReadLogEntry {\n\t/** The query type enum value (BoundingRect, ComputedStyle, etc.). */\n\tqueryType: number;\n\t/** The target node ID as a string. */\n\tnodeId: string;\n\t/** Round-trip latency in milliseconds. */\n\tlatencyMs: number;\n\t/** Whether the read succeeded, timed out, or threw an error. */\n\tresult: \"success\" | \"timeout\" | \"error\";\n\t/** High-resolution timestamp (via `performance.now()`). */\n\ttimestamp: number;\n}\n\n/** A single scheduler frame log entry. */\nexport interface SchedulerLogEntry {\n\t/** Monotonically increasing frame counter. */\n\tframeId: number;\n\t/** Number of mutations processed in this frame. */\n\tactionsProcessed: number;\n\t/** Total wall-clock time spent processing this frame in ms. */\n\tframeTimeMs: number;\n\t/** Number of mutations remaining in the queue after this frame. */\n\tqueueDepth: number;\n\t/** High-resolution timestamp (via `performance.now()`). */\n\ttimestamp: number;\n}\n\n/** A warning entry emitted when async-dom detects a potential problem. */\nexport interface WarningLogEntry {\n\t/** Machine-readable warning code (see `WarningCode`). */\n\tcode: string;\n\t/** Human-readable description of the problem. */\n\tmessage: string;\n\t/** Additional context data relevant to the warning. */\n\tcontext: Record<string, unknown>;\n\t/** High-resolution timestamp (via `performance.now()`). */\n\ttimestamp: number;\n}\n\nexport const WarningCode = {\n\tMISSING_NODE: \"ASYNC_DOM_MISSING_NODE\",\n\tSYNC_TIMEOUT: \"ASYNC_DOM_SYNC_TIMEOUT\",\n\tLISTENER_NOT_FOUND: \"ASYNC_DOM_LISTENER_NOT_FOUND\",\n\tEVENT_ATTACH_FAILED: \"ASYNC_DOM_EVENT_ATTACH_FAILED\",\n\tTRANSPORT_NOT_OPEN: \"ASYNC_DOM_TRANSPORT_NOT_OPEN\",\n\tBLOCKED_PROPERTY: \"ASYNC_DOM_BLOCKED_PROPERTY\",\n\tWORKER_ERROR: \"WORKER_ERROR\",\n\tWORKER_UNHANDLED_REJECTION: \"WORKER_UNHANDLED_REJECTION\",\n} as const;\n\nexport const WarningDescriptions: Record<\n\t(typeof WarningCode)[keyof typeof WarningCode],\n\t{ description: string; suggestion: string }\n> = {\n\tASYNC_DOM_MISSING_NODE: {\n\t\tdescription: \"A DOM mutation referenced a node ID that doesn't exist in the node cache.\",\n\t\tsuggestion:\n\t\t\t\"Ensure nodes are created before being referenced. Check for race conditions between create and update mutations.\",\n\t},\n\tASYNC_DOM_SYNC_TIMEOUT: {\n\t\tdescription:\n\t\t\t\"A synchronous read (getBoundingClientRect, computedStyle) timed out waiting for the main thread response.\",\n\t\tsuggestion: \"Reduce sync read frequency, increase timeout, or use cached values when possible.\",\n\t},\n\tASYNC_DOM_LISTENER_NOT_FOUND: {\n\t\tdescription: \"An event was received for a listener ID that is not registered.\",\n\t\tsuggestion:\n\t\t\t\"This may indicate a timing issue where a listener was removed before its event was processed.\",\n\t},\n\tASYNC_DOM_EVENT_ATTACH_FAILED: {\n\t\tdescription: \"Failed to attach an event listener to a DOM node.\",\n\t\tsuggestion: \"Verify the target node exists in the DOM when the listener is being attached.\",\n\t},\n\tASYNC_DOM_TRANSPORT_NOT_OPEN: {\n\t\tdescription: \"Attempted to send a message through a closed or connecting transport.\",\n\t\tsuggestion: \"Ensure the transport connection is established before sending mutations.\",\n\t},\n\tASYNC_DOM_BLOCKED_PROPERTY: {\n\t\tdescription: \"A setProperty call was blocked because the property is not in the allowed list.\",\n\t\tsuggestion:\n\t\t\t\"Add the property to additionalAllowedProperties in the renderer permissions if it's safe.\",\n\t},\n\tWORKER_ERROR: {\n\t\tdescription: \"An unhandled error occurred in the worker thread.\",\n\t\tsuggestion:\n\t\t\t\"Check the stack trace for the error source. Add error handling in your worker code.\",\n\t},\n\tWORKER_UNHANDLED_REJECTION: {\n\t\tdescription: \"An unhandled promise rejection occurred in the worker thread.\",\n\t\tsuggestion:\n\t\t\t\"Add .catch() handlers to promises or use try/catch with async/await in your worker code.\",\n\t},\n};\n\nconst defaultLogger: DebugLogger = {\n\twarning(entry) {\n\t\tconsole.warn(`[async-dom] ${entry.code}: ${entry.message}`, entry.context);\n\t},\n\tmutation(entry) {\n\t\tconsole.log(`[async-dom:${entry.side}] mutation:${entry.action}`, entry.mutation);\n\t},\n\tevent(entry) {\n\t\tconsole.log(\n\t\t\t`[async-dom:${entry.side}] event:${entry.phase} ${entry.eventType} listenerId=${entry.listenerId}`,\n\t\t);\n\t},\n\tsyncRead(entry) {\n\t\tconsole.log(\n\t\t\t`[async-dom] sync:${entry.queryType} node=${entry.nodeId} ${entry.result} (${entry.latencyMs.toFixed(1)}ms)`,\n\t\t);\n\t},\n\tscheduler(entry) {\n\t\tconsole.log(\n\t\t\t`[async-dom] frame:${entry.frameId} actions=${entry.actionsProcessed} time=${entry.frameTimeMs.toFixed(1)}ms queue=${entry.queueDepth}`,\n\t\t);\n\t},\n};\n\nexport class DebugStats {\n\tmutationsAdded = 0;\n\tmutationsCoalesced = 0;\n\tmutationsFlushed = 0;\n\tmutationsApplied = 0;\n\teventsForwarded = 0;\n\teventsDispatched = 0;\n\tsyncReadRequests = 0;\n\tsyncReadTimeouts = 0;\n\n\tsnapshot(): Record<string, number> {\n\t\treturn {\n\t\t\tmutationsAdded: this.mutationsAdded,\n\t\t\tmutationsCoalesced: this.mutationsCoalesced,\n\t\t\tmutationsFlushed: this.mutationsFlushed,\n\t\t\tmutationsApplied: this.mutationsApplied,\n\t\t\teventsForwarded: this.eventsForwarded,\n\t\t\teventsDispatched: this.eventsDispatched,\n\t\t\tsyncReadRequests: this.syncReadRequests,\n\t\t\tsyncReadTimeouts: this.syncReadTimeouts,\n\t\t};\n\t}\n\n\treset(): void {\n\t\tthis.mutationsAdded = 0;\n\t\tthis.mutationsCoalesced = 0;\n\t\tthis.mutationsFlushed = 0;\n\t\tthis.mutationsApplied = 0;\n\t\tthis.eventsForwarded = 0;\n\t\tthis.eventsDispatched = 0;\n\t\tthis.syncReadRequests = 0;\n\t\tthis.syncReadTimeouts = 0;\n\t}\n}\n\n/**\n * Mutation-to-event correlation index (Feature 19: \"Why Was This Node Updated?\").\n *\n * Indexes mutations by nodeId and links them to their batch and causal event,\n * allowing reverse lookups: given a nodeId, find why it was updated.\n */\nexport class MutationEventCorrelation {\n\t/** Map from nodeId -> list of { batchUid, action, timestamp, causalEvent } */\n\tprivate nodeIndex = new Map<\n\t\tnumber,\n\t\tArray<{\n\t\t\tbatchUid: number | undefined;\n\t\t\taction: string;\n\t\t\ttimestamp: number;\n\t\t\tcausalEvent: { eventType: string; listenerId: string; timestamp: number } | null;\n\t\t}>\n\t>();\n\n\tprivate maxEntriesPerNode = 20;\n\tprivate batchEventMap = new Map<\n\t\tnumber,\n\t\t{ eventType: string; listenerId: string; timestamp: number }\n\t>();\n\n\t/** Register a batch's causal event for later correlation. */\n\tregisterBatchEvent(\n\t\tbatchUid: number,\n\t\tcausalEvent: { eventType: string; listenerId: string; timestamp: number },\n\t): void {\n\t\tthis.batchEventMap.set(batchUid, causalEvent);\n\t\t// Limit size\n\t\tif (this.batchEventMap.size > 500) {\n\t\t\tconst firstKey = this.batchEventMap.keys().next().value;\n\t\t\tif (firstKey !== undefined) this.batchEventMap.delete(firstKey);\n\t\t}\n\t}\n\n\t/** Index a mutation entry for a specific node. */\n\tindexMutation(entry: MutationLogEntry): void {\n\t\tconst m = entry.mutation as Record<string, unknown>;\n\t\tconst nodeId = m.id as number | undefined;\n\t\tif (nodeId == null) return;\n\n\t\tconst causalEvent =\n\t\t\tentry.batchUid != null ? (this.batchEventMap.get(entry.batchUid) ?? null) : null;\n\n\t\tlet list = this.nodeIndex.get(nodeId);\n\t\tif (!list) {\n\t\t\tlist = [];\n\t\t\tthis.nodeIndex.set(nodeId, list);\n\t\t}\n\t\tlist.push({\n\t\t\tbatchUid: entry.batchUid,\n\t\t\taction: entry.action,\n\t\t\ttimestamp: entry.timestamp,\n\t\t\tcausalEvent,\n\t\t});\n\t\tif (list.length > this.maxEntriesPerNode) {\n\t\t\tlist.shift();\n\t\t}\n\t}\n\n\t/** Look up the chain: mutation -> batch -> event for a given nodeId. */\n\tgetWhyUpdated(nodeId: number): Array<{\n\t\tbatchUid: number | undefined;\n\t\taction: string;\n\t\ttimestamp: number;\n\t\tcausalEvent: { eventType: string; listenerId: string; timestamp: number } | null;\n\t}> {\n\t\treturn this.nodeIndex.get(nodeId) ?? [];\n\t}\n\n\t/** Clear all data. */\n\tclear(): void {\n\t\tthis.nodeIndex.clear();\n\t\tthis.batchEventMap.clear();\n\t}\n}\n\nexport function resolveDebugHooks(options?: DebugOptions): {\n\tonMutation: ((entry: MutationLogEntry) => void) | null;\n\tonEvent: ((entry: EventLogEntry) => void) | null;\n\tonSyncRead: ((entry: SyncReadLogEntry) => void) | null;\n\tonScheduler: ((entry: SchedulerLogEntry) => void) | null;\n\tonWarning: ((entry: WarningLogEntry) => void) | null;\n} {\n\tif (!options)\n\t\treturn {\n\t\t\tonMutation: null,\n\t\t\tonEvent: null,\n\t\t\tonSyncRead: null,\n\t\t\tonScheduler: null,\n\t\t\tonWarning: null,\n\t\t};\n\tconst logger = { ...defaultLogger, ...options.logger };\n\treturn {\n\t\tonMutation: options.logMutations ? (e) => logger.mutation(e) : null,\n\t\tonEvent: options.logEvents ? (e) => logger.event(e) : null,\n\t\tonSyncRead: options.logSyncReads ? (e) => logger.syncRead(e) : null,\n\t\tonScheduler: options.logScheduler ? (e) => logger.scheduler(e) : null,\n\t\tonWarning: options.logWarnings ? (e) => logger.warning(e) : null,\n\t};\n}\n","/**\n * Type-safe message protocol for async-dom communication.\n *\n * All messages between the main thread and worker threads use discriminated\n * unions for compile-time safety and exhaustive switch handling.\n */\n\n/**\n * Branded numeric type for DOM node identifiers.\n * The brand prevents accidental use of plain numbers as NodeIds.\n */\nexport type NodeId = number & { readonly __brand: \"NodeId\" };\n\n/** Branded string type identifying an application instance. */\nexport type AppId = string & { readonly __brand: \"AppId\" };\n\n/** Branded string type identifying a connected client (for multi-client server mode). */\nexport type ClientId = string & { readonly __brand: \"ClientId\" };\n\n/**\n * Reserved structural node IDs.\n * These correspond to the well-known DOM nodes that always exist.\n * Dynamic node IDs start at 11 to avoid collisions.\n */\nexport const BODY_NODE_ID = 1 as NodeId;\nexport const HEAD_NODE_ID = 2 as NodeId;\nexport const HTML_NODE_ID = 3 as NodeId;\nexport const DOCUMENT_NODE_ID = 4 as NodeId;\n\nlet _nodeIdCounter = 10; // Start after reserved IDs\n\n/**\n * Create a new unique numeric NodeId (auto-incremented).\n */\nexport function createNodeId(): NodeId {\n\treturn ++_nodeIdCounter as NodeId;\n}\n\n/**\n * Reset the node ID counter (for testing only).\n */\nexport function _resetNodeIdCounter(): void {\n\t_nodeIdCounter = 10;\n}\n\n/** Cast a plain string to a branded AppId. */\nexport function createAppId(id: string): AppId {\n\treturn id as AppId;\n}\n\n/** Cast a plain string to a branded ClientId. */\nexport function createClientId(id: string): ClientId {\n\treturn id as ClientId;\n}\n\n/** Standard DOM insertAdjacentHTML position values. */\nexport type InsertPosition = \"beforebegin\" | \"afterbegin\" | \"beforeend\" | \"afterend\";\n\n/**\n * Discriminated union of all DOM mutations sent from worker to main thread.\n *\n * Mutation lifecycle:\n * 1. Worker-side VirtualElement/VirtualDocument methods create DomMutation objects\n * 2. Mutations are collected by MutationCollector into batches\n * 3. Batches are wrapped in a MutationMessage and sent via Transport\n * 4. Main-thread FrameScheduler queues and prioritizes mutations\n * 5. DomRenderer.apply() executes each mutation against the real DOM\n *\n * Each variant carries the target node's `id` plus action-specific data.\n * Mutations marked `optional: true` (e.g., style updates) may be dropped\n * by the scheduler under frame budget pressure.\n */\nexport type DomMutation =\n\t| { action: \"createNode\"; id: NodeId; tag: string; textContent?: string }\n\t| { action: \"createComment\"; id: NodeId; textContent: string }\n\t| { action: \"appendChild\"; id: NodeId; childId: NodeId }\n\t| { action: \"removeNode\"; id: NodeId }\n\t| { action: \"removeChild\"; id: NodeId; childId: NodeId }\n\t| {\n\t\t\taction: \"insertBefore\";\n\t\t\tid: NodeId;\n\t\t\tnewId: NodeId;\n\t\t\trefId: NodeId | null;\n\t }\n\t| {\n\t\t\taction: \"setAttribute\";\n\t\t\tid: NodeId;\n\t\t\tname: string;\n\t\t\tvalue: string;\n\t\t\toptional?: boolean;\n\t }\n\t| { action: \"removeAttribute\"; id: NodeId; name: string }\n\t| {\n\t\t\taction: \"setStyle\";\n\t\t\tid: NodeId;\n\t\t\tproperty: string;\n\t\t\tvalue: string;\n\t\t\toptional?: boolean;\n\t }\n\t| { action: \"setProperty\"; id: NodeId; property: string; value: unknown }\n\t| { action: \"setTextContent\"; id: NodeId; textContent: string }\n\t| { action: \"setClassName\"; id: NodeId; name: string }\n\t| { action: \"setHTML\"; id: NodeId; html: string }\n\t| {\n\t\t\taction: \"addEventListener\";\n\t\t\tid: NodeId;\n\t\t\tname: string;\n\t\t\tlistenerId: string;\n\t }\n\t| { action: \"headAppendChild\"; id: NodeId }\n\t| { action: \"bodyAppendChild\"; id: NodeId }\n\t| { action: \"pushState\"; state: unknown; title: string; url: string }\n\t| { action: \"replaceState\"; state: unknown; title: string; url: string }\n\t| { action: \"scrollTo\"; x: number; y: number }\n\t| { action: \"insertAdjacentHTML\"; id: NodeId; position: InsertPosition; html: string }\n\t| {\n\t\t\taction: \"configureEvent\";\n\t\t\tid: NodeId;\n\t\t\tname: string;\n\t\t\tpreventDefault: boolean;\n\t\t\tpassive?: boolean;\n\t }\n\t| { action: \"removeEventListener\"; id: NodeId; listenerId: string }\n\t| { action: \"callMethod\"; id: NodeId; method: string; args: unknown[] };\n\n/** Convenience union of all possible mutation action string literals. */\nexport type MutationAction = DomMutation[\"action\"];\n\n/** Scheduler priority level. High-priority mutations are processed first each frame. */\nexport type Priority = \"high\" | \"normal\" | \"low\";\n\n/**\n * Envelope wrapping a batch of mutations with routing and timing metadata.\n * Sent from worker thread to main thread via Transport.\n */\nexport interface MutationMessage {\n\ttype: \"mutation\";\n\tappId: AppId;\n\tuid: number;\n\tmutations: DomMutation[];\n\tpriority?: Priority;\n\tsentAt?: number;\n\t/** Causal event that triggered this batch (Feature 15: Causality Graph). */\n\tcausalEvent?: { eventType: string; listenerId: string; timestamp: number };\n}\n\n/**\n * Serialized event data sent from main thread to worker.\n * Contains a flat subset of DOM event properties that can be transferred via postMessage.\n * Target and relatedTarget are serialized as NodeId strings, not DOM references.\n */\nexport interface SerializedEvent {\n\ttype: string;\n\ttarget: string | null;\n\tcurrentTarget: string | null;\n\t// Mouse event properties\n\tclientX?: number;\n\tclientY?: number;\n\tpageX?: number;\n\tpageY?: number;\n\tscreenX?: number;\n\tscreenY?: number;\n\toffsetX?: number;\n\toffsetY?: number;\n\tbutton?: number;\n\tbuttons?: number;\n\t// Keyboard event properties\n\tkey?: string;\n\tcode?: string;\n\tkeyCode?: number;\n\t// Modifier keys\n\taltKey?: boolean;\n\tctrlKey?: boolean;\n\tmetaKey?: boolean;\n\tshiftKey?: boolean;\n\t// Common properties\n\tbubbles?: boolean;\n\tcancelable?: boolean;\n\tcomposed?: boolean;\n\tdetail?: number;\n\teventPhase?: number;\n\tisTrusted?: boolean;\n\ttimeStamp?: number;\n\t// Input event properties\n\tdata?: string;\n\tinputType?: string;\n\t// Related target\n\trelatedTarget?: string | null;\n\t// Wheel event properties\n\tdeltaX?: number;\n\tdeltaY?: number;\n\tdeltaZ?: number;\n\tdeltaMode?: number;\n\t// Input state synchronization\n\tvalue?: string;\n\tchecked?: boolean;\n\tselectedIndex?: number;\n\t// Media element state\n\tcurrentTime?: number;\n\tduration?: number;\n\tpaused?: boolean;\n\tended?: boolean;\n\treadyState?: number;\n}\n\n/** Event message sent from main thread to worker to dispatch a DOM event. */\nexport interface EventMessage {\n\ttype: \"event\";\n\tappId: AppId;\n\tlistenerId: string;\n\tevent: SerializedEvent;\n\tclientId?: ClientId;\n}\n\n/** Serialized window.location data sent during app initialization. */\nexport interface SerializedLocation {\n\thash: string;\n\thref: string;\n\tport: string;\n\thost: string;\n\torigin: string;\n\thostname: string;\n\tpathname: string;\n\tprotocol: string;\n\tsearch: string;\n\tstate: unknown;\n}\n\n/** Serialized error data for cross-thread error reporting, including causal chain via `cause`. */\nexport interface SerializedError {\n\tmessage: string;\n\tstack?: string;\n\tname?: string;\n\tcause?: SerializedError;\n\tfilename?: string;\n\tlineno?: number;\n\tcolno?: number;\n\tisUnhandledRejection?: boolean;\n}\n\n/**\n * System-level control messages exchanged between main thread and worker.\n * Includes lifecycle events (init/ready), sync queries, diagnostics, and multi-client management.\n */\nexport type SystemMessage =\n\t| { type: \"init\"; appId: AppId; location: SerializedLocation; sharedBuffer?: SharedArrayBuffer }\n\t| { type: \"ready\"; appId: AppId }\n\t| { type: \"error\"; appId: AppId; error: SerializedError }\n\t| { type: \"visibility\"; state: \"visible\" | \"hidden\" | \"prerender\" }\n\t| {\n\t\t\ttype: \"query\";\n\t\t\tappId: AppId;\n\t\t\tuid: number;\n\t\t\tnodeId: NodeId;\n\t\t\tquery: \"boundingRect\" | \"computedStyle\" | \"nodeProperty\" | \"windowProperty\";\n\t\t\tproperty?: string;\n\t }\n\t| { type: \"queryResult\"; uid: number; result: unknown }\n\t| { type: \"debugQuery\"; query: string }\n\t| { type: \"debugResult\"; query: string; result: unknown }\n\t| {\n\t\t\ttype: \"eventTimingResult\";\n\t\t\tlistenerId: string;\n\t\t\teventType: string;\n\t\t\tdispatchMs: number;\n\t\t\tmutationCount: number;\n\t\t\ttransportMs: number;\n\t }\n\t| { type: \"perfEntries\"; appId: AppId; entries: PerfEntryData[] }\n\t| { type: \"ping\" }\n\t| { type: \"pong\" }\n\t| { type: \"ack\"; appId: AppId; lastUid: number }\n\t| { type: \"clientConnect\"; clientId: ClientId; metadata?: Record<string, unknown> }\n\t| { type: \"clientDisconnect\"; clientId: ClientId }\n\t| { type: \"snapshotComplete\" };\n\n/** Serialized performance entry sent from worker to main thread (Feature 16). */\nexport interface PerfEntryData {\n\tname: string;\n\tstartTime: number;\n\tduration: number;\n\tentryType: string;\n}\n\n/** Top-level discriminated union of all messages in the async-dom protocol. */\nexport type Message = MutationMessage | EventMessage | SystemMessage;\n\n/** Type guard: narrows a Message to MutationMessage. */\nexport function isMutationMessage(msg: Message): msg is MutationMessage {\n\treturn msg.type === \"mutation\";\n}\n\n/** Type guard: narrows a Message to EventMessage. */\nexport function isEventMessage(msg: Message): msg is EventMessage {\n\treturn msg.type === \"event\";\n}\n\n/** Type guard: narrows a Message to SystemMessage. */\nexport function isSystemMessage(msg: Message): msg is SystemMessage {\n\treturn !isMutationMessage(msg) && !isEventMessage(msg);\n}\n","/**\n * SharedArrayBuffer-based synchronous communication channel.\n *\n * Allows a worker thread to make blocking reads from the main thread\n * using Atomics.wait/notify. Inspired by Partytown's approach.\n *\n * Buffer layout (SharedArrayBuffer):\n * Int32Array view:\n * [0] — signal: 0=idle, 1=request-pending, 2=response-ready\n * [1] — query type enum\n * [2] — request data length (bytes)\n * [3] — response data length (bytes)\n * Uint8Array view at offset 16: request data (JSON-encoded)\n * Uint8Array view at offset 16+REQUEST_REGION_SIZE: response data (JSON-encoded)\n */\n\nconst HEADER_SIZE = 16; // 4 Int32s\nconst REQUEST_REGION_SIZE = 4096;\nconst DEFAULT_BUFFER_SIZE = 65536; // 64KB\nconst SIGNAL_IDLE = 0;\nconst SIGNAL_REQUEST = 1;\nconst SIGNAL_RESPONSE = 2;\nconst MAX_RETRIES = 5;\nconst WAIT_TIMEOUT_MS = 100;\n\n/** Type of synchronous query that a worker can make to the main thread. */\nexport enum QueryType {\n\t/** Request element.getBoundingClientRect() result. */\n\tBoundingRect = 0,\n\t/** Request window.getComputedStyle() result for a property. */\n\tComputedStyle = 1,\n\t/** Request a DOM node property (e.g., clientWidth, scrollTop). */\n\tNodeProperty = 2,\n\t/** Request a window property (e.g., innerWidth). */\n\tWindowProperty = 3,\n}\n\n/** A pending query read from the shared buffer by the main-thread host. */\nexport interface PendingQuery {\n\t/** Which type of DOM query to execute. */\n\tqueryType: QueryType;\n\t/** JSON-encoded request payload (e.g., `{\"nodeId\": 42, \"property\": \"clientWidth\"}`). */\n\tdata: string;\n}\n\n/**\n * Worker-side synchronous channel.\n * Uses Atomics.wait to block until the main thread responds.\n */\nexport class SyncChannel {\n\tprivate signal: Int32Array;\n\tprivate meta: Int32Array;\n\tprivate requestRegion: Uint8Array;\n\tprivate responseRegion: Uint8Array;\n\tprivate encoder = new TextEncoder();\n\tprivate decoder = new TextDecoder();\n\n\tprivate constructor(buffer: SharedArrayBuffer) {\n\t\tthis.signal = new Int32Array(buffer, 0, 4);\n\t\tthis.meta = this.signal; // same view, different semantic access\n\t\tthis.requestRegion = new Uint8Array(buffer, HEADER_SIZE, REQUEST_REGION_SIZE);\n\t\tthis.responseRegion = new Uint8Array(\n\t\t\tbuffer,\n\t\t\tHEADER_SIZE + REQUEST_REGION_SIZE,\n\t\t\tbuffer.byteLength - HEADER_SIZE - REQUEST_REGION_SIZE,\n\t\t);\n\t}\n\n\t/**\n\t * Create a new SyncChannel with a fresh SharedArrayBuffer.\n\t * The returned buffer must be transferred to the worker via postMessage.\n\t * @param size - Total buffer size in bytes (default: 64KB)\n\t */\n\tstatic create(size: number = DEFAULT_BUFFER_SIZE): {\n\t\tchannel: SyncChannel;\n\t\tbuffer: SharedArrayBuffer;\n\t} {\n\t\tconst buffer = new SharedArrayBuffer(size);\n\t\treturn { channel: new SyncChannel(buffer), buffer };\n\t}\n\n\t/** Attach to an existing SharedArrayBuffer received from the main thread. */\n\tstatic fromBuffer(sab: SharedArrayBuffer): SyncChannel {\n\t\treturn new SyncChannel(sab);\n\t}\n\n\t/**\n\t * Send a synchronous request to the main thread and block until response.\n\t *\n\t * Protocol:\n\t * 1. Write JSON-encoded request data to the request region\n\t * 2. Set query type and data length in the header via Atomics.store (memory fence)\n\t * 3. Set signal to SIGNAL_REQUEST and notify the main thread\n\t * 4. Block with Atomics.wait until signal changes or timeout (100ms per retry, 5 retries max)\n\t * 5. Read JSON-encoded response from the response region\n\t *\n\t * @param queryType - The type of DOM query to execute\n\t * @param data - JSON-encoded request payload\n\t * @returns Parsed response object, or null on timeout or parse failure\n\t */\n\trequest(queryType: QueryType, data: string): unknown {\n\t\tconst encoded = this.encoder.encode(data);\n\t\tif (encoded.byteLength > REQUEST_REGION_SIZE) {\n\t\t\treturn null; // Request too large\n\t\t}\n\n\t\t// Write request data, then metadata, then signal.\n\t\t// Atomics.store on meta provides a memory fence ensuring\n\t\t// the plain byte writes to requestRegion are visible before\n\t\t// the signal is set on weakly-ordered architectures (ARM).\n\t\tthis.requestRegion.set(encoded);\n\t\tAtomics.store(this.meta, 1, queryType);\n\t\tAtomics.store(this.meta, 2, encoded.byteLength);\n\t\tAtomics.store(this.meta, 3, 0);\n\n\t\t// Signal request pending — meta stores above act as release fence\n\t\tAtomics.store(this.signal, 0, SIGNAL_REQUEST);\n\t\tAtomics.notify(this.signal, 0);\n\n\t\t// Wait for response with retries\n\t\tfor (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n\t\t\tconst result = Atomics.wait(this.signal, 0, SIGNAL_REQUEST, WAIT_TIMEOUT_MS);\n\t\t\tif (result === \"not-equal\") {\n\t\t\t\t// Signal already changed — response may be ready\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (result === \"ok\") {\n\t\t\t\t// Woken up — check if response is ready\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// result === \"timed-out\" — retry\n\t\t}\n\n\t\tconst currentSignal = Atomics.load(this.signal, 0);\n\t\tif (currentSignal !== SIGNAL_RESPONSE) {\n\t\t\t// Reset to idle on timeout\n\t\t\tAtomics.store(this.signal, 0, SIGNAL_IDLE);\n\t\t\treturn null;\n\t\t}\n\n\t\t// Read response\n\t\tconst responseLength = Atomics.load(this.meta, 3);\n\t\tif (responseLength === 0) {\n\t\t\tAtomics.store(this.signal, 0, SIGNAL_IDLE);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst responseBytes = this.responseRegion.slice(0, responseLength);\n\t\tconst responseStr = this.decoder.decode(responseBytes);\n\n\t\t// Reset to idle\n\t\tAtomics.store(this.signal, 0, SIGNAL_IDLE);\n\n\t\ttry {\n\t\t\treturn JSON.parse(responseStr);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n}\n\n/**\n * Main-thread host for the sync channel.\n * Polls for pending requests and writes responses.\n */\nexport class SyncChannelHost {\n\tprivate signal: Int32Array;\n\tprivate meta: Int32Array;\n\tprivate requestRegion: Uint8Array;\n\tprivate responseRegion: Uint8Array;\n\tprivate encoder = new TextEncoder();\n\tprivate decoder = new TextDecoder();\n\tprivate polling = false;\n\tprivate pollChannel: MessageChannel | null = null;\n\n\tconstructor(buffer: SharedArrayBuffer) {\n\t\tthis.signal = new Int32Array(buffer, 0, 4);\n\t\tthis.meta = this.signal;\n\t\tthis.requestRegion = new Uint8Array(buffer, HEADER_SIZE, REQUEST_REGION_SIZE);\n\t\tthis.responseRegion = new Uint8Array(\n\t\t\tbuffer,\n\t\t\tHEADER_SIZE + REQUEST_REGION_SIZE,\n\t\t\tbuffer.byteLength - HEADER_SIZE - REQUEST_REGION_SIZE,\n\t\t);\n\t}\n\n\t/**\n\t * Non-blocking check for a pending query.\n\t */\n\tpoll(): PendingQuery | null {\n\t\tconst currentSignal = Atomics.load(this.signal, 0);\n\t\tif (currentSignal !== SIGNAL_REQUEST) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst queryType = Atomics.load(this.meta, 1) as QueryType;\n\t\tconst dataLength = Atomics.load(this.meta, 2);\n\t\tconst dataBytes = this.requestRegion.slice(0, dataLength);\n\t\tconst data = this.decoder.decode(dataBytes);\n\n\t\treturn { queryType, data };\n\t}\n\n\t/**\n\t * Write a response and wake the worker.\n\t */\n\trespond(data: unknown): void {\n\t\tconst json = JSON.stringify(data);\n\t\tconst encoded = this.encoder.encode(json);\n\t\t// Write response bytes, then length (acts as memory fence for\n\t\t// the plain byte writes above), then signal.\n\t\tthis.responseRegion.set(encoded);\n\t\tAtomics.store(this.meta, 3, encoded.byteLength);\n\t\tAtomics.store(this.signal, 0, SIGNAL_RESPONSE);\n\t\tAtomics.notify(this.signal, 0);\n\t}\n\n\t/**\n\t * Start polling for requests using a MessageChannel for lowest-latency scheduling.\n\t *\n\t * Uses MessageChannel.postMessage for microtask-level poll frequency when active,\n\t * with exponential backoff (up to 16ms) when idle to reduce CPU usage.\n\t * Falls back to setInterval(4ms) when MessageChannel is unavailable.\n\t *\n\t * @param handler - Synchronous function that executes the query and returns the result\n\t */\n\tstartPolling(handler: (query: PendingQuery) => unknown): void {\n\t\tif (this.polling) return;\n\t\tthis.polling = true;\n\n\t\tif (typeof MessageChannel !== \"undefined\") {\n\t\t\tthis.pollChannel = new MessageChannel();\n\t\t\tlet idleCount = 0;\n\t\t\tconst pollOnce = () => {\n\t\t\t\tif (!this.polling) return;\n\t\t\t\tconst query = this.poll();\n\t\t\t\tif (query) {\n\t\t\t\t\tidleCount = 0;\n\t\t\t\t\tconst result = handler(query);\n\t\t\t\t\tthis.respond(result);\n\t\t\t\t\t// Immediate next poll after handling a request\n\t\t\t\t\tthis.pollChannel?.port2.postMessage(null);\n\t\t\t\t} else {\n\t\t\t\t\t// Exponential backoff: 0, 0, 1ms, 2ms, 4ms, 8ms, capped at 16ms\n\t\t\t\t\tidleCount++;\n\t\t\t\t\tif (idleCount <= 2) {\n\t\t\t\t\t\tthis.pollChannel?.port2.postMessage(null);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst delay = Math.min(1 << (idleCount - 3), 16);\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (this.polling) {\n\t\t\t\t\t\t\t\tthis.pollChannel?.port2.postMessage(null);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, delay);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis.pollChannel.port1.onmessage = pollOnce;\n\t\t\tthis.pollChannel.port2.postMessage(null);\n\t\t} else {\n\t\t\tconst intervalId = setInterval(() => {\n\t\t\t\tif (!this.polling) {\n\t\t\t\t\tclearInterval(intervalId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst query = this.poll();\n\t\t\t\tif (query) {\n\t\t\t\t\tconst result = handler(query);\n\t\t\t\t\tthis.respond(result);\n\t\t\t\t}\n\t\t\t}, 4);\n\t\t}\n\t}\n\n\t/**\n\t * Stop polling for requests.\n\t */\n\tstopPolling(): void {\n\t\tthis.polling = false;\n\t\tif (this.pollChannel) {\n\t\t\tthis.pollChannel.port1.close();\n\t\t\tthis.pollChannel.port2.close();\n\t\t\tthis.pollChannel = null;\n\t\t}\n\t}\n}\n"],"mappings":"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"}