ziex 0.1.0-dev.1389 → 0.1.0-dev.1466

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 (49) 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 +490 -174
  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 +1959 -1532
  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 +45 -0
  26. package/runtime/kv.js +543 -0
  27. package/wasm/constants.d.ts +33 -0
  28. package/wasm/core.d.ts +23 -33
  29. package/wasm/dom_cmd.d.ts +15 -0
  30. package/wasm/generated/event_bits.d.ts +2 -0
  31. package/wasm/generated/events.d.ts +1 -0
  32. package/wasm/generated/tag_indices.d.ts +2 -0
  33. package/wasm/generated/tags.d.ts +1 -0
  34. package/wasm/index.d.ts +15 -13
  35. package/wasm/index.js +911 -676
  36. package/wasm/init.dev.js +895 -674
  37. package/wasm/init.js +3 -3
  38. package/wasm/wasi.d.ts +1 -5
  39. package/browser/kv.d.ts +0 -13
  40. package/cloudflare/app.d.ts +0 -2
  41. package/cloudflare/db.d.ts +0 -2
  42. package/cloudflare/index.d.ts +0 -4
  43. package/cloudflare/kv.d.ts +0 -2
  44. package/cloudflare/worker.d.ts +0 -3
  45. package/db.d.ts +0 -22
  46. package/kv.d.ts +0 -42
  47. /package/{aws-lambda → platforms/aws-lambda}/index.d.ts +0 -0
  48. /package/{vercel → platforms/vercel}/index.d.ts +0 -0
  49. /package/{wasi.d.ts → runtime/wasi.d.ts} +0 -0
package/wasm/init.dev.js CHANGED
@@ -1,3 +1,27 @@
1
+ // src/wasm/constants.ts
2
+ var DOM_CMD_HEADER_SIZE = 8;
3
+ var DOM_CMD_RECORD_SIZE = 24;
4
+ var DomOp_CreateElement = 1;
5
+ var DomOp_CreateText = 2;
6
+ var DomOp_HydrateInsert = 3;
7
+ var DomOp_SetAttr = 4;
8
+ var DomOp_SetProp = 5;
9
+ var DomOp_RemoveAttr = 6;
10
+ var DomOp_SetNodeValue = 7;
11
+ var DomOp_SetInnerHtml = 8;
12
+ var DomOp_AppendChild = 9;
13
+ var DomOp_InsertBefore = 10;
14
+ var DomOp_RemoveChild = 11;
15
+ var DomOp_ReplaceChild = 12;
16
+ var CallbackType_FetchSuccess = 1;
17
+ var CallbackType_FetchError = 2;
18
+ var CallbackType_Timeout = 3;
19
+ var CallbackType_Interval = 4;
20
+ var CallbackType_WebSocketOpen = 5;
21
+ var CallbackType_WebSocketMessage = 6;
22
+ var CallbackType_WebSocketError = 7;
23
+ var CallbackType_WebSocketClose = 8;
24
+
1
25
  // ../../vendor/jsz/js/src/zigjs.ts
2
26
  var NAN_PREFIX = 2146959360;
3
27
  var predefined = {
@@ -51,6 +75,10 @@ var ZigJS = class {
51
75
  * */
52
76
  valueGet(out, id, ptr, len) {
53
77
  const val = this.loadValue(id);
78
+ if (val === null || val === void 0 || typeof val !== "object" && typeof val !== "function") {
79
+ this.storeValue(out, void 0);
80
+ return;
81
+ }
54
82
  const str = this.loadString(ptr, len);
55
83
  const result = Reflect.get(val, str);
56
84
  this.storeValue(out, result);
@@ -99,11 +127,15 @@ var ZigJS = class {
99
127
  * */
100
128
  valueStringCopy(id, ptr, max) {
101
129
  if (this.memory == null) return;
130
+ const dest = ptr >>> 0;
131
+ const cap = max >>> 0;
102
132
  const val = this.loadValue(id);
133
+ if (typeof val !== "string") return;
103
134
  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);
135
+ if (bytes.byteLength > cap || bytes.length === 0) return;
136
+ const buf = this.memory.buffer;
137
+ if (dest + bytes.length > buf.byteLength) return;
138
+ new Uint8Array(buf, dest, bytes.length).set(bytes);
107
139
  }
108
140
  /**
109
141
  * Call a constructor given by id.
@@ -111,8 +143,10 @@ var ZigJS = class {
111
143
  valueNew(out, id, argsAddr, argsLen) {
112
144
  const fn = this.loadValue(id);
113
145
  const args = [];
114
- for (let i = 0; i < argsLen; i++) {
115
- args.push(this.loadRef(argsAddr + i * 8));
146
+ const base = argsAddr >>> 0;
147
+ const count = argsLen >>> 0;
148
+ for (let i = 0; i < count; i++) {
149
+ args.push(this.loadRef(base + i * 8));
116
150
  }
117
151
  const result = Reflect.construct(fn, args);
118
152
  this.storeValue(out, result);
@@ -122,13 +156,23 @@ var ZigJS = class {
122
156
  * */
123
157
  funcApply(out, id, thisRefAddr, argsAddr, argsLen) {
124
158
  const fn = this.loadValue(id);
125
- const thisVal = this.loadRef(thisRefAddr);
159
+ const thisVal = this.loadRef(thisRefAddr >>> 0);
126
160
  const args = [];
127
- for (let i = 0; i < argsLen; i++) {
128
- args.push(this.loadRef(argsAddr + i * 8));
161
+ const base = argsAddr >>> 0;
162
+ const count = argsLen >>> 0;
163
+ for (let i = 0; i < count; i++) {
164
+ args.push(this.loadRef(base + i * 8));
165
+ }
166
+ if (typeof fn !== "function") {
167
+ this.storeValue(out, void 0);
168
+ return;
169
+ }
170
+ try {
171
+ const result = Reflect.apply(fn, thisVal, args);
172
+ this.storeValue(out, result);
173
+ } catch {
174
+ this.storeValue(out, void 0);
129
175
  }
130
- const result = Reflect.apply(fn, thisVal, args);
131
- this.storeValue(out, result);
132
176
  }
133
177
  /**
134
178
  * This can be used to load a value given by an ID. A WASM function
@@ -149,19 +193,21 @@ var ZigJS = class {
149
193
  }
150
194
  loadRef(refAddr) {
151
195
  if (this.memory == null) return;
196
+ const addr = refAddr >>> 0;
152
197
  const view = new DataView(this.memory.buffer);
153
- const floatVal = view.getFloat64(refAddr, true);
198
+ const floatVal = view.getFloat64(addr, true);
154
199
  if (!isNaN(floatVal)) return floatVal;
155
- const id = this.loadRefId(refAddr);
200
+ const id = this.loadRefId(addr);
156
201
  return this.values[id];
157
202
  }
158
203
  loadRefId(refAddr) {
159
204
  if (this.memory == null) return 0;
160
- return new DataView(this.memory.buffer).getUint32(refAddr, true);
205
+ return new DataView(this.memory.buffer).getUint32(refAddr >>> 0, true);
161
206
  }
162
207
  storeValue(out, val) {
163
208
  if (this.memory == null) return;
164
209
  const view = new DataView(this.memory.buffer);
210
+ out = out >>> 0;
165
211
  if (typeof val === "number") {
166
212
  if (isNaN(val)) {
167
213
  view.setUint32(out, predefined.nan, true);
@@ -215,13 +261,17 @@ var ZigJS = class {
215
261
  }
216
262
  loadString(ptr, len) {
217
263
  if (this.memory == null) return "";
218
- const arr = new Uint8ClampedArray(this.memory.buffer, ptr, Number(len));
264
+ const start = ptr >>> 0;
265
+ const length = Number(len) >>> 0;
266
+ const buf = this.memory.buffer;
267
+ if (length === 0 || start + length > buf.byteLength) return "";
268
+ const arr = new Uint8ClampedArray(buf, start, length);
219
269
  const data = arr.slice();
220
270
  return decoder.decode(data);
221
271
  }
222
272
  };
223
273
 
224
- // src/fetch.ts
274
+ // src/runtime/fetch.ts
225
275
  function createFetchImports(getMemory) {
226
276
  const encoder2 = new TextEncoder();
227
277
  const decoder2 = new TextDecoder();
@@ -288,17 +338,6 @@ function createFetchImports(getMemory) {
288
338
  }
289
339
 
290
340
  // 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
341
  var jsz = new ZigJS();
303
342
  var tempRefBuffer = new ArrayBuffer(8);
304
343
  var tempRefView = new DataView(tempRefBuffer);
@@ -309,6 +348,20 @@ function storeValueGetRef(val) {
309
348
  jsz.memory = originalMemory;
310
349
  return tempRefView.getBigUint64(0, true);
311
350
  }
351
+ function loadValueFromRef(ref) {
352
+ tempRefView.setBigUint64(0, ref, true);
353
+ const originalMemory = jsz.memory;
354
+ jsz.memory = { buffer: tempRefBuffer };
355
+ const val = jsz.loadRef(0);
356
+ jsz.memory = originalMemory;
357
+ return val;
358
+ }
359
+ function releaseValueRef(ref) {
360
+ tempRefView.setBigUint64(0, ref, true);
361
+ if (!Number.isNaN(tempRefView.getFloat64(0, true))) return;
362
+ const id = tempRefView.getUint32(0, true);
363
+ if (id > 6) jsz.deleteValue(id);
364
+ }
312
365
  var textDecoder = new TextDecoder();
313
366
  var textEncoder = new TextEncoder();
314
367
  var memoryView = null;
@@ -321,20 +374,19 @@ function getMemoryView() {
321
374
  }
322
375
  return memoryView;
323
376
  }
324
- var stringCache = /* @__PURE__ */ new Map();
325
- function stringCacheKey(ptr, len) {
326
- return ptr * 65536 + len;
327
- }
328
377
  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;
378
+ const start = ptr >>> 0;
379
+ const length = len >>> 0;
380
+ if (length === 0) return "";
381
+ const view = getMemoryView();
382
+ if (start + length > view.byteLength) return "";
383
+ return textDecoder.decode(view.subarray(start, start + length));
335
384
  }
336
385
  function writeBytes(ptr, data) {
337
- getMemoryView().set(data, ptr);
386
+ const start = ptr >>> 0;
387
+ const view = getMemoryView();
388
+ if (start + data.length > view.byteLength) return;
389
+ view.set(data, start);
338
390
  }
339
391
  function wrapPromisingExport(fn) {
340
392
  if (!fn) return void 0;
@@ -354,30 +406,26 @@ function invokeWasmExport(fn, ...args) {
354
406
  var ZxBridgeCore = class _ZxBridgeCore {
355
407
  #intervals = /* @__PURE__ */ new Map();
356
408
  #handler;
357
- #fetchCompleteHandler;
358
409
  constructor(exports) {
359
410
  this._alloc = exports.__zx_alloc;
360
411
  this.#handler = wrapPromisingExport(exports.__zx_cb);
361
- const fetchCompleteHandler = wrapPromisingExport(exports.__zx_fetch_complete);
362
- if (!fetchCompleteHandler) {
363
- throw new Error("__zx_fetch_complete not exported from WASM");
412
+ if (!this.#handler) {
413
+ console.warn("__zx_cb not exported from WASM");
364
414
  }
365
- this.#fetchCompleteHandler = fetchCompleteHandler;
366
415
  if (exports.memory) jsz.memory = exports.memory;
367
416
  }
368
417
  /** Invoke the unified callback handler */
369
- #invoke(type, id, data) {
418
+ _invoke(type, id, a = 0n, b = 0n, c = 0n) {
370
419
  const handler = this.#handler;
371
420
  if (!handler) {
372
421
  console.warn("__zx_cb not exported from WASM");
373
422
  return;
374
423
  }
375
- const dataRef = storeValueGetRef(data);
376
- invokeWasmExport(handler, type, id, dataRef);
424
+ invokeWasmExport(handler, type, id, a, b, c);
377
425
  }
378
426
  /**
379
427
  * Async fetch with full options support.
380
- * Calls __zx_fetch_complete when done.
428
+ * Completes via `__zx_cb(fetch_success|fetch_error, ...)`.
381
429
  */
382
430
  fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
383
431
  const url = readString(urlPtr, urlLen);
@@ -416,22 +464,23 @@ var ZxBridgeCore = class _ZxBridgeCore {
416
464
  }
417
465
  /** Notify WASM that a fetch completed. `body` is raw bytes on success, text on error. */
418
466
  _notifyFetchComplete(fetchId, statusCode, body, isError) {
419
- const handler = this.#fetchCompleteHandler;
420
467
  const encoded = typeof body === "string" ? textEncoder.encode(body) : body;
421
- const ptr = this._alloc(encoded.length);
468
+ const ptr = this._alloc(encoded.length) >>> 0;
469
+ if (!ptr && encoded.length > 0) return;
422
470
  writeBytes(ptr, encoded);
423
- invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
471
+ const type = isError ? CallbackType_FetchError : CallbackType_FetchSuccess;
472
+ this._invoke(type, fetchId, BigInt(statusCode), BigInt(ptr), BigInt(encoded.length));
424
473
  }
425
474
  /** Set a timeout and callback when it fires */
426
475
  setTimeout(callbackId, delayMs) {
427
476
  setTimeout(() => {
428
- this.#invoke(CallbackType.Timeout, callbackId, null);
477
+ this._invoke(CallbackType_Timeout, callbackId);
429
478
  }, delayMs);
430
479
  }
431
480
  /** Set an interval and callback each time it fires */
432
481
  setInterval(callbackId, intervalMs) {
433
482
  const handle = setInterval(() => {
434
- this.#invoke(CallbackType.Interval, callbackId, null);
483
+ this._invoke(CallbackType_Interval, callbackId);
435
484
  }, intervalMs);
436
485
  this.#intervals.set(callbackId, handle);
437
486
  }
@@ -449,18 +498,24 @@ var ZxBridgeCore = class _ZxBridgeCore {
449
498
  }
450
499
  this.#intervals.clear();
451
500
  }
452
- /** Write a string to WASM memory, returning pointer and length */
501
+ /** Write a string to WASM memory, returning `[ptr, len]`. */
453
502
  _writeStringToWasm(str) {
454
- return this._writeBytesToWasm(textEncoder.encode(str));
503
+ return this.writeBytesToWasm(textEncoder.encode(str));
455
504
  }
456
- _writeBytesToWasm(data) {
457
- const ptr = this._alloc(data.length);
505
+ writeBytesToWasm(data) {
506
+ if (data.length === 0) return [0, 0];
507
+ const ptr = this._alloc(data.length) >>> 0;
508
+ if (!ptr) return [0, 0];
458
509
  writeBytes(ptr, data);
459
- return { ptr, len: data.length };
510
+ return [ptr, data.length];
460
511
  }
461
512
  /** Log a message from WASM at the given level (0=error, 1=warn, 2=info, 3=debug) */
462
513
  static log(level, ptr, len) {
463
- const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
514
+ const start = ptr >>> 0;
515
+ const length = len >>> 0;
516
+ const view = getMemoryView();
517
+ if (start + length > view.byteLength) return;
518
+ const msg = textDecoder.decode(view.subarray(start, start + length));
464
519
  switch (level) {
465
520
  case 0:
466
521
  console.error(msg);
@@ -492,7 +547,7 @@ var ZxBridgeCore = class _ZxBridgeCore {
492
547
  __zx: {
493
548
  _log: (level, ptr, len) => _ZxBridgeCore.log(level, ptr, len),
494
549
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
495
- bridgeRef.current?.fetchAsync(
550
+ bridgeRef[0]?.fetchAsync(
496
551
  urlPtr,
497
552
  urlLen,
498
553
  methodPtr,
@@ -506,542 +561,41 @@ var ZxBridgeCore = class _ZxBridgeCore {
506
561
  );
507
562
  },
508
563
  _setTimeout: (callbackId, delayMs) => {
509
- bridgeRef.current?.setTimeout(callbackId, delayMs);
564
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
510
565
  },
511
566
  _setInterval: (callbackId, intervalMs) => {
512
- bridgeRef.current?.setInterval(callbackId, intervalMs);
567
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
513
568
  },
514
569
  _clearInterval: (callbackId) => {
515
- bridgeRef.current?.clearInterval(callbackId);
570
+ bridgeRef[0]?.clearInterval(callbackId);
516
571
  }
517
572
  }
518
573
  };
519
574
  }
520
575
  };
521
-
522
- // src/kv.ts
523
- function putOptions(ttlSeconds) {
524
- if (ttlSeconds < 60) return void 0;
525
- return { expirationTtl: ttlSeconds };
526
- }
527
- function isSyncKVNamespace(binding) {
528
- const candidate = binding;
529
- return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
530
- }
531
- function createKVImports(bindings, getMemory) {
532
- const encoder2 = new TextEncoder();
533
- const decoder2 = new TextDecoder();
534
- function readStr(ptr, len) {
535
- return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
536
- }
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
- function binding(ns) {
543
- return bindings[ns] ?? bindings["default"] ?? null;
544
- }
545
- const Suspending = WebAssembly.Suspending;
546
- if (typeof Suspending !== "function") {
547
- let syncBinding2 = function(ns) {
548
- const candidate = binding(ns);
549
- return candidate && isSyncKVNamespace(candidate) ? candidate : null;
550
- };
551
- var syncBinding = syncBinding2;
552
- return {
553
- kv_get: (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
554
- const b = syncBinding2(readStr(ns_ptr, ns_len));
555
- if (!b) return -1;
556
- const value = b.getSync(readStr(key_ptr, key_len));
557
- if (value === null) return -1;
558
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
559
- },
560
- kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
561
- const b = syncBinding2(readStr(ns_ptr, ns_len));
562
- if (!b) return 0;
563
- b.putSync(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
564
- return 0;
565
- },
566
- kv_delete: (ns_ptr, ns_len, key_ptr, key_len) => {
567
- const b = syncBinding2(readStr(ns_ptr, ns_len));
568
- if (!b) return 0;
569
- b.deleteSync(readStr(key_ptr, key_len));
570
- return 0;
571
- },
572
- kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, buf_ptr, buf_max) => {
573
- const b = syncBinding2(readStr(ns_ptr, ns_len));
574
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
575
- const prefix = readStr(pfx_ptr, pfx_len);
576
- 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))));
578
- }
579
- };
580
- }
581
- return {
582
- kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
583
- const b = binding(readStr(ns_ptr, ns_len));
584
- if (!b) return -1;
585
- const value = await b.get(readStr(key_ptr, key_len));
586
- if (value === null) return -1;
587
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
588
- }),
589
- kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
590
- const b = binding(readStr(ns_ptr, ns_len));
591
- if (!b) return -1;
592
- await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
593
- return 0;
594
- }),
595
- kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
596
- const b = binding(readStr(ns_ptr, ns_len));
597
- if (!b) return -1;
598
- await b.delete(readStr(key_ptr, key_len));
599
- return 0;
600
- }),
601
- kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
602
- const b = binding(readStr(ns_ptr, ns_len));
603
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
604
- const prefix = readStr(prefix_ptr, prefix_len);
605
- 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))));
607
- })
608
- };
609
- }
610
-
611
- // src/browser/kv.ts
612
- function getIndexedDb() {
613
- if (typeof indexedDB === "undefined") {
614
- throw new Error("IndexedDB is not available in this environment");
615
- }
616
- return indexedDB;
617
- }
618
- function requestToPromise(request) {
619
- return new Promise((resolve, reject) => {
620
- request.onsuccess = () => resolve(request.result);
621
- request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
622
- });
623
- }
624
- function transactionToPromise(transaction) {
625
- return new Promise((resolve, reject) => {
626
- transaction.oncomplete = () => resolve();
627
- transaction.onabort = () => reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
628
- transaction.onerror = () => reject(transaction.error ?? new Error("IndexedDB transaction failed"));
629
- });
630
- }
631
- function createIndexedDbKV(options = {}) {
632
- const databaseName = options.databaseName ?? "ziex-kv";
633
- const storeName = options.storeName ?? "kv";
634
- const namespace = options.namespace ?? "default";
635
- const dbPromise = new Promise((resolve, reject) => {
636
- const request = getIndexedDb().open(databaseName, 1);
637
- request.onupgradeneeded = () => {
638
- const db = request.result;
639
- if (!db.objectStoreNames.contains(storeName)) {
640
- db.createObjectStore(storeName);
641
- }
642
- };
643
- request.onsuccess = () => resolve(request.result);
644
- request.onerror = () => reject(request.error ?? new Error("Failed to open IndexedDB"));
645
- });
646
- const scopedKey = (key) => `${namespace}:${key}`;
647
- return {
648
- async get(key) {
649
- const db = await dbPromise;
650
- const tx = db.transaction(storeName, "readonly");
651
- const store = tx.objectStore(storeName);
652
- const value = await requestToPromise(store.get(scopedKey(key)));
653
- await transactionToPromise(tx);
654
- console.debug(`KV GET - Key: ${key}, Value: ${value}`);
655
- return typeof value === "string" ? value : null;
656
- },
657
- async put(key, value) {
658
- const db = await dbPromise;
659
- const tx = db.transaction(storeName, "readwrite");
660
- tx.objectStore(storeName).put(value, scopedKey(key));
661
- await transactionToPromise(tx);
662
- console.debug(`KV PUT - Key: ${key}, Value: ${value}`);
663
- },
664
- async delete(key) {
665
- const db = await dbPromise;
666
- const tx = db.transaction(storeName, "readwrite");
667
- tx.objectStore(storeName).delete(scopedKey(key));
668
- await transactionToPromise(tx);
669
- },
670
- async list(options2) {
671
- const db = await dbPromise;
672
- const tx = db.transaction(storeName, "readonly");
673
- const store = tx.objectStore(storeName);
674
- const keys = await requestToPromise(store.getAllKeys());
675
- await transactionToPromise(tx);
676
- const prefix = scopedKey(options2?.prefix ?? "");
677
- return {
678
- keys: keys.filter((key) => typeof key === "string" && key.startsWith(prefix)).map((key) => ({ name: key.slice(namespace.length + 1) }))
679
- };
680
- }
681
- };
682
- }
683
- function getLocalStorage() {
684
- if (typeof localStorage === "undefined") {
685
- throw new Error("localStorage is not available in this environment");
576
+ function writeBytesOut(getMemory, allocRef, outPtrAddr, data) {
577
+ if (data.length === 0) {
578
+ new DataView(getMemory().buffer).setUint32(outPtrAddr, 0, true);
579
+ return 0;
686
580
  }
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
- };
581
+ const alloc = allocRef[0];
582
+ if (!alloc) return -1;
583
+ const ptr = alloc(data.length) >>> 0;
584
+ if (!ptr) return -1;
585
+ const buffer = getMemory().buffer;
586
+ if (ptr + data.length > buffer.byteLength) return -1;
587
+ new Uint8Array(buffer, ptr, data.length).set(data);
588
+ new DataView(buffer).setUint32(outPtrAddr >>> 0, ptr, true);
589
+ return data.length;
728
590
  }
729
- function hasJSPI() {
730
- return typeof WebAssembly.Suspending === "function" && typeof WebAssembly.promising === "function";
591
+ function writeJsonOut(getMemory, allocRef, outPtrAddr, value) {
592
+ return writeBytesOut(getMemory, allocRef, outPtrAddr, textEncoder.encode(JSON.stringify(value)));
731
593
  }
732
- function createBrowserKVBindings(options = {}) {
733
- const namespace = options.namespace ?? "default";
734
- return {
735
- [namespace]: hasJSPI() ? createIndexedDbKV(options) : createLocalStorageKV(options)
736
- };
594
+ function bindWasmAlloc(allocRef, exports) {
595
+ allocRef[0] = exports.__zx_alloc;
737
596
  }
738
597
 
739
- // src/wasm/index.ts
740
- var ZxBridge = class extends ZxBridgeCore {
741
- #websockets = /* @__PURE__ */ new Map();
742
- #wsOnOpenHandler;
743
- #wsOnMessageHandler;
744
- #wsOnErrorHandler;
745
- #wsOnCloseHandler;
746
- #eventbridge;
747
- #eventbridgeAsync;
748
- constructor(exports) {
749
- super(exports);
750
- this.#wsOnOpenHandler = wrapPromisingExport(exports.__zx_ws_onopen);
751
- this.#wsOnMessageHandler = wrapPromisingExport(exports.__zx_ws_onmessage);
752
- this.#wsOnErrorHandler = wrapPromisingExport(exports.__zx_ws_onerror);
753
- this.#wsOnCloseHandler = wrapPromisingExport(exports.__zx_ws_onclose);
754
- this.#eventbridge = exports.__zx_eventbridge;
755
- this.#eventbridgeAsync = wrapPromisingExport(
756
- exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
757
- );
758
- }
759
- eventMaySuspend(velementId, eventTypeId) {
760
- return !!((eventHandlerModes.get(velementId) ?? 0) & 1 << eventTypeId);
761
- }
762
- setEventHandlerMode(velementId, eventTypeId, maySuspend) {
763
- 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);
768
- }
769
- clearEventHandlerModes(velementId) {
770
- eventHandlerModes.delete(velementId);
771
- }
772
- /** Submit a form action with bound-state round-trip. */
773
- submitFormActionAsync(form, actionId, statesJson, fetchId) {
774
- const formData = new FormData(form);
775
- formData.append("__$states", statesJson);
776
- fetch(window.location.href, {
777
- method: "POST",
778
- // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
779
- headers: { "x-action": String(actionId >>> 0) },
780
- body: formData
781
- }).then(async (response) => {
782
- const text = await response.text();
783
- this._notifyFetchComplete(fetchId, response.status, text, false);
784
- }).catch((error) => {
785
- const msg = error instanceof Error ? error.message : "Fetch failed";
786
- this._notifyFetchComplete(fetchId, 0, msg, true);
787
- });
788
- }
789
- /**
790
- * Create and connect a WebSocket.
791
- * Calls __zx_ws_onopen, __zx_ws_onmessage, __zx_ws_onerror, __zx_ws_onclose.
792
- */
793
- wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
794
- const url = readString(urlPtr, urlLen);
795
- const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
796
- const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
797
- try {
798
- const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
799
- ws.binaryType = "arraybuffer";
800
- ws.onopen = () => {
801
- const handler = this.#wsOnOpenHandler;
802
- if (!handler) return;
803
- const protocol = ws.protocol || "";
804
- const { ptr, len } = this._writeStringToWasm(protocol);
805
- invokeWasmExport(handler, wsId, ptr, len);
806
- };
807
- ws.onmessage = (event) => {
808
- const handler = this.#wsOnMessageHandler;
809
- if (!handler) return;
810
- const isBinary = event.data instanceof ArrayBuffer;
811
- const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
812
- const { ptr, len } = this._writeBytesToWasm(data);
813
- invokeWasmExport(handler, wsId, ptr, len, isBinary ? 1 : 0);
814
- };
815
- ws.onerror = (_event) => {
816
- const handler = this.#wsOnErrorHandler;
817
- if (!handler) return;
818
- const { ptr, len } = this._writeStringToWasm("WebSocket error");
819
- invokeWasmExport(handler, wsId, ptr, len);
820
- };
821
- ws.onclose = (event) => {
822
- const handler = this.#wsOnCloseHandler;
823
- if (!handler) return;
824
- const reason = event.reason || "";
825
- const { ptr, len } = this._writeStringToWasm(reason);
826
- invokeWasmExport(handler, wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
827
- this.#websockets.delete(wsId);
828
- };
829
- this.#websockets.set(wsId, ws);
830
- } catch (error) {
831
- const handler = this.#wsOnErrorHandler;
832
- if (handler) {
833
- const msg = error instanceof Error ? error.message : "WebSocket connection failed";
834
- const { ptr, len } = this._writeStringToWasm(msg);
835
- invokeWasmExport(handler, wsId, ptr, len);
836
- }
837
- }
838
- }
839
- /** Send data over WebSocket */
840
- wsSend(wsId, dataPtr, dataLen, isBinary) {
841
- const ws = this.#websockets.get(wsId);
842
- if (!ws || ws.readyState !== WebSocket.OPEN) return;
843
- const memory = getMemoryView();
844
- if (isBinary) {
845
- ws.send(memory.slice(dataPtr, dataPtr + dataLen));
846
- } else {
847
- ws.send(textDecoder.decode(memory.subarray(dataPtr, dataPtr + dataLen)));
848
- }
849
- }
850
- /** Close WebSocket connection */
851
- wsClose(wsId, code, reasonPtr, reasonLen) {
852
- const ws = this.#websockets.get(wsId);
853
- if (!ws) return;
854
- const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : void 0;
855
- try {
856
- if (reason) ws.close(code, reason);
857
- else ws.close(code);
858
- } catch {
859
- ws.close();
860
- }
861
- }
862
- dispose() {
863
- super.dispose();
864
- eventHandlerModes.clear();
865
- for (const ws of this.#websockets.values()) {
866
- try {
867
- ws.close();
868
- } catch {
869
- }
870
- }
871
- this.#websockets.clear();
872
- }
873
- /** Handle a DOM event (called by event delegation) */
874
- eventbridge(velementId, eventTypeId, event) {
875
- const eventRef = storeValueGetRef(event);
876
- if (this.eventMaySuspend(velementId, eventTypeId)) {
877
- invokeWasmExport(this.#eventbridgeAsync, velementId, eventTypeId, eventRef);
878
- return;
879
- }
880
- invokeWasmExport(this.#eventbridge, velementId, eventTypeId, eventRef);
881
- }
882
- /** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
883
- static createImportObject(bridgeRef) {
884
- return {
885
- ...jsz.importObject(),
886
- __zx_net: createFetchImports(() => {
887
- if (!jsz.memory) throw new Error("WASM memory is not ready");
888
- return jsz.memory;
889
- }),
890
- __zx: {
891
- _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
892
- _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
893
- bridgeRef.current?.setEventHandlerMode(vnodeId, eventTypeId, maySuspend !== 0);
894
- },
895
- _clearEventHandlerModes: (vnodeId) => {
896
- bridgeRef.current?.clearEventHandlerModes(vnodeId);
897
- },
898
- _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
899
- bridgeRef.current?.fetchAsync(
900
- urlPtr,
901
- urlLen,
902
- methodPtr,
903
- methodLen,
904
- headersPtr,
905
- headersLen,
906
- bodyPtr,
907
- bodyLen,
908
- timeoutMs,
909
- fetchId
910
- );
911
- },
912
- _setTimeout: (callbackId, delayMs) => {
913
- bridgeRef.current?.setTimeout(callbackId, delayMs);
914
- },
915
- _setInterval: (callbackId, intervalMs) => {
916
- bridgeRef.current?.setInterval(callbackId, intervalMs);
917
- },
918
- _clearInterval: (callbackId) => {
919
- bridgeRef.current?.clearInterval(callbackId);
920
- },
921
- // WebSocket API
922
- _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
923
- bridgeRef.current?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
924
- },
925
- _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
926
- bridgeRef.current?.wsSend(wsId, dataPtr, dataLen, isBinary);
927
- },
928
- _wsClose: (wsId, code, reasonPtr, reasonLen) => {
929
- bridgeRef.current?.wsClose(wsId, code, reasonPtr, reasonLen);
930
- },
931
- _ce: (id, vnodeId) => {
932
- const tagName = TAG_NAMES[id];
933
- 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);
937
- },
938
- _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);
944
- },
945
- _sa: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
946
- domNodes.get(vnodeId)?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
947
- },
948
- _sp: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
949
- const el = domNodes.get(vnodeId);
950
- if (el) {
951
- const name = readString(namePtr, nameLen);
952
- const val = readString(valPtr, valLen);
953
- if (name === "checked" || name === "selected" || name === "muted") {
954
- el[name] = val !== "false";
955
- } else {
956
- el[name] = val;
957
- }
958
- }
959
- },
960
- _ra: (vnodeId, namePtr, nameLen) => {
961
- domNodes.get(vnodeId)?.removeAttribute(readString(namePtr, nameLen));
962
- },
963
- _snv: (vnodeId, ptr, len) => {
964
- const node = domNodes.get(vnodeId);
965
- if (node) node.nodeValue = readString(ptr, len);
966
- },
967
- _srh: (vnodeId, ptr, len) => {
968
- const el = domNodes.get(vnodeId);
969
- if (el) el.innerHTML = readString(ptr, len);
970
- },
971
- _ac: (parentId, childId) => {
972
- const parent = domNodes.get(parentId);
973
- const child = domNodes.get(childId);
974
- if (parent && child) parent.appendChild(child);
975
- },
976
- _ib: (parentId, childId, refId) => {
977
- const parent = domNodes.get(parentId);
978
- const child = domNodes.get(childId);
979
- const ref = domNodes.get(refId) ?? null;
980
- if (parent && child) parent.insertBefore(child, ref);
981
- },
982
- _rc: (parentId, childId) => {
983
- const parent = domNodes.get(parentId);
984
- const child = domNodes.get(childId);
985
- if (parent && child) {
986
- parent.removeChild(child);
987
- cleanupDomNodes(child);
988
- }
989
- },
990
- _rpc: (parentId, newId, oldId) => {
991
- const parent = domNodes.get(parentId);
992
- const newChild = domNodes.get(newId);
993
- const oldChild = domNodes.get(oldId);
994
- if (parent && newChild && oldChild) {
995
- parent.replaceChild(newChild, oldChild);
996
- cleanupDomNodes(oldChild);
997
- }
998
- },
999
- _getLocationHref: (bufPtr, bufLen) => {
1000
- const bytes = textEncoder.encode(window.location.href);
1001
- const len = Math.min(bytes.length, bufLen);
1002
- writeBytes(bufPtr, bytes.subarray(0, len));
1003
- return len;
1004
- },
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));
1013
- return len;
1014
- },
1015
- _submitFormAction: (vnodeId, actionId) => {
1016
- const form = domNodes.get(vnodeId);
1017
- if (!form || !(form instanceof HTMLFormElement)) return;
1018
- const formData = new FormData(form);
1019
- fetch(window.location.href, {
1020
- method: "POST",
1021
- // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
1022
- headers: { "x-action": String(actionId >>> 0) },
1023
- body: formData
1024
- }).catch(() => {
1025
- });
1026
- },
1027
- _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
1028
- const form = domNodes.get(vnodeId);
1029
- if (!form || !(form instanceof HTMLFormElement)) return;
1030
- const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
1031
- bridgeRef.current?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1032
- }
1033
- }
1034
- };
1035
- }
1036
- };
1037
- var domNodes = /* @__PURE__ */ new Map();
1038
- 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]);
1043
- }
1044
- var SVG_TAG_START_INDEX = 140;
598
+ // src/wasm/generated/tags.ts
1045
599
  var TAG_NAMES = [
1046
600
  "aside",
1047
601
  "fragment",
@@ -1183,7 +737,6 @@ var TAG_NAMES = [
1183
737
  "strike",
1184
738
  "tt",
1185
739
  "xmp",
1186
- // SVG Tags
1187
740
  "animate",
1188
741
  "animateMotion",
1189
742
  "animateTransform",
@@ -1242,112 +795,780 @@ var TAG_NAMES = [
1242
795
  "textPath",
1243
796
  "tspan",
1244
797
  "use",
1245
- "view"
1246
- ];
1247
- 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 }
798
+ "view",
799
+ "custom"
1268
800
  ];
1269
- var eventHandlerModes = /* @__PURE__ */ new Map();
1270
- function initEventDelegation(bridge, rootSelector = "body") {
1271
- const root = document.querySelector(rootSelector);
1272
- if (!root) return () => {
1273
- };
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;
801
+
802
+ // src/wasm/generated/tag_indices.ts
803
+ var SVG_TAG_START_INDEX = 140;
804
+ var CUSTOM_TAG_INDEX = 199;
805
+
806
+ // src/wasm/dom_cmd.ts
807
+ function flushDomCmds(ptr, len, ctx) {
808
+ const start = ptr >>> 0;
809
+ const length = len >>> 0;
810
+ if (length < DOM_CMD_HEADER_SIZE) return;
811
+ const mem = getMemoryView();
812
+ if (start + length > mem.byteLength) return;
813
+ const view = new DataView(mem.buffer, mem.byteOffset + start, length);
814
+ const count = view.getUint32(0, true);
815
+ const recordsBytes = count * DOM_CMD_RECORD_SIZE;
816
+ if (DOM_CMD_HEADER_SIZE + recordsBytes > length) return;
817
+ const { domNodes: domNodes2, cleanupDomNodes: cleanupDomNodes2 } = ctx;
818
+ for (let i = 0; i < count; i++) {
819
+ const off = DOM_CMD_HEADER_SIZE + i * DOM_CMD_RECORD_SIZE;
820
+ const op = view.getUint8(off);
821
+ const p0 = view.getUint32(off + 4, true);
822
+ const p1 = view.getUint32(off + 8, true);
823
+ const p2 = view.getUint32(off + 12, true);
824
+ const p3 = view.getUint32(off + 16, true);
825
+ const p4 = view.getUint32(off + 20, true);
826
+ switch (op) {
827
+ case DomOp_CreateElement: {
828
+ const isCustom = p0 === CUSTOM_TAG_INDEX;
829
+ const tagName = isCustom ? readString(p2, p3) : TAG_NAMES[p0];
830
+ const el = !isCustom && p0 >= SVG_TAG_START_INDEX ? document.createElementNS("http://www.w3.org/2000/svg", tagName) : document.createElement(tagName);
831
+ el.__zx_ref = p1;
832
+ domNodes2.set(p1, el);
833
+ break;
834
+ }
835
+ case DomOp_CreateText: {
836
+ const node = document.createTextNode(readString(p0, p1));
837
+ node.__zx_ref = p2;
838
+ domNodes2.set(p2, node);
839
+ break;
840
+ }
841
+ case DomOp_HydrateInsert: {
842
+ const child = domNodes2.get(p0);
843
+ const ref = BigInt(p1) | BigInt(p2) << 32n;
844
+ const end = loadValueFromRef(ref);
845
+ if (!child || !end?.parentNode) break;
846
+ end.parentNode.insertBefore(child, end);
847
+ break;
848
+ }
849
+ case DomOp_SetAttr: {
850
+ domNodes2.get(p0)?.setAttribute(readString(p1, p2), readString(p3, p4));
851
+ break;
852
+ }
853
+ case DomOp_SetProp: {
854
+ const el = domNodes2.get(p0);
855
+ if (el) {
856
+ const name = readString(p1, p2);
857
+ const val = readString(p3, p4);
858
+ if (name === "checked" || name === "selected" || name === "muted") {
859
+ el[name] = val !== "false";
860
+ } else {
861
+ el[name] = val;
862
+ }
1283
863
  }
1284
- target = target.parentElement;
864
+ break;
1285
865
  }
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));
866
+ case DomOp_RemoveAttr: {
867
+ domNodes2.get(p0)?.removeAttribute(readString(p1, p2));
868
+ break;
869
+ }
870
+ case DomOp_SetNodeValue: {
871
+ const node = domNodes2.get(p0);
872
+ if (node) node.nodeValue = readString(p1, p2);
873
+ break;
874
+ }
875
+ case DomOp_SetInnerHtml: {
876
+ const el = domNodes2.get(p0);
877
+ if (el) el.innerHTML = readString(p1, p2);
878
+ break;
879
+ }
880
+ case DomOp_AppendChild: {
881
+ const parent = domNodes2.get(p0);
882
+ const child = domNodes2.get(p1);
883
+ if (parent && child) parent.appendChild(child);
884
+ break;
885
+ }
886
+ case DomOp_InsertBefore: {
887
+ const parent = domNodes2.get(p0);
888
+ const child = domNodes2.get(p1);
889
+ const refNode = domNodes2.get(p2) ?? null;
890
+ if (parent && child) parent.insertBefore(child, refNode);
891
+ break;
892
+ }
893
+ case DomOp_RemoveChild: {
894
+ const parent = domNodes2.get(p0);
895
+ const child = domNodes2.get(p1);
896
+ if (parent && child) {
897
+ parent.removeChild(child);
898
+ cleanupDomNodes2(child);
899
+ }
900
+ break;
901
+ }
902
+ case DomOp_ReplaceChild: {
903
+ const parent = domNodes2.get(p0);
904
+ const newChild = domNodes2.get(p1);
905
+ const oldChild = domNodes2.get(p2);
906
+ if (parent && newChild && oldChild) {
907
+ parent.replaceChild(newChild, oldChild);
908
+ cleanupDomNodes2(oldChild);
909
+ }
910
+ break;
911
+ }
912
+ default:
913
+ break;
914
+ }
1290
915
  }
1291
- return () => {
1292
- for (const remove of removers) remove();
1293
- };
1294
- }
1295
- var DEFAULT_URL = "/assets/_/main.wasm";
1296
- var activeRuntime = null;
1297
- function buildDevtoolsLocation() {
1298
- return {
1299
- href: window.location.href,
1300
- origin: window.location.origin,
1301
- host: window.location.host,
1302
- pathname: window.location.pathname
1303
- };
1304
916
  }
1305
- function normalizeOptions(options = {}) {
1306
- return {
1307
- url: options.url,
1308
- eventDelegationRoot: options.eventDelegationRoot,
1309
- importObject: options.importObject,
1310
- kv: options.kv
1311
- };
917
+
918
+ // src/runtime/kv/extern.ts
919
+ function putOptions(ttlSeconds) {
920
+ if (ttlSeconds < 60) return void 0;
921
+ return { expirationTtl: ttlSeconds };
1312
922
  }
1313
- function registerDevReinit(options) {
1314
- if (typeof window === "undefined") return;
1315
- const reinit = () => init(options);
1316
- window.__zx_dev_reinit = reinit;
1317
- window.__ZIEX_DEVTOOLS_GLOBAL_HOOK__ = {
1318
- location: buildDevtoolsLocation(),
1319
- reinit
1320
- };
923
+ function isSyncKVNamespace(binding) {
924
+ const candidate = binding;
925
+ return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
1321
926
  }
1322
- async function init(options = {}) {
1323
- const normalizedOptions = normalizeOptions(options);
1324
- if (activeRuntime) {
1325
- activeRuntime.dispose();
1326
- activeRuntime = null;
927
+ function createKVImports(bindings, getMemory, allocRef) {
928
+ const encoder2 = new TextEncoder();
929
+ const decoder2 = new TextDecoder();
930
+ function readStr(ptr, len) {
931
+ return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
932
+ }
933
+ function binding(ns) {
934
+ return bindings[ns] ?? bindings["default"] ?? null;
935
+ }
936
+ const Suspending = WebAssembly.Suspending;
937
+ if (typeof Suspending !== "function") {
938
+ let syncBinding2 = function(ns) {
939
+ const candidate = binding(ns);
940
+ return candidate && isSyncKVNamespace(candidate) ? candidate : null;
941
+ };
942
+ var syncBinding = syncBinding2;
943
+ return {
944
+ kv_get: (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
945
+ const b = syncBinding2(readStr(ns_ptr, ns_len));
946
+ if (!b) return -1;
947
+ const value = b.getSync(readStr(key_ptr, key_len));
948
+ if (value === null) return -1;
949
+ return writeBytesOut(getMemory, allocRef, out_ptr, encoder2.encode(value));
950
+ },
951
+ kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
952
+ const b = syncBinding2(readStr(ns_ptr, ns_len));
953
+ if (!b) return 0;
954
+ b.putSync(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
955
+ return 0;
956
+ },
957
+ kv_delete: (ns_ptr, ns_len, key_ptr, key_len) => {
958
+ const b = syncBinding2(readStr(ns_ptr, ns_len));
959
+ if (!b) return 0;
960
+ b.deleteSync(readStr(key_ptr, key_len));
961
+ return 0;
962
+ },
963
+ kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, out_ptr) => {
964
+ const b = syncBinding2(readStr(ns_ptr, ns_len));
965
+ if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
966
+ const prefix = readStr(pfx_ptr, pfx_len);
967
+ const result = b.listSync(prefix.length > 0 ? { prefix } : void 0);
968
+ return writeJsonOut(getMemory, allocRef, out_ptr, result.keys.map((k) => k.name));
969
+ }
970
+ };
971
+ }
972
+ return {
973
+ kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
974
+ const b = binding(readStr(ns_ptr, ns_len));
975
+ if (!b) return -1;
976
+ const value = await b.get(readStr(key_ptr, key_len));
977
+ if (value === null) return -1;
978
+ return writeBytesOut(getMemory, allocRef, out_ptr, encoder2.encode(value));
979
+ }),
980
+ kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
981
+ const b = binding(readStr(ns_ptr, ns_len));
982
+ if (!b) return -1;
983
+ await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
984
+ return 0;
985
+ }),
986
+ kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
987
+ const b = binding(readStr(ns_ptr, ns_len));
988
+ if (!b) return -1;
989
+ await b.delete(readStr(key_ptr, key_len));
990
+ return 0;
991
+ }),
992
+ kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, out_ptr) => {
993
+ const b = binding(readStr(ns_ptr, ns_len));
994
+ if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
995
+ const prefix = readStr(prefix_ptr, prefix_len);
996
+ const result = await b.list(prefix.length > 0 ? { prefix } : void 0);
997
+ const names = result.keys.map((k) => k.name);
998
+ if (names.length === 0) {
999
+ new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
1000
+ return 0;
1001
+ }
1002
+ return writeJsonOut(getMemory, allocRef, out_ptr, names);
1003
+ })
1004
+ };
1005
+ }
1006
+
1007
+ // src/runtime/kv/localstorage.ts
1008
+ function getLocalStorage() {
1009
+ if (typeof localStorage === "undefined") {
1010
+ throw new Error("localStorage is not available in this environment");
1011
+ }
1012
+ return localStorage;
1013
+ }
1014
+ function createLocalStorageKV(options = {}) {
1015
+ const storage = getLocalStorage();
1016
+ const namespace = options.namespace ?? "default";
1017
+ const storagePrefix = options.storagePrefix ?? "ziex-kv";
1018
+ const scopedKey = (key) => `${storagePrefix}:${namespace}:${key}`;
1019
+ const namespacePrefix = scopedKey("");
1020
+ return {
1021
+ getSync(key) {
1022
+ return storage.getItem(scopedKey(key));
1023
+ },
1024
+ async get(key) {
1025
+ return this.getSync(key);
1026
+ },
1027
+ putSync(key, value) {
1028
+ storage.setItem(scopedKey(key), value);
1029
+ },
1030
+ async put(key, value) {
1031
+ this.putSync(key, value);
1032
+ },
1033
+ deleteSync(key) {
1034
+ storage.removeItem(scopedKey(key));
1035
+ },
1036
+ async delete(key) {
1037
+ this.deleteSync(key);
1038
+ },
1039
+ listSync(options2) {
1040
+ const prefix = namespacePrefix + (options2?.prefix ?? "");
1041
+ const keys = [];
1042
+ for (let i = 0; i < storage.length; i += 1) {
1043
+ const key = storage.key(i);
1044
+ if (!key || !key.startsWith(prefix)) continue;
1045
+ keys.push({ name: key.slice(namespacePrefix.length) });
1046
+ }
1047
+ return { keys };
1048
+ },
1049
+ async list(options2) {
1050
+ return this.listSync(options2);
1051
+ }
1052
+ };
1053
+ }
1054
+
1055
+ // src/runtime/kv/indexdb.ts
1056
+ function getIndexedDb() {
1057
+ if (typeof indexedDB === "undefined") {
1058
+ throw new Error("IndexedDB is not available in this environment");
1059
+ }
1060
+ return indexedDB;
1061
+ }
1062
+ function requestToPromise(request) {
1063
+ return new Promise((resolve, reject) => {
1064
+ request.onsuccess = () => resolve(request.result);
1065
+ request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
1066
+ });
1067
+ }
1068
+ function transactionToPromise(transaction) {
1069
+ return new Promise((resolve, reject) => {
1070
+ transaction.oncomplete = () => resolve();
1071
+ transaction.onabort = () => reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
1072
+ transaction.onerror = () => reject(transaction.error ?? new Error("IndexedDB transaction failed"));
1073
+ });
1074
+ }
1075
+ function createIndexedDbKV(options = {}) {
1076
+ const databaseName = options.databaseName ?? "ziex-kv";
1077
+ const storeName = options.storeName ?? "kv";
1078
+ const namespace = options.namespace ?? "default";
1079
+ const dbPromise = new Promise((resolve, reject) => {
1080
+ const request = getIndexedDb().open(databaseName, 1);
1081
+ request.onupgradeneeded = () => {
1082
+ const db = request.result;
1083
+ if (!db.objectStoreNames.contains(storeName)) {
1084
+ db.createObjectStore(storeName);
1085
+ }
1086
+ };
1087
+ request.onsuccess = () => resolve(request.result);
1088
+ request.onerror = () => reject(request.error ?? new Error("Failed to open IndexedDB"));
1089
+ });
1090
+ const scopedKey = (key) => `${namespace}:${key}`;
1091
+ return {
1092
+ async get(key) {
1093
+ const db = await dbPromise;
1094
+ const tx = db.transaction(storeName, "readonly");
1095
+ const store = tx.objectStore(storeName);
1096
+ const value = await requestToPromise(store.get(scopedKey(key)));
1097
+ await transactionToPromise(tx);
1098
+ return typeof value === "string" ? value : null;
1099
+ },
1100
+ async put(key, value) {
1101
+ const db = await dbPromise;
1102
+ const tx = db.transaction(storeName, "readwrite");
1103
+ tx.objectStore(storeName).put(value, scopedKey(key));
1104
+ await transactionToPromise(tx);
1105
+ },
1106
+ async delete(key) {
1107
+ const db = await dbPromise;
1108
+ const tx = db.transaction(storeName, "readwrite");
1109
+ tx.objectStore(storeName).delete(scopedKey(key));
1110
+ await transactionToPromise(tx);
1111
+ },
1112
+ async list(options2) {
1113
+ const db = await dbPromise;
1114
+ const tx = db.transaction(storeName, "readonly");
1115
+ const store = tx.objectStore(storeName);
1116
+ const keys = await requestToPromise(store.getAllKeys());
1117
+ await transactionToPromise(tx);
1118
+ const prefix = scopedKey(options2?.prefix ?? "");
1119
+ return {
1120
+ keys: keys.filter((key) => typeof key === "string" && key.startsWith(prefix)).map((key) => ({ name: key.slice(namespace.length + 1) }))
1121
+ };
1122
+ }
1123
+ };
1124
+ }
1125
+
1126
+ // src/runtime/kv.ts
1127
+ function hasJSPI() {
1128
+ return typeof WebAssembly.Suspending === "function" && typeof WebAssembly.promising === "function";
1129
+ }
1130
+ function createBrowserKVBindings(options = {}) {
1131
+ const namespace = options.namespace ?? "default";
1132
+ const isIndexedDb = hasJSPI() && !options.forceLocalStorage;
1133
+ return {
1134
+ [namespace]: isIndexedDb ? createIndexedDbKV(options) : createLocalStorageKV(options)
1135
+ };
1136
+ }
1137
+
1138
+ // src/wasm/generated/events.ts
1139
+ var DELEGATED_EVENTS = [
1140
+ "click",
1141
+ "dblclick",
1142
+ "input",
1143
+ "change",
1144
+ "submit",
1145
+ "focusin",
1146
+ "focusout",
1147
+ "keydown",
1148
+ "keyup",
1149
+ "keypress",
1150
+ "mouseenter",
1151
+ "mouseleave",
1152
+ "mousedown",
1153
+ "mouseup",
1154
+ "mousemove",
1155
+ "touchstart",
1156
+ "touchend",
1157
+ "touchmove",
1158
+ "scroll",
1159
+ "wheel",
1160
+ "pointerdown",
1161
+ "pointermove",
1162
+ "pointerup",
1163
+ "pointercancel",
1164
+ "pointerenter",
1165
+ "pointerleave",
1166
+ "lostpointercapture"
1167
+ ];
1168
+
1169
+ // src/wasm/generated/event_bits.ts
1170
+ var HIGH_FREQ_EVENT_BITS = 3031040;
1171
+
1172
+ // src/wasm/index.ts
1173
+ var ZxBridge = class extends ZxBridgeCore {
1174
+ #websockets = /* @__PURE__ */ new Map();
1175
+ #eventbridge;
1176
+ #eventbridgeAsync;
1177
+ constructor(exports) {
1178
+ super(exports);
1179
+ this.#eventbridge = exports.__zx_eventbridge;
1180
+ this.#eventbridgeAsync = wrapPromisingExport(
1181
+ exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
1182
+ );
1183
+ }
1184
+ hasEventHandler(velementId, eventTypeId) {
1185
+ return !!((eventHandlersPresent.get(velementId) ?? 0) & 1 << eventTypeId);
1186
+ }
1187
+ eventMaySuspend(velementId, eventTypeId) {
1188
+ return !!((eventHandlersSuspend.get(velementId) ?? 0) & 1 << eventTypeId);
1189
+ }
1190
+ setEventHandlerMode(velementId, eventTypeId, maySuspend) {
1191
+ const bit = 1 << eventTypeId;
1192
+ const present = (eventHandlersPresent.get(velementId) ?? 0) | bit;
1193
+ eventHandlersPresent.set(velementId, present);
1194
+ const suspendBits = eventHandlersSuspend.get(velementId) ?? 0;
1195
+ const nextSuspend = maySuspend ? suspendBits | bit : suspendBits & ~bit;
1196
+ if (nextSuspend === 0) eventHandlersSuspend.delete(velementId);
1197
+ else eventHandlersSuspend.set(velementId, nextSuspend);
1198
+ ensureDelegatedListener(eventTypeId);
1199
+ }
1200
+ clearEventHandlerModes(velementId) {
1201
+ const present = eventHandlersPresent.get(velementId) ?? 0;
1202
+ eventHandlersPresent.delete(velementId);
1203
+ eventHandlersSuspend.delete(velementId);
1204
+ for (let bits = present & HIGH_FREQ_EVENT_BITS; bits !== 0; bits &= bits - 1) {
1205
+ maybeRemoveHighFreqListener(31 - Math.clz32(bits));
1206
+ }
1207
+ }
1208
+ /** Submit a form action with bound-state round-trip. */
1209
+ submitFormActionAsync(form, actionId, statesJson, fetchId) {
1210
+ const formData = new FormData(form);
1211
+ formData.append("__$states", statesJson);
1212
+ fetch(window.location.href, {
1213
+ method: "POST",
1214
+ // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
1215
+ headers: { "x-action": String(actionId >>> 0) },
1216
+ body: formData
1217
+ }).then(async (response) => {
1218
+ const text = await response.text();
1219
+ this._notifyFetchComplete(fetchId, response.status, text, false);
1220
+ }).catch((error) => {
1221
+ const msg = error instanceof Error ? error.message : "Fetch failed";
1222
+ this._notifyFetchComplete(fetchId, 0, msg, true);
1223
+ });
1224
+ }
1225
+ /**
1226
+ * Create and connect a WebSocket.
1227
+ * Completes via `__zx_cb(ws_open|ws_message|ws_error|ws_close, ...)`.
1228
+ */
1229
+ wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
1230
+ const url = readString(urlPtr, urlLen);
1231
+ const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
1232
+ const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
1233
+ try {
1234
+ const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
1235
+ ws.binaryType = "arraybuffer";
1236
+ ws.onopen = () => {
1237
+ const protocol = ws.protocol || "";
1238
+ const [ptr, len] = this._writeStringToWasm(protocol);
1239
+ this._invoke(CallbackType_WebSocketOpen, wsId, BigInt(ptr), BigInt(len));
1240
+ };
1241
+ ws.onmessage = (event) => {
1242
+ const isBinary = event.data instanceof ArrayBuffer;
1243
+ const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
1244
+ const [ptr, len] = this.writeBytesToWasm(data);
1245
+ this._invoke(CallbackType_WebSocketMessage, wsId, BigInt(ptr), BigInt(len), BigInt(isBinary ? 1 : 0));
1246
+ };
1247
+ ws.onerror = (_event) => {
1248
+ const [ptr, len] = this._writeStringToWasm("WebSocket error");
1249
+ this._invoke(CallbackType_WebSocketError, wsId, BigInt(ptr), BigInt(len));
1250
+ };
1251
+ ws.onclose = (event) => {
1252
+ const reason = event.reason || "";
1253
+ const [ptr, len] = this._writeStringToWasm(reason);
1254
+ const c = BigInt(len) | BigInt(event.wasClean ? 1 : 0) << 32n;
1255
+ this._invoke(CallbackType_WebSocketClose, wsId, BigInt(event.code), BigInt(ptr), c);
1256
+ this.#websockets.delete(wsId);
1257
+ };
1258
+ this.#websockets.set(wsId, ws);
1259
+ } catch (error) {
1260
+ const msg = error instanceof Error ? error.message : "WebSocket connection failed";
1261
+ const [ptr, len] = this._writeStringToWasm(msg);
1262
+ this._invoke(CallbackType_WebSocketError, wsId, BigInt(ptr), BigInt(len));
1263
+ }
1264
+ }
1265
+ /** Send data over WebSocket */
1266
+ wsSend(wsId, dataPtr, dataLen, isBinary) {
1267
+ const ws = this.#websockets.get(wsId);
1268
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
1269
+ const memory = getMemoryView();
1270
+ const start = dataPtr >>> 0;
1271
+ const length = dataLen >>> 0;
1272
+ if (start + length > memory.byteLength) return;
1273
+ if (isBinary) {
1274
+ ws.send(memory.slice(start, start + length));
1275
+ } else {
1276
+ ws.send(textDecoder.decode(memory.subarray(start, start + length)));
1277
+ }
1278
+ }
1279
+ /** Close WebSocket connection */
1280
+ wsClose(wsId, code, reasonPtr, reasonLen) {
1281
+ const ws = this.#websockets.get(wsId);
1282
+ if (!ws) return;
1283
+ const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : void 0;
1284
+ try {
1285
+ if (reason) ws.close(code, reason);
1286
+ else ws.close(code);
1287
+ } catch {
1288
+ ws.close();
1289
+ }
1290
+ }
1291
+ dispose() {
1292
+ super.dispose();
1293
+ eventHandlersPresent.clear();
1294
+ eventHandlersSuspend.clear();
1295
+ for (const ws of this.#websockets.values()) {
1296
+ try {
1297
+ ws.close();
1298
+ } catch {
1299
+ }
1300
+ }
1301
+ this.#websockets.clear();
1302
+ }
1303
+ /**
1304
+ * Dispatch to WASM for one vnode. Caller owns `eventRef` lifetime
1305
+ * (store once per bubble, release after sync/async work completes).
1306
+ */
1307
+ eventbridge(velementId, eventTypeId, eventRef) {
1308
+ const id = BigInt(velementId >>> 0);
1309
+ if (this.eventMaySuspend(velementId, eventTypeId)) {
1310
+ return invokeWasmExport(this.#eventbridgeAsync, id, eventTypeId, eventRef);
1311
+ }
1312
+ invokeWasmExport(this.#eventbridge, id, eventTypeId, eventRef);
1313
+ }
1314
+ /** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
1315
+ static createImportObject(bridgeRef) {
1316
+ return {
1317
+ ...jsz.importObject(),
1318
+ __zx_net: createFetchImports(() => {
1319
+ if (!jsz.memory) throw new Error("WASM memory is not ready");
1320
+ return jsz.memory;
1321
+ }),
1322
+ __zx: {
1323
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
1324
+ _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
1325
+ bridgeRef[0]?.setEventHandlerMode(Number(vnodeId), eventTypeId, maySuspend !== 0);
1326
+ },
1327
+ _clearEventHandlerModes: (vnodeId) => {
1328
+ bridgeRef[0]?.clearEventHandlerModes(Number(vnodeId));
1329
+ },
1330
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
1331
+ bridgeRef[0]?.fetchAsync(
1332
+ urlPtr,
1333
+ urlLen,
1334
+ methodPtr,
1335
+ methodLen,
1336
+ headersPtr,
1337
+ headersLen,
1338
+ bodyPtr,
1339
+ bodyLen,
1340
+ timeoutMs,
1341
+ fetchId
1342
+ );
1343
+ },
1344
+ _setTimeout: (callbackId, delayMs) => {
1345
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
1346
+ },
1347
+ _setInterval: (callbackId, intervalMs) => {
1348
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
1349
+ },
1350
+ _clearInterval: (callbackId) => {
1351
+ bridgeRef[0]?.clearInterval(callbackId);
1352
+ },
1353
+ // WebSocket API
1354
+ _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
1355
+ bridgeRef[0]?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
1356
+ },
1357
+ _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
1358
+ bridgeRef[0]?.wsSend(wsId, dataPtr, dataLen, isBinary);
1359
+ },
1360
+ _wsClose: (wsId, code, reasonPtr, reasonLen) => {
1361
+ bridgeRef[0]?.wsClose(wsId, code, reasonPtr, reasonLen);
1362
+ },
1363
+ _flush: (ptr, len) => {
1364
+ flushDomCmds(ptr, len, {
1365
+ domNodes,
1366
+ cleanupDomNodes
1367
+ });
1368
+ },
1369
+ _getLocationHref: (bufPtr, bufLen) => {
1370
+ const bytes = textEncoder.encode(window.location.href);
1371
+ const len = Math.min(bytes.length, bufLen);
1372
+ writeBytes(bufPtr, bytes.subarray(0, len));
1373
+ return len;
1374
+ },
1375
+ _getFormData: (eventRef, outPtrAddr) => {
1376
+ const event = loadValueFromRef(eventRef);
1377
+ const el = event?.target;
1378
+ const form = el instanceof HTMLFormElement ? el : el?.closest?.("form") ?? null;
1379
+ if (!form) return 0;
1380
+ const entries = [];
1381
+ for (const [k, v] of new FormData(form).entries()) {
1382
+ entries.push(k, String(v));
1383
+ }
1384
+ const bytes = textEncoder.encode(JSON.stringify(entries));
1385
+ const [ptr, len] = bridgeRef[0].writeBytesToWasm(bytes);
1386
+ new DataView(jsz.memory.buffer).setUint32(outPtrAddr, ptr, true);
1387
+ return len;
1388
+ },
1389
+ _submitFormAction: (vnodeId, actionId) => {
1390
+ const form = domNodes.get(Number(vnodeId));
1391
+ if (!form || !(form instanceof HTMLFormElement)) return;
1392
+ const formData = new FormData(form);
1393
+ fetch(window.location.href, {
1394
+ method: "POST",
1395
+ // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
1396
+ headers: { "x-action": String(actionId >>> 0) },
1397
+ body: formData
1398
+ }).catch(() => {
1399
+ });
1400
+ },
1401
+ _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
1402
+ const form = domNodes.get(Number(vnodeId));
1403
+ if (!form || !(form instanceof HTMLFormElement)) return;
1404
+ const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
1405
+ bridgeRef[0]?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1406
+ }
1407
+ }
1408
+ };
1409
+ }
1410
+ };
1411
+ var domNodes = /* @__PURE__ */ new Map();
1412
+ var eventHandlersPresent = /* @__PURE__ */ new Map();
1413
+ var eventHandlersSuspend = /* @__PURE__ */ new Map();
1414
+ function cleanupDomNodes(node) {
1415
+ const stack = [node];
1416
+ let highFreqBits = 0;
1417
+ while (stack.length > 0) {
1418
+ const n = stack.pop();
1419
+ const ref = n.__zx_ref;
1420
+ if (typeof ref === "number") {
1421
+ const present = eventHandlersPresent.get(ref);
1422
+ if (present !== void 0) {
1423
+ highFreqBits |= present;
1424
+ eventHandlersPresent.delete(ref);
1425
+ eventHandlersSuspend.delete(ref);
1426
+ }
1427
+ domNodes.delete(ref);
1428
+ }
1429
+ const children = n.childNodes;
1430
+ for (let i = 0; i < children.length; i++) stack.push(children[i]);
1431
+ }
1432
+ for (let bits = highFreqBits & HIGH_FREQ_EVENT_BITS; bits !== 0; bits &= bits - 1) {
1433
+ maybeRemoveHighFreqListener(31 - Math.clz32(bits));
1434
+ }
1435
+ }
1436
+ var delegationState = null;
1437
+ function makeDelegatedListener(bridge, eventTypeId) {
1438
+ return (event) => {
1439
+ let eventRef;
1440
+ const pending = [];
1441
+ let target = event.target;
1442
+ while (target && target !== document.body) {
1443
+ const zxRef = target.__zx_ref;
1444
+ if (typeof zxRef === "number" && bridge.hasEventHandler(zxRef, eventTypeId)) {
1445
+ if (eventRef === void 0) eventRef = storeValueGetRef(event);
1446
+ const result = bridge.eventbridge(zxRef, eventTypeId, eventRef);
1447
+ if (result && typeof result.then === "function") {
1448
+ pending.push(result);
1449
+ }
1450
+ if (event.cancelBubble) break;
1451
+ }
1452
+ target = target.parentElement;
1453
+ }
1454
+ if (eventRef !== void 0) {
1455
+ const ref = eventRef;
1456
+ if (pending.length > 0) {
1457
+ Promise.all(pending).finally(() => releaseValueRef(ref));
1458
+ } else {
1459
+ releaseValueRef(ref);
1460
+ }
1461
+ }
1462
+ };
1463
+ }
1464
+ function ensureDelegatedListener(eventTypeId) {
1465
+ const state = delegationState;
1466
+ if (!state || state.attached.has(eventTypeId)) return;
1467
+ const domType = DELEGATED_EVENTS[eventTypeId];
1468
+ if (!domType) return;
1469
+ const passive = domType.startsWith("touch") || domType === "scroll";
1470
+ const options = { passive };
1471
+ const listener = makeDelegatedListener(state.bridge, eventTypeId);
1472
+ state.root.addEventListener(domType, listener, options);
1473
+ state.attached.set(eventTypeId, { listener, options });
1474
+ }
1475
+ function anyHandlerForType(eventTypeId) {
1476
+ const bit = 1 << eventTypeId;
1477
+ for (const mask of eventHandlersPresent.values()) {
1478
+ if (mask & bit) return true;
1479
+ }
1480
+ return false;
1481
+ }
1482
+ function maybeRemoveHighFreqListener(eventTypeId) {
1483
+ if ((HIGH_FREQ_EVENT_BITS & 1 << eventTypeId) === 0) return;
1484
+ if (anyHandlerForType(eventTypeId)) return;
1485
+ const state = delegationState;
1486
+ if (!state) return;
1487
+ const entry = state.attached.get(eventTypeId);
1488
+ if (!entry) return;
1489
+ const domType = DELEGATED_EVENTS[eventTypeId];
1490
+ state.root.removeEventListener(domType, entry.listener, entry.options);
1491
+ state.attached.delete(eventTypeId);
1492
+ }
1493
+ function initEventDelegation(bridge, rootSelector = "body") {
1494
+ const root = document.querySelector(rootSelector);
1495
+ if (!root) return () => {
1496
+ };
1497
+ delegationState = { root, bridge, attached: /* @__PURE__ */ new Map() };
1498
+ for (let eventTypeId = 0; eventTypeId < DELEGATED_EVENTS.length; eventTypeId++) {
1499
+ if ((HIGH_FREQ_EVENT_BITS & 1 << eventTypeId) !== 0) continue;
1500
+ ensureDelegatedListener(eventTypeId);
1501
+ }
1502
+ return () => {
1503
+ if (!delegationState) return;
1504
+ for (const [eventTypeId, entry] of delegationState.attached) {
1505
+ const domType = DELEGATED_EVENTS[eventTypeId];
1506
+ delegationState.root.removeEventListener(domType, entry.listener, entry.options);
1507
+ }
1508
+ delegationState.attached.clear();
1509
+ delegationState = null;
1510
+ };
1511
+ }
1512
+ var activeRuntime = null;
1513
+ function buildDevtoolsLocation() {
1514
+ return {
1515
+ href: window.location.href,
1516
+ origin: window.location.origin,
1517
+ host: window.location.host,
1518
+ pathname: window.location.pathname
1519
+ };
1520
+ }
1521
+ function normalizeOptions(options = {}) {
1522
+ return {
1523
+ url: options.url,
1524
+ eventDelegationRoot: options.eventDelegationRoot,
1525
+ importObject: options.importObject,
1526
+ kv: options.kv
1527
+ };
1528
+ }
1529
+ function registerDevReinit(options) {
1530
+ if (typeof window === "undefined") return;
1531
+ const reinit = () => init(options);
1532
+ window.__zx_dev_reinit = reinit;
1533
+ window.__ZIEX_DEVTOOLS_GLOBAL_HOOK__ = {
1534
+ location: buildDevtoolsLocation(),
1535
+ reinit
1536
+ };
1537
+ }
1538
+ async function init(options = {}) {
1539
+ const normalizedOptions = normalizeOptions(options);
1540
+ if (activeRuntime) {
1541
+ activeRuntime.dispose();
1542
+ activeRuntime = null;
1543
+ }
1544
+ const url = options.url ?? document.getElementById("__$wasmlink")?.href;
1545
+ if (!url) throw new Error("WASM URL is not set");
1546
+ const bridgeRef = [null];
1547
+ let wasmMemory = null;
1548
+ const allocRef = [null];
1549
+ const getMemory = () => {
1550
+ if (wasmMemory) return wasmMemory;
1551
+ if (jsz.memory) return jsz.memory;
1552
+ throw new Error("WASM memory is not ready");
1553
+ };
1554
+ const importObject = {
1555
+ ...ZxBridge.createImportObject(bridgeRef),
1556
+ ...options.importObject
1557
+ };
1558
+ if (true) {
1559
+ importObject.__zx_kv = createKVImports(
1560
+ options.kv ?? createBrowserKVBindings(),
1561
+ getMemory,
1562
+ allocRef
1563
+ );
1327
1564
  }
1328
- const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
1329
- const bridgeRef = { current: null };
1330
- 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
- })
1338
- };
1339
- const importObject = Object.assign(
1340
- {},
1341
- ZxBridge.createImportObject(bridgeRef),
1342
- kvImportObject,
1343
- options.importObject
1344
- );
1345
1565
  const source = await WebAssembly.instantiateStreaming(fetch(url), importObject);
1346
1566
  const { instance } = source;
1347
1567
  wasmMemory = instance.exports.memory;
1348
1568
  jsz.memory = wasmMemory;
1569
+ bindWasmAlloc(allocRef, instance.exports);
1349
1570
  const bridge = new ZxBridge(instance.exports);
1350
- bridgeRef.current = bridge;
1571
+ bridgeRef[0] = bridge;
1351
1572
  domNodes.clear();
1352
1573
  const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
1353
1574
  const main = wrapPromisingExport(instance.exports.mainClient);