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