ziex 0.1.0-dev.786 → 0.1.0-dev.804

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.
@@ -9,26 +9,1042 @@ var __export = (target, all) => {
9
9
  });
10
10
  };
11
11
 
12
- // src/cloudflare/worker.ts
13
- var exports_worker = {};
14
- __export(exports_worker, {
12
+ // ../../vendor/jsz/js/src/zigjs.ts
13
+ var NAN_PREFIX = 2146959360;
14
+ var predefined = {
15
+ nan: 0,
16
+ null: 1,
17
+ true: 2,
18
+ false: 3,
19
+ undefined: 4,
20
+ globalThis: 5,
21
+ runtime: 6
22
+ };
23
+ var PREDEFINED_ID_MAX = 6;
24
+ var encoder = new TextEncoder;
25
+ var decoder = new TextDecoder("utf-8");
26
+
27
+ class ZigJS {
28
+ memory;
29
+ values = [NaN, null, true, false, undefined, globalThis, this];
30
+ idPool = [];
31
+ importObject() {
32
+ return {
33
+ "zig-js": {
34
+ valueGet: this.valueGet.bind(this),
35
+ valueSet: this.valueSet.bind(this),
36
+ valueDeinit: this.valueDeinit.bind(this),
37
+ valueObjectCreate: this.valueObjectCreate.bind(this),
38
+ valueStringCreate: this.valueStringCreate.bind(this),
39
+ valueStringLen: this.valueStringLen.bind(this),
40
+ valueStringCopy: this.valueStringCopy.bind(this),
41
+ valueNew: this.valueNew.bind(this),
42
+ funcApply: this.funcApply.bind(this)
43
+ }
44
+ };
45
+ }
46
+ valueGet(out, id, ptr, len) {
47
+ const val = this.loadValue(id);
48
+ const str = this.loadString(ptr, len);
49
+ const result = Reflect.get(val, str);
50
+ this.storeValue(out, result);
51
+ }
52
+ valueSet(id, ptr, len, refAddr) {
53
+ const obj = this.loadValue(id);
54
+ const str = this.loadString(ptr, len);
55
+ const val = this.loadRef(refAddr);
56
+ Reflect.set(obj, str, val);
57
+ }
58
+ valueDeinit(id) {
59
+ if (id > PREDEFINED_ID_MAX) {
60
+ this.values[id] = null;
61
+ this.idPool.push(id);
62
+ }
63
+ }
64
+ valueObjectCreate(out) {
65
+ this.storeValue(out, new Object);
66
+ }
67
+ valueStringCreate(out, ptr, len) {
68
+ const str = this.loadString(ptr, len);
69
+ this.storeValue(out, str);
70
+ }
71
+ valueStringLen(id) {
72
+ const val = this.loadValue(id);
73
+ const buf = encoder.encode(val);
74
+ return buf.byteLength;
75
+ }
76
+ valueStringCopy(id, ptr, max) {
77
+ if (this.memory == null)
78
+ return;
79
+ const val = this.loadValue(id);
80
+ const bytes = encoder.encode(val);
81
+ if (bytes.byteLength > max)
82
+ return;
83
+ new Uint8Array(this.memory.buffer, ptr, bytes.length).set(bytes);
84
+ }
85
+ valueNew(out, id, argsAddr, argsLen) {
86
+ const fn = this.loadValue(id);
87
+ const args = [];
88
+ for (let i = 0;i < argsLen; i++) {
89
+ args.push(this.loadRef(argsAddr + i * 8));
90
+ }
91
+ const result = Reflect.construct(fn, args);
92
+ this.storeValue(out, result);
93
+ }
94
+ funcApply(out, id, thisRefAddr, argsAddr, argsLen) {
95
+ const fn = this.loadValue(id);
96
+ const thisVal = this.loadRef(thisRefAddr);
97
+ const args = [];
98
+ for (let i = 0;i < argsLen; i++) {
99
+ args.push(this.loadRef(argsAddr + i * 8));
100
+ }
101
+ const result = Reflect.apply(fn, thisVal, args);
102
+ this.storeValue(out, result);
103
+ }
104
+ loadValue(id) {
105
+ return this.values[id];
106
+ }
107
+ deleteValue(id) {
108
+ const val = this.values[id];
109
+ this.valueDeinit(id);
110
+ return val;
111
+ }
112
+ loadRef(refAddr) {
113
+ if (this.memory == null)
114
+ return;
115
+ const view = new DataView(this.memory.buffer);
116
+ const floatVal = view.getFloat64(refAddr, true);
117
+ if (!isNaN(floatVal))
118
+ return floatVal;
119
+ const id = this.loadRefId(refAddr);
120
+ return this.values[id];
121
+ }
122
+ loadRefId(refAddr) {
123
+ if (this.memory == null)
124
+ return 0;
125
+ return new DataView(this.memory.buffer).getUint32(refAddr, true);
126
+ }
127
+ storeValue(out, val) {
128
+ if (this.memory == null)
129
+ return;
130
+ const view = new DataView(this.memory.buffer);
131
+ if (typeof val === "number") {
132
+ if (isNaN(val)) {
133
+ view.setUint32(out, predefined.nan, true);
134
+ view.setUint32(out + 4, NAN_PREFIX, true);
135
+ } else {
136
+ view.setFloat64(out, val, true);
137
+ }
138
+ return;
139
+ }
140
+ if (val === null) {
141
+ view.setUint32(out, predefined.null, true);
142
+ view.setUint32(out + 4, NAN_PREFIX, true);
143
+ return;
144
+ }
145
+ if (val === undefined) {
146
+ view.setUint32(out, predefined.undefined, true);
147
+ view.setUint32(out + 4, NAN_PREFIX, true);
148
+ return;
149
+ }
150
+ let id = this.idPool.pop();
151
+ if (id === undefined) {
152
+ id = this.values.length;
153
+ }
154
+ this.values[id] = val;
155
+ let typeId = 0;
156
+ switch (typeof val) {
157
+ case "object":
158
+ typeId = 1;
159
+ break;
160
+ case "string":
161
+ typeId = 2;
162
+ break;
163
+ case "symbol":
164
+ typeId = 3;
165
+ break;
166
+ case "function":
167
+ typeId = 4;
168
+ break;
169
+ }
170
+ view.setUint32(out, Number(id), true);
171
+ view.setUint32(out + 4, NAN_PREFIX | typeId, true);
172
+ }
173
+ loadString(ptr, len) {
174
+ if (this.memory == null)
175
+ return "";
176
+ const arr = new Uint8ClampedArray(this.memory.buffer, ptr, Number(len));
177
+ const data = arr.slice();
178
+ return decoder.decode(data);
179
+ }
180
+ }
181
+ // src/wasm/core.ts
182
+ var CallbackType = {
183
+ Event: 0,
184
+ FetchSuccess: 1,
185
+ FetchError: 2,
186
+ Timeout: 3,
187
+ Interval: 4,
188
+ WebSocketOpen: 5,
189
+ WebSocketMessage: 6,
190
+ WebSocketError: 7,
191
+ WebSocketClose: 8
192
+ };
193
+ var jsz = new ZigJS;
194
+ var tempRefBuffer = new ArrayBuffer(8);
195
+ var tempRefView = new DataView(tempRefBuffer);
196
+ function storeValueGetRef(val) {
197
+ const originalMemory = jsz.memory;
198
+ jsz.memory = { buffer: tempRefBuffer };
199
+ jsz.storeValue(0, val);
200
+ jsz.memory = originalMemory;
201
+ return tempRefView.getBigUint64(0, true);
202
+ }
203
+ var textDecoder = new TextDecoder;
204
+ var textEncoder = new TextEncoder;
205
+ var memoryView = null;
206
+ var memoryBuffer = null;
207
+ function getMemoryView() {
208
+ const buf = jsz.memory.buffer;
209
+ if (buf !== memoryBuffer) {
210
+ memoryBuffer = buf;
211
+ memoryView = new Uint8Array(buf);
212
+ }
213
+ return memoryView;
214
+ }
215
+ var stringCache = new Map;
216
+ function stringCacheKey(ptr, len) {
217
+ return ptr * 65536 + len;
218
+ }
219
+ function readString(ptr, len) {
220
+ const key = stringCacheKey(ptr, len);
221
+ const cached = stringCache.get(key);
222
+ if (cached !== undefined)
223
+ return cached;
224
+ const str = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
225
+ stringCache.set(key, str);
226
+ return str;
227
+ }
228
+ function writeBytes(ptr, data) {
229
+ getMemoryView().set(data, ptr);
230
+ }
231
+
232
+ class ZxBridgeCore {
233
+ #intervals = new Map;
234
+ _alloc;
235
+ #handler;
236
+ #fetchCompleteHandler;
237
+ constructor(exports) {
238
+ this._alloc = exports.__zx_alloc;
239
+ this.#handler = exports.__zx_cb;
240
+ this.#fetchCompleteHandler = exports.__zx_fetch_complete;
241
+ if (exports.memory)
242
+ jsz.memory = exports.memory;
243
+ }
244
+ #invoke(type, id, data) {
245
+ const handler = this.#handler;
246
+ if (!handler) {
247
+ console.warn("__zx_cb not exported from WASM");
248
+ return;
249
+ }
250
+ const dataRef = storeValueGetRef(data);
251
+ handler(type, id, dataRef);
252
+ }
253
+ fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
254
+ const url = readString(urlPtr, urlLen);
255
+ const method = methodLen > 0 ? readString(methodPtr, methodLen) : "GET";
256
+ const headersJson = headersLen > 0 ? readString(headersPtr, headersLen) : "{}";
257
+ const body = bodyLen > 0 ? readString(bodyPtr, bodyLen) : undefined;
258
+ let headers = {};
259
+ try {
260
+ headers = JSON.parse(headersJson);
261
+ } catch {
262
+ for (const line of headersJson.split(`
263
+ `)) {
264
+ const colonIdx = line.indexOf(":");
265
+ if (colonIdx > 0) {
266
+ headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
267
+ }
268
+ }
269
+ }
270
+ const controller = new AbortController;
271
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
272
+ const fetchOptions = {
273
+ method,
274
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
275
+ body: method !== "GET" && method !== "HEAD" ? body : undefined,
276
+ signal: controller.signal
277
+ };
278
+ fetch(url, fetchOptions).then(async (response) => {
279
+ if (timeout)
280
+ clearTimeout(timeout);
281
+ const text = await response.text();
282
+ this._notifyFetchComplete(fetchId, response.status, text, false);
283
+ }).catch((error) => {
284
+ if (timeout)
285
+ clearTimeout(timeout);
286
+ const isAbort = error.name === "AbortError";
287
+ const errorMsg = isAbort ? "Request timeout" : error.message ?? "Fetch failed";
288
+ this._notifyFetchComplete(fetchId, 0, errorMsg, true);
289
+ });
290
+ }
291
+ _notifyFetchComplete(fetchId, statusCode, body, isError) {
292
+ const handler = this.#fetchCompleteHandler;
293
+ const encoded = textEncoder.encode(body);
294
+ const ptr = this._alloc(encoded.length);
295
+ writeBytes(ptr, encoded);
296
+ handler(fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
297
+ }
298
+ setTimeout(callbackId, delayMs) {
299
+ setTimeout(() => {
300
+ this.#invoke(CallbackType.Timeout, callbackId, null);
301
+ }, delayMs);
302
+ }
303
+ setInterval(callbackId, intervalMs) {
304
+ const handle = setInterval(() => {
305
+ this.#invoke(CallbackType.Interval, callbackId, null);
306
+ }, intervalMs);
307
+ this.#intervals.set(callbackId, handle);
308
+ }
309
+ clearInterval(callbackId) {
310
+ const handle = this.#intervals.get(callbackId);
311
+ if (handle !== undefined) {
312
+ clearInterval(handle);
313
+ this.#intervals.delete(callbackId);
314
+ }
315
+ }
316
+ _writeStringToWasm(str) {
317
+ return this._writeBytesToWasm(textEncoder.encode(str));
318
+ }
319
+ _writeBytesToWasm(data) {
320
+ const ptr = this._alloc(data.length);
321
+ writeBytes(ptr, data);
322
+ return { ptr, len: data.length };
323
+ }
324
+ static log(level, ptr, len) {
325
+ const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
326
+ switch (level) {
327
+ case 0:
328
+ console.error(msg);
329
+ break;
330
+ case 1:
331
+ console.warn(msg);
332
+ break;
333
+ case 3:
334
+ console.debug(msg);
335
+ break;
336
+ default:
337
+ console.log(msg);
338
+ break;
339
+ }
340
+ }
341
+ static createImportObject(bridgeRef) {
342
+ return {
343
+ ...jsz.importObject(),
344
+ __zx: {
345
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
346
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
347
+ bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
348
+ },
349
+ _setTimeout: (callbackId, delayMs) => {
350
+ bridgeRef.current?.setTimeout(callbackId, delayMs);
351
+ },
352
+ _setInterval: (callbackId, intervalMs) => {
353
+ bridgeRef.current?.setInterval(callbackId, intervalMs);
354
+ },
355
+ _clearInterval: (callbackId) => {
356
+ bridgeRef.current?.clearInterval(callbackId);
357
+ }
358
+ }
359
+ };
360
+ }
361
+ }
362
+ // src/wasm/index.ts
363
+ class ZxBridge extends ZxBridgeCore {
364
+ #websockets = new Map;
365
+ #wsOnOpenHandler;
366
+ #wsOnMessageHandler;
367
+ #wsOnErrorHandler;
368
+ #wsOnCloseHandler;
369
+ #eventbridge;
370
+ constructor(exports) {
371
+ super(exports);
372
+ this.#wsOnOpenHandler = exports.__zx_ws_onopen;
373
+ this.#wsOnMessageHandler = exports.__zx_ws_onmessage;
374
+ this.#wsOnErrorHandler = exports.__zx_ws_onerror;
375
+ this.#wsOnCloseHandler = exports.__zx_ws_onclose;
376
+ this.#eventbridge = exports.__zx_eventbridge;
377
+ }
378
+ submitFormActionAsync(form, statesJson, fetchId) {
379
+ const formData = new FormData(form);
380
+ formData.append("__zx_states", statesJson);
381
+ fetch(window.location.href, {
382
+ method: "POST",
383
+ headers: { "X-ZX-Action": "1" },
384
+ body: formData
385
+ }).then(async (response) => {
386
+ const text = await response.text();
387
+ this._notifyFetchComplete(fetchId, response.status, text, false);
388
+ }).catch((error) => {
389
+ const msg = error instanceof Error ? error.message : "Fetch failed";
390
+ this._notifyFetchComplete(fetchId, 0, msg, true);
391
+ });
392
+ }
393
+ wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
394
+ const url = readString(urlPtr, urlLen);
395
+ const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
396
+ const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : undefined;
397
+ try {
398
+ const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
399
+ ws.binaryType = "arraybuffer";
400
+ ws.onopen = () => {
401
+ const handler = this.#wsOnOpenHandler;
402
+ if (!handler)
403
+ return;
404
+ const protocol = ws.protocol || "";
405
+ const { ptr, len } = this._writeStringToWasm(protocol);
406
+ handler(wsId, ptr, len);
407
+ };
408
+ ws.onmessage = (event) => {
409
+ const handler = this.#wsOnMessageHandler;
410
+ if (!handler)
411
+ return;
412
+ const isBinary = event.data instanceof ArrayBuffer;
413
+ const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
414
+ const { ptr, len } = this._writeBytesToWasm(data);
415
+ handler(wsId, ptr, len, isBinary ? 1 : 0);
416
+ };
417
+ ws.onerror = (_event) => {
418
+ const handler = this.#wsOnErrorHandler;
419
+ if (!handler)
420
+ return;
421
+ const { ptr, len } = this._writeStringToWasm("WebSocket error");
422
+ handler(wsId, ptr, len);
423
+ };
424
+ ws.onclose = (event) => {
425
+ const handler = this.#wsOnCloseHandler;
426
+ if (!handler)
427
+ return;
428
+ const reason = event.reason || "";
429
+ const { ptr, len } = this._writeStringToWasm(reason);
430
+ handler(wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
431
+ this.#websockets.delete(wsId);
432
+ };
433
+ this.#websockets.set(wsId, ws);
434
+ } catch (error) {
435
+ const handler = this.#wsOnErrorHandler;
436
+ if (handler) {
437
+ const msg = error instanceof Error ? error.message : "WebSocket connection failed";
438
+ const { ptr, len } = this._writeStringToWasm(msg);
439
+ handler(wsId, ptr, len);
440
+ }
441
+ }
442
+ }
443
+ wsSend(wsId, dataPtr, dataLen, isBinary) {
444
+ const ws = this.#websockets.get(wsId);
445
+ if (!ws || ws.readyState !== WebSocket.OPEN)
446
+ return;
447
+ const memory = getMemoryView();
448
+ if (isBinary) {
449
+ ws.send(memory.slice(dataPtr, dataPtr + dataLen));
450
+ } else {
451
+ ws.send(textDecoder.decode(memory.subarray(dataPtr, dataPtr + dataLen)));
452
+ }
453
+ }
454
+ wsClose(wsId, code, reasonPtr, reasonLen) {
455
+ const ws = this.#websockets.get(wsId);
456
+ if (!ws)
457
+ return;
458
+ const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : undefined;
459
+ try {
460
+ if (reason)
461
+ ws.close(code, reason);
462
+ else
463
+ ws.close(code);
464
+ } catch {
465
+ ws.close();
466
+ }
467
+ }
468
+ eventbridge(velementId, eventTypeId, event) {
469
+ if (!this.#eventbridge)
470
+ return;
471
+ const eventRef = storeValueGetRef(event);
472
+ this.#eventbridge(velementId, eventTypeId, eventRef);
473
+ }
474
+ static createImportObject(bridgeRef) {
475
+ return {
476
+ ...jsz.importObject(),
477
+ __zx: {
478
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
479
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
480
+ bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
481
+ },
482
+ _setTimeout: (callbackId, delayMs) => {
483
+ bridgeRef.current?.setTimeout(callbackId, delayMs);
484
+ },
485
+ _setInterval: (callbackId, intervalMs) => {
486
+ bridgeRef.current?.setInterval(callbackId, intervalMs);
487
+ },
488
+ _clearInterval: (callbackId) => {
489
+ bridgeRef.current?.clearInterval(callbackId);
490
+ },
491
+ _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
492
+ bridgeRef.current?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
493
+ },
494
+ _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
495
+ bridgeRef.current?.wsSend(wsId, dataPtr, dataLen, isBinary);
496
+ },
497
+ _wsClose: (wsId, code, reasonPtr, reasonLen) => {
498
+ bridgeRef.current?.wsClose(wsId, code, reasonPtr, reasonLen);
499
+ },
500
+ _ce: (id, vnodeId) => {
501
+ const tagName = TAG_NAMES[id];
502
+ const el = id >= SVG_TAG_START_INDEX ? document.createElementNS("http://www.w3.org/2000/svg", tagName) : document.createElement(tagName);
503
+ el.__zx_ref = Number(vnodeId);
504
+ domNodes.set(vnodeId, el);
505
+ return storeValueGetRef(el);
506
+ },
507
+ _ct: (ptr, len, vnodeId) => {
508
+ const text = readString(ptr, len);
509
+ const node = document.createTextNode(text);
510
+ node.__zx_ref = Number(vnodeId);
511
+ domNodes.set(vnodeId, node);
512
+ return storeValueGetRef(node);
513
+ },
514
+ _sa: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
515
+ domNodes.get(vnodeId)?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
516
+ },
517
+ _ra: (vnodeId, namePtr, nameLen) => {
518
+ domNodes.get(vnodeId)?.removeAttribute(readString(namePtr, nameLen));
519
+ },
520
+ _snv: (vnodeId, ptr, len) => {
521
+ const node = domNodes.get(vnodeId);
522
+ if (node)
523
+ node.nodeValue = readString(ptr, len);
524
+ },
525
+ _ac: (parentId, childId) => {
526
+ const parent = domNodes.get(parentId);
527
+ const child = domNodes.get(childId);
528
+ if (parent && child)
529
+ parent.appendChild(child);
530
+ },
531
+ _ib: (parentId, childId, refId) => {
532
+ const parent = domNodes.get(parentId);
533
+ const child = domNodes.get(childId);
534
+ const ref = domNodes.get(refId) ?? null;
535
+ if (parent && child)
536
+ parent.insertBefore(child, ref);
537
+ },
538
+ _rc: (parentId, childId) => {
539
+ const parent = domNodes.get(parentId);
540
+ const child = domNodes.get(childId);
541
+ if (parent && child) {
542
+ parent.removeChild(child);
543
+ cleanupDomNodes(child);
544
+ }
545
+ },
546
+ _rpc: (parentId, newId, oldId) => {
547
+ const parent = domNodes.get(parentId);
548
+ const newChild = domNodes.get(newId);
549
+ const oldChild = domNodes.get(oldId);
550
+ if (parent && newChild && oldChild) {
551
+ parent.replaceChild(newChild, oldChild);
552
+ cleanupDomNodes(oldChild);
553
+ }
554
+ },
555
+ _getLocationHref: (bufPtr, bufLen) => {
556
+ const bytes = textEncoder.encode(window.location.href);
557
+ const len = Math.min(bytes.length, bufLen);
558
+ writeBytes(bufPtr, bytes.subarray(0, len));
559
+ return len;
560
+ },
561
+ _getFormData: (vnodeId, bufPtr, bufLen) => {
562
+ const form = domNodes.get(vnodeId);
563
+ if (!form || !(form instanceof HTMLFormElement))
564
+ return 0;
565
+ const formData = new FormData(form);
566
+ const urlEncoded = new URLSearchParams(formData).toString();
567
+ const bytes = textEncoder.encode(urlEncoded);
568
+ const len = Math.min(bytes.length, bufLen);
569
+ writeBytes(bufPtr, bytes.subarray(0, len));
570
+ return len;
571
+ },
572
+ _submitFormAction: (vnodeId) => {
573
+ const form = domNodes.get(vnodeId);
574
+ if (!form || !(form instanceof HTMLFormElement))
575
+ return;
576
+ const formData = new FormData(form);
577
+ fetch(window.location.href, {
578
+ method: "POST",
579
+ headers: { "X-ZX-Action": "1" },
580
+ body: formData
581
+ }).catch(() => {});
582
+ },
583
+ _submitFormActionAsync: (vnodeId, statesPtr, statesLen, fetchId) => {
584
+ const form = domNodes.get(vnodeId);
585
+ if (!form || !(form instanceof HTMLFormElement))
586
+ return;
587
+ const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
588
+ bridgeRef.current?.submitFormActionAsync(form, statesJson, fetchId);
589
+ }
590
+ }
591
+ };
592
+ }
593
+ }
594
+ var domNodes = new Map;
595
+ function cleanupDomNodes(node) {
596
+ const ref = node.__zx_ref;
597
+ if (ref !== undefined)
598
+ domNodes.delete(BigInt(ref));
599
+ const children = node.childNodes;
600
+ for (let i = 0;i < children.length; i++)
601
+ cleanupDomNodes(children[i]);
602
+ }
603
+ var SVG_TAG_START_INDEX = 140;
604
+ var TAG_NAMES = [
605
+ "aside",
606
+ "fragment",
607
+ "iframe",
608
+ "slot",
609
+ "img",
610
+ "html",
611
+ "base",
612
+ "head",
613
+ "link",
614
+ "meta",
615
+ "script",
616
+ "style",
617
+ "title",
618
+ "address",
619
+ "article",
620
+ "body",
621
+ "h1",
622
+ "h6",
623
+ "footer",
624
+ "header",
625
+ "h2",
626
+ "h3",
627
+ "h4",
628
+ "h5",
629
+ "hgroup",
630
+ "nav",
631
+ "section",
632
+ "dd",
633
+ "dl",
634
+ "dt",
635
+ "div",
636
+ "figcaption",
637
+ "figure",
638
+ "hr",
639
+ "li",
640
+ "ol",
641
+ "ul",
642
+ "menu",
643
+ "main",
644
+ "p",
645
+ "picture",
646
+ "pre",
647
+ "a",
648
+ "abbr",
649
+ "b",
650
+ "bdi",
651
+ "bdo",
652
+ "br",
653
+ "cite",
654
+ "code",
655
+ "data",
656
+ "time",
657
+ "dfn",
658
+ "em",
659
+ "i",
660
+ "kbd",
661
+ "mark",
662
+ "q",
663
+ "blockquote",
664
+ "rp",
665
+ "ruby",
666
+ "rt",
667
+ "rtc",
668
+ "rb",
669
+ "s",
670
+ "del",
671
+ "ins",
672
+ "samp",
673
+ "small",
674
+ "span",
675
+ "strong",
676
+ "sub",
677
+ "sup",
678
+ "u",
679
+ "var",
680
+ "wbr",
681
+ "area",
682
+ "map",
683
+ "audio",
684
+ "source",
685
+ "track",
686
+ "video",
687
+ "embed",
688
+ "object",
689
+ "param",
690
+ "canvas",
691
+ "noscript",
692
+ "caption",
693
+ "table",
694
+ "col",
695
+ "colgroup",
696
+ "tbody",
697
+ "tr",
698
+ "thead",
699
+ "tfoot",
700
+ "td",
701
+ "th",
702
+ "button",
703
+ "datalist",
704
+ "option",
705
+ "fieldset",
706
+ "label",
707
+ "form",
708
+ "input",
709
+ "keygen",
710
+ "legend",
711
+ "meter",
712
+ "optgroup",
713
+ "select",
714
+ "output",
715
+ "progress",
716
+ "textarea",
717
+ "details",
718
+ "dialog",
719
+ "menuitem",
720
+ "summary",
721
+ "content",
722
+ "element",
723
+ "shadow",
724
+ "template",
725
+ "acronym",
726
+ "applet",
727
+ "basefont",
728
+ "font",
729
+ "big",
730
+ "blink",
731
+ "center",
732
+ "command",
733
+ "dir",
734
+ "frame",
735
+ "frameset",
736
+ "isindex",
737
+ "listing",
738
+ "marquee",
739
+ "noembed",
740
+ "plaintext",
741
+ "spacer",
742
+ "strike",
743
+ "tt",
744
+ "xmp",
745
+ "animate",
746
+ "animateMotion",
747
+ "animateTransform",
748
+ "circle",
749
+ "clipPath",
750
+ "defs",
751
+ "desc",
752
+ "ellipse",
753
+ "feBlend",
754
+ "feColorMatrix",
755
+ "feComponentTransfer",
756
+ "feComposite",
757
+ "feConvolveMatrix",
758
+ "feDiffuseLighting",
759
+ "feDisplacementMap",
760
+ "feDistantLight",
761
+ "feDropShadow",
762
+ "feFlood",
763
+ "feFuncA",
764
+ "feFuncB",
765
+ "feFuncG",
766
+ "feFuncR",
767
+ "feGaussianBlur",
768
+ "feImage",
769
+ "feMerge",
770
+ "feMergeNode",
771
+ "feMorphology",
772
+ "feOffset",
773
+ "fePointLight",
774
+ "feSpecularLighting",
775
+ "feSpotLight",
776
+ "feTile",
777
+ "feTurbulence",
778
+ "filter",
779
+ "foreignObject",
780
+ "g",
781
+ "image",
782
+ "line",
783
+ "linearGradient",
784
+ "marker",
785
+ "mask",
786
+ "metadata",
787
+ "mpath",
788
+ "path",
789
+ "pattern",
790
+ "polygon",
791
+ "polyline",
792
+ "radialGradient",
793
+ "rect",
794
+ "set",
795
+ "stop",
796
+ "svg",
797
+ "switch",
798
+ "symbol",
799
+ "text",
800
+ "textPath",
801
+ "tspan",
802
+ "use",
803
+ "view"
804
+ ];
805
+ var DELEGATED_EVENTS = [
806
+ "click",
807
+ "dblclick",
808
+ "input",
809
+ "change",
810
+ "submit",
811
+ "focus",
812
+ "blur",
813
+ "keydown",
814
+ "keyup",
815
+ "keypress",
816
+ "mouseenter",
817
+ "mouseleave",
818
+ "mousedown",
819
+ "mouseup",
820
+ "mousemove",
821
+ "touchstart",
822
+ "touchend",
823
+ "touchmove",
824
+ "scroll"
825
+ ];
826
+ var EVENT_TYPE_MAP = {
827
+ click: 0,
828
+ dblclick: 1,
829
+ input: 2,
830
+ change: 3,
831
+ submit: 4,
832
+ focus: 5,
833
+ blur: 6,
834
+ keydown: 7,
835
+ keyup: 8,
836
+ keypress: 9,
837
+ mouseenter: 10,
838
+ mouseleave: 11,
839
+ mousedown: 12,
840
+ mouseup: 13,
841
+ mousemove: 14,
842
+ touchstart: 15,
843
+ touchend: 16,
844
+ touchmove: 17,
845
+ scroll: 18
846
+ };
847
+ function initEventDelegation(bridge, rootSelector = "body") {
848
+ const root = document.querySelector(rootSelector);
849
+ if (!root)
850
+ return;
851
+ for (const eventType of DELEGATED_EVENTS) {
852
+ root.addEventListener(eventType, (event) => {
853
+ let target = event.target;
854
+ while (target && target !== document.body) {
855
+ const zxRef = target.__zx_ref;
856
+ if (zxRef !== undefined) {
857
+ bridge.eventbridge(BigInt(zxRef), EVENT_TYPE_MAP[eventType] ?? 0, event);
858
+ if (event.cancelBubble)
859
+ break;
860
+ }
861
+ target = target.parentElement;
862
+ }
863
+ }, { passive: eventType.startsWith("touch") || eventType === "scroll" });
864
+ }
865
+ }
866
+ var DEFAULT_URL = "/assets/main.wasm";
867
+ async function init(options = {}) {
868
+ const url = options.url ?? DEFAULT_URL;
869
+ const bridgeRef = { current: null };
870
+ const importObject = Object.assign({}, ZxBridge.createImportObject(bridgeRef), options.importObject);
871
+ const source = await WebAssembly.instantiateStreaming(fetch(url), importObject);
872
+ const { instance } = source;
873
+ jsz.memory = instance.exports.memory;
874
+ const bridge = new ZxBridge(instance.exports);
875
+ bridgeRef.current = bridge;
876
+ initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
877
+ const main = instance.exports.mainClient;
878
+ if (typeof main === "function")
879
+ main();
880
+ return { source, bridge };
881
+ }
882
+
883
+ // src/runtime.ts
884
+ var exports_runtime = {};
885
+ __export(exports_runtime, {
15
886
  run: () => run,
16
- respond: () => respond,
17
- prepare: () => prepare
887
+ buildWsImports: () => buildWsImports,
888
+ attachWebSocket: () => attachWebSocket
18
889
  });
19
890
 
20
- // src/cloudflare/kv.ts
891
+ // src/wasm/wasi.ts
892
+ var decoder2 = new TextDecoder;
893
+ var encoder2 = new TextEncoder;
894
+
895
+ class ZxWasiBridge {
896
+ #alloc;
897
+ #fetchCompleteHandler;
898
+ #memory;
899
+ #cb;
900
+ #intervals = new Map;
901
+ #memView = null;
902
+ #memBuf = null;
903
+ constructor(exports) {
904
+ this.#memory = exports.memory;
905
+ this.#alloc = exports.__zx_alloc;
906
+ this.#fetchCompleteHandler = exports.__zx_fetch_complete;
907
+ this.#cb = exports.__zx_cb;
908
+ }
909
+ #view() {
910
+ const buf = this.#memory.buffer;
911
+ if (buf !== this.#memBuf) {
912
+ this.#memBuf = buf;
913
+ this.#memView = new Uint8Array(buf);
914
+ }
915
+ return this.#memView;
916
+ }
917
+ #readString(ptr, len) {
918
+ return decoder2.decode(this.#view().subarray(ptr, ptr + len));
919
+ }
920
+ #writeBytes(ptr, data) {
921
+ this.#view().set(data, ptr);
922
+ }
923
+ log(level, ptr, len) {
924
+ const msg = decoder2.decode(this.#view().subarray(ptr, ptr + len));
925
+ switch (level) {
926
+ case 0:
927
+ console.error(msg);
928
+ break;
929
+ case 1:
930
+ console.warn(msg);
931
+ break;
932
+ case 3:
933
+ console.debug(msg);
934
+ break;
935
+ default:
936
+ console.log(msg);
937
+ break;
938
+ }
939
+ }
940
+ fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
941
+ const url = this.#readString(urlPtr, urlLen);
942
+ const method = methodLen > 0 ? this.#readString(methodPtr, methodLen) : "GET";
943
+ const headersJson = headersLen > 0 ? this.#readString(headersPtr, headersLen) : "{}";
944
+ const body = bodyLen > 0 ? this.#readString(bodyPtr, bodyLen) : undefined;
945
+ let headers = {};
946
+ try {
947
+ headers = JSON.parse(headersJson);
948
+ } catch {
949
+ for (const line of headersJson.split(`
950
+ `)) {
951
+ const i = line.indexOf(":");
952
+ if (i > 0)
953
+ headers[line.slice(0, i)] = line.slice(i + 1);
954
+ }
955
+ }
956
+ const controller = new AbortController;
957
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
958
+ fetch(url, {
959
+ method,
960
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
961
+ body: method !== "GET" && method !== "HEAD" ? body : undefined,
962
+ signal: controller.signal
963
+ }).then(async (res) => {
964
+ if (timeout)
965
+ clearTimeout(timeout);
966
+ this.#notifyFetchComplete(fetchId, res.status, await res.text(), false);
967
+ }).catch((err) => {
968
+ if (timeout)
969
+ clearTimeout(timeout);
970
+ const msg = err.name === "AbortError" ? "Request timeout" : err.message ?? "Fetch failed";
971
+ this.#notifyFetchComplete(fetchId, 0, msg, true);
972
+ });
973
+ }
974
+ #notifyFetchComplete(fetchId, status, body, isError) {
975
+ const encoded = encoder2.encode(body);
976
+ const ptr = this.#alloc(encoded.length);
977
+ this.#writeBytes(ptr, encoded);
978
+ this.#fetchCompleteHandler(fetchId, status, ptr, encoded.length, isError ? 1 : 0);
979
+ }
980
+ setTimeout(callbackId, delayMs) {
981
+ setTimeout(() => this.#cb?.(3, callbackId, 0n), delayMs);
982
+ }
983
+ setInterval(callbackId, intervalMs) {
984
+ const handle = setInterval(() => this.#cb?.(4, callbackId, 0n), intervalMs);
985
+ this.#intervals.set(callbackId, handle);
986
+ }
987
+ clearInterval(callbackId) {
988
+ const handle = this.#intervals.get(callbackId);
989
+ if (handle !== undefined) {
990
+ clearInterval(handle);
991
+ this.#intervals.delete(callbackId);
992
+ }
993
+ }
994
+ static createImportObject(bridgeRef) {
995
+ return {
996
+ __zx: {
997
+ _log: (level, ptr, len) => {
998
+ bridgeRef.current?.log(level, ptr, len);
999
+ },
1000
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
1001
+ bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
1002
+ },
1003
+ _setTimeout: (callbackId, delayMs) => {
1004
+ bridgeRef.current?.setTimeout(callbackId, delayMs);
1005
+ },
1006
+ _setInterval: (callbackId, intervalMs) => {
1007
+ bridgeRef.current?.setInterval(callbackId, intervalMs);
1008
+ },
1009
+ _clearInterval: (callbackId) => {
1010
+ bridgeRef.current?.clearInterval(callbackId);
1011
+ }
1012
+ }
1013
+ };
1014
+ }
1015
+ }
1016
+
1017
+ // src/kv.ts
21
1018
  var exports_kv = {};
22
1019
  __export(exports_kv, {
1020
+ createMemoryKV: () => createMemoryKV,
23
1021
  createKVImports: () => createKVImports
24
1022
  });
1023
+ function createMemoryKV() {
1024
+ const store = new Map;
1025
+ return {
1026
+ async get(key) {
1027
+ return store.get(key) ?? null;
1028
+ },
1029
+ async put(key, value) {
1030
+ store.set(key, value);
1031
+ },
1032
+ async delete(key) {
1033
+ store.delete(key);
1034
+ },
1035
+ async list(options) {
1036
+ const keys = [...store.keys()].filter((k) => !options?.prefix || k.startsWith(options.prefix)).map((name) => ({ name }));
1037
+ return { keys };
1038
+ }
1039
+ };
1040
+ }
25
1041
  function createKVImports(bindings, getMemory) {
26
- const encoder = new TextEncoder;
27
- const decoder = new TextDecoder;
1042
+ const encoder3 = new TextEncoder;
1043
+ const decoder3 = new TextDecoder;
28
1044
  function readStr(ptr, len) {
29
- return decoder.decode(new Uint8Array(getMemory().buffer, ptr, len));
1045
+ return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
30
1046
  }
31
- function writeBytes(buf_ptr, buf_max, data) {
1047
+ function writeBytes2(buf_ptr, buf_max, data) {
32
1048
  if (data.length > buf_max)
33
1049
  return -2;
34
1050
  new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
@@ -38,6 +1054,14 @@ function createKVImports(bindings, getMemory) {
38
1054
  return bindings[ns] ?? bindings["default"] ?? null;
39
1055
  }
40
1056
  const Suspending = WebAssembly.Suspending;
1057
+ if (typeof Suspending !== "function") {
1058
+ return {
1059
+ kv_get: (_ns, _nsLen, _key, _keyLen, _buf, _max) => -1,
1060
+ kv_put: (_ns, _nsLen, _key, _keyLen, _val, _valLen) => 0,
1061
+ kv_delete: (_ns, _nsLen, _key, _keyLen) => 0,
1062
+ kv_list: (_ns, _nsLen, _pfx, _pfxLen, buf_ptr, buf_max) => writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"))
1063
+ };
1064
+ }
41
1065
  return {
42
1066
  kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
43
1067
  const b = binding(readStr(ns_ptr, ns_len));
@@ -46,7 +1070,7 @@ function createKVImports(bindings, getMemory) {
46
1070
  const value = await b.get(readStr(key_ptr, key_len));
47
1071
  if (value === null)
48
1072
  return -1;
49
- return writeBytes(buf_ptr, buf_max, encoder.encode(value));
1073
+ return writeBytes2(buf_ptr, buf_max, encoder3.encode(value));
50
1074
  }),
51
1075
  kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len) => {
52
1076
  const b = binding(readStr(ns_ptr, ns_len));
@@ -65,15 +1089,15 @@ function createKVImports(bindings, getMemory) {
65
1089
  kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
66
1090
  const b = binding(readStr(ns_ptr, ns_len));
67
1091
  if (!b)
68
- return writeBytes(buf_ptr, buf_max, encoder.encode("[]"));
1092
+ return writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"));
69
1093
  const prefix = readStr(prefix_ptr, prefix_len);
70
1094
  const result = await b.list(prefix.length > 0 ? { prefix } : undefined);
71
- return writeBytes(buf_ptr, buf_max, encoder.encode(JSON.stringify(result.keys.map((k) => k.name))));
1095
+ return writeBytes2(buf_ptr, buf_max, encoder3.encode(JSON.stringify(result.keys.map((k) => k.name))));
72
1096
  })
73
1097
  };
74
1098
  }
75
1099
 
76
- // src/cloudflare/worker.ts
1100
+ // src/wasi.ts
77
1101
  class ProcExit extends Error {
78
1102
  code;
79
1103
  constructor(code) {
@@ -83,10 +1107,10 @@ class ProcExit extends Error {
83
1107
  }
84
1108
  function createWasiImports({
85
1109
  request,
86
- stdinData
1110
+ stdinData,
1111
+ onStdout
87
1112
  }) {
88
- const encoder = new TextEncoder;
89
- const decoder = new TextDecoder;
1113
+ const encoder3 = new TextEncoder;
90
1114
  const url = new URL(request.url);
91
1115
  const argStrings = [
92
1116
  "wasm",
@@ -97,19 +1121,34 @@ function createWasiImports({
97
1121
  "--search",
98
1122
  url.search
99
1123
  ];
100
- for (const name of FORWARDED_HEADERS) {
101
- const value = request.headers.get(name);
1124
+ request.headers.forEach((value, name) => {
102
1125
  if (value)
103
1126
  argStrings.push("--header", `${name}:${value}`);
104
- }
105
- const encodedArgs = argStrings.map((a) => encoder.encode(a + "\x00"));
1127
+ });
1128
+ const encodedArgs = argStrings.map((a) => encoder3.encode(a + "\x00"));
106
1129
  const argBufSize = encodedArgs.reduce((s, a) => s + a.length, 0);
107
1130
  let wasmMemory = null;
108
1131
  const setMemory = (m2) => {
109
1132
  wasmMemory = m2;
110
1133
  };
111
1134
  const stdoutChunks = [];
112
- const stderrChunks = [];
1135
+ let stderrMeta = "";
1136
+ let stderrPartial = "";
1137
+ const stderrDecoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
1138
+ function processStderrChunk(chunk) {
1139
+ const text = stderrDecoder.decode(chunk, { stream: true });
1140
+ const lines = (stderrPartial + text).split(`
1141
+ `);
1142
+ stderrPartial = lines.pop() ?? "";
1143
+ for (const line of lines) {
1144
+ if (line.startsWith("__EDGE_META__:")) {
1145
+ stderrMeta += line + `
1146
+ `;
1147
+ } else if (line.length > 0) {
1148
+ console.error("[ziex]", line);
1149
+ }
1150
+ }
1151
+ }
113
1152
  let stdinOffset = 0;
114
1153
  function v() {
115
1154
  return new DataView(wasmMemory.buffer);
@@ -151,10 +1190,13 @@ function createWasiImports({
151
1190
  const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
152
1191
  const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
153
1192
  const chunk = mem.slice(buf_ptr, buf_ptr + buf_len);
154
- if (fd === 1)
155
- stdoutChunks.push(chunk);
156
- else if (fd === 2)
157
- stderrChunks.push(chunk);
1193
+ if (fd === 1) {
1194
+ if (onStdout)
1195
+ onStdout(chunk);
1196
+ else
1197
+ stdoutChunks.push(chunk);
1198
+ } else if (fd === 2)
1199
+ processStderrChunk(chunk);
158
1200
  written += buf_len;
159
1201
  }
160
1202
  dv.setUint32(nwritten_ptr, written, true);
@@ -262,67 +1304,150 @@ function createWasiImports({
262
1304
  fd_readdir(_fd, _buf, _buf_len, _cookie, bufused_ptr) {
263
1305
  v().setUint32(bufused_ptr, 0, true);
264
1306
  return 76;
1307
+ },
1308
+ poll_oneoff(_in, _out, _nsubscriptions, nevents_ptr) {
1309
+ v().setUint32(nevents_ptr, 0, true);
1310
+ return 0;
265
1311
  }
266
1312
  };
267
1313
  function collectOutput() {
1314
+ const remaining = stderrDecoder.decode(undefined, { stream: false });
1315
+ const tail = stderrPartial + remaining;
1316
+ if (tail.length > 0) {
1317
+ if (tail.startsWith("__EDGE_META__:"))
1318
+ stderrMeta += tail;
1319
+ else
1320
+ console.error("[ziex]", tail);
1321
+ stderrPartial = "";
1322
+ }
268
1323
  return {
269
1324
  stdout: mergeUint8Arrays(stdoutChunks),
270
- stderrText: decoder.decode(mergeUint8Arrays(stderrChunks))
1325
+ stderrText: stderrMeta
271
1326
  };
272
1327
  }
273
1328
  return { wasiImport, setMemory, collectOutput };
274
1329
  }
275
- function buildResponse({
276
- stdout,
277
- stderrText
278
- }) {
279
- const meta = parseEdgeMeta(stderrText);
280
- return new Response(stdout.buffer, {
281
- status: meta.status,
282
- headers: meta.headers
283
- });
1330
+ function mergeUint8Arrays(arrays) {
1331
+ const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
1332
+ const result = new Uint8Array(totalLen);
1333
+ let offset = 0;
1334
+ for (const arr of arrays) {
1335
+ result.set(arr, offset);
1336
+ offset += arr.length;
1337
+ }
1338
+ return result;
284
1339
  }
285
- async function run({
286
- request,
287
- env,
288
- ctx,
289
- module,
290
- kv: kvBindings,
291
- imports
292
- }) {
293
- const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : undefined;
294
- const { wasiImport, setMemory, collectOutput } = createWasiImports({ request, stdinData });
295
- let wasmMemory = null;
296
- const mem = () => wasmMemory;
297
- const instance = new WebAssembly.Instance(module, {
298
- wasi_snapshot_preview1: wasiImport,
299
- ...kvBindings ? { __zx_kv: createKVImports(kvBindings, mem) } : {},
300
- ...imports ? imports(mem) : {}
1340
+
1341
+ // src/runtime.ts
1342
+ function buildWsImports(Suspending, mem, decoder3, ws) {
1343
+ const readStr = (ptr, len) => decoder3.decode(new Uint8Array(mem().buffer, ptr, len));
1344
+ return {
1345
+ ws_upgrade: () => {
1346
+ ws.upgraded = true;
1347
+ },
1348
+ ws_write: (ptr, len) => {
1349
+ const data = new Uint8Array(mem().buffer, ptr, len).slice();
1350
+ if (!ws.server) {
1351
+ ws.pendingWrites.push(data);
1352
+ } else {
1353
+ ws.server.send(data);
1354
+ }
1355
+ },
1356
+ ws_close: (code, reason_ptr, reason_len) => {
1357
+ ws.server?.close(code, decoder3.decode(new Uint8Array(mem().buffer, reason_ptr, reason_len)));
1358
+ },
1359
+ ws_recv: Suspending ? new Suspending(async (buf_ptr, buf_max) => {
1360
+ if (ws._resolveFirstSuspend) {
1361
+ const fn = ws._resolveFirstSuspend;
1362
+ ws._resolveFirstSuspend = undefined;
1363
+ fn();
1364
+ }
1365
+ const deliver = (bytes) => {
1366
+ if (bytes === null)
1367
+ return -1;
1368
+ const n = Math.min(bytes.length, buf_max);
1369
+ new Uint8Array(mem().buffer, buf_ptr, n).set(bytes.subarray(0, n));
1370
+ return n;
1371
+ };
1372
+ if (ws.messageQueue.length > 0)
1373
+ return deliver(ws.messageQueue.shift());
1374
+ return new Promise((resolve) => {
1375
+ ws.recvResolve = (bytes) => resolve(deliver(bytes));
1376
+ });
1377
+ }) : (_buf_ptr, _buf_max) => -1,
1378
+ ws_subscribe: (ptr, len) => {
1379
+ ws.subscribe?.(readStr(ptr, len));
1380
+ },
1381
+ ws_unsubscribe: (ptr, len) => {
1382
+ ws.unsubscribe?.(readStr(ptr, len));
1383
+ },
1384
+ ws_publish: (topic_ptr, topic_len, data_ptr, data_len) => {
1385
+ const topic = readStr(topic_ptr, topic_len);
1386
+ const data = new Uint8Array(mem().buffer, data_ptr, data_len).slice();
1387
+ return ws.publish?.(topic, data) ?? 0;
1388
+ },
1389
+ ws_is_subscribed: (ptr, len) => ws.isSubscribed?.(readStr(ptr, len)) ? 1 : 0
1390
+ };
1391
+ }
1392
+ function attachWebSocket(ws) {
1393
+ const WebSocketPairCtor = globalThis.WebSocketPair;
1394
+ const pair = new WebSocketPairCtor;
1395
+ const client = pair[0];
1396
+ const server = pair[1];
1397
+ ws.server = server;
1398
+ server.accept();
1399
+ for (const data of ws.pendingWrites)
1400
+ server.send(data);
1401
+ ws.pendingWrites = [];
1402
+ server.addEventListener("message", (event) => {
1403
+ const data = typeof event.data === "string" ? new TextEncoder().encode(event.data) : new Uint8Array(event.data);
1404
+ if (ws.recvResolve) {
1405
+ const res = ws.recvResolve;
1406
+ ws.recvResolve = null;
1407
+ res(data);
1408
+ } else {
1409
+ ws.messageQueue.push(data);
1410
+ }
301
1411
  });
302
- wasmMemory = instance.exports.memory;
303
- setMemory(wasmMemory);
304
- const start = WebAssembly.promising(instance.exports._start);
305
- try {
306
- await start();
307
- } catch (e) {
308
- if (!(e instanceof Error) || !e.message.startsWith("proc_exit"))
309
- throw e;
1412
+ server.addEventListener("close", () => {
1413
+ if (ws.recvResolve) {
1414
+ const res = ws.recvResolve;
1415
+ ws.recvResolve = null;
1416
+ res(null);
1417
+ }
1418
+ });
1419
+ return { client };
1420
+ }
1421
+ function buildSysImports(jspi, Suspending) {
1422
+ return {
1423
+ sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {}
1424
+ };
1425
+ }
1426
+ function executeWasm(instance, jspi, Suspending, wsState) {
1427
+ if (!jspi) {
1428
+ try {
1429
+ instance.exports._start();
1430
+ } catch (e) {
1431
+ if (!(e instanceof ProcExit))
1432
+ throw e;
1433
+ }
1434
+ return Promise.resolve();
310
1435
  }
311
- return buildResponse(collectOutput());
1436
+ const start = WebAssembly.promising(instance.exports._start);
1437
+ return start().catch((e) => {
1438
+ if (e instanceof Error && e.message.startsWith("proc_exit"))
1439
+ return;
1440
+ throw e;
1441
+ }).finally(() => {
1442
+ if (wsState.recvResolve) {
1443
+ const res = wsState.recvResolve;
1444
+ wsState.recvResolve = null;
1445
+ res(null);
1446
+ }
1447
+ });
312
1448
  }
313
- var FORWARDED_HEADERS = [
314
- "content-type",
315
- "accept",
316
- "authorization",
317
- "cookie",
318
- "user-agent",
319
- "referer",
320
- "x-forwarded-for",
321
- "x-forwarded-proto",
322
- "x-real-ip"
323
- ];
324
1449
  function parseEdgeMeta(stderrText) {
325
- const meta = { status: 200, headers: new Headers };
1450
+ const meta = { status: 200, headers: new Headers, streaming: false };
326
1451
  const metaPrefix = "__EDGE_META__:";
327
1452
  const metaLine = stderrText.split(`
328
1453
  `).find((line) => line.startsWith(metaPrefix));
@@ -331,6 +1456,8 @@ function parseEdgeMeta(stderrText) {
331
1456
  const parsed = JSON.parse(metaLine.slice(metaPrefix.length));
332
1457
  if (parsed.status)
333
1458
  meta.status = parsed.status;
1459
+ if (parsed.streaming === true)
1460
+ meta.streaming = true;
334
1461
  if (Array.isArray(parsed.headers)) {
335
1462
  for (const [name, value] of parsed.headers) {
336
1463
  meta.headers.append(name, value);
@@ -340,72 +1467,241 @@ function parseEdgeMeta(stderrText) {
340
1467
  }
341
1468
  return meta;
342
1469
  }
343
- function mergeUint8Arrays(arrays) {
344
- const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
345
- const result = new Uint8Array(totalLen);
346
- let offset = 0;
347
- for (const arr of arrays) {
348
- result.set(arr, offset);
349
- offset += arr.length;
1470
+ async function run({
1471
+ request,
1472
+ env,
1473
+ ctx,
1474
+ module,
1475
+ kv: kvBindings,
1476
+ imports,
1477
+ wasi,
1478
+ websocket: doNamespace
1479
+ }) {
1480
+ if (doNamespace && request.headers.get("upgrade")?.toLowerCase() === "websocket") {
1481
+ const id = doNamespace.idFromName(new URL(request.url).pathname);
1482
+ return doNamespace.get(id).fetch(request);
350
1483
  }
351
- return result;
1484
+ const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : undefined;
1485
+ const stdoutChunks = [];
1486
+ let streamWriter = null;
1487
+ const { wasiImport, setMemory, collectOutput } = createWasiImports({
1488
+ request,
1489
+ stdinData,
1490
+ onStdout: (chunk) => {
1491
+ if (streamWriter)
1492
+ streamWriter.write(chunk);
1493
+ else
1494
+ stdoutChunks.push(chunk);
1495
+ }
1496
+ });
1497
+ let wasmMemory = null;
1498
+ const mem = () => wasmMemory;
1499
+ const bridgeRef = { current: null };
1500
+ const Suspending = WebAssembly.Suspending;
1501
+ const jspi = typeof Suspending === "function";
1502
+ const wsState = {
1503
+ upgraded: false,
1504
+ server: null,
1505
+ pendingWrites: [],
1506
+ messageQueue: [],
1507
+ recvResolve: null
1508
+ };
1509
+ const instance = new WebAssembly.Instance(module, {
1510
+ wasi_snapshot_preview1: { ...wasi?.wasiImport, ...wasiImport },
1511
+ __zx_sys: buildSysImports(jspi, Suspending),
1512
+ __zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder, wsState),
1513
+ __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
1514
+ ...imports ? imports(mem) : {},
1515
+ ...ZxWasiBridge.createImportObject(bridgeRef)
1516
+ });
1517
+ wasmMemory = instance.exports.memory;
1518
+ setMemory(wasmMemory);
1519
+ bridgeRef.current = new ZxWasiBridge(instance.exports);
1520
+ const wasmPromise = executeWasm(instance, jspi, Suspending, wsState);
1521
+ if (wsState.upgraded) {
1522
+ const server = attachWebSocket(wsState);
1523
+ ctx?.waitUntil(wasmPromise);
1524
+ return new Response(null, { status: 101, webSocket: server.client });
1525
+ }
1526
+ const { stderrText } = collectOutput();
1527
+ const meta = parseEdgeMeta(stderrText);
1528
+ if (meta.streaming) {
1529
+ const { readable, writable } = new TransformStream;
1530
+ streamWriter = writable.getWriter();
1531
+ for (const chunk of stdoutChunks)
1532
+ streamWriter.write(chunk);
1533
+ stdoutChunks.length = 0;
1534
+ wasmPromise.finally(() => streamWriter?.close());
1535
+ return new Response(readable, { status: meta.status, headers: meta.headers });
1536
+ }
1537
+ await wasmPromise;
1538
+ const body = mergeUint8Arrays(stdoutChunks);
1539
+ meta.headers.delete("transfer-encoding");
1540
+ if (!meta.headers.has("content-length"))
1541
+ meta.headers.set("content-length", String(body.byteLength));
1542
+ return new Response(body.buffer, { status: meta.status, headers: meta.headers });
352
1543
  }
353
- async function collectStream(readable, chunks) {
354
- const reader = readable.getReader();
355
- while (true) {
356
- const { done, value } = await reader.read();
357
- if (done)
358
- break;
359
- if (value)
360
- chunks.push(value);
1544
+ // src/app.ts
1545
+ async function resolveModule(input) {
1546
+ if (typeof input === "string") {
1547
+ if (input.startsWith("http://") || input.startsWith("https://")) {
1548
+ return WebAssembly.compileStreaming(fetch(input));
1549
+ }
1550
+ const url = input.startsWith("/") ? `file://${input}` : input;
1551
+ return WebAssembly.compile(await fetch(url).then((r) => r.arrayBuffer()));
1552
+ }
1553
+ if (input instanceof URL) {
1554
+ return WebAssembly.compileStreaming(fetch(input));
1555
+ }
1556
+ if (input instanceof Response) {
1557
+ return WebAssembly.compileStreaming(input);
1558
+ }
1559
+ if (input instanceof ArrayBuffer) {
1560
+ return WebAssembly.compile(input);
361
1561
  }
1562
+ if (ArrayBuffer.isView(input)) {
1563
+ return WebAssembly.compile(input.buffer);
1564
+ }
1565
+ return input;
362
1566
  }
363
- function prepare({
364
- request,
365
- env,
366
- ctx
367
- }) {
368
- const stdout = new TransformStream;
369
- const stderr = new TransformStream;
370
- const url = new URL(request.url);
371
- const args = [
372
- "--pathname",
373
- url.pathname,
374
- "--method",
375
- request.method,
376
- "--search",
377
- url.search
378
- ];
379
- for (const name of FORWARDED_HEADERS) {
380
- const value = request.headers.get(name);
381
- if (value) {
382
- args.push("--header", `${name}:${value}`);
1567
+
1568
+ class Ziex {
1569
+ options;
1570
+ resolved = null;
1571
+ constructor(options) {
1572
+ this.options = options;
1573
+ }
1574
+ async getModule() {
1575
+ if (!this.resolved)
1576
+ this.resolved = await resolveModule(this.options.module);
1577
+ return this.resolved;
1578
+ }
1579
+ resolveKV(env) {
1580
+ const { kv } = this.options;
1581
+ if (kv === undefined)
1582
+ return;
1583
+ if (typeof kv === "object" && kv !== null) {
1584
+ const result = {};
1585
+ for (const [name, key] of Object.entries(kv)) {
1586
+ result[name] = env[key];
1587
+ }
1588
+ return result;
383
1589
  }
1590
+ return { default: env[kv] };
384
1591
  }
385
- const stdin = request.body ?? undefined;
386
- return { args, stdout, stderr, stdin };
1592
+ fetch = async (request, env, ctx) => {
1593
+ const module = await this.getModule();
1594
+ const { wasi, imports, websocket } = this.options;
1595
+ return run({
1596
+ request,
1597
+ env,
1598
+ ctx,
1599
+ module,
1600
+ wasi,
1601
+ imports,
1602
+ kv: this.resolveKV(env),
1603
+ websocket: websocket !== undefined ? env[websocket] : undefined
1604
+ });
1605
+ };
387
1606
  }
388
- async function respond({
389
- exec,
390
- stdout,
391
- stderr
392
- }) {
393
- const stdoutChunks = [];
394
- const stderrChunks = [];
395
- const stderrReadable = stderr instanceof ReadableStream ? stderr : stderr.readable;
396
- await Promise.all([
397
- exec,
398
- collectStream(stdout.readable, stdoutChunks),
399
- collectStream(stderrReadable, stderrChunks)
400
- ]);
401
- const stderrText = new TextDecoder().decode(mergeUint8Arrays(stderrChunks));
402
- const meta = parseEdgeMeta(stderrText);
403
- return new Response(mergeUint8Arrays(stdoutChunks).buffer, {
404
- status: meta.status,
405
- headers: meta.headers
406
- });
1607
+ // src/cloudflare/do.ts
1608
+ function createWebSocketDO(module, options) {
1609
+ return class ZxWebSocketDO {
1610
+ doState;
1611
+ env;
1612
+ connections = new Map;
1613
+ constructor(state, env) {
1614
+ this.doState = state;
1615
+ this.env = env;
1616
+ }
1617
+ async fetch(request) {
1618
+ const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : undefined;
1619
+ const { wasiImport, setMemory } = createWasiImports({ request, stdinData });
1620
+ let wasmMemory = null;
1621
+ const mem = () => wasmMemory;
1622
+ const bridgeRef = { current: null };
1623
+ const bridgeImports = ZxBridge.createImportObject(bridgeRef);
1624
+ const Suspending = WebAssembly.Suspending;
1625
+ const jspi = typeof Suspending === "function";
1626
+ const decoder3 = new TextDecoder;
1627
+ let _resolveFirstSuspend;
1628
+ const firstSuspendPromise = new Promise((resolve) => {
1629
+ _resolveFirstSuspend = resolve;
1630
+ });
1631
+ let wasmExited = false;
1632
+ const connState = {
1633
+ upgraded: false,
1634
+ server: null,
1635
+ pendingWrites: [],
1636
+ messageQueue: [],
1637
+ recvResolve: null,
1638
+ _resolveFirstSuspend,
1639
+ topics: new Set,
1640
+ subscribe: (topic) => connState.topics.add(topic),
1641
+ unsubscribe: (topic) => connState.topics.delete(topic),
1642
+ publish: (topic, data) => {
1643
+ let count = 0;
1644
+ for (const [ws, conn] of this.connections) {
1645
+ if (conn.topics.has(topic)) {
1646
+ try {
1647
+ ws.send(data);
1648
+ count++;
1649
+ } catch {}
1650
+ }
1651
+ }
1652
+ if (!connState.server && connState.topics.has(topic)) {
1653
+ connState.pendingWrites.push(data.slice());
1654
+ count++;
1655
+ }
1656
+ return count;
1657
+ },
1658
+ isSubscribed: (topic) => connState.topics.has(topic)
1659
+ };
1660
+ const sysImports = {
1661
+ sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {}
1662
+ };
1663
+ const wsImports = buildWsImports(jspi ? Suspending : null, mem, decoder3, connState);
1664
+ const kvBindings = options?.kv?.(this.env);
1665
+ const instance = new WebAssembly.Instance(module, {
1666
+ wasi_snapshot_preview1: wasiImport,
1667
+ __zx_sys: sysImports,
1668
+ __zx_ws: wsImports,
1669
+ __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
1670
+ ...options?.imports ? options.imports(mem) : {},
1671
+ ...bridgeImports
1672
+ });
1673
+ wasmMemory = instance.exports.memory;
1674
+ setMemory(wasmMemory);
1675
+ bridgeRef.current = new ZxBridge(instance.exports);
1676
+ const start = WebAssembly.promising(instance.exports._start);
1677
+ const wasmPromise = start().catch((e) => {
1678
+ wasmExited = true;
1679
+ if (e instanceof Error && e.message.startsWith("proc_exit"))
1680
+ return;
1681
+ console.error("[ZxWebSocketDO] WASM error:", e);
1682
+ }).finally(() => {
1683
+ if (connState.server)
1684
+ this.connections.delete(connState.server);
1685
+ if (connState.recvResolve) {
1686
+ const res = connState.recvResolve;
1687
+ connState.recvResolve = null;
1688
+ res(null);
1689
+ }
1690
+ });
1691
+ await Promise.race([firstSuspendPromise, wasmPromise]);
1692
+ if (!connState.upgraded || wasmExited) {
1693
+ return new Response("WebSocket upgrade expected", { status: 426 });
1694
+ }
1695
+ const { client } = attachWebSocket(connState);
1696
+ this.connections.set(connState.server, connState);
1697
+ this.doState.waitUntil(wasmPromise);
1698
+ return new Response(null, { status: 101, webSocket: client });
1699
+ }
1700
+ };
407
1701
  }
408
1702
  export {
409
- exports_worker as worker,
410
- exports_kv as kv
1703
+ exports_runtime as worker,
1704
+ exports_kv as kv,
1705
+ createWebSocketDO,
1706
+ Ziex
411
1707
  };