ziex 0.0.1-dev.7 → 0.1.0-dev.1000

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.
package/wasm/index.js CHANGED
@@ -1,4 +1,19 @@
1
- // node_modules/jsz/js/src/zigjs.ts
1
+ var __defProp = Object.defineProperty;
2
+ var __returnValue = (v) => v;
3
+ function __exportSetter(name, newValue) {
4
+ this[name] = __returnValue.bind(null, newValue);
5
+ }
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true,
11
+ configurable: true,
12
+ set: __exportSetter.bind(all, name)
13
+ });
14
+ };
15
+
16
+ // ../../vendor/jsz/js/src/zigjs.ts
2
17
  var NAN_PREFIX = 2146959360;
3
18
  var predefined = {
4
19
  nan: 0,
@@ -167,53 +182,1090 @@ class ZigJS {
167
182
  return decoder.decode(data);
168
183
  }
169
184
  }
170
- // src/wasm/index.ts
171
- var DEFAULT_URL = "/assets/main.wasm";
172
- var MAX_EVENTS = 100;
173
- var jsz = new ZigJS;
174
- var importObject = {
175
- module: {},
176
- env: {},
177
- ...jsz.importObject()
185
+ // src/wasm/core.ts
186
+ var CallbackType = {
187
+ Event: 0,
188
+ FetchSuccess: 1,
189
+ FetchError: 2,
190
+ Timeout: 3,
191
+ Interval: 4,
192
+ WebSocketOpen: 5,
193
+ WebSocketMessage: 6,
194
+ WebSocketError: 7,
195
+ WebSocketClose: 8
178
196
  };
197
+ var jsz = new ZigJS;
198
+ var tempRefBuffer = new ArrayBuffer(8);
199
+ var tempRefView = new DataView(tempRefBuffer);
200
+ function storeValueGetRef(val) {
201
+ const originalMemory = jsz.memory;
202
+ jsz.memory = { buffer: tempRefBuffer };
203
+ jsz.storeValue(0, val);
204
+ jsz.memory = originalMemory;
205
+ return tempRefView.getBigUint64(0, true);
206
+ }
207
+ var textDecoder = new TextDecoder;
208
+ var textEncoder = new TextEncoder;
209
+ var memoryView = null;
210
+ var memoryBuffer = null;
211
+ function getMemoryView() {
212
+ const buf = jsz.memory.buffer;
213
+ if (buf !== memoryBuffer) {
214
+ memoryBuffer = buf;
215
+ memoryView = new Uint8Array(buf);
216
+ }
217
+ return memoryView;
218
+ }
219
+ var stringCache = new Map;
220
+ function stringCacheKey(ptr, len) {
221
+ return ptr * 65536 + len;
222
+ }
223
+ function readString(ptr, len) {
224
+ const key = stringCacheKey(ptr, len);
225
+ const cached = stringCache.get(key);
226
+ if (cached !== undefined)
227
+ return cached;
228
+ const str = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
229
+ stringCache.set(key, str);
230
+ return str;
231
+ }
232
+ function writeBytes(ptr, data) {
233
+ getMemoryView().set(data, ptr);
234
+ }
235
+ function wrapPromisingExport(fn) {
236
+ if (!fn)
237
+ return;
238
+ const promising = WebAssembly.promising;
239
+ if (typeof promising !== "function")
240
+ return fn;
241
+ return promising(fn);
242
+ }
243
+ function invokeWasmExport(fn, ...args) {
244
+ if (!fn)
245
+ return;
246
+ const result = fn(...args);
247
+ if (result && typeof result.then === "function") {
248
+ result.then(undefined, (error) => {
249
+ console.error(error);
250
+ });
251
+ }
252
+ }
253
+
254
+ class ZxBridgeCore {
255
+ #intervals = new Map;
256
+ _alloc;
257
+ #handler;
258
+ #fetchCompleteHandler;
259
+ constructor(exports) {
260
+ this._alloc = exports.__zx_alloc;
261
+ this.#handler = wrapPromisingExport(exports.__zx_cb);
262
+ const fetchCompleteHandler = wrapPromisingExport(exports.__zx_fetch_complete);
263
+ if (!fetchCompleteHandler) {
264
+ throw new Error("__zx_fetch_complete not exported from WASM");
265
+ }
266
+ this.#fetchCompleteHandler = fetchCompleteHandler;
267
+ if (exports.memory)
268
+ jsz.memory = exports.memory;
269
+ }
270
+ #invoke(type, id, data) {
271
+ const handler = this.#handler;
272
+ if (!handler) {
273
+ console.warn("__zx_cb not exported from WASM");
274
+ return;
275
+ }
276
+ const dataRef = storeValueGetRef(data);
277
+ invokeWasmExport(handler, type, id, dataRef);
278
+ }
279
+ fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
280
+ const url = readString(urlPtr, urlLen);
281
+ const method = methodLen > 0 ? readString(methodPtr, methodLen) : "GET";
282
+ const headersJson = headersLen > 0 ? readString(headersPtr, headersLen) : "{}";
283
+ const body = bodyLen > 0 ? readString(bodyPtr, bodyLen) : undefined;
284
+ let headers = {};
285
+ try {
286
+ headers = JSON.parse(headersJson);
287
+ } catch {
288
+ for (const line of headersJson.split(`
289
+ `)) {
290
+ const colonIdx = line.indexOf(":");
291
+ if (colonIdx > 0) {
292
+ headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
293
+ }
294
+ }
295
+ }
296
+ const controller = new AbortController;
297
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
298
+ const fetchOptions = {
299
+ method,
300
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
301
+ body: method !== "GET" && method !== "HEAD" ? body : undefined,
302
+ signal: controller.signal
303
+ };
304
+ fetch(url, fetchOptions).then(async (response) => {
305
+ if (timeout)
306
+ clearTimeout(timeout);
307
+ const text = await response.text();
308
+ this._notifyFetchComplete(fetchId, response.status, text, false);
309
+ }).catch((error) => {
310
+ if (timeout)
311
+ clearTimeout(timeout);
312
+ const isAbort = error.name === "AbortError";
313
+ const errorMsg = isAbort ? "Request timeout" : error.message ?? "Fetch failed";
314
+ this._notifyFetchComplete(fetchId, 0, errorMsg, true);
315
+ });
316
+ }
317
+ _notifyFetchComplete(fetchId, statusCode, body, isError) {
318
+ const handler = this.#fetchCompleteHandler;
319
+ const encoded = textEncoder.encode(body);
320
+ const ptr = this._alloc(encoded.length);
321
+ writeBytes(ptr, encoded);
322
+ invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
323
+ }
324
+ setTimeout(callbackId, delayMs) {
325
+ setTimeout(() => {
326
+ this.#invoke(CallbackType.Timeout, callbackId, null);
327
+ }, delayMs);
328
+ }
329
+ setInterval(callbackId, intervalMs) {
330
+ const handle = setInterval(() => {
331
+ this.#invoke(CallbackType.Interval, callbackId, null);
332
+ }, intervalMs);
333
+ this.#intervals.set(callbackId, handle);
334
+ }
335
+ clearInterval(callbackId) {
336
+ const handle = this.#intervals.get(callbackId);
337
+ if (handle !== undefined) {
338
+ clearInterval(handle);
339
+ this.#intervals.delete(callbackId);
340
+ }
341
+ }
342
+ dispose() {
343
+ for (const handle of this.#intervals.values()) {
344
+ clearInterval(handle);
345
+ }
346
+ this.#intervals.clear();
347
+ }
348
+ _writeStringToWasm(str) {
349
+ return this._writeBytesToWasm(textEncoder.encode(str));
350
+ }
351
+ _writeBytesToWasm(data) {
352
+ const ptr = this._alloc(data.length);
353
+ writeBytes(ptr, data);
354
+ return { ptr, len: data.length };
355
+ }
356
+ static log(level, ptr, len) {
357
+ const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
358
+ switch (level) {
359
+ case 0:
360
+ console.error(msg);
361
+ break;
362
+ case 1:
363
+ console.warn(msg);
364
+ break;
365
+ case 3:
366
+ console.debug(msg);
367
+ break;
368
+ default:
369
+ console.log(msg);
370
+ break;
371
+ }
372
+ }
373
+ static createImportObject(bridgeRef) {
374
+ return {
375
+ ...jsz.importObject(),
376
+ __zx: {
377
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
378
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
379
+ bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
380
+ },
381
+ _setTimeout: (callbackId, delayMs) => {
382
+ bridgeRef.current?.setTimeout(callbackId, delayMs);
383
+ },
384
+ _setInterval: (callbackId, intervalMs) => {
385
+ bridgeRef.current?.setInterval(callbackId, intervalMs);
386
+ },
387
+ _clearInterval: (callbackId) => {
388
+ bridgeRef.current?.clearInterval(callbackId);
389
+ }
390
+ }
391
+ };
392
+ }
393
+ }
394
+ // src/kv.ts
395
+ var exports_kv = {};
396
+ __export(exports_kv, {
397
+ createMemoryKV: () => createMemoryKV,
398
+ createKVImports: () => createKVImports
399
+ });
400
+ function createMemoryKV() {
401
+ const store = new Map;
402
+ return {
403
+ async get(key) {
404
+ return store.get(key) ?? null;
405
+ },
406
+ async put(key, value) {
407
+ store.set(key, value);
408
+ },
409
+ async delete(key) {
410
+ store.delete(key);
411
+ },
412
+ async list(options) {
413
+ const keys = [...store.keys()].filter((k) => !options?.prefix || k.startsWith(options.prefix)).map((name) => ({ name }));
414
+ return { keys };
415
+ }
416
+ };
417
+ }
418
+ function isSyncKVNamespace(binding) {
419
+ const candidate = binding;
420
+ return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
421
+ }
422
+ function createKVImports(bindings, getMemory) {
423
+ const encoder2 = new TextEncoder;
424
+ const decoder2 = new TextDecoder;
425
+ function readStr(ptr, len) {
426
+ return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
427
+ }
428
+ function writeBytes2(buf_ptr, buf_max, data) {
429
+ if (data.length > buf_max)
430
+ return -2;
431
+ new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
432
+ return data.length;
433
+ }
434
+ function binding(ns) {
435
+ return bindings[ns] ?? bindings["default"] ?? null;
436
+ }
437
+ const Suspending = WebAssembly.Suspending;
438
+ if (typeof Suspending !== "function") {
439
+ let syncBinding = function(ns) {
440
+ const candidate = binding(ns);
441
+ return candidate && isSyncKVNamespace(candidate) ? candidate : null;
442
+ };
443
+ return {
444
+ kv_get: (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
445
+ const b = syncBinding(readStr(ns_ptr, ns_len));
446
+ if (!b)
447
+ return -1;
448
+ const value = b.getSync(readStr(key_ptr, key_len));
449
+ if (value === null)
450
+ return -1;
451
+ return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
452
+ },
453
+ kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len) => {
454
+ const b = syncBinding(readStr(ns_ptr, ns_len));
455
+ if (!b)
456
+ return 0;
457
+ b.putSync(readStr(key_ptr, key_len), readStr(val_ptr, val_len));
458
+ return 0;
459
+ },
460
+ kv_delete: (ns_ptr, ns_len, key_ptr, key_len) => {
461
+ const b = syncBinding(readStr(ns_ptr, ns_len));
462
+ if (!b)
463
+ return 0;
464
+ b.deleteSync(readStr(key_ptr, key_len));
465
+ return 0;
466
+ },
467
+ kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, buf_ptr, buf_max) => {
468
+ const b = syncBinding(readStr(ns_ptr, ns_len));
469
+ if (!b)
470
+ return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
471
+ const prefix = readStr(pfx_ptr, pfx_len);
472
+ const result = b.listSync(prefix.length > 0 ? { prefix } : undefined);
473
+ return writeBytes2(buf_ptr, buf_max, encoder2.encode(JSON.stringify(result.keys.map((k) => k.name))));
474
+ }
475
+ };
476
+ }
477
+ return {
478
+ kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
479
+ const b = binding(readStr(ns_ptr, ns_len));
480
+ if (!b)
481
+ return -1;
482
+ const value = await b.get(readStr(key_ptr, key_len));
483
+ if (value === null)
484
+ return -1;
485
+ return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
486
+ }),
487
+ kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len) => {
488
+ const b = binding(readStr(ns_ptr, ns_len));
489
+ if (!b)
490
+ return -1;
491
+ await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len));
492
+ return 0;
493
+ }),
494
+ kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
495
+ const b = binding(readStr(ns_ptr, ns_len));
496
+ if (!b)
497
+ return -1;
498
+ await b.delete(readStr(key_ptr, key_len));
499
+ return 0;
500
+ }),
501
+ kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
502
+ const b = binding(readStr(ns_ptr, ns_len));
503
+ if (!b)
504
+ return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
505
+ const prefix = readStr(prefix_ptr, prefix_len);
506
+ const result = await b.list(prefix.length > 0 ? { prefix } : undefined);
507
+ return writeBytes2(buf_ptr, buf_max, encoder2.encode(JSON.stringify(result.keys.map((k) => k.name))));
508
+ })
509
+ };
510
+ }
511
+
512
+ // src/browser/kv.ts
513
+ function getIndexedDb() {
514
+ if (typeof indexedDB === "undefined") {
515
+ throw new Error("IndexedDB is not available in this environment");
516
+ }
517
+ return indexedDB;
518
+ }
519
+ function requestToPromise(request) {
520
+ return new Promise((resolve, reject) => {
521
+ request.onsuccess = () => resolve(request.result);
522
+ request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
523
+ });
524
+ }
525
+ function transactionToPromise(transaction) {
526
+ return new Promise((resolve, reject) => {
527
+ transaction.oncomplete = () => resolve();
528
+ transaction.onabort = () => reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
529
+ transaction.onerror = () => reject(transaction.error ?? new Error("IndexedDB transaction failed"));
530
+ });
531
+ }
532
+ function createIndexedDbKV(options = {}) {
533
+ const databaseName = options.databaseName ?? "ziex-kv";
534
+ const storeName = options.storeName ?? "kv";
535
+ const namespace = options.namespace ?? "default";
536
+ const dbPromise = new Promise((resolve, reject) => {
537
+ const request = getIndexedDb().open(databaseName, 1);
538
+ request.onupgradeneeded = () => {
539
+ const db = request.result;
540
+ if (!db.objectStoreNames.contains(storeName)) {
541
+ db.createObjectStore(storeName);
542
+ }
543
+ };
544
+ request.onsuccess = () => resolve(request.result);
545
+ request.onerror = () => reject(request.error ?? new Error("Failed to open IndexedDB"));
546
+ });
547
+ const scopedKey = (key) => `${namespace}:${key}`;
548
+ return {
549
+ async get(key) {
550
+ const db = await dbPromise;
551
+ const tx = db.transaction(storeName, "readonly");
552
+ const store = tx.objectStore(storeName);
553
+ const value = await requestToPromise(store.get(scopedKey(key)));
554
+ await transactionToPromise(tx);
555
+ console.debug(`KV GET - Key: ${key}, Value: ${value}`);
556
+ return typeof value === "string" ? value : null;
557
+ },
558
+ async put(key, value) {
559
+ const db = await dbPromise;
560
+ const tx = db.transaction(storeName, "readwrite");
561
+ tx.objectStore(storeName).put(value, scopedKey(key));
562
+ await transactionToPromise(tx);
563
+ console.debug(`KV PUT - Key: ${key}, Value: ${value}`);
564
+ },
565
+ async delete(key) {
566
+ const db = await dbPromise;
567
+ const tx = db.transaction(storeName, "readwrite");
568
+ tx.objectStore(storeName).delete(scopedKey(key));
569
+ await transactionToPromise(tx);
570
+ },
571
+ async list(options2) {
572
+ const db = await dbPromise;
573
+ const tx = db.transaction(storeName, "readonly");
574
+ const store = tx.objectStore(storeName);
575
+ const keys = await requestToPromise(store.getAllKeys());
576
+ await transactionToPromise(tx);
577
+ const prefix = scopedKey(options2?.prefix ?? "");
578
+ return {
579
+ keys: keys.filter((key) => typeof key === "string" && key.startsWith(prefix)).map((key) => ({ name: key.slice(namespace.length + 1) }))
580
+ };
581
+ }
582
+ };
583
+ }
584
+ function getLocalStorage() {
585
+ if (typeof localStorage === "undefined") {
586
+ throw new Error("localStorage is not available in this environment");
587
+ }
588
+ return localStorage;
589
+ }
590
+ function createLocalStorageKV(options = {}) {
591
+ const storage = getLocalStorage();
592
+ const namespace = options.namespace ?? "default";
593
+ const storagePrefix = options.storagePrefix ?? "ziex-kv";
594
+ const scopedKey = (key) => `${storagePrefix}:${namespace}:${key}`;
595
+ const namespacePrefix = scopedKey("");
596
+ return {
597
+ getSync(key) {
598
+ return storage.getItem(scopedKey(key));
599
+ },
600
+ async get(key) {
601
+ return this.getSync(key);
602
+ },
603
+ putSync(key, value) {
604
+ storage.setItem(scopedKey(key), value);
605
+ },
606
+ async put(key, value) {
607
+ this.putSync(key, value);
608
+ },
609
+ deleteSync(key) {
610
+ storage.removeItem(scopedKey(key));
611
+ },
612
+ async delete(key) {
613
+ this.deleteSync(key);
614
+ },
615
+ listSync(options2) {
616
+ const prefix = namespacePrefix + (options2?.prefix ?? "");
617
+ const keys = [];
618
+ for (let i = 0;i < storage.length; i += 1) {
619
+ const key = storage.key(i);
620
+ if (!key || !key.startsWith(prefix))
621
+ continue;
622
+ keys.push({ name: key.slice(namespacePrefix.length) });
623
+ }
624
+ return { keys };
625
+ },
626
+ async list(options2) {
627
+ return this.listSync(options2);
628
+ }
629
+ };
630
+ }
631
+ function hasJSPI() {
632
+ return typeof WebAssembly.Suspending === "function" && typeof WebAssembly.promising === "function";
633
+ }
634
+ function createBrowserKVBindings(options = {}) {
635
+ const namespace = options.namespace ?? "default";
636
+ return {
637
+ [namespace]: hasJSPI() ? createIndexedDbKV(options) : createLocalStorageKV(options)
638
+ };
639
+ }
179
640
 
180
- class ZXInstance {
181
- exports;
182
- events;
183
- actions;
184
- constructor({ exports, events = [] }) {
185
- this.exports = exports;
186
- this.events = events;
187
- this.actions = {};
188
- Object.entries(exports).forEach(([name, func]) => {
189
- if (typeof func !== "function")
190
- return;
191
- this.actions[name] = this.#actionWrapper.bind(this, name);
641
+ // src/wasm/index.ts
642
+ class ZxBridge extends ZxBridgeCore {
643
+ #websockets = new Map;
644
+ #wsOnOpenHandler;
645
+ #wsOnMessageHandler;
646
+ #wsOnErrorHandler;
647
+ #wsOnCloseHandler;
648
+ #eventbridge;
649
+ #eventbridgeAsync;
650
+ constructor(exports) {
651
+ super(exports);
652
+ this.#wsOnOpenHandler = wrapPromisingExport(exports.__zx_ws_onopen);
653
+ this.#wsOnMessageHandler = wrapPromisingExport(exports.__zx_ws_onmessage);
654
+ this.#wsOnErrorHandler = wrapPromisingExport(exports.__zx_ws_onerror);
655
+ this.#wsOnCloseHandler = wrapPromisingExport(exports.__zx_ws_onclose);
656
+ this.#eventbridge = exports.__zx_eventbridge;
657
+ this.#eventbridgeAsync = wrapPromisingExport(exports.__zx_eventbridge_async ?? exports.__zx_eventbridge);
658
+ }
659
+ eventMaySuspend(velementId, eventTypeId) {
660
+ return !!((eventHandlerModes.get(velementId) ?? 0) & 1 << eventTypeId);
661
+ }
662
+ setEventHandlerMode(velementId, eventTypeId, maySuspend) {
663
+ const bit = 1 << eventTypeId;
664
+ const current = eventHandlerModes.get(velementId) ?? 0;
665
+ const next = maySuspend ? current | bit : current & ~bit;
666
+ if (next === 0)
667
+ eventHandlerModes.delete(velementId);
668
+ else
669
+ eventHandlerModes.set(velementId, next);
670
+ }
671
+ clearEventHandlerModes(velementId) {
672
+ eventHandlerModes.delete(velementId);
673
+ }
674
+ submitFormActionAsync(form, statesJson, fetchId) {
675
+ const formData = new FormData(form);
676
+ formData.append("__$states", statesJson);
677
+ fetch(window.location.href, {
678
+ method: "POST",
679
+ headers: { "X-ZX-Action": "1" },
680
+ body: formData
681
+ }).then(async (response) => {
682
+ const text = await response.text();
683
+ this._notifyFetchComplete(fetchId, response.status, text, false);
684
+ }).catch((error) => {
685
+ const msg = error instanceof Error ? error.message : "Fetch failed";
686
+ this._notifyFetchComplete(fetchId, 0, msg, true);
192
687
  });
193
688
  }
194
- addEvent(event) {
195
- if (this.events.length >= MAX_EVENTS)
196
- this.events.length = 0;
197
- const idx = this.events.push(event);
198
- return idx - 1;
689
+ wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
690
+ const url = readString(urlPtr, urlLen);
691
+ const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
692
+ const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : undefined;
693
+ try {
694
+ const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
695
+ ws.binaryType = "arraybuffer";
696
+ ws.onopen = () => {
697
+ const handler = this.#wsOnOpenHandler;
698
+ if (!handler)
699
+ return;
700
+ const protocol = ws.protocol || "";
701
+ const { ptr, len } = this._writeStringToWasm(protocol);
702
+ invokeWasmExport(handler, wsId, ptr, len);
703
+ };
704
+ ws.onmessage = (event) => {
705
+ const handler = this.#wsOnMessageHandler;
706
+ if (!handler)
707
+ return;
708
+ const isBinary = event.data instanceof ArrayBuffer;
709
+ const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
710
+ const { ptr, len } = this._writeBytesToWasm(data);
711
+ invokeWasmExport(handler, wsId, ptr, len, isBinary ? 1 : 0);
712
+ };
713
+ ws.onerror = (_event) => {
714
+ const handler = this.#wsOnErrorHandler;
715
+ if (!handler)
716
+ return;
717
+ const { ptr, len } = this._writeStringToWasm("WebSocket error");
718
+ invokeWasmExport(handler, wsId, ptr, len);
719
+ };
720
+ ws.onclose = (event) => {
721
+ const handler = this.#wsOnCloseHandler;
722
+ if (!handler)
723
+ return;
724
+ const reason = event.reason || "";
725
+ const { ptr, len } = this._writeStringToWasm(reason);
726
+ invokeWasmExport(handler, wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
727
+ this.#websockets.delete(wsId);
728
+ };
729
+ this.#websockets.set(wsId, ws);
730
+ } catch (error) {
731
+ const handler = this.#wsOnErrorHandler;
732
+ if (handler) {
733
+ const msg = error instanceof Error ? error.message : "WebSocket connection failed";
734
+ const { ptr, len } = this._writeStringToWasm(msg);
735
+ invokeWasmExport(handler, wsId, ptr, len);
736
+ }
737
+ }
738
+ }
739
+ wsSend(wsId, dataPtr, dataLen, isBinary) {
740
+ const ws = this.#websockets.get(wsId);
741
+ if (!ws || ws.readyState !== WebSocket.OPEN)
742
+ return;
743
+ const memory = getMemoryView();
744
+ if (isBinary) {
745
+ ws.send(memory.slice(dataPtr, dataPtr + dataLen));
746
+ } else {
747
+ ws.send(textDecoder.decode(memory.subarray(dataPtr, dataPtr + dataLen)));
748
+ }
749
+ }
750
+ wsClose(wsId, code, reasonPtr, reasonLen) {
751
+ const ws = this.#websockets.get(wsId);
752
+ if (!ws)
753
+ return;
754
+ const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : undefined;
755
+ try {
756
+ if (reason)
757
+ ws.close(code, reason);
758
+ else
759
+ ws.close(code);
760
+ } catch {
761
+ ws.close();
762
+ }
199
763
  }
200
- #actionWrapper(name, ...args) {
201
- const func = this.exports[name];
202
- if (typeof func !== "function")
203
- throw new Error(`Action ${name} is not a function`);
204
- const eventId = this.addEvent(args[0]);
205
- return func(eventId);
764
+ dispose() {
765
+ super.dispose();
766
+ eventHandlerModes.clear();
767
+ for (const ws of this.#websockets.values()) {
768
+ try {
769
+ ws.close();
770
+ } catch {}
771
+ }
772
+ this.#websockets.clear();
773
+ }
774
+ eventbridge(velementId, eventTypeId, event) {
775
+ const eventRef = storeValueGetRef(event);
776
+ if (this.eventMaySuspend(velementId, eventTypeId)) {
777
+ invokeWasmExport(this.#eventbridgeAsync, velementId, eventTypeId, eventRef);
778
+ return;
779
+ }
780
+ invokeWasmExport(this.#eventbridge, velementId, eventTypeId, eventRef);
781
+ }
782
+ static createImportObject(bridgeRef) {
783
+ return {
784
+ ...jsz.importObject(),
785
+ __zx: {
786
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
787
+ _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
788
+ bridgeRef.current?.setEventHandlerMode(vnodeId, eventTypeId, maySuspend !== 0);
789
+ },
790
+ _clearEventHandlerModes: (vnodeId) => {
791
+ bridgeRef.current?.clearEventHandlerModes(vnodeId);
792
+ },
793
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
794
+ bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
795
+ },
796
+ _setTimeout: (callbackId, delayMs) => {
797
+ bridgeRef.current?.setTimeout(callbackId, delayMs);
798
+ },
799
+ _setInterval: (callbackId, intervalMs) => {
800
+ bridgeRef.current?.setInterval(callbackId, intervalMs);
801
+ },
802
+ _clearInterval: (callbackId) => {
803
+ bridgeRef.current?.clearInterval(callbackId);
804
+ },
805
+ _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
806
+ bridgeRef.current?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
807
+ },
808
+ _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
809
+ bridgeRef.current?.wsSend(wsId, dataPtr, dataLen, isBinary);
810
+ },
811
+ _wsClose: (wsId, code, reasonPtr, reasonLen) => {
812
+ bridgeRef.current?.wsClose(wsId, code, reasonPtr, reasonLen);
813
+ },
814
+ _ce: (id, vnodeId) => {
815
+ const tagName = TAG_NAMES[id];
816
+ const el = id >= SVG_TAG_START_INDEX ? document.createElementNS("http://www.w3.org/2000/svg", tagName) : document.createElement(tagName);
817
+ el.__zx_ref = Number(vnodeId);
818
+ domNodes.set(vnodeId, el);
819
+ return storeValueGetRef(el);
820
+ },
821
+ _ct: (ptr, len, vnodeId) => {
822
+ const text = readString(ptr, len);
823
+ const node = document.createTextNode(text);
824
+ node.__zx_ref = Number(vnodeId);
825
+ domNodes.set(vnodeId, node);
826
+ return storeValueGetRef(node);
827
+ },
828
+ _sa: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
829
+ domNodes.get(vnodeId)?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
830
+ },
831
+ _ra: (vnodeId, namePtr, nameLen) => {
832
+ domNodes.get(vnodeId)?.removeAttribute(readString(namePtr, nameLen));
833
+ },
834
+ _snv: (vnodeId, ptr, len) => {
835
+ const node = domNodes.get(vnodeId);
836
+ if (node)
837
+ node.nodeValue = readString(ptr, len);
838
+ },
839
+ _ac: (parentId, childId) => {
840
+ const parent = domNodes.get(parentId);
841
+ const child = domNodes.get(childId);
842
+ if (parent && child)
843
+ parent.appendChild(child);
844
+ },
845
+ _ib: (parentId, childId, refId) => {
846
+ const parent = domNodes.get(parentId);
847
+ const child = domNodes.get(childId);
848
+ const ref = domNodes.get(refId) ?? null;
849
+ if (parent && child)
850
+ parent.insertBefore(child, ref);
851
+ },
852
+ _rc: (parentId, childId) => {
853
+ const parent = domNodes.get(parentId);
854
+ const child = domNodes.get(childId);
855
+ if (parent && child) {
856
+ parent.removeChild(child);
857
+ cleanupDomNodes(child);
858
+ }
859
+ },
860
+ _rpc: (parentId, newId, oldId) => {
861
+ const parent = domNodes.get(parentId);
862
+ const newChild = domNodes.get(newId);
863
+ const oldChild = domNodes.get(oldId);
864
+ if (parent && newChild && oldChild) {
865
+ parent.replaceChild(newChild, oldChild);
866
+ cleanupDomNodes(oldChild);
867
+ }
868
+ },
869
+ _getLocationHref: (bufPtr, bufLen) => {
870
+ const bytes = textEncoder.encode(window.location.href);
871
+ const len = Math.min(bytes.length, bufLen);
872
+ writeBytes(bufPtr, bytes.subarray(0, len));
873
+ return len;
874
+ },
875
+ _getFormData: (vnodeId, bufPtr, bufLen) => {
876
+ const form = domNodes.get(vnodeId);
877
+ if (!form || !(form instanceof HTMLFormElement))
878
+ return 0;
879
+ const formData = new FormData(form);
880
+ const urlEncoded = new URLSearchParams(formData).toString();
881
+ const bytes = textEncoder.encode(urlEncoded);
882
+ const len = Math.min(bytes.length, bufLen);
883
+ writeBytes(bufPtr, bytes.subarray(0, len));
884
+ return len;
885
+ },
886
+ _submitFormAction: (vnodeId) => {
887
+ const form = domNodes.get(vnodeId);
888
+ if (!form || !(form instanceof HTMLFormElement))
889
+ return;
890
+ const formData = new FormData(form);
891
+ fetch(window.location.href, {
892
+ method: "POST",
893
+ headers: { "X-ZX-Action": "1" },
894
+ body: formData
895
+ }).catch(() => {});
896
+ },
897
+ _submitFormActionAsync: (vnodeId, statesPtr, statesLen, fetchId) => {
898
+ const form = domNodes.get(vnodeId);
899
+ if (!form || !(form instanceof HTMLFormElement))
900
+ return;
901
+ const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
902
+ bridgeRef.current?.submitFormActionAsync(form, statesJson, fetchId);
903
+ }
904
+ }
905
+ };
206
906
  }
207
907
  }
908
+ var domNodes = new Map;
909
+ function cleanupDomNodes(node) {
910
+ const ref = node.__zx_ref;
911
+ if (ref !== undefined)
912
+ domNodes.delete(BigInt(ref));
913
+ const children = node.childNodes;
914
+ for (let i = 0;i < children.length; i++)
915
+ cleanupDomNodes(children[i]);
916
+ }
917
+ var SVG_TAG_START_INDEX = 140;
918
+ var TAG_NAMES = [
919
+ "aside",
920
+ "fragment",
921
+ "iframe",
922
+ "slot",
923
+ "img",
924
+ "html",
925
+ "base",
926
+ "head",
927
+ "link",
928
+ "meta",
929
+ "script",
930
+ "style",
931
+ "title",
932
+ "address",
933
+ "article",
934
+ "body",
935
+ "h1",
936
+ "h6",
937
+ "footer",
938
+ "header",
939
+ "h2",
940
+ "h3",
941
+ "h4",
942
+ "h5",
943
+ "hgroup",
944
+ "nav",
945
+ "section",
946
+ "dd",
947
+ "dl",
948
+ "dt",
949
+ "div",
950
+ "figcaption",
951
+ "figure",
952
+ "hr",
953
+ "li",
954
+ "ol",
955
+ "ul",
956
+ "menu",
957
+ "main",
958
+ "p",
959
+ "picture",
960
+ "pre",
961
+ "a",
962
+ "abbr",
963
+ "b",
964
+ "bdi",
965
+ "bdo",
966
+ "br",
967
+ "cite",
968
+ "code",
969
+ "data",
970
+ "time",
971
+ "dfn",
972
+ "em",
973
+ "i",
974
+ "kbd",
975
+ "mark",
976
+ "q",
977
+ "blockquote",
978
+ "rp",
979
+ "ruby",
980
+ "rt",
981
+ "rtc",
982
+ "rb",
983
+ "s",
984
+ "del",
985
+ "ins",
986
+ "samp",
987
+ "small",
988
+ "span",
989
+ "strong",
990
+ "sub",
991
+ "sup",
992
+ "u",
993
+ "var",
994
+ "wbr",
995
+ "area",
996
+ "map",
997
+ "audio",
998
+ "source",
999
+ "track",
1000
+ "video",
1001
+ "embed",
1002
+ "object",
1003
+ "param",
1004
+ "canvas",
1005
+ "noscript",
1006
+ "caption",
1007
+ "table",
1008
+ "col",
1009
+ "colgroup",
1010
+ "tbody",
1011
+ "tr",
1012
+ "thead",
1013
+ "tfoot",
1014
+ "td",
1015
+ "th",
1016
+ "button",
1017
+ "datalist",
1018
+ "option",
1019
+ "fieldset",
1020
+ "label",
1021
+ "form",
1022
+ "input",
1023
+ "keygen",
1024
+ "legend",
1025
+ "meter",
1026
+ "optgroup",
1027
+ "select",
1028
+ "output",
1029
+ "progress",
1030
+ "textarea",
1031
+ "details",
1032
+ "dialog",
1033
+ "menuitem",
1034
+ "summary",
1035
+ "content",
1036
+ "element",
1037
+ "shadow",
1038
+ "template",
1039
+ "acronym",
1040
+ "applet",
1041
+ "basefont",
1042
+ "font",
1043
+ "big",
1044
+ "blink",
1045
+ "center",
1046
+ "command",
1047
+ "dir",
1048
+ "frame",
1049
+ "frameset",
1050
+ "isindex",
1051
+ "listing",
1052
+ "marquee",
1053
+ "noembed",
1054
+ "plaintext",
1055
+ "spacer",
1056
+ "strike",
1057
+ "tt",
1058
+ "xmp",
1059
+ "animate",
1060
+ "animateMotion",
1061
+ "animateTransform",
1062
+ "circle",
1063
+ "clipPath",
1064
+ "defs",
1065
+ "desc",
1066
+ "ellipse",
1067
+ "feBlend",
1068
+ "feColorMatrix",
1069
+ "feComponentTransfer",
1070
+ "feComposite",
1071
+ "feConvolveMatrix",
1072
+ "feDiffuseLighting",
1073
+ "feDisplacementMap",
1074
+ "feDistantLight",
1075
+ "feDropShadow",
1076
+ "feFlood",
1077
+ "feFuncA",
1078
+ "feFuncB",
1079
+ "feFuncG",
1080
+ "feFuncR",
1081
+ "feGaussianBlur",
1082
+ "feImage",
1083
+ "feMerge",
1084
+ "feMergeNode",
1085
+ "feMorphology",
1086
+ "feOffset",
1087
+ "fePointLight",
1088
+ "feSpecularLighting",
1089
+ "feSpotLight",
1090
+ "feTile",
1091
+ "feTurbulence",
1092
+ "filter",
1093
+ "foreignObject",
1094
+ "g",
1095
+ "image",
1096
+ "line",
1097
+ "linearGradient",
1098
+ "marker",
1099
+ "mask",
1100
+ "metadata",
1101
+ "mpath",
1102
+ "path",
1103
+ "pattern",
1104
+ "polygon",
1105
+ "polyline",
1106
+ "radialGradient",
1107
+ "rect",
1108
+ "set",
1109
+ "stop",
1110
+ "svg",
1111
+ "switch",
1112
+ "symbol",
1113
+ "text",
1114
+ "textPath",
1115
+ "tspan",
1116
+ "use",
1117
+ "view"
1118
+ ];
1119
+ var DELEGATED_EVENTS = [
1120
+ "click",
1121
+ "dblclick",
1122
+ "input",
1123
+ "change",
1124
+ "submit",
1125
+ "focus",
1126
+ "blur",
1127
+ "keydown",
1128
+ "keyup",
1129
+ "keypress",
1130
+ "mouseenter",
1131
+ "mouseleave",
1132
+ "mousedown",
1133
+ "mouseup",
1134
+ "mousemove",
1135
+ "touchstart",
1136
+ "touchend",
1137
+ "touchmove",
1138
+ "scroll"
1139
+ ];
1140
+ var EVENT_TYPE_MAP = {
1141
+ click: 0,
1142
+ dblclick: 1,
1143
+ input: 2,
1144
+ change: 3,
1145
+ submit: 4,
1146
+ focus: 5,
1147
+ blur: 6,
1148
+ keydown: 7,
1149
+ keyup: 8,
1150
+ keypress: 9,
1151
+ mouseenter: 10,
1152
+ mouseleave: 11,
1153
+ mousedown: 12,
1154
+ mouseup: 13,
1155
+ mousemove: 14,
1156
+ touchstart: 15,
1157
+ touchend: 16,
1158
+ touchmove: 17,
1159
+ scroll: 18
1160
+ };
1161
+ var eventHandlerModes = new Map;
1162
+ function initEventDelegation(bridge, rootSelector = "body") {
1163
+ const root = document.querySelector(rootSelector);
1164
+ if (!root)
1165
+ return () => {};
1166
+ const removers = [];
1167
+ for (const eventType of DELEGATED_EVENTS) {
1168
+ const listener = (event) => {
1169
+ let target = event.target;
1170
+ while (target && target !== document.body) {
1171
+ const zxRef = target.__zx_ref;
1172
+ if (zxRef !== undefined) {
1173
+ bridge.eventbridge(BigInt(zxRef), EVENT_TYPE_MAP[eventType] ?? 0, event);
1174
+ if (event.cancelBubble)
1175
+ break;
1176
+ }
1177
+ target = target.parentElement;
1178
+ }
1179
+ };
1180
+ const options = { passive: eventType.startsWith("touch") || eventType === "scroll" };
1181
+ root.addEventListener(eventType, listener, options);
1182
+ removers.push(() => root.removeEventListener(eventType, listener, options));
1183
+ }
1184
+ return () => {
1185
+ for (const remove of removers)
1186
+ remove();
1187
+ };
1188
+ }
1189
+ var DEFAULT_URL = "/assets/_/main.wasm";
1190
+ var activeRuntime = null;
1191
+ function buildDevtoolsLocation() {
1192
+ return {
1193
+ href: window.location.href,
1194
+ origin: window.location.origin,
1195
+ host: window.location.host,
1196
+ pathname: window.location.pathname
1197
+ };
1198
+ }
1199
+ function normalizeOptions(options = {}) {
1200
+ return {
1201
+ url: options.url,
1202
+ eventDelegationRoot: options.eventDelegationRoot,
1203
+ importObject: options.importObject,
1204
+ kv: options.kv
1205
+ };
1206
+ }
1207
+ function registerDevReinit(options) {
1208
+ if (typeof window === "undefined")
1209
+ return;
1210
+ const reinit = () => init(options);
1211
+ window.__zx_dev_reinit = reinit;
1212
+ window.__ZIEX_DEVTOOLS_GLOBAL_HOOK__ = {
1213
+ location: buildDevtoolsLocation(),
1214
+ reinit
1215
+ };
1216
+ }
208
1217
  async function init(options = {}) {
209
- const url = options?.url ?? DEFAULT_URL;
210
- const { instance } = await WebAssembly.instantiateStreaming(fetch(url), importObject);
211
- jsz.memory = instance.exports.memory;
212
- window._zx = new ZXInstance({ exports: instance.exports });
213
- const main = instance.exports.mainClient;
214
- if (typeof main === "function")
215
- main();
1218
+ const normalizedOptions = normalizeOptions(options);
1219
+ if (activeRuntime) {
1220
+ activeRuntime.dispose();
1221
+ activeRuntime = null;
1222
+ }
1223
+ const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
1224
+ const bridgeRef = { current: null };
1225
+ let wasmMemory = null;
1226
+ const kvBindings = options.kv ?? createBrowserKVBindings();
1227
+ const kvImportObject = {
1228
+ __zx_kv: createKVImports(kvBindings, () => {
1229
+ if (wasmMemory)
1230
+ return wasmMemory;
1231
+ if (jsz.memory)
1232
+ return jsz.memory;
1233
+ throw new Error("WASM memory is not ready");
1234
+ })
1235
+ };
1236
+ const importObject = Object.assign({}, ZxBridge.createImportObject(bridgeRef), kvImportObject, options.importObject);
1237
+ const source = await WebAssembly.instantiateStreaming(fetch(url), importObject);
1238
+ const { instance } = source;
1239
+ wasmMemory = instance.exports.memory;
1240
+ jsz.memory = wasmMemory;
1241
+ const bridge = new ZxBridge(instance.exports);
1242
+ bridgeRef.current = bridge;
1243
+ domNodes.clear();
1244
+ const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
1245
+ const main = wrapPromisingExport(instance.exports.mainClient);
1246
+ invokeWasmExport(main);
1247
+ activeRuntime = {
1248
+ options: normalizedOptions,
1249
+ dispose: () => {
1250
+ disposeDelegation();
1251
+ bridge.dispose();
1252
+ domNodes.clear();
1253
+ }
1254
+ };
1255
+ registerDevReinit(normalizedOptions);
1256
+ return { source, bridge };
216
1257
  }
217
1258
  export {
218
- init
1259
+ writeBytes,
1260
+ textEncoder,
1261
+ textDecoder,
1262
+ storeValueGetRef,
1263
+ readString,
1264
+ jsz,
1265
+ initEventDelegation,
1266
+ init,
1267
+ getMemoryView,
1268
+ ZxBridgeCore,
1269
+ ZxBridge,
1270
+ CallbackType
219
1271
  };