ziex 0.1.0-dev.966 → 0.1.0-dev.987
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/browser/kv.d.ts +13 -0
- package/cloudflare/index.js +350 -110
- package/index.js +45 -8
- package/kv.d.ts +17 -2
- package/package.json +2 -2
- package/wasm/core.d.ts +2 -0
- package/wasm/index.d.ts +18 -0
- package/wasm/index.js +344 -23
- package/wasm/init.js +321 -23
package/browser/kv.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { KVNamespace, SyncKVNamespace } from "../kv";
|
|
2
|
+
export type IndexedDbKVOptions = {
|
|
3
|
+
databaseName?: string;
|
|
4
|
+
storeName?: string;
|
|
5
|
+
namespace?: string;
|
|
6
|
+
};
|
|
7
|
+
export type BrowserKVOptions = IndexedDbKVOptions & {
|
|
8
|
+
storagePrefix?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function createIndexedDbKV(options?: IndexedDbKVOptions): KVNamespace;
|
|
11
|
+
export declare function createLocalStorageKV(options?: BrowserKVOptions): SyncKVNamespace;
|
|
12
|
+
export declare function hasJSPI(): boolean;
|
|
13
|
+
export declare function createBrowserKVBindings(options?: BrowserKVOptions): Record<string, KVNamespace>;
|
package/cloudflare/index.js
CHANGED
|
@@ -232,6 +232,24 @@ function readString(ptr, len) {
|
|
|
232
232
|
function writeBytes(ptr, data) {
|
|
233
233
|
getMemoryView().set(data, ptr);
|
|
234
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
|
+
}
|
|
235
253
|
|
|
236
254
|
class ZxBridgeCore {
|
|
237
255
|
#intervals = new Map;
|
|
@@ -240,8 +258,12 @@ class ZxBridgeCore {
|
|
|
240
258
|
#fetchCompleteHandler;
|
|
241
259
|
constructor(exports) {
|
|
242
260
|
this._alloc = exports.__zx_alloc;
|
|
243
|
-
this.#handler = exports.__zx_cb;
|
|
244
|
-
|
|
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;
|
|
245
267
|
if (exports.memory)
|
|
246
268
|
jsz.memory = exports.memory;
|
|
247
269
|
}
|
|
@@ -252,7 +274,7 @@ class ZxBridgeCore {
|
|
|
252
274
|
return;
|
|
253
275
|
}
|
|
254
276
|
const dataRef = storeValueGetRef(data);
|
|
255
|
-
handler
|
|
277
|
+
invokeWasmExport(handler, type, id, dataRef);
|
|
256
278
|
}
|
|
257
279
|
fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
|
|
258
280
|
const url = readString(urlPtr, urlLen);
|
|
@@ -297,7 +319,7 @@ class ZxBridgeCore {
|
|
|
297
319
|
const encoded = textEncoder.encode(body);
|
|
298
320
|
const ptr = this._alloc(encoded.length);
|
|
299
321
|
writeBytes(ptr, encoded);
|
|
300
|
-
handler
|
|
322
|
+
invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
|
|
301
323
|
}
|
|
302
324
|
setTimeout(callbackId, delayMs) {
|
|
303
325
|
setTimeout(() => {
|
|
@@ -369,6 +391,253 @@ class ZxBridgeCore {
|
|
|
369
391
|
};
|
|
370
392
|
}
|
|
371
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
|
+
}
|
|
640
|
+
|
|
372
641
|
// src/wasm/index.ts
|
|
373
642
|
class ZxBridge extends ZxBridgeCore {
|
|
374
643
|
#websockets = new Map;
|
|
@@ -377,13 +646,30 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
377
646
|
#wsOnErrorHandler;
|
|
378
647
|
#wsOnCloseHandler;
|
|
379
648
|
#eventbridge;
|
|
649
|
+
#eventbridgeAsync;
|
|
380
650
|
constructor(exports) {
|
|
381
651
|
super(exports);
|
|
382
|
-
this.#wsOnOpenHandler = exports.__zx_ws_onopen;
|
|
383
|
-
this.#wsOnMessageHandler = exports.__zx_ws_onmessage;
|
|
384
|
-
this.#wsOnErrorHandler = exports.__zx_ws_onerror;
|
|
385
|
-
this.#wsOnCloseHandler = exports.__zx_ws_onclose;
|
|
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);
|
|
386
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);
|
|
387
673
|
}
|
|
388
674
|
submitFormActionAsync(form, statesJson, fetchId) {
|
|
389
675
|
const formData = new FormData(form);
|
|
@@ -413,7 +699,7 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
413
699
|
return;
|
|
414
700
|
const protocol = ws.protocol || "";
|
|
415
701
|
const { ptr, len } = this._writeStringToWasm(protocol);
|
|
416
|
-
handler
|
|
702
|
+
invokeWasmExport(handler, wsId, ptr, len);
|
|
417
703
|
};
|
|
418
704
|
ws.onmessage = (event) => {
|
|
419
705
|
const handler = this.#wsOnMessageHandler;
|
|
@@ -422,14 +708,14 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
422
708
|
const isBinary = event.data instanceof ArrayBuffer;
|
|
423
709
|
const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
|
|
424
710
|
const { ptr, len } = this._writeBytesToWasm(data);
|
|
425
|
-
handler
|
|
711
|
+
invokeWasmExport(handler, wsId, ptr, len, isBinary ? 1 : 0);
|
|
426
712
|
};
|
|
427
713
|
ws.onerror = (_event) => {
|
|
428
714
|
const handler = this.#wsOnErrorHandler;
|
|
429
715
|
if (!handler)
|
|
430
716
|
return;
|
|
431
717
|
const { ptr, len } = this._writeStringToWasm("WebSocket error");
|
|
432
|
-
handler
|
|
718
|
+
invokeWasmExport(handler, wsId, ptr, len);
|
|
433
719
|
};
|
|
434
720
|
ws.onclose = (event) => {
|
|
435
721
|
const handler = this.#wsOnCloseHandler;
|
|
@@ -437,7 +723,7 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
437
723
|
return;
|
|
438
724
|
const reason = event.reason || "";
|
|
439
725
|
const { ptr, len } = this._writeStringToWasm(reason);
|
|
440
|
-
handler
|
|
726
|
+
invokeWasmExport(handler, wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
|
|
441
727
|
this.#websockets.delete(wsId);
|
|
442
728
|
};
|
|
443
729
|
this.#websockets.set(wsId, ws);
|
|
@@ -446,7 +732,7 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
446
732
|
if (handler) {
|
|
447
733
|
const msg = error instanceof Error ? error.message : "WebSocket connection failed";
|
|
448
734
|
const { ptr, len } = this._writeStringToWasm(msg);
|
|
449
|
-
handler
|
|
735
|
+
invokeWasmExport(handler, wsId, ptr, len);
|
|
450
736
|
}
|
|
451
737
|
}
|
|
452
738
|
}
|
|
@@ -477,6 +763,7 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
477
763
|
}
|
|
478
764
|
dispose() {
|
|
479
765
|
super.dispose();
|
|
766
|
+
eventHandlerModes.clear();
|
|
480
767
|
for (const ws of this.#websockets.values()) {
|
|
481
768
|
try {
|
|
482
769
|
ws.close();
|
|
@@ -485,16 +772,24 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
485
772
|
this.#websockets.clear();
|
|
486
773
|
}
|
|
487
774
|
eventbridge(velementId, eventTypeId, event) {
|
|
488
|
-
if (!this.#eventbridge)
|
|
489
|
-
return;
|
|
490
775
|
const eventRef = storeValueGetRef(event);
|
|
491
|
-
this
|
|
776
|
+
if (this.eventMaySuspend(velementId, eventTypeId)) {
|
|
777
|
+
invokeWasmExport(this.#eventbridgeAsync, velementId, eventTypeId, eventRef);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
invokeWasmExport(this.#eventbridge, velementId, eventTypeId, eventRef);
|
|
492
781
|
}
|
|
493
782
|
static createImportObject(bridgeRef) {
|
|
494
783
|
return {
|
|
495
784
|
...jsz.importObject(),
|
|
496
785
|
__zx: {
|
|
497
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
|
+
},
|
|
498
793
|
_fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
|
|
499
794
|
bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
|
|
500
795
|
},
|
|
@@ -863,6 +1158,7 @@ var EVENT_TYPE_MAP = {
|
|
|
863
1158
|
touchmove: 17,
|
|
864
1159
|
scroll: 18
|
|
865
1160
|
};
|
|
1161
|
+
var eventHandlerModes = new Map;
|
|
866
1162
|
function initEventDelegation(bridge, rootSelector = "body") {
|
|
867
1163
|
const root = document.querySelector(rootSelector);
|
|
868
1164
|
if (!root)
|
|
@@ -892,17 +1188,31 @@ function initEventDelegation(bridge, rootSelector = "body") {
|
|
|
892
1188
|
}
|
|
893
1189
|
var DEFAULT_URL = "/assets/_/main.wasm";
|
|
894
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
|
+
}
|
|
895
1199
|
function normalizeOptions(options = {}) {
|
|
896
1200
|
return {
|
|
897
1201
|
url: options.url,
|
|
898
1202
|
eventDelegationRoot: options.eventDelegationRoot,
|
|
899
|
-
importObject: options.importObject
|
|
1203
|
+
importObject: options.importObject,
|
|
1204
|
+
kv: options.kv
|
|
900
1205
|
};
|
|
901
1206
|
}
|
|
902
1207
|
function registerDevReinit(options) {
|
|
903
1208
|
if (typeof window === "undefined")
|
|
904
1209
|
return;
|
|
905
|
-
|
|
1210
|
+
const reinit = () => init(options);
|
|
1211
|
+
window.__zx_dev_reinit = reinit;
|
|
1212
|
+
window.__ZIEX_DEVTOOLS_GLOBAL_HOOK__ = {
|
|
1213
|
+
location: buildDevtoolsLocation(),
|
|
1214
|
+
reinit
|
|
1215
|
+
};
|
|
906
1216
|
}
|
|
907
1217
|
async function init(options = {}) {
|
|
908
1218
|
const normalizedOptions = normalizeOptions(options);
|
|
@@ -912,17 +1222,28 @@ async function init(options = {}) {
|
|
|
912
1222
|
}
|
|
913
1223
|
const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
|
|
914
1224
|
const bridgeRef = { current: null };
|
|
915
|
-
|
|
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);
|
|
916
1237
|
const source = await WebAssembly.instantiateStreaming(fetch(url), importObject);
|
|
917
1238
|
const { instance } = source;
|
|
918
|
-
|
|
1239
|
+
wasmMemory = instance.exports.memory;
|
|
1240
|
+
jsz.memory = wasmMemory;
|
|
919
1241
|
const bridge = new ZxBridge(instance.exports);
|
|
920
1242
|
bridgeRef.current = bridge;
|
|
921
1243
|
domNodes.clear();
|
|
922
1244
|
const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
|
|
923
|
-
const main = instance.exports.mainClient;
|
|
924
|
-
|
|
925
|
-
main();
|
|
1245
|
+
const main = wrapPromisingExport(instance.exports.mainClient);
|
|
1246
|
+
invokeWasmExport(main);
|
|
926
1247
|
activeRuntime = {
|
|
927
1248
|
options: normalizedOptions,
|
|
928
1249
|
dispose: () => {
|
|
@@ -1069,89 +1390,6 @@ class ZxWasiBridge {
|
|
|
1069
1390
|
}
|
|
1070
1391
|
}
|
|
1071
1392
|
|
|
1072
|
-
// src/kv.ts
|
|
1073
|
-
var exports_kv = {};
|
|
1074
|
-
__export(exports_kv, {
|
|
1075
|
-
createMemoryKV: () => createMemoryKV,
|
|
1076
|
-
createKVImports: () => createKVImports
|
|
1077
|
-
});
|
|
1078
|
-
function createMemoryKV() {
|
|
1079
|
-
const store = new Map;
|
|
1080
|
-
return {
|
|
1081
|
-
async get(key) {
|
|
1082
|
-
return store.get(key) ?? null;
|
|
1083
|
-
},
|
|
1084
|
-
async put(key, value) {
|
|
1085
|
-
store.set(key, value);
|
|
1086
|
-
},
|
|
1087
|
-
async delete(key) {
|
|
1088
|
-
store.delete(key);
|
|
1089
|
-
},
|
|
1090
|
-
async list(options) {
|
|
1091
|
-
const keys = [...store.keys()].filter((k) => !options?.prefix || k.startsWith(options.prefix)).map((name) => ({ name }));
|
|
1092
|
-
return { keys };
|
|
1093
|
-
}
|
|
1094
|
-
};
|
|
1095
|
-
}
|
|
1096
|
-
function createKVImports(bindings, getMemory) {
|
|
1097
|
-
const encoder3 = new TextEncoder;
|
|
1098
|
-
const decoder3 = new TextDecoder;
|
|
1099
|
-
function readStr(ptr, len) {
|
|
1100
|
-
return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
|
|
1101
|
-
}
|
|
1102
|
-
function writeBytes2(buf_ptr, buf_max, data) {
|
|
1103
|
-
if (data.length > buf_max)
|
|
1104
|
-
return -2;
|
|
1105
|
-
new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
|
|
1106
|
-
return data.length;
|
|
1107
|
-
}
|
|
1108
|
-
function binding(ns) {
|
|
1109
|
-
return bindings[ns] ?? bindings["default"] ?? null;
|
|
1110
|
-
}
|
|
1111
|
-
const Suspending = WebAssembly.Suspending;
|
|
1112
|
-
if (typeof Suspending !== "function") {
|
|
1113
|
-
return {
|
|
1114
|
-
kv_get: (_ns, _nsLen, _key, _keyLen, _buf, _max) => -1,
|
|
1115
|
-
kv_put: (_ns, _nsLen, _key, _keyLen, _val, _valLen) => 0,
|
|
1116
|
-
kv_delete: (_ns, _nsLen, _key, _keyLen) => 0,
|
|
1117
|
-
kv_list: (_ns, _nsLen, _pfx, _pfxLen, buf_ptr, buf_max) => writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"))
|
|
1118
|
-
};
|
|
1119
|
-
}
|
|
1120
|
-
return {
|
|
1121
|
-
kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
|
|
1122
|
-
const b = binding(readStr(ns_ptr, ns_len));
|
|
1123
|
-
if (!b)
|
|
1124
|
-
return -1;
|
|
1125
|
-
const value = await b.get(readStr(key_ptr, key_len));
|
|
1126
|
-
if (value === null)
|
|
1127
|
-
return -1;
|
|
1128
|
-
return writeBytes2(buf_ptr, buf_max, encoder3.encode(value));
|
|
1129
|
-
}),
|
|
1130
|
-
kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len) => {
|
|
1131
|
-
const b = binding(readStr(ns_ptr, ns_len));
|
|
1132
|
-
if (!b)
|
|
1133
|
-
return -1;
|
|
1134
|
-
await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len));
|
|
1135
|
-
return 0;
|
|
1136
|
-
}),
|
|
1137
|
-
kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
|
|
1138
|
-
const b = binding(readStr(ns_ptr, ns_len));
|
|
1139
|
-
if (!b)
|
|
1140
|
-
return -1;
|
|
1141
|
-
await b.delete(readStr(key_ptr, key_len));
|
|
1142
|
-
return 0;
|
|
1143
|
-
}),
|
|
1144
|
-
kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
|
|
1145
|
-
const b = binding(readStr(ns_ptr, ns_len));
|
|
1146
|
-
if (!b)
|
|
1147
|
-
return writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"));
|
|
1148
|
-
const prefix = readStr(prefix_ptr, prefix_len);
|
|
1149
|
-
const result = await b.list(prefix.length > 0 ? { prefix } : undefined);
|
|
1150
|
-
return writeBytes2(buf_ptr, buf_max, encoder3.encode(JSON.stringify(result.keys.map((k) => k.name))));
|
|
1151
|
-
})
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
1393
|
// src/db.ts
|
|
1156
1394
|
function decodeBlob(base64) {
|
|
1157
1395
|
const binary = atob(base64);
|
|
@@ -1723,18 +1961,20 @@ async function run({
|
|
|
1723
1961
|
ctx?.waitUntil(wasmPromise);
|
|
1724
1962
|
return new Response(null, { status: 101, webSocket: server.client });
|
|
1725
1963
|
}
|
|
1726
|
-
const { stderrText } = collectOutput();
|
|
1727
|
-
const
|
|
1728
|
-
if (
|
|
1964
|
+
const { stderrText: earlyStderrText } = collectOutput();
|
|
1965
|
+
const earlyMeta = parseEdgeMeta(earlyStderrText);
|
|
1966
|
+
if (earlyMeta.streaming) {
|
|
1729
1967
|
const { readable, writable } = new TransformStream;
|
|
1730
1968
|
streamWriter = writable.getWriter();
|
|
1731
1969
|
for (const chunk of stdoutChunks)
|
|
1732
1970
|
streamWriter.write(chunk);
|
|
1733
1971
|
stdoutChunks.length = 0;
|
|
1734
1972
|
wasmPromise.finally(() => streamWriter?.close());
|
|
1735
|
-
return new Response(readable, { status:
|
|
1973
|
+
return new Response(readable, { status: earlyMeta.status, headers: earlyMeta.headers });
|
|
1736
1974
|
}
|
|
1737
1975
|
await wasmPromise;
|
|
1976
|
+
const { stderrText } = collectOutput();
|
|
1977
|
+
const meta = parseEdgeMeta(stderrText);
|
|
1738
1978
|
const body = mergeUint8Arrays(stdoutChunks);
|
|
1739
1979
|
meta.headers.delete("transfer-encoding");
|
|
1740
1980
|
if (!meta.headers.has("content-length"))
|