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/index.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,15 @@ 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
- };
317
+ var CallbackType_Event = 0;
318
+ var CallbackType_FetchSuccess = 1;
319
+ var CallbackType_FetchError = 2;
320
+ var CallbackType_Timeout = 3;
321
+ var CallbackType_Interval = 4;
322
+ var CallbackType_WebSocketOpen = 5;
323
+ var CallbackType_WebSocketMessage = 6;
324
+ var CallbackType_WebSocketError = 7;
325
+ var CallbackType_WebSocketClose = 8;
302
326
  var jsz = new ZigJS();
303
327
  var tempRefBuffer = new ArrayBuffer(8);
304
328
  var tempRefView = new DataView(tempRefBuffer);
@@ -309,6 +333,20 @@ function storeValueGetRef(val) {
309
333
  jsz.memory = originalMemory;
310
334
  return tempRefView.getBigUint64(0, true);
311
335
  }
336
+ function loadValueFromRef(ref) {
337
+ tempRefView.setBigUint64(0, ref, true);
338
+ const originalMemory = jsz.memory;
339
+ jsz.memory = { buffer: tempRefBuffer };
340
+ const val = jsz.loadRef(0);
341
+ jsz.memory = originalMemory;
342
+ return val;
343
+ }
344
+ function releaseValueRef(ref) {
345
+ tempRefView.setBigUint64(0, ref, true);
346
+ if (!Number.isNaN(tempRefView.getFloat64(0, true))) return;
347
+ const id = tempRefView.getUint32(0, true);
348
+ if (id > 6) jsz.deleteValue(id);
349
+ }
312
350
  var textDecoder = new TextDecoder();
313
351
  var textEncoder = new TextEncoder();
314
352
  var memoryView = null;
@@ -321,20 +359,19 @@ function getMemoryView() {
321
359
  }
322
360
  return memoryView;
323
361
  }
324
- var stringCache = /* @__PURE__ */ new Map();
325
- function stringCacheKey(ptr, len) {
326
- return ptr * 65536 + len;
327
- }
328
362
  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;
363
+ const start = ptr >>> 0;
364
+ const length = len >>> 0;
365
+ if (length === 0) return "";
366
+ const view = getMemoryView();
367
+ if (start + length > view.byteLength) return "";
368
+ return textDecoder.decode(view.subarray(start, start + length));
335
369
  }
336
370
  function writeBytes(ptr, data) {
337
- getMemoryView().set(data, ptr);
371
+ const start = ptr >>> 0;
372
+ const view = getMemoryView();
373
+ if (start + data.length > view.byteLength) return;
374
+ view.set(data, start);
338
375
  }
339
376
  function wrapPromisingExport(fn) {
340
377
  if (!fn) return void 0;
@@ -418,20 +455,21 @@ var ZxBridgeCore = class _ZxBridgeCore {
418
455
  _notifyFetchComplete(fetchId, statusCode, body, isError) {
419
456
  const handler = this.#fetchCompleteHandler;
420
457
  const encoded = typeof body === "string" ? textEncoder.encode(body) : body;
421
- const ptr = this._alloc(encoded.length);
458
+ const ptr = this._alloc(encoded.length) >>> 0;
459
+ if (!ptr && encoded.length > 0) return;
422
460
  writeBytes(ptr, encoded);
423
461
  invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
424
462
  }
425
463
  /** Set a timeout and callback when it fires */
426
464
  setTimeout(callbackId, delayMs) {
427
465
  setTimeout(() => {
428
- this.#invoke(CallbackType.Timeout, callbackId, null);
466
+ this.#invoke(3, callbackId, null);
429
467
  }, delayMs);
430
468
  }
431
469
  /** Set an interval and callback each time it fires */
432
470
  setInterval(callbackId, intervalMs) {
433
471
  const handle = setInterval(() => {
434
- this.#invoke(CallbackType.Interval, callbackId, null);
472
+ this.#invoke(4, callbackId, null);
435
473
  }, intervalMs);
436
474
  this.#intervals.set(callbackId, handle);
437
475
  }
@@ -449,18 +487,24 @@ var ZxBridgeCore = class _ZxBridgeCore {
449
487
  }
450
488
  this.#intervals.clear();
451
489
  }
452
- /** Write a string to WASM memory, returning pointer and length */
490
+ /** Write a string to WASM memory, returning `[ptr, len]`. */
453
491
  _writeStringToWasm(str) {
454
- return this._writeBytesToWasm(textEncoder.encode(str));
492
+ return this.writeBytesToWasm(textEncoder.encode(str));
455
493
  }
456
- _writeBytesToWasm(data) {
457
- const ptr = this._alloc(data.length);
494
+ writeBytesToWasm(data) {
495
+ if (data.length === 0) return [0, 0];
496
+ const ptr = this._alloc(data.length) >>> 0;
497
+ if (!ptr) return [0, 0];
458
498
  writeBytes(ptr, data);
459
- return { ptr, len: data.length };
499
+ return [ptr, data.length];
460
500
  }
461
501
  /** Log a message from WASM at the given level (0=error, 1=warn, 2=info, 3=debug) */
462
502
  static log(level, ptr, len) {
463
- const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
503
+ const start = ptr >>> 0;
504
+ const length = len >>> 0;
505
+ const view = getMemoryView();
506
+ if (start + length > view.byteLength) return;
507
+ const msg = textDecoder.decode(view.subarray(start, start + length));
464
508
  switch (level) {
465
509
  case 0:
466
510
  console.error(msg);
@@ -492,7 +536,7 @@ var ZxBridgeCore = class _ZxBridgeCore {
492
536
  __zx: {
493
537
  _log: (level, ptr, len) => _ZxBridgeCore.log(level, ptr, len),
494
538
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
495
- bridgeRef.current?.fetchAsync(
539
+ bridgeRef[0]?.fetchAsync(
496
540
  urlPtr,
497
541
  urlLen,
498
542
  methodPtr,
@@ -506,20 +550,41 @@ var ZxBridgeCore = class _ZxBridgeCore {
506
550
  );
507
551
  },
508
552
  _setTimeout: (callbackId, delayMs) => {
509
- bridgeRef.current?.setTimeout(callbackId, delayMs);
553
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
510
554
  },
511
555
  _setInterval: (callbackId, intervalMs) => {
512
- bridgeRef.current?.setInterval(callbackId, intervalMs);
556
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
513
557
  },
514
558
  _clearInterval: (callbackId) => {
515
- bridgeRef.current?.clearInterval(callbackId);
559
+ bridgeRef[0]?.clearInterval(callbackId);
516
560
  }
517
561
  }
518
562
  };
519
563
  }
520
564
  };
565
+ function writeBytesOut(getMemory, allocRef, outPtrAddr, data) {
566
+ if (data.length === 0) {
567
+ new DataView(getMemory().buffer).setUint32(outPtrAddr, 0, true);
568
+ return 0;
569
+ }
570
+ const alloc = allocRef[0];
571
+ if (!alloc) return -1;
572
+ const ptr = alloc(data.length) >>> 0;
573
+ if (!ptr) return -1;
574
+ const buffer = getMemory().buffer;
575
+ if (ptr + data.length > buffer.byteLength) return -1;
576
+ new Uint8Array(buffer, ptr, data.length).set(data);
577
+ new DataView(buffer).setUint32(outPtrAddr >>> 0, ptr, true);
578
+ return data.length;
579
+ }
580
+ function writeJsonOut(getMemory, allocRef, outPtrAddr, value) {
581
+ return writeBytesOut(getMemory, allocRef, outPtrAddr, textEncoder.encode(JSON.stringify(value)));
582
+ }
583
+ function bindWasmAlloc(allocRef, exports) {
584
+ allocRef[0] = exports.__zx_alloc;
585
+ }
521
586
 
522
- // src/kv.ts
587
+ // src/runtime/kv/extern.ts
523
588
  function putOptions(ttlSeconds) {
524
589
  if (ttlSeconds < 60) return void 0;
525
590
  return { expirationTtl: ttlSeconds };
@@ -528,17 +593,12 @@ function isSyncKVNamespace(binding) {
528
593
  const candidate = binding;
529
594
  return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
530
595
  }
531
- function createKVImports(bindings, getMemory) {
596
+ function createKVImports(bindings, getMemory, allocRef) {
532
597
  const encoder2 = new TextEncoder();
533
598
  const decoder2 = new TextDecoder();
534
599
  function readStr(ptr, len) {
535
600
  return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
536
601
  }
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
602
  function binding(ns) {
543
603
  return bindings[ns] ?? bindings["default"] ?? null;
544
604
  }
@@ -550,12 +610,12 @@ function createKVImports(bindings, getMemory) {
550
610
  };
551
611
  var syncBinding = syncBinding2;
552
612
  return {
553
- kv_get: (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
613
+ kv_get: (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
554
614
  const b = syncBinding2(readStr(ns_ptr, ns_len));
555
615
  if (!b) return -1;
556
616
  const value = b.getSync(readStr(key_ptr, key_len));
557
617
  if (value === null) return -1;
558
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
618
+ return writeBytesOut(getMemory, allocRef, out_ptr, encoder2.encode(value));
559
619
  },
560
620
  kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
561
621
  const b = syncBinding2(readStr(ns_ptr, ns_len));
@@ -569,22 +629,22 @@ function createKVImports(bindings, getMemory) {
569
629
  b.deleteSync(readStr(key_ptr, key_len));
570
630
  return 0;
571
631
  },
572
- kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, buf_ptr, buf_max) => {
632
+ kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, out_ptr) => {
573
633
  const b = syncBinding2(readStr(ns_ptr, ns_len));
574
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
634
+ if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
575
635
  const prefix = readStr(pfx_ptr, pfx_len);
576
636
  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))));
637
+ return writeJsonOut(getMemory, allocRef, out_ptr, result.keys.map((k) => k.name));
578
638
  }
579
639
  };
580
640
  }
581
641
  return {
582
- kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
642
+ kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
583
643
  const b = binding(readStr(ns_ptr, ns_len));
584
644
  if (!b) return -1;
585
645
  const value = await b.get(readStr(key_ptr, key_len));
586
646
  if (value === null) return -1;
587
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
647
+ return writeBytesOut(getMemory, allocRef, out_ptr, encoder2.encode(value));
588
648
  }),
589
649
  kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
590
650
  const b = binding(readStr(ns_ptr, ns_len));
@@ -598,17 +658,70 @@ function createKVImports(bindings, getMemory) {
598
658
  await b.delete(readStr(key_ptr, key_len));
599
659
  return 0;
600
660
  }),
601
- kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
661
+ kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, out_ptr) => {
602
662
  const b = binding(readStr(ns_ptr, ns_len));
603
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
663
+ if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
604
664
  const prefix = readStr(prefix_ptr, prefix_len);
605
665
  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))));
666
+ const names = result.keys.map((k) => k.name);
667
+ if (names.length === 0) {
668
+ new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
669
+ return 0;
670
+ }
671
+ return writeJsonOut(getMemory, allocRef, out_ptr, names);
607
672
  })
608
673
  };
609
674
  }
610
675
 
611
- // src/browser/kv.ts
676
+ // src/runtime/kv/localstorage.ts
677
+ function getLocalStorage() {
678
+ if (typeof localStorage === "undefined") {
679
+ throw new Error("localStorage is not available in this environment");
680
+ }
681
+ return localStorage;
682
+ }
683
+ function createLocalStorageKV(options = {}) {
684
+ const storage = getLocalStorage();
685
+ const namespace = options.namespace ?? "default";
686
+ const storagePrefix = options.storagePrefix ?? "ziex-kv";
687
+ const scopedKey = (key) => `${storagePrefix}:${namespace}:${key}`;
688
+ const namespacePrefix = scopedKey("");
689
+ return {
690
+ getSync(key) {
691
+ return storage.getItem(scopedKey(key));
692
+ },
693
+ async get(key) {
694
+ return this.getSync(key);
695
+ },
696
+ putSync(key, value) {
697
+ storage.setItem(scopedKey(key), value);
698
+ },
699
+ async put(key, value) {
700
+ this.putSync(key, value);
701
+ },
702
+ deleteSync(key) {
703
+ storage.removeItem(scopedKey(key));
704
+ },
705
+ async delete(key) {
706
+ this.deleteSync(key);
707
+ },
708
+ listSync(options2) {
709
+ const prefix = namespacePrefix + (options2?.prefix ?? "");
710
+ const keys = [];
711
+ for (let i = 0; i < storage.length; i += 1) {
712
+ const key = storage.key(i);
713
+ if (!key || !key.startsWith(prefix)) continue;
714
+ keys.push({ name: key.slice(namespacePrefix.length) });
715
+ }
716
+ return { keys };
717
+ },
718
+ async list(options2) {
719
+ return this.listSync(options2);
720
+ }
721
+ };
722
+ }
723
+
724
+ // src/runtime/kv/indexdb.ts
612
725
  function getIndexedDb() {
613
726
  if (typeof indexedDB === "undefined") {
614
727
  throw new Error("IndexedDB is not available in this environment");
@@ -651,7 +764,6 @@ function createIndexedDbKV(options = {}) {
651
764
  const store = tx.objectStore(storeName);
652
765
  const value = await requestToPromise(store.get(scopedKey(key)));
653
766
  await transactionToPromise(tx);
654
- console.debug(`KV GET - Key: ${key}, Value: ${value}`);
655
767
  return typeof value === "string" ? value : null;
656
768
  },
657
769
  async put(key, value) {
@@ -659,7 +771,6 @@ function createIndexedDbKV(options = {}) {
659
771
  const tx = db.transaction(storeName, "readwrite");
660
772
  tx.objectStore(storeName).put(value, scopedKey(key));
661
773
  await transactionToPromise(tx);
662
- console.debug(`KV PUT - Key: ${key}, Value: ${value}`);
663
774
  },
664
775
  async delete(key) {
665
776
  const db = await dbPromise;
@@ -680,52 +791,8 @@ function createIndexedDbKV(options = {}) {
680
791
  }
681
792
  };
682
793
  }
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
- }
794
+
795
+ // src/runtime/kv.ts
729
796
  function hasJSPI() {
730
797
  return typeof WebAssembly.Suspending === "function" && typeof WebAssembly.promising === "function";
731
798
  }
@@ -756,18 +823,29 @@ var ZxBridge = class extends ZxBridgeCore {
756
823
  exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
757
824
  );
758
825
  }
826
+ hasEventHandler(velementId, eventTypeId) {
827
+ return !!((eventHandlersPresent.get(velementId) ?? 0) & 1 << eventTypeId);
828
+ }
759
829
  eventMaySuspend(velementId, eventTypeId) {
760
- return !!((eventHandlerModes.get(velementId) ?? 0) & 1 << eventTypeId);
830
+ return !!((eventHandlersSuspend.get(velementId) ?? 0) & 1 << eventTypeId);
761
831
  }
762
832
  setEventHandlerMode(velementId, eventTypeId, maySuspend) {
763
833
  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);
834
+ const present = (eventHandlersPresent.get(velementId) ?? 0) | bit;
835
+ eventHandlersPresent.set(velementId, present);
836
+ const suspendBits = eventHandlersSuspend.get(velementId) ?? 0;
837
+ const nextSuspend = maySuspend ? suspendBits | bit : suspendBits & ~bit;
838
+ if (nextSuspend === 0) eventHandlersSuspend.delete(velementId);
839
+ else eventHandlersSuspend.set(velementId, nextSuspend);
840
+ ensureDelegatedListener(eventTypeId);
768
841
  }
769
842
  clearEventHandlerModes(velementId) {
770
- eventHandlerModes.delete(velementId);
843
+ const present = eventHandlersPresent.get(velementId) ?? 0;
844
+ eventHandlersPresent.delete(velementId);
845
+ eventHandlersSuspend.delete(velementId);
846
+ for (const eventTypeId of HIGH_FREQ_EVENT_IDS) {
847
+ if (present & 1 << eventTypeId) maybeRemoveHighFreqListener(eventTypeId);
848
+ }
771
849
  }
772
850
  /** Submit a form action with bound-state round-trip. */
773
851
  submitFormActionAsync(form, actionId, statesJson, fetchId) {
@@ -801,7 +879,7 @@ var ZxBridge = class extends ZxBridgeCore {
801
879
  const handler = this.#wsOnOpenHandler;
802
880
  if (!handler) return;
803
881
  const protocol = ws.protocol || "";
804
- const { ptr, len } = this._writeStringToWasm(protocol);
882
+ const [ptr, len] = this._writeStringToWasm(protocol);
805
883
  invokeWasmExport(handler, wsId, ptr, len);
806
884
  };
807
885
  ws.onmessage = (event) => {
@@ -809,20 +887,20 @@ var ZxBridge = class extends ZxBridgeCore {
809
887
  if (!handler) return;
810
888
  const isBinary = event.data instanceof ArrayBuffer;
811
889
  const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
812
- const { ptr, len } = this._writeBytesToWasm(data);
890
+ const [ptr, len] = this.writeBytesToWasm(data);
813
891
  invokeWasmExport(handler, wsId, ptr, len, isBinary ? 1 : 0);
814
892
  };
815
893
  ws.onerror = (_event) => {
816
894
  const handler = this.#wsOnErrorHandler;
817
895
  if (!handler) return;
818
- const { ptr, len } = this._writeStringToWasm("WebSocket error");
896
+ const [ptr, len] = this._writeStringToWasm("WebSocket error");
819
897
  invokeWasmExport(handler, wsId, ptr, len);
820
898
  };
821
899
  ws.onclose = (event) => {
822
900
  const handler = this.#wsOnCloseHandler;
823
901
  if (!handler) return;
824
902
  const reason = event.reason || "";
825
- const { ptr, len } = this._writeStringToWasm(reason);
903
+ const [ptr, len] = this._writeStringToWasm(reason);
826
904
  invokeWasmExport(handler, wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
827
905
  this.#websockets.delete(wsId);
828
906
  };
@@ -831,7 +909,7 @@ var ZxBridge = class extends ZxBridgeCore {
831
909
  const handler = this.#wsOnErrorHandler;
832
910
  if (handler) {
833
911
  const msg = error instanceof Error ? error.message : "WebSocket connection failed";
834
- const { ptr, len } = this._writeStringToWasm(msg);
912
+ const [ptr, len] = this._writeStringToWasm(msg);
835
913
  invokeWasmExport(handler, wsId, ptr, len);
836
914
  }
837
915
  }
@@ -841,10 +919,13 @@ var ZxBridge = class extends ZxBridgeCore {
841
919
  const ws = this.#websockets.get(wsId);
842
920
  if (!ws || ws.readyState !== WebSocket.OPEN) return;
843
921
  const memory = getMemoryView();
922
+ const start = dataPtr >>> 0;
923
+ const length = dataLen >>> 0;
924
+ if (start + length > memory.byteLength) return;
844
925
  if (isBinary) {
845
- ws.send(memory.slice(dataPtr, dataPtr + dataLen));
926
+ ws.send(memory.slice(start, start + length));
846
927
  } else {
847
- ws.send(textDecoder.decode(memory.subarray(dataPtr, dataPtr + dataLen)));
928
+ ws.send(textDecoder.decode(memory.subarray(start, start + length)));
848
929
  }
849
930
  }
850
931
  /** Close WebSocket connection */
@@ -861,7 +942,8 @@ var ZxBridge = class extends ZxBridgeCore {
861
942
  }
862
943
  dispose() {
863
944
  super.dispose();
864
- eventHandlerModes.clear();
945
+ eventHandlersPresent.clear();
946
+ eventHandlersSuspend.clear();
865
947
  for (const ws of this.#websockets.values()) {
866
948
  try {
867
949
  ws.close();
@@ -870,14 +952,16 @@ var ZxBridge = class extends ZxBridgeCore {
870
952
  }
871
953
  this.#websockets.clear();
872
954
  }
873
- /** Handle a DOM event (called by event delegation) */
874
- eventbridge(velementId, eventTypeId, event) {
875
- const eventRef = storeValueGetRef(event);
955
+ /**
956
+ * Dispatch to WASM for one vnode. Caller owns `eventRef` lifetime
957
+ * (store once per bubble, release after sync/async work completes).
958
+ */
959
+ eventbridge(velementId, eventTypeId, eventRef) {
960
+ const id = BigInt(velementId >>> 0);
876
961
  if (this.eventMaySuspend(velementId, eventTypeId)) {
877
- invokeWasmExport(this.#eventbridgeAsync, velementId, eventTypeId, eventRef);
878
- return;
962
+ return invokeWasmExport(this.#eventbridgeAsync, id, eventTypeId, eventRef);
879
963
  }
880
- invokeWasmExport(this.#eventbridge, velementId, eventTypeId, eventRef);
964
+ invokeWasmExport(this.#eventbridge, id, eventTypeId, eventRef);
881
965
  }
882
966
  /** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
883
967
  static createImportObject(bridgeRef) {
@@ -890,13 +974,13 @@ var ZxBridge = class extends ZxBridgeCore {
890
974
  __zx: {
891
975
  _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
892
976
  _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
893
- bridgeRef.current?.setEventHandlerMode(vnodeId, eventTypeId, maySuspend !== 0);
977
+ bridgeRef[0]?.setEventHandlerMode(Number(vnodeId), eventTypeId, maySuspend !== 0);
894
978
  },
895
979
  _clearEventHandlerModes: (vnodeId) => {
896
- bridgeRef.current?.clearEventHandlerModes(vnodeId);
980
+ bridgeRef[0]?.clearEventHandlerModes(Number(vnodeId));
897
981
  },
898
982
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
899
- bridgeRef.current?.fetchAsync(
983
+ bridgeRef[0]?.fetchAsync(
900
984
  urlPtr,
901
985
  urlLen,
902
986
  methodPtr,
@@ -910,43 +994,49 @@ var ZxBridge = class extends ZxBridgeCore {
910
994
  );
911
995
  },
912
996
  _setTimeout: (callbackId, delayMs) => {
913
- bridgeRef.current?.setTimeout(callbackId, delayMs);
997
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
914
998
  },
915
999
  _setInterval: (callbackId, intervalMs) => {
916
- bridgeRef.current?.setInterval(callbackId, intervalMs);
1000
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
917
1001
  },
918
1002
  _clearInterval: (callbackId) => {
919
- bridgeRef.current?.clearInterval(callbackId);
1003
+ bridgeRef[0]?.clearInterval(callbackId);
920
1004
  },
921
1005
  // WebSocket API
922
1006
  _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
923
- bridgeRef.current?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
1007
+ bridgeRef[0]?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
924
1008
  },
925
1009
  _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
926
- bridgeRef.current?.wsSend(wsId, dataPtr, dataLen, isBinary);
1010
+ bridgeRef[0]?.wsSend(wsId, dataPtr, dataLen, isBinary);
927
1011
  },
928
1012
  _wsClose: (wsId, code, reasonPtr, reasonLen) => {
929
- bridgeRef.current?.wsClose(wsId, code, reasonPtr, reasonLen);
1013
+ bridgeRef[0]?.wsClose(wsId, code, reasonPtr, reasonLen);
930
1014
  },
931
1015
  _ce: (id, vnodeId) => {
1016
+ const nid = Number(vnodeId);
932
1017
  const tagName = TAG_NAMES[id];
933
1018
  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);
1019
+ el.__zx_ref = nid;
1020
+ domNodes.set(nid, el);
937
1021
  },
938
1022
  _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);
1023
+ const nid = Number(vnodeId);
1024
+ const node = document.createTextNode(readString(ptr, len));
1025
+ node.__zx_ref = nid;
1026
+ domNodes.set(nid, node);
1027
+ },
1028
+ /** Insert vnode before a jsz-held end comment (hydration). */
1029
+ _ih: (vnodeId, endCommentRef) => {
1030
+ const child = domNodes.get(Number(vnodeId));
1031
+ const end = loadValueFromRef(endCommentRef);
1032
+ if (!child || !end?.parentNode) return;
1033
+ end.parentNode.insertBefore(child, end);
944
1034
  },
945
1035
  _sa: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
946
- domNodes.get(vnodeId)?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
1036
+ domNodes.get(Number(vnodeId))?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
947
1037
  },
948
1038
  _sp: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
949
- const el = domNodes.get(vnodeId);
1039
+ const el = domNodes.get(Number(vnodeId));
950
1040
  if (el) {
951
1041
  const name = readString(namePtr, nameLen);
952
1042
  const val = readString(valPtr, valLen);
@@ -958,39 +1048,39 @@ var ZxBridge = class extends ZxBridgeCore {
958
1048
  }
959
1049
  },
960
1050
  _ra: (vnodeId, namePtr, nameLen) => {
961
- domNodes.get(vnodeId)?.removeAttribute(readString(namePtr, nameLen));
1051
+ domNodes.get(Number(vnodeId))?.removeAttribute(readString(namePtr, nameLen));
962
1052
  },
963
1053
  _snv: (vnodeId, ptr, len) => {
964
- const node = domNodes.get(vnodeId);
1054
+ const node = domNodes.get(Number(vnodeId));
965
1055
  if (node) node.nodeValue = readString(ptr, len);
966
1056
  },
967
1057
  _srh: (vnodeId, ptr, len) => {
968
- const el = domNodes.get(vnodeId);
1058
+ const el = domNodes.get(Number(vnodeId));
969
1059
  if (el) el.innerHTML = readString(ptr, len);
970
1060
  },
971
1061
  _ac: (parentId, childId) => {
972
- const parent = domNodes.get(parentId);
973
- const child = domNodes.get(childId);
1062
+ const parent = domNodes.get(Number(parentId));
1063
+ const child = domNodes.get(Number(childId));
974
1064
  if (parent && child) parent.appendChild(child);
975
1065
  },
976
1066
  _ib: (parentId, childId, refId) => {
977
- const parent = domNodes.get(parentId);
978
- const child = domNodes.get(childId);
979
- const ref = domNodes.get(refId) ?? null;
1067
+ const parent = domNodes.get(Number(parentId));
1068
+ const child = domNodes.get(Number(childId));
1069
+ const ref = domNodes.get(Number(refId)) ?? null;
980
1070
  if (parent && child) parent.insertBefore(child, ref);
981
1071
  },
982
1072
  _rc: (parentId, childId) => {
983
- const parent = domNodes.get(parentId);
984
- const child = domNodes.get(childId);
1073
+ const parent = domNodes.get(Number(parentId));
1074
+ const child = domNodes.get(Number(childId));
985
1075
  if (parent && child) {
986
1076
  parent.removeChild(child);
987
1077
  cleanupDomNodes(child);
988
1078
  }
989
1079
  },
990
1080
  _rpc: (parentId, newId, oldId) => {
991
- const parent = domNodes.get(parentId);
992
- const newChild = domNodes.get(newId);
993
- const oldChild = domNodes.get(oldId);
1081
+ const parent = domNodes.get(Number(parentId));
1082
+ const newChild = domNodes.get(Number(newId));
1083
+ const oldChild = domNodes.get(Number(oldId));
994
1084
  if (parent && newChild && oldChild) {
995
1085
  parent.replaceChild(newChild, oldChild);
996
1086
  cleanupDomNodes(oldChild);
@@ -1002,18 +1092,22 @@ var ZxBridge = class extends ZxBridgeCore {
1002
1092
  writeBytes(bufPtr, bytes.subarray(0, len));
1003
1093
  return len;
1004
1094
  },
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));
1095
+ _getFormData: (eventRef, outPtrAddr) => {
1096
+ const event = loadValueFromRef(eventRef);
1097
+ const el = event?.target;
1098
+ const form = el instanceof HTMLFormElement ? el : el?.closest?.("form") ?? null;
1099
+ if (!form) return 0;
1100
+ const entries = [];
1101
+ for (const [k, v] of new FormData(form).entries()) {
1102
+ entries.push(k, String(v));
1103
+ }
1104
+ const bytes = textEncoder.encode(JSON.stringify(entries));
1105
+ const [ptr, len] = bridgeRef[0].writeBytesToWasm(bytes);
1106
+ new DataView(jsz.memory.buffer).setUint32(outPtrAddr, ptr, true);
1013
1107
  return len;
1014
1108
  },
1015
1109
  _submitFormAction: (vnodeId, actionId) => {
1016
- const form = domNodes.get(vnodeId);
1110
+ const form = domNodes.get(Number(vnodeId));
1017
1111
  if (!form || !(form instanceof HTMLFormElement)) return;
1018
1112
  const formData = new FormData(form);
1019
1113
  fetch(window.location.href, {
@@ -1025,21 +1119,39 @@ var ZxBridge = class extends ZxBridgeCore {
1025
1119
  });
1026
1120
  },
1027
1121
  _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
1028
- const form = domNodes.get(vnodeId);
1122
+ const form = domNodes.get(Number(vnodeId));
1029
1123
  if (!form || !(form instanceof HTMLFormElement)) return;
1030
1124
  const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
1031
- bridgeRef.current?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1125
+ bridgeRef[0]?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1032
1126
  }
1033
1127
  }
1034
1128
  };
1035
1129
  }
1036
1130
  };
1037
1131
  var domNodes = /* @__PURE__ */ new Map();
1132
+ var eventHandlersPresent = /* @__PURE__ */ new Map();
1133
+ var eventHandlersSuspend = /* @__PURE__ */ new Map();
1038
1134
  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]);
1135
+ const stack = [node];
1136
+ let highFreqBits = 0;
1137
+ while (stack.length > 0) {
1138
+ const n = stack.pop();
1139
+ const ref = n.__zx_ref;
1140
+ if (typeof ref === "number") {
1141
+ const present = eventHandlersPresent.get(ref);
1142
+ if (present !== void 0) {
1143
+ highFreqBits |= present;
1144
+ eventHandlersPresent.delete(ref);
1145
+ eventHandlersSuspend.delete(ref);
1146
+ }
1147
+ domNodes.delete(ref);
1148
+ }
1149
+ const children = n.childNodes;
1150
+ for (let i = 0; i < children.length; i++) stack.push(children[i]);
1151
+ }
1152
+ for (const eventTypeId of HIGH_FREQ_EVENT_IDS) {
1153
+ if (highFreqBits & 1 << eventTypeId) maybeRemoveHighFreqListener(eventTypeId);
1154
+ }
1043
1155
  }
1044
1156
  var SVG_TAG_START_INDEX = 140;
1045
1157
  var TAG_NAMES = [
@@ -1245,54 +1357,115 @@ var TAG_NAMES = [
1245
1357
  "view"
1246
1358
  ];
1247
1359
  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 }
1360
+ "click",
1361
+ "dblclick",
1362
+ "input",
1363
+ "change",
1364
+ "submit",
1365
+ // focus/blur do not bubble - listen to focusin/focusout instead.
1366
+ "focusin",
1367
+ "focusout",
1368
+ "keydown",
1369
+ "keyup",
1370
+ "keypress",
1371
+ "mouseenter",
1372
+ "mouseleave",
1373
+ "mousedown",
1374
+ "mouseup",
1375
+ "mousemove",
1376
+ "touchstart",
1377
+ "touchend",
1378
+ "touchmove",
1379
+ "scroll",
1380
+ "wheel",
1381
+ "pointerdown",
1382
+ "pointermove",
1383
+ "pointerup",
1384
+ "pointercancel"
1268
1385
  ];
1269
- var eventHandlerModes = /* @__PURE__ */ new Map();
1386
+ var HIGH_FREQ_EVENT_IDS = new Set([
1387
+ DELEGATED_EVENTS.indexOf("mousemove"),
1388
+ DELEGATED_EVENTS.indexOf("pointermove"),
1389
+ DELEGATED_EVENTS.indexOf("wheel"),
1390
+ DELEGATED_EVENTS.indexOf("scroll"),
1391
+ DELEGATED_EVENTS.indexOf("touchmove")
1392
+ ].filter((id) => id >= 0));
1393
+ var delegationState = null;
1394
+ function makeDelegatedListener(bridge, eventTypeId) {
1395
+ return (event) => {
1396
+ let eventRef;
1397
+ const pending = [];
1398
+ let target = event.target;
1399
+ while (target && target !== document.body) {
1400
+ const zxRef = target.__zx_ref;
1401
+ if (typeof zxRef === "number" && bridge.hasEventHandler(zxRef, eventTypeId)) {
1402
+ if (eventRef === void 0) eventRef = storeValueGetRef(event);
1403
+ const result = bridge.eventbridge(zxRef, eventTypeId, eventRef);
1404
+ if (result && typeof result.then === "function") {
1405
+ pending.push(result);
1406
+ }
1407
+ if (event.cancelBubble) break;
1408
+ }
1409
+ target = target.parentElement;
1410
+ }
1411
+ if (eventRef !== void 0) {
1412
+ const ref = eventRef;
1413
+ if (pending.length > 0) {
1414
+ Promise.all(pending).finally(() => releaseValueRef(ref));
1415
+ } else {
1416
+ releaseValueRef(ref);
1417
+ }
1418
+ }
1419
+ };
1420
+ }
1421
+ function ensureDelegatedListener(eventTypeId) {
1422
+ const state = delegationState;
1423
+ if (!state || state.attached.has(eventTypeId)) return;
1424
+ const domType = DELEGATED_EVENTS[eventTypeId];
1425
+ if (!domType) return;
1426
+ const passive = domType.startsWith("touch") || domType === "scroll";
1427
+ const options = { passive };
1428
+ const listener = makeDelegatedListener(state.bridge, eventTypeId);
1429
+ state.root.addEventListener(domType, listener, options);
1430
+ state.attached.set(eventTypeId, { listener, options });
1431
+ }
1432
+ function anyHandlerForType(eventTypeId) {
1433
+ const bit = 1 << eventTypeId;
1434
+ for (const mask of eventHandlersPresent.values()) {
1435
+ if (mask & bit) return true;
1436
+ }
1437
+ return false;
1438
+ }
1439
+ function maybeRemoveHighFreqListener(eventTypeId) {
1440
+ if (!HIGH_FREQ_EVENT_IDS.has(eventTypeId)) return;
1441
+ if (anyHandlerForType(eventTypeId)) return;
1442
+ const state = delegationState;
1443
+ if (!state) return;
1444
+ const entry = state.attached.get(eventTypeId);
1445
+ if (!entry) return;
1446
+ const domType = DELEGATED_EVENTS[eventTypeId];
1447
+ state.root.removeEventListener(domType, entry.listener, entry.options);
1448
+ state.attached.delete(eventTypeId);
1449
+ }
1270
1450
  function initEventDelegation(bridge, rootSelector = "body") {
1271
1451
  const root = document.querySelector(rootSelector);
1272
1452
  if (!root) return () => {
1273
1453
  };
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));
1454
+ delegationState = { root, bridge, attached: /* @__PURE__ */ new Map() };
1455
+ for (let eventTypeId = 0; eventTypeId < DELEGATED_EVENTS.length; eventTypeId++) {
1456
+ if (HIGH_FREQ_EVENT_IDS.has(eventTypeId)) continue;
1457
+ ensureDelegatedListener(eventTypeId);
1290
1458
  }
1291
1459
  return () => {
1292
- for (const remove of removers) remove();
1460
+ if (!delegationState) return;
1461
+ for (const [eventTypeId, entry] of delegationState.attached) {
1462
+ const domType = DELEGATED_EVENTS[eventTypeId];
1463
+ delegationState.root.removeEventListener(domType, entry.listener, entry.options);
1464
+ }
1465
+ delegationState.attached.clear();
1466
+ delegationState = null;
1293
1467
  };
1294
1468
  }
1295
- var DEFAULT_URL = "/assets/_/main.wasm";
1296
1469
  var activeRuntime = null;
1297
1470
  function buildDevtoolsLocation() {
1298
1471
  return {
@@ -1325,29 +1498,34 @@ async function init(options = {}) {
1325
1498
  activeRuntime.dispose();
1326
1499
  activeRuntime = null;
1327
1500
  }
1328
- const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
1329
- const bridgeRef = { current: null };
1501
+ const url = options.url ?? document.getElementById("__$wasmlink")?.href;
1502
+ if (!url) throw new Error("WASM URL is not set");
1503
+ const bridgeRef = [null];
1330
1504
  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
- })
1505
+ const allocRef = [null];
1506
+ const getMemory = () => {
1507
+ if (wasmMemory) return wasmMemory;
1508
+ if (jsz.memory) return jsz.memory;
1509
+ throw new Error("WASM memory is not ready");
1510
+ };
1511
+ const importObject = {
1512
+ ...ZxBridge.createImportObject(bridgeRef),
1513
+ ...options.importObject
1338
1514
  };
1339
- const importObject = Object.assign(
1340
- {},
1341
- ZxBridge.createImportObject(bridgeRef),
1342
- kvImportObject,
1343
- options.importObject
1344
- );
1515
+ if (true) {
1516
+ importObject.__zx_kv = createKVImports(
1517
+ options.kv ?? createBrowserKVBindings(),
1518
+ getMemory,
1519
+ allocRef
1520
+ );
1521
+ }
1345
1522
  const source = await WebAssembly.instantiateStreaming(fetch(url), importObject);
1346
1523
  const { instance } = source;
1347
1524
  wasmMemory = instance.exports.memory;
1348
1525
  jsz.memory = wasmMemory;
1526
+ bindWasmAlloc(allocRef, instance.exports);
1349
1527
  const bridge = new ZxBridge(instance.exports);
1350
- bridgeRef.current = bridge;
1528
+ bridgeRef[0] = bridge;
1351
1529
  domNodes.clear();
1352
1530
  const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
1353
1531
  const main = wrapPromisingExport(instance.exports.mainClient);
@@ -1364,16 +1542,29 @@ async function init(options = {}) {
1364
1542
  return { source, bridge };
1365
1543
  }
1366
1544
  export {
1367
- CallbackType,
1545
+ CallbackType_Event,
1546
+ CallbackType_FetchError,
1547
+ CallbackType_FetchSuccess,
1548
+ CallbackType_Interval,
1549
+ CallbackType_Timeout,
1550
+ CallbackType_WebSocketClose,
1551
+ CallbackType_WebSocketError,
1552
+ CallbackType_WebSocketMessage,
1553
+ CallbackType_WebSocketOpen,
1368
1554
  ZxBridge,
1369
1555
  ZxBridgeCore,
1556
+ bindWasmAlloc,
1370
1557
  getMemoryView,
1371
1558
  init,
1372
1559
  initEventDelegation,
1373
1560
  jsz,
1561
+ loadValueFromRef,
1374
1562
  readString,
1563
+ releaseValueRef,
1375
1564
  storeValueGetRef,
1376
1565
  textDecoder,
1377
1566
  textEncoder,
1378
- writeBytes
1567
+ writeBytes,
1568
+ writeBytesOut,
1569
+ writeJsonOut
1379
1570
  };