ziex 0.1.0-dev.1387 → 0.1.0-dev.1458

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 (43) hide show
  1. package/README.md +4 -1
  2. package/app.d.ts +6 -6
  3. package/build.zig.zon +1 -1
  4. package/index.js +477 -169
  5. package/package.json +7 -5
  6. package/{aws-lambda → platforms/aws-lambda}/index.js +1 -1
  7. package/platforms/cloudflare/app.d.ts +2 -0
  8. package/platforms/cloudflare/db.d.ts +6 -0
  9. package/{cloudflare → platforms/cloudflare}/do.d.ts +5 -5
  10. package/platforms/cloudflare/index.d.ts +4 -0
  11. package/{cloudflare → platforms/cloudflare}/index.js +1666 -1293
  12. package/platforms/cloudflare/kv.d.ts +5 -0
  13. package/platforms/cloudflare/worker.d.ts +3 -0
  14. package/{vercel → platforms/vercel}/index.js +1 -1
  15. package/runtime/db/extern.d.ts +38 -0
  16. package/runtime/db/sqlite.d.ts +7 -0
  17. package/runtime/db.d.ts +3 -0
  18. package/runtime/db.js +419 -0
  19. package/{fetch.d.ts → runtime/fetch.d.ts} +1 -1
  20. package/{runtime.d.ts → runtime/index.d.ts} +6 -15
  21. package/runtime/kv/extern.d.ts +11 -0
  22. package/runtime/kv/indexdb.d.ts +7 -0
  23. package/runtime/kv/localstorage.d.ts +6 -0
  24. package/runtime/kv/memory.d.ts +6 -0
  25. package/runtime/kv.d.ts +44 -0
  26. package/runtime/kv.js +542 -0
  27. package/wasm/core.d.ts +29 -27
  28. package/wasm/index.d.ts +13 -12
  29. package/wasm/index.js +431 -240
  30. package/wasm/init.dev.js +407 -238
  31. package/wasm/init.js +3 -3
  32. package/wasm/wasi.d.ts +1 -5
  33. package/browser/kv.d.ts +0 -13
  34. package/cloudflare/app.d.ts +0 -2
  35. package/cloudflare/db.d.ts +0 -2
  36. package/cloudflare/index.d.ts +0 -4
  37. package/cloudflare/kv.d.ts +0 -2
  38. package/cloudflare/worker.d.ts +0 -3
  39. package/db.d.ts +0 -22
  40. package/kv.d.ts +0 -42
  41. /package/{aws-lambda → platforms/aws-lambda}/index.d.ts +0 -0
  42. /package/{vercel → platforms/vercel}/index.d.ts +0 -0
  43. /package/{wasi.d.ts → runtime/wasi.d.ts} +0 -0
package/wasm/init.dev.js CHANGED
@@ -51,6 +51,10 @@ var ZigJS = class {
51
51
  * */
52
52
  valueGet(out, id, ptr, len) {
53
53
  const val = this.loadValue(id);
54
+ if (val === null || val === void 0 || typeof val !== "object" && typeof val !== "function") {
55
+ this.storeValue(out, void 0);
56
+ return;
57
+ }
54
58
  const str = this.loadString(ptr, len);
55
59
  const result = Reflect.get(val, str);
56
60
  this.storeValue(out, result);
@@ -99,11 +103,15 @@ var ZigJS = class {
99
103
  * */
100
104
  valueStringCopy(id, ptr, max) {
101
105
  if (this.memory == null) return;
106
+ const dest = ptr >>> 0;
107
+ const cap = max >>> 0;
102
108
  const val = this.loadValue(id);
109
+ if (typeof val !== "string") return;
103
110
  const bytes = encoder.encode(val);
104
- if (bytes.byteLength > max) return;
105
- if (bytes.length === 0) return;
106
- new Uint8Array(this.memory.buffer, ptr, bytes.length).set(bytes);
111
+ if (bytes.byteLength > cap || bytes.length === 0) return;
112
+ const buf = this.memory.buffer;
113
+ if (dest + bytes.length > buf.byteLength) return;
114
+ new Uint8Array(buf, dest, bytes.length).set(bytes);
107
115
  }
108
116
  /**
109
117
  * Call a constructor given by id.
@@ -111,8 +119,10 @@ var ZigJS = class {
111
119
  valueNew(out, id, argsAddr, argsLen) {
112
120
  const fn = this.loadValue(id);
113
121
  const args = [];
114
- for (let i = 0; i < argsLen; i++) {
115
- args.push(this.loadRef(argsAddr + i * 8));
122
+ const base = argsAddr >>> 0;
123
+ const count = argsLen >>> 0;
124
+ for (let i = 0; i < count; i++) {
125
+ args.push(this.loadRef(base + i * 8));
116
126
  }
117
127
  const result = Reflect.construct(fn, args);
118
128
  this.storeValue(out, result);
@@ -122,13 +132,23 @@ var ZigJS = class {
122
132
  * */
123
133
  funcApply(out, id, thisRefAddr, argsAddr, argsLen) {
124
134
  const fn = this.loadValue(id);
125
- const thisVal = this.loadRef(thisRefAddr);
135
+ const thisVal = this.loadRef(thisRefAddr >>> 0);
126
136
  const args = [];
127
- for (let i = 0; i < argsLen; i++) {
128
- args.push(this.loadRef(argsAddr + i * 8));
137
+ const base = argsAddr >>> 0;
138
+ const count = argsLen >>> 0;
139
+ for (let i = 0; i < count; i++) {
140
+ args.push(this.loadRef(base + i * 8));
141
+ }
142
+ if (typeof fn !== "function") {
143
+ this.storeValue(out, void 0);
144
+ return;
145
+ }
146
+ try {
147
+ const result = Reflect.apply(fn, thisVal, args);
148
+ this.storeValue(out, result);
149
+ } catch {
150
+ this.storeValue(out, void 0);
129
151
  }
130
- const result = Reflect.apply(fn, thisVal, args);
131
- this.storeValue(out, result);
132
152
  }
133
153
  /**
134
154
  * This can be used to load a value given by an ID. A WASM function
@@ -149,19 +169,21 @@ var ZigJS = class {
149
169
  }
150
170
  loadRef(refAddr) {
151
171
  if (this.memory == null) return;
172
+ const addr = refAddr >>> 0;
152
173
  const view = new DataView(this.memory.buffer);
153
- const floatVal = view.getFloat64(refAddr, true);
174
+ const floatVal = view.getFloat64(addr, true);
154
175
  if (!isNaN(floatVal)) return floatVal;
155
- const id = this.loadRefId(refAddr);
176
+ const id = this.loadRefId(addr);
156
177
  return this.values[id];
157
178
  }
158
179
  loadRefId(refAddr) {
159
180
  if (this.memory == null) return 0;
160
- return new DataView(this.memory.buffer).getUint32(refAddr, true);
181
+ return new DataView(this.memory.buffer).getUint32(refAddr >>> 0, true);
161
182
  }
162
183
  storeValue(out, val) {
163
184
  if (this.memory == null) return;
164
185
  const view = new DataView(this.memory.buffer);
186
+ out = out >>> 0;
165
187
  if (typeof val === "number") {
166
188
  if (isNaN(val)) {
167
189
  view.setUint32(out, predefined.nan, true);
@@ -215,13 +237,17 @@ var ZigJS = class {
215
237
  }
216
238
  loadString(ptr, len) {
217
239
  if (this.memory == null) return "";
218
- const arr = new Uint8ClampedArray(this.memory.buffer, ptr, Number(len));
240
+ const start = ptr >>> 0;
241
+ const length = Number(len) >>> 0;
242
+ const buf = this.memory.buffer;
243
+ if (length === 0 || start + length > buf.byteLength) return "";
244
+ const arr = new Uint8ClampedArray(buf, start, length);
219
245
  const data = arr.slice();
220
246
  return decoder.decode(data);
221
247
  }
222
248
  };
223
249
 
224
- // src/fetch.ts
250
+ // src/runtime/fetch.ts
225
251
  function createFetchImports(getMemory) {
226
252
  const encoder2 = new TextEncoder();
227
253
  const decoder2 = new TextDecoder();
@@ -288,17 +314,6 @@ function createFetchImports(getMemory) {
288
314
  }
289
315
 
290
316
  // src/wasm/core.ts
291
- var CallbackType = {
292
- Event: 0,
293
- FetchSuccess: 1,
294
- FetchError: 2,
295
- Timeout: 3,
296
- Interval: 4,
297
- WebSocketOpen: 5,
298
- WebSocketMessage: 6,
299
- WebSocketError: 7,
300
- WebSocketClose: 8
301
- };
302
317
  var jsz = new ZigJS();
303
318
  var tempRefBuffer = new ArrayBuffer(8);
304
319
  var tempRefView = new DataView(tempRefBuffer);
@@ -309,6 +324,20 @@ function storeValueGetRef(val) {
309
324
  jsz.memory = originalMemory;
310
325
  return tempRefView.getBigUint64(0, true);
311
326
  }
327
+ function loadValueFromRef(ref) {
328
+ tempRefView.setBigUint64(0, ref, true);
329
+ const originalMemory = jsz.memory;
330
+ jsz.memory = { buffer: tempRefBuffer };
331
+ const val = jsz.loadRef(0);
332
+ jsz.memory = originalMemory;
333
+ return val;
334
+ }
335
+ function releaseValueRef(ref) {
336
+ tempRefView.setBigUint64(0, ref, true);
337
+ if (!Number.isNaN(tempRefView.getFloat64(0, true))) return;
338
+ const id = tempRefView.getUint32(0, true);
339
+ if (id > 6) jsz.deleteValue(id);
340
+ }
312
341
  var textDecoder = new TextDecoder();
313
342
  var textEncoder = new TextEncoder();
314
343
  var memoryView = null;
@@ -321,20 +350,19 @@ function getMemoryView() {
321
350
  }
322
351
  return memoryView;
323
352
  }
324
- var stringCache = /* @__PURE__ */ new Map();
325
- function stringCacheKey(ptr, len) {
326
- return ptr * 65536 + len;
327
- }
328
353
  function readString(ptr, len) {
329
- const key = stringCacheKey(ptr, len);
330
- const cached = stringCache.get(key);
331
- if (cached !== void 0) return cached;
332
- const str = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
333
- stringCache.set(key, str);
334
- return str;
354
+ const start = ptr >>> 0;
355
+ const length = len >>> 0;
356
+ if (length === 0) return "";
357
+ const view = getMemoryView();
358
+ if (start + length > view.byteLength) return "";
359
+ return textDecoder.decode(view.subarray(start, start + length));
335
360
  }
336
361
  function writeBytes(ptr, data) {
337
- getMemoryView().set(data, ptr);
362
+ const start = ptr >>> 0;
363
+ const view = getMemoryView();
364
+ if (start + data.length > view.byteLength) return;
365
+ view.set(data, start);
338
366
  }
339
367
  function wrapPromisingExport(fn) {
340
368
  if (!fn) return void 0;
@@ -418,20 +446,21 @@ var ZxBridgeCore = class _ZxBridgeCore {
418
446
  _notifyFetchComplete(fetchId, statusCode, body, isError) {
419
447
  const handler = this.#fetchCompleteHandler;
420
448
  const encoded = typeof body === "string" ? textEncoder.encode(body) : body;
421
- const ptr = this._alloc(encoded.length);
449
+ const ptr = this._alloc(encoded.length) >>> 0;
450
+ if (!ptr && encoded.length > 0) return;
422
451
  writeBytes(ptr, encoded);
423
452
  invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
424
453
  }
425
454
  /** Set a timeout and callback when it fires */
426
455
  setTimeout(callbackId, delayMs) {
427
456
  setTimeout(() => {
428
- this.#invoke(CallbackType.Timeout, callbackId, null);
457
+ this.#invoke(3, callbackId, null);
429
458
  }, delayMs);
430
459
  }
431
460
  /** Set an interval and callback each time it fires */
432
461
  setInterval(callbackId, intervalMs) {
433
462
  const handle = setInterval(() => {
434
- this.#invoke(CallbackType.Interval, callbackId, null);
463
+ this.#invoke(4, callbackId, null);
435
464
  }, intervalMs);
436
465
  this.#intervals.set(callbackId, handle);
437
466
  }
@@ -449,18 +478,24 @@ var ZxBridgeCore = class _ZxBridgeCore {
449
478
  }
450
479
  this.#intervals.clear();
451
480
  }
452
- /** Write a string to WASM memory, returning pointer and length */
481
+ /** Write a string to WASM memory, returning `[ptr, len]`. */
453
482
  _writeStringToWasm(str) {
454
- return this._writeBytesToWasm(textEncoder.encode(str));
483
+ return this.writeBytesToWasm(textEncoder.encode(str));
455
484
  }
456
- _writeBytesToWasm(data) {
457
- const ptr = this._alloc(data.length);
485
+ writeBytesToWasm(data) {
486
+ if (data.length === 0) return [0, 0];
487
+ const ptr = this._alloc(data.length) >>> 0;
488
+ if (!ptr) return [0, 0];
458
489
  writeBytes(ptr, data);
459
- return { ptr, len: data.length };
490
+ return [ptr, data.length];
460
491
  }
461
492
  /** Log a message from WASM at the given level (0=error, 1=warn, 2=info, 3=debug) */
462
493
  static log(level, ptr, len) {
463
- const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
494
+ const start = ptr >>> 0;
495
+ const length = len >>> 0;
496
+ const view = getMemoryView();
497
+ if (start + length > view.byteLength) return;
498
+ const msg = textDecoder.decode(view.subarray(start, start + length));
464
499
  switch (level) {
465
500
  case 0:
466
501
  console.error(msg);
@@ -492,7 +527,7 @@ var ZxBridgeCore = class _ZxBridgeCore {
492
527
  __zx: {
493
528
  _log: (level, ptr, len) => _ZxBridgeCore.log(level, ptr, len),
494
529
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
495
- bridgeRef.current?.fetchAsync(
530
+ bridgeRef[0]?.fetchAsync(
496
531
  urlPtr,
497
532
  urlLen,
498
533
  methodPtr,
@@ -506,20 +541,41 @@ var ZxBridgeCore = class _ZxBridgeCore {
506
541
  );
507
542
  },
508
543
  _setTimeout: (callbackId, delayMs) => {
509
- bridgeRef.current?.setTimeout(callbackId, delayMs);
544
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
510
545
  },
511
546
  _setInterval: (callbackId, intervalMs) => {
512
- bridgeRef.current?.setInterval(callbackId, intervalMs);
547
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
513
548
  },
514
549
  _clearInterval: (callbackId) => {
515
- bridgeRef.current?.clearInterval(callbackId);
550
+ bridgeRef[0]?.clearInterval(callbackId);
516
551
  }
517
552
  }
518
553
  };
519
554
  }
520
555
  };
556
+ function writeBytesOut(getMemory, allocRef, outPtrAddr, data) {
557
+ if (data.length === 0) {
558
+ new DataView(getMemory().buffer).setUint32(outPtrAddr, 0, true);
559
+ return 0;
560
+ }
561
+ const alloc = allocRef[0];
562
+ if (!alloc) return -1;
563
+ const ptr = alloc(data.length) >>> 0;
564
+ if (!ptr) return -1;
565
+ const buffer = getMemory().buffer;
566
+ if (ptr + data.length > buffer.byteLength) return -1;
567
+ new Uint8Array(buffer, ptr, data.length).set(data);
568
+ new DataView(buffer).setUint32(outPtrAddr >>> 0, ptr, true);
569
+ return data.length;
570
+ }
571
+ function writeJsonOut(getMemory, allocRef, outPtrAddr, value) {
572
+ return writeBytesOut(getMemory, allocRef, outPtrAddr, textEncoder.encode(JSON.stringify(value)));
573
+ }
574
+ function bindWasmAlloc(allocRef, exports) {
575
+ allocRef[0] = exports.__zx_alloc;
576
+ }
521
577
 
522
- // src/kv.ts
578
+ // src/runtime/kv/extern.ts
523
579
  function putOptions(ttlSeconds) {
524
580
  if (ttlSeconds < 60) return void 0;
525
581
  return { expirationTtl: ttlSeconds };
@@ -528,17 +584,12 @@ function isSyncKVNamespace(binding) {
528
584
  const candidate = binding;
529
585
  return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
530
586
  }
531
- function createKVImports(bindings, getMemory) {
587
+ function createKVImports(bindings, getMemory, allocRef) {
532
588
  const encoder2 = new TextEncoder();
533
589
  const decoder2 = new TextDecoder();
534
590
  function readStr(ptr, len) {
535
591
  return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
536
592
  }
537
- function writeBytes2(buf_ptr, buf_max, data) {
538
- if (data.length > buf_max) return -2;
539
- new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
540
- return data.length;
541
- }
542
593
  function binding(ns) {
543
594
  return bindings[ns] ?? bindings["default"] ?? null;
544
595
  }
@@ -550,12 +601,12 @@ function createKVImports(bindings, getMemory) {
550
601
  };
551
602
  var syncBinding = syncBinding2;
552
603
  return {
553
- kv_get: (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
604
+ kv_get: (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
554
605
  const b = syncBinding2(readStr(ns_ptr, ns_len));
555
606
  if (!b) return -1;
556
607
  const value = b.getSync(readStr(key_ptr, key_len));
557
608
  if (value === null) return -1;
558
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
609
+ return writeBytesOut(getMemory, allocRef, out_ptr, encoder2.encode(value));
559
610
  },
560
611
  kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
561
612
  const b = syncBinding2(readStr(ns_ptr, ns_len));
@@ -569,22 +620,22 @@ function createKVImports(bindings, getMemory) {
569
620
  b.deleteSync(readStr(key_ptr, key_len));
570
621
  return 0;
571
622
  },
572
- kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, buf_ptr, buf_max) => {
623
+ kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, out_ptr) => {
573
624
  const b = syncBinding2(readStr(ns_ptr, ns_len));
574
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
625
+ if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
575
626
  const prefix = readStr(pfx_ptr, pfx_len);
576
627
  const result = b.listSync(prefix.length > 0 ? { prefix } : void 0);
577
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(JSON.stringify(result.keys.map((k) => k.name))));
628
+ return writeJsonOut(getMemory, allocRef, out_ptr, result.keys.map((k) => k.name));
578
629
  }
579
630
  };
580
631
  }
581
632
  return {
582
- kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
633
+ kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
583
634
  const b = binding(readStr(ns_ptr, ns_len));
584
635
  if (!b) return -1;
585
636
  const value = await b.get(readStr(key_ptr, key_len));
586
637
  if (value === null) return -1;
587
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
638
+ return writeBytesOut(getMemory, allocRef, out_ptr, encoder2.encode(value));
588
639
  }),
589
640
  kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
590
641
  const b = binding(readStr(ns_ptr, ns_len));
@@ -598,17 +649,70 @@ function createKVImports(bindings, getMemory) {
598
649
  await b.delete(readStr(key_ptr, key_len));
599
650
  return 0;
600
651
  }),
601
- kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
652
+ kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, out_ptr) => {
602
653
  const b = binding(readStr(ns_ptr, ns_len));
603
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
654
+ if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
604
655
  const prefix = readStr(prefix_ptr, prefix_len);
605
656
  const result = await b.list(prefix.length > 0 ? { prefix } : void 0);
606
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(JSON.stringify(result.keys.map((k) => k.name))));
657
+ const names = result.keys.map((k) => k.name);
658
+ if (names.length === 0) {
659
+ new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
660
+ return 0;
661
+ }
662
+ return writeJsonOut(getMemory, allocRef, out_ptr, names);
607
663
  })
608
664
  };
609
665
  }
610
666
 
611
- // src/browser/kv.ts
667
+ // src/runtime/kv/localstorage.ts
668
+ function getLocalStorage() {
669
+ if (typeof localStorage === "undefined") {
670
+ throw new Error("localStorage is not available in this environment");
671
+ }
672
+ return localStorage;
673
+ }
674
+ function createLocalStorageKV(options = {}) {
675
+ const storage = getLocalStorage();
676
+ const namespace = options.namespace ?? "default";
677
+ const storagePrefix = options.storagePrefix ?? "ziex-kv";
678
+ const scopedKey = (key) => `${storagePrefix}:${namespace}:${key}`;
679
+ const namespacePrefix = scopedKey("");
680
+ return {
681
+ getSync(key) {
682
+ return storage.getItem(scopedKey(key));
683
+ },
684
+ async get(key) {
685
+ return this.getSync(key);
686
+ },
687
+ putSync(key, value) {
688
+ storage.setItem(scopedKey(key), value);
689
+ },
690
+ async put(key, value) {
691
+ this.putSync(key, value);
692
+ },
693
+ deleteSync(key) {
694
+ storage.removeItem(scopedKey(key));
695
+ },
696
+ async delete(key) {
697
+ this.deleteSync(key);
698
+ },
699
+ listSync(options2) {
700
+ const prefix = namespacePrefix + (options2?.prefix ?? "");
701
+ const keys = [];
702
+ for (let i = 0; i < storage.length; i += 1) {
703
+ const key = storage.key(i);
704
+ if (!key || !key.startsWith(prefix)) continue;
705
+ keys.push({ name: key.slice(namespacePrefix.length) });
706
+ }
707
+ return { keys };
708
+ },
709
+ async list(options2) {
710
+ return this.listSync(options2);
711
+ }
712
+ };
713
+ }
714
+
715
+ // src/runtime/kv/indexdb.ts
612
716
  function getIndexedDb() {
613
717
  if (typeof indexedDB === "undefined") {
614
718
  throw new Error("IndexedDB is not available in this environment");
@@ -651,7 +755,6 @@ function createIndexedDbKV(options = {}) {
651
755
  const store = tx.objectStore(storeName);
652
756
  const value = await requestToPromise(store.get(scopedKey(key)));
653
757
  await transactionToPromise(tx);
654
- console.debug(`KV GET - Key: ${key}, Value: ${value}`);
655
758
  return typeof value === "string" ? value : null;
656
759
  },
657
760
  async put(key, value) {
@@ -659,7 +762,6 @@ function createIndexedDbKV(options = {}) {
659
762
  const tx = db.transaction(storeName, "readwrite");
660
763
  tx.objectStore(storeName).put(value, scopedKey(key));
661
764
  await transactionToPromise(tx);
662
- console.debug(`KV PUT - Key: ${key}, Value: ${value}`);
663
765
  },
664
766
  async delete(key) {
665
767
  const db = await dbPromise;
@@ -680,52 +782,8 @@ function createIndexedDbKV(options = {}) {
680
782
  }
681
783
  };
682
784
  }
683
- function getLocalStorage() {
684
- if (typeof localStorage === "undefined") {
685
- throw new Error("localStorage is not available in this environment");
686
- }
687
- return localStorage;
688
- }
689
- function createLocalStorageKV(options = {}) {
690
- const storage = getLocalStorage();
691
- const namespace = options.namespace ?? "default";
692
- const storagePrefix = options.storagePrefix ?? "ziex-kv";
693
- const scopedKey = (key) => `${storagePrefix}:${namespace}:${key}`;
694
- const namespacePrefix = scopedKey("");
695
- return {
696
- getSync(key) {
697
- return storage.getItem(scopedKey(key));
698
- },
699
- async get(key) {
700
- return this.getSync(key);
701
- },
702
- putSync(key, value) {
703
- storage.setItem(scopedKey(key), value);
704
- },
705
- async put(key, value) {
706
- this.putSync(key, value);
707
- },
708
- deleteSync(key) {
709
- storage.removeItem(scopedKey(key));
710
- },
711
- async delete(key) {
712
- this.deleteSync(key);
713
- },
714
- listSync(options2) {
715
- const prefix = namespacePrefix + (options2?.prefix ?? "");
716
- const keys = [];
717
- for (let i = 0; i < storage.length; i += 1) {
718
- const key = storage.key(i);
719
- if (!key || !key.startsWith(prefix)) continue;
720
- keys.push({ name: key.slice(namespacePrefix.length) });
721
- }
722
- return { keys };
723
- },
724
- async list(options2) {
725
- return this.listSync(options2);
726
- }
727
- };
728
- }
785
+
786
+ // src/runtime/kv.ts
729
787
  function hasJSPI() {
730
788
  return typeof WebAssembly.Suspending === "function" && typeof WebAssembly.promising === "function";
731
789
  }
@@ -756,18 +814,29 @@ var ZxBridge = class extends ZxBridgeCore {
756
814
  exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
757
815
  );
758
816
  }
817
+ hasEventHandler(velementId, eventTypeId) {
818
+ return !!((eventHandlersPresent.get(velementId) ?? 0) & 1 << eventTypeId);
819
+ }
759
820
  eventMaySuspend(velementId, eventTypeId) {
760
- return !!((eventHandlerModes.get(velementId) ?? 0) & 1 << eventTypeId);
821
+ return !!((eventHandlersSuspend.get(velementId) ?? 0) & 1 << eventTypeId);
761
822
  }
762
823
  setEventHandlerMode(velementId, eventTypeId, maySuspend) {
763
824
  const bit = 1 << eventTypeId;
764
- const current = eventHandlerModes.get(velementId) ?? 0;
765
- const next = maySuspend ? current | bit : current & ~bit;
766
- if (next === 0) eventHandlerModes.delete(velementId);
767
- else eventHandlerModes.set(velementId, next);
825
+ const present = (eventHandlersPresent.get(velementId) ?? 0) | bit;
826
+ eventHandlersPresent.set(velementId, present);
827
+ const suspendBits = eventHandlersSuspend.get(velementId) ?? 0;
828
+ const nextSuspend = maySuspend ? suspendBits | bit : suspendBits & ~bit;
829
+ if (nextSuspend === 0) eventHandlersSuspend.delete(velementId);
830
+ else eventHandlersSuspend.set(velementId, nextSuspend);
831
+ ensureDelegatedListener(eventTypeId);
768
832
  }
769
833
  clearEventHandlerModes(velementId) {
770
- eventHandlerModes.delete(velementId);
834
+ const present = eventHandlersPresent.get(velementId) ?? 0;
835
+ eventHandlersPresent.delete(velementId);
836
+ eventHandlersSuspend.delete(velementId);
837
+ for (const eventTypeId of HIGH_FREQ_EVENT_IDS) {
838
+ if (present & 1 << eventTypeId) maybeRemoveHighFreqListener(eventTypeId);
839
+ }
771
840
  }
772
841
  /** Submit a form action with bound-state round-trip. */
773
842
  submitFormActionAsync(form, actionId, statesJson, fetchId) {
@@ -801,7 +870,7 @@ var ZxBridge = class extends ZxBridgeCore {
801
870
  const handler = this.#wsOnOpenHandler;
802
871
  if (!handler) return;
803
872
  const protocol = ws.protocol || "";
804
- const { ptr, len } = this._writeStringToWasm(protocol);
873
+ const [ptr, len] = this._writeStringToWasm(protocol);
805
874
  invokeWasmExport(handler, wsId, ptr, len);
806
875
  };
807
876
  ws.onmessage = (event) => {
@@ -809,20 +878,20 @@ var ZxBridge = class extends ZxBridgeCore {
809
878
  if (!handler) return;
810
879
  const isBinary = event.data instanceof ArrayBuffer;
811
880
  const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
812
- const { ptr, len } = this._writeBytesToWasm(data);
881
+ const [ptr, len] = this.writeBytesToWasm(data);
813
882
  invokeWasmExport(handler, wsId, ptr, len, isBinary ? 1 : 0);
814
883
  };
815
884
  ws.onerror = (_event) => {
816
885
  const handler = this.#wsOnErrorHandler;
817
886
  if (!handler) return;
818
- const { ptr, len } = this._writeStringToWasm("WebSocket error");
887
+ const [ptr, len] = this._writeStringToWasm("WebSocket error");
819
888
  invokeWasmExport(handler, wsId, ptr, len);
820
889
  };
821
890
  ws.onclose = (event) => {
822
891
  const handler = this.#wsOnCloseHandler;
823
892
  if (!handler) return;
824
893
  const reason = event.reason || "";
825
- const { ptr, len } = this._writeStringToWasm(reason);
894
+ const [ptr, len] = this._writeStringToWasm(reason);
826
895
  invokeWasmExport(handler, wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
827
896
  this.#websockets.delete(wsId);
828
897
  };
@@ -831,7 +900,7 @@ var ZxBridge = class extends ZxBridgeCore {
831
900
  const handler = this.#wsOnErrorHandler;
832
901
  if (handler) {
833
902
  const msg = error instanceof Error ? error.message : "WebSocket connection failed";
834
- const { ptr, len } = this._writeStringToWasm(msg);
903
+ const [ptr, len] = this._writeStringToWasm(msg);
835
904
  invokeWasmExport(handler, wsId, ptr, len);
836
905
  }
837
906
  }
@@ -841,10 +910,13 @@ var ZxBridge = class extends ZxBridgeCore {
841
910
  const ws = this.#websockets.get(wsId);
842
911
  if (!ws || ws.readyState !== WebSocket.OPEN) return;
843
912
  const memory = getMemoryView();
913
+ const start = dataPtr >>> 0;
914
+ const length = dataLen >>> 0;
915
+ if (start + length > memory.byteLength) return;
844
916
  if (isBinary) {
845
- ws.send(memory.slice(dataPtr, dataPtr + dataLen));
917
+ ws.send(memory.slice(start, start + length));
846
918
  } else {
847
- ws.send(textDecoder.decode(memory.subarray(dataPtr, dataPtr + dataLen)));
919
+ ws.send(textDecoder.decode(memory.subarray(start, start + length)));
848
920
  }
849
921
  }
850
922
  /** Close WebSocket connection */
@@ -861,7 +933,8 @@ var ZxBridge = class extends ZxBridgeCore {
861
933
  }
862
934
  dispose() {
863
935
  super.dispose();
864
- eventHandlerModes.clear();
936
+ eventHandlersPresent.clear();
937
+ eventHandlersSuspend.clear();
865
938
  for (const ws of this.#websockets.values()) {
866
939
  try {
867
940
  ws.close();
@@ -870,14 +943,16 @@ var ZxBridge = class extends ZxBridgeCore {
870
943
  }
871
944
  this.#websockets.clear();
872
945
  }
873
- /** Handle a DOM event (called by event delegation) */
874
- eventbridge(velementId, eventTypeId, event) {
875
- const eventRef = storeValueGetRef(event);
946
+ /**
947
+ * Dispatch to WASM for one vnode. Caller owns `eventRef` lifetime
948
+ * (store once per bubble, release after sync/async work completes).
949
+ */
950
+ eventbridge(velementId, eventTypeId, eventRef) {
951
+ const id = BigInt(velementId >>> 0);
876
952
  if (this.eventMaySuspend(velementId, eventTypeId)) {
877
- invokeWasmExport(this.#eventbridgeAsync, velementId, eventTypeId, eventRef);
878
- return;
953
+ return invokeWasmExport(this.#eventbridgeAsync, id, eventTypeId, eventRef);
879
954
  }
880
- invokeWasmExport(this.#eventbridge, velementId, eventTypeId, eventRef);
955
+ invokeWasmExport(this.#eventbridge, id, eventTypeId, eventRef);
881
956
  }
882
957
  /** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
883
958
  static createImportObject(bridgeRef) {
@@ -890,13 +965,13 @@ var ZxBridge = class extends ZxBridgeCore {
890
965
  __zx: {
891
966
  _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
892
967
  _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
893
- bridgeRef.current?.setEventHandlerMode(vnodeId, eventTypeId, maySuspend !== 0);
968
+ bridgeRef[0]?.setEventHandlerMode(Number(vnodeId), eventTypeId, maySuspend !== 0);
894
969
  },
895
970
  _clearEventHandlerModes: (vnodeId) => {
896
- bridgeRef.current?.clearEventHandlerModes(vnodeId);
971
+ bridgeRef[0]?.clearEventHandlerModes(Number(vnodeId));
897
972
  },
898
973
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
899
- bridgeRef.current?.fetchAsync(
974
+ bridgeRef[0]?.fetchAsync(
900
975
  urlPtr,
901
976
  urlLen,
902
977
  methodPtr,
@@ -910,43 +985,49 @@ var ZxBridge = class extends ZxBridgeCore {
910
985
  );
911
986
  },
912
987
  _setTimeout: (callbackId, delayMs) => {
913
- bridgeRef.current?.setTimeout(callbackId, delayMs);
988
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
914
989
  },
915
990
  _setInterval: (callbackId, intervalMs) => {
916
- bridgeRef.current?.setInterval(callbackId, intervalMs);
991
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
917
992
  },
918
993
  _clearInterval: (callbackId) => {
919
- bridgeRef.current?.clearInterval(callbackId);
994
+ bridgeRef[0]?.clearInterval(callbackId);
920
995
  },
921
996
  // WebSocket API
922
997
  _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
923
- bridgeRef.current?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
998
+ bridgeRef[0]?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
924
999
  },
925
1000
  _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
926
- bridgeRef.current?.wsSend(wsId, dataPtr, dataLen, isBinary);
1001
+ bridgeRef[0]?.wsSend(wsId, dataPtr, dataLen, isBinary);
927
1002
  },
928
1003
  _wsClose: (wsId, code, reasonPtr, reasonLen) => {
929
- bridgeRef.current?.wsClose(wsId, code, reasonPtr, reasonLen);
1004
+ bridgeRef[0]?.wsClose(wsId, code, reasonPtr, reasonLen);
930
1005
  },
931
1006
  _ce: (id, vnodeId) => {
1007
+ const nid = Number(vnodeId);
932
1008
  const tagName = TAG_NAMES[id];
933
1009
  const el = id >= SVG_TAG_START_INDEX ? document.createElementNS("http://www.w3.org/2000/svg", tagName) : document.createElement(tagName);
934
- el.__zx_ref = Number(vnodeId);
935
- domNodes.set(vnodeId, el);
936
- return storeValueGetRef(el);
1010
+ el.__zx_ref = nid;
1011
+ domNodes.set(nid, el);
937
1012
  },
938
1013
  _ct: (ptr, len, vnodeId) => {
939
- const text = readString(ptr, len);
940
- const node = document.createTextNode(text);
941
- node.__zx_ref = Number(vnodeId);
942
- domNodes.set(vnodeId, node);
943
- return storeValueGetRef(node);
1014
+ const nid = Number(vnodeId);
1015
+ const node = document.createTextNode(readString(ptr, len));
1016
+ node.__zx_ref = nid;
1017
+ domNodes.set(nid, node);
1018
+ },
1019
+ /** Insert vnode before a jsz-held end comment (hydration). */
1020
+ _ih: (vnodeId, endCommentRef) => {
1021
+ const child = domNodes.get(Number(vnodeId));
1022
+ const end = loadValueFromRef(endCommentRef);
1023
+ if (!child || !end?.parentNode) return;
1024
+ end.parentNode.insertBefore(child, end);
944
1025
  },
945
1026
  _sa: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
946
- domNodes.get(vnodeId)?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
1027
+ domNodes.get(Number(vnodeId))?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
947
1028
  },
948
1029
  _sp: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
949
- const el = domNodes.get(vnodeId);
1030
+ const el = domNodes.get(Number(vnodeId));
950
1031
  if (el) {
951
1032
  const name = readString(namePtr, nameLen);
952
1033
  const val = readString(valPtr, valLen);
@@ -958,39 +1039,39 @@ var ZxBridge = class extends ZxBridgeCore {
958
1039
  }
959
1040
  },
960
1041
  _ra: (vnodeId, namePtr, nameLen) => {
961
- domNodes.get(vnodeId)?.removeAttribute(readString(namePtr, nameLen));
1042
+ domNodes.get(Number(vnodeId))?.removeAttribute(readString(namePtr, nameLen));
962
1043
  },
963
1044
  _snv: (vnodeId, ptr, len) => {
964
- const node = domNodes.get(vnodeId);
1045
+ const node = domNodes.get(Number(vnodeId));
965
1046
  if (node) node.nodeValue = readString(ptr, len);
966
1047
  },
967
1048
  _srh: (vnodeId, ptr, len) => {
968
- const el = domNodes.get(vnodeId);
1049
+ const el = domNodes.get(Number(vnodeId));
969
1050
  if (el) el.innerHTML = readString(ptr, len);
970
1051
  },
971
1052
  _ac: (parentId, childId) => {
972
- const parent = domNodes.get(parentId);
973
- const child = domNodes.get(childId);
1053
+ const parent = domNodes.get(Number(parentId));
1054
+ const child = domNodes.get(Number(childId));
974
1055
  if (parent && child) parent.appendChild(child);
975
1056
  },
976
1057
  _ib: (parentId, childId, refId) => {
977
- const parent = domNodes.get(parentId);
978
- const child = domNodes.get(childId);
979
- const ref = domNodes.get(refId) ?? null;
1058
+ const parent = domNodes.get(Number(parentId));
1059
+ const child = domNodes.get(Number(childId));
1060
+ const ref = domNodes.get(Number(refId)) ?? null;
980
1061
  if (parent && child) parent.insertBefore(child, ref);
981
1062
  },
982
1063
  _rc: (parentId, childId) => {
983
- const parent = domNodes.get(parentId);
984
- const child = domNodes.get(childId);
1064
+ const parent = domNodes.get(Number(parentId));
1065
+ const child = domNodes.get(Number(childId));
985
1066
  if (parent && child) {
986
1067
  parent.removeChild(child);
987
1068
  cleanupDomNodes(child);
988
1069
  }
989
1070
  },
990
1071
  _rpc: (parentId, newId, oldId) => {
991
- const parent = domNodes.get(parentId);
992
- const newChild = domNodes.get(newId);
993
- const oldChild = domNodes.get(oldId);
1072
+ const parent = domNodes.get(Number(parentId));
1073
+ const newChild = domNodes.get(Number(newId));
1074
+ const oldChild = domNodes.get(Number(oldId));
994
1075
  if (parent && newChild && oldChild) {
995
1076
  parent.replaceChild(newChild, oldChild);
996
1077
  cleanupDomNodes(oldChild);
@@ -1002,18 +1083,22 @@ var ZxBridge = class extends ZxBridgeCore {
1002
1083
  writeBytes(bufPtr, bytes.subarray(0, len));
1003
1084
  return len;
1004
1085
  },
1005
- _getFormData: (vnodeId, bufPtr, bufLen) => {
1006
- const form = domNodes.get(vnodeId);
1007
- if (!form || !(form instanceof HTMLFormElement)) return 0;
1008
- const formData = new FormData(form);
1009
- const urlEncoded = new URLSearchParams(formData).toString();
1010
- const bytes = textEncoder.encode(urlEncoded);
1011
- const len = Math.min(bytes.length, bufLen);
1012
- writeBytes(bufPtr, bytes.subarray(0, len));
1086
+ _getFormData: (eventRef, outPtrAddr) => {
1087
+ const event = loadValueFromRef(eventRef);
1088
+ const el = event?.target;
1089
+ const form = el instanceof HTMLFormElement ? el : el?.closest?.("form") ?? null;
1090
+ if (!form) return 0;
1091
+ const entries = [];
1092
+ for (const [k, v] of new FormData(form).entries()) {
1093
+ entries.push(k, String(v));
1094
+ }
1095
+ const bytes = textEncoder.encode(JSON.stringify(entries));
1096
+ const [ptr, len] = bridgeRef[0].writeBytesToWasm(bytes);
1097
+ new DataView(jsz.memory.buffer).setUint32(outPtrAddr, ptr, true);
1013
1098
  return len;
1014
1099
  },
1015
1100
  _submitFormAction: (vnodeId, actionId) => {
1016
- const form = domNodes.get(vnodeId);
1101
+ const form = domNodes.get(Number(vnodeId));
1017
1102
  if (!form || !(form instanceof HTMLFormElement)) return;
1018
1103
  const formData = new FormData(form);
1019
1104
  fetch(window.location.href, {
@@ -1025,21 +1110,39 @@ var ZxBridge = class extends ZxBridgeCore {
1025
1110
  });
1026
1111
  },
1027
1112
  _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
1028
- const form = domNodes.get(vnodeId);
1113
+ const form = domNodes.get(Number(vnodeId));
1029
1114
  if (!form || !(form instanceof HTMLFormElement)) return;
1030
1115
  const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
1031
- bridgeRef.current?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1116
+ bridgeRef[0]?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1032
1117
  }
1033
1118
  }
1034
1119
  };
1035
1120
  }
1036
1121
  };
1037
1122
  var domNodes = /* @__PURE__ */ new Map();
1123
+ var eventHandlersPresent = /* @__PURE__ */ new Map();
1124
+ var eventHandlersSuspend = /* @__PURE__ */ new Map();
1038
1125
  function cleanupDomNodes(node) {
1039
- const ref = node.__zx_ref;
1040
- if (ref !== void 0) domNodes.delete(BigInt(ref));
1041
- const children = node.childNodes;
1042
- for (let i = 0; i < children.length; i++) cleanupDomNodes(children[i]);
1126
+ const stack = [node];
1127
+ let highFreqBits = 0;
1128
+ while (stack.length > 0) {
1129
+ const n = stack.pop();
1130
+ const ref = n.__zx_ref;
1131
+ if (typeof ref === "number") {
1132
+ const present = eventHandlersPresent.get(ref);
1133
+ if (present !== void 0) {
1134
+ highFreqBits |= present;
1135
+ eventHandlersPresent.delete(ref);
1136
+ eventHandlersSuspend.delete(ref);
1137
+ }
1138
+ domNodes.delete(ref);
1139
+ }
1140
+ const children = n.childNodes;
1141
+ for (let i = 0; i < children.length; i++) stack.push(children[i]);
1142
+ }
1143
+ for (const eventTypeId of HIGH_FREQ_EVENT_IDS) {
1144
+ if (highFreqBits & 1 << eventTypeId) maybeRemoveHighFreqListener(eventTypeId);
1145
+ }
1043
1146
  }
1044
1147
  var SVG_TAG_START_INDEX = 140;
1045
1148
  var TAG_NAMES = [
@@ -1245,54 +1348,115 @@ var TAG_NAMES = [
1245
1348
  "view"
1246
1349
  ];
1247
1350
  var DELEGATED_EVENTS = [
1248
- { domType: "click", eventTypeId: 0 },
1249
- { domType: "dblclick", eventTypeId: 1 },
1250
- { domType: "input", eventTypeId: 2 },
1251
- { domType: "change", eventTypeId: 3 },
1252
- { domType: "submit", eventTypeId: 4 },
1253
- // focus/blur do not bubble, so delegated handlers must listen to focusin/focusout.
1254
- { domType: "focusin", eventTypeId: 5 },
1255
- { domType: "focusout", eventTypeId: 6 },
1256
- { domType: "keydown", eventTypeId: 7 },
1257
- { domType: "keyup", eventTypeId: 8 },
1258
- { domType: "keypress", eventTypeId: 9 },
1259
- { domType: "mouseenter", eventTypeId: 10 },
1260
- { domType: "mouseleave", eventTypeId: 11 },
1261
- { domType: "mousedown", eventTypeId: 12 },
1262
- { domType: "mouseup", eventTypeId: 13 },
1263
- { domType: "mousemove", eventTypeId: 14 },
1264
- { domType: "touchstart", eventTypeId: 15 },
1265
- { domType: "touchend", eventTypeId: 16 },
1266
- { domType: "touchmove", eventTypeId: 17 },
1267
- { domType: "scroll", eventTypeId: 18 }
1351
+ "click",
1352
+ "dblclick",
1353
+ "input",
1354
+ "change",
1355
+ "submit",
1356
+ // focus/blur do not bubble - listen to focusin/focusout instead.
1357
+ "focusin",
1358
+ "focusout",
1359
+ "keydown",
1360
+ "keyup",
1361
+ "keypress",
1362
+ "mouseenter",
1363
+ "mouseleave",
1364
+ "mousedown",
1365
+ "mouseup",
1366
+ "mousemove",
1367
+ "touchstart",
1368
+ "touchend",
1369
+ "touchmove",
1370
+ "scroll",
1371
+ "wheel",
1372
+ "pointerdown",
1373
+ "pointermove",
1374
+ "pointerup",
1375
+ "pointercancel"
1268
1376
  ];
1269
- var eventHandlerModes = /* @__PURE__ */ new Map();
1377
+ var HIGH_FREQ_EVENT_IDS = new Set([
1378
+ DELEGATED_EVENTS.indexOf("mousemove"),
1379
+ DELEGATED_EVENTS.indexOf("pointermove"),
1380
+ DELEGATED_EVENTS.indexOf("wheel"),
1381
+ DELEGATED_EVENTS.indexOf("scroll"),
1382
+ DELEGATED_EVENTS.indexOf("touchmove")
1383
+ ].filter((id) => id >= 0));
1384
+ var delegationState = null;
1385
+ function makeDelegatedListener(bridge, eventTypeId) {
1386
+ return (event) => {
1387
+ let eventRef;
1388
+ const pending = [];
1389
+ let target = event.target;
1390
+ while (target && target !== document.body) {
1391
+ const zxRef = target.__zx_ref;
1392
+ if (typeof zxRef === "number" && bridge.hasEventHandler(zxRef, eventTypeId)) {
1393
+ if (eventRef === void 0) eventRef = storeValueGetRef(event);
1394
+ const result = bridge.eventbridge(zxRef, eventTypeId, eventRef);
1395
+ if (result && typeof result.then === "function") {
1396
+ pending.push(result);
1397
+ }
1398
+ if (event.cancelBubble) break;
1399
+ }
1400
+ target = target.parentElement;
1401
+ }
1402
+ if (eventRef !== void 0) {
1403
+ const ref = eventRef;
1404
+ if (pending.length > 0) {
1405
+ Promise.all(pending).finally(() => releaseValueRef(ref));
1406
+ } else {
1407
+ releaseValueRef(ref);
1408
+ }
1409
+ }
1410
+ };
1411
+ }
1412
+ function ensureDelegatedListener(eventTypeId) {
1413
+ const state = delegationState;
1414
+ if (!state || state.attached.has(eventTypeId)) return;
1415
+ const domType = DELEGATED_EVENTS[eventTypeId];
1416
+ if (!domType) return;
1417
+ const passive = domType.startsWith("touch") || domType === "scroll";
1418
+ const options = { passive };
1419
+ const listener = makeDelegatedListener(state.bridge, eventTypeId);
1420
+ state.root.addEventListener(domType, listener, options);
1421
+ state.attached.set(eventTypeId, { listener, options });
1422
+ }
1423
+ function anyHandlerForType(eventTypeId) {
1424
+ const bit = 1 << eventTypeId;
1425
+ for (const mask of eventHandlersPresent.values()) {
1426
+ if (mask & bit) return true;
1427
+ }
1428
+ return false;
1429
+ }
1430
+ function maybeRemoveHighFreqListener(eventTypeId) {
1431
+ if (!HIGH_FREQ_EVENT_IDS.has(eventTypeId)) return;
1432
+ if (anyHandlerForType(eventTypeId)) return;
1433
+ const state = delegationState;
1434
+ if (!state) return;
1435
+ const entry = state.attached.get(eventTypeId);
1436
+ if (!entry) return;
1437
+ const domType = DELEGATED_EVENTS[eventTypeId];
1438
+ state.root.removeEventListener(domType, entry.listener, entry.options);
1439
+ state.attached.delete(eventTypeId);
1440
+ }
1270
1441
  function initEventDelegation(bridge, rootSelector = "body") {
1271
1442
  const root = document.querySelector(rootSelector);
1272
1443
  if (!root) return () => {
1273
1444
  };
1274
- const removers = [];
1275
- for (const delegatedEvent of DELEGATED_EVENTS) {
1276
- const listener = (event) => {
1277
- let target = event.target;
1278
- while (target && target !== document.body) {
1279
- const zxRef = target.__zx_ref;
1280
- if (zxRef !== void 0) {
1281
- bridge.eventbridge(BigInt(zxRef), delegatedEvent.eventTypeId, event);
1282
- if (event.cancelBubble) break;
1283
- }
1284
- target = target.parentElement;
1285
- }
1286
- };
1287
- const options = { passive: delegatedEvent.domType.startsWith("touch") || delegatedEvent.domType === "scroll" };
1288
- root.addEventListener(delegatedEvent.domType, listener, options);
1289
- removers.push(() => root.removeEventListener(delegatedEvent.domType, listener, options));
1445
+ delegationState = { root, bridge, attached: /* @__PURE__ */ new Map() };
1446
+ for (let eventTypeId = 0; eventTypeId < DELEGATED_EVENTS.length; eventTypeId++) {
1447
+ if (HIGH_FREQ_EVENT_IDS.has(eventTypeId)) continue;
1448
+ ensureDelegatedListener(eventTypeId);
1290
1449
  }
1291
1450
  return () => {
1292
- for (const remove of removers) remove();
1451
+ if (!delegationState) return;
1452
+ for (const [eventTypeId, entry] of delegationState.attached) {
1453
+ const domType = DELEGATED_EVENTS[eventTypeId];
1454
+ delegationState.root.removeEventListener(domType, entry.listener, entry.options);
1455
+ }
1456
+ delegationState.attached.clear();
1457
+ delegationState = null;
1293
1458
  };
1294
1459
  }
1295
- var DEFAULT_URL = "/assets/_/main.wasm";
1296
1460
  var activeRuntime = null;
1297
1461
  function buildDevtoolsLocation() {
1298
1462
  return {
@@ -1325,29 +1489,34 @@ async function init(options = {}) {
1325
1489
  activeRuntime.dispose();
1326
1490
  activeRuntime = null;
1327
1491
  }
1328
- const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
1329
- const bridgeRef = { current: null };
1492
+ const url = options.url ?? document.getElementById("__$wasmlink")?.href;
1493
+ if (!url) throw new Error("WASM URL is not set");
1494
+ const bridgeRef = [null];
1330
1495
  let wasmMemory = null;
1331
- const kvBindings = options.kv ?? createBrowserKVBindings();
1332
- const kvImportObject = {
1333
- __zx_kv: createKVImports(kvBindings, () => {
1334
- if (wasmMemory) return wasmMemory;
1335
- if (jsz.memory) return jsz.memory;
1336
- throw new Error("WASM memory is not ready");
1337
- })
1496
+ const allocRef = [null];
1497
+ const getMemory = () => {
1498
+ if (wasmMemory) return wasmMemory;
1499
+ if (jsz.memory) return jsz.memory;
1500
+ throw new Error("WASM memory is not ready");
1501
+ };
1502
+ const importObject = {
1503
+ ...ZxBridge.createImportObject(bridgeRef),
1504
+ ...options.importObject
1338
1505
  };
1339
- const importObject = Object.assign(
1340
- {},
1341
- ZxBridge.createImportObject(bridgeRef),
1342
- kvImportObject,
1343
- options.importObject
1344
- );
1506
+ if (true) {
1507
+ importObject.__zx_kv = createKVImports(
1508
+ options.kv ?? createBrowserKVBindings(),
1509
+ getMemory,
1510
+ allocRef
1511
+ );
1512
+ }
1345
1513
  const source = await WebAssembly.instantiateStreaming(fetch(url), importObject);
1346
1514
  const { instance } = source;
1347
1515
  wasmMemory = instance.exports.memory;
1348
1516
  jsz.memory = wasmMemory;
1517
+ bindWasmAlloc(allocRef, instance.exports);
1349
1518
  const bridge = new ZxBridge(instance.exports);
1350
- bridgeRef.current = bridge;
1519
+ bridgeRef[0] = bridge;
1351
1520
  domNodes.clear();
1352
1521
  const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
1353
1522
  const main = wrapPromisingExport(instance.exports.mainClient);