ziex 0.1.0-dev.1466 → 0.1.0-dev.1568

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.
@@ -1,257 +1,3 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/runtime/index.ts
8
- var runtime_exports = {};
9
- __export(runtime_exports, {
10
- attachWebSocket: () => attachWebSocket,
11
- buildWsImports: () => buildWsImports,
12
- run: () => run
13
- });
14
-
15
- // src/wasm/constants.ts
16
- var DOM_CMD_HEADER_SIZE = 8;
17
- var DOM_CMD_RECORD_SIZE = 24;
18
- var DomOp_CreateElement = 1;
19
- var DomOp_CreateText = 2;
20
- var DomOp_HydrateInsert = 3;
21
- var DomOp_SetAttr = 4;
22
- var DomOp_SetProp = 5;
23
- var DomOp_RemoveAttr = 6;
24
- var DomOp_SetNodeValue = 7;
25
- var DomOp_SetInnerHtml = 8;
26
- var DomOp_AppendChild = 9;
27
- var DomOp_InsertBefore = 10;
28
- var DomOp_RemoveChild = 11;
29
- var DomOp_ReplaceChild = 12;
30
- var CallbackType_FetchSuccess = 1;
31
- var CallbackType_FetchError = 2;
32
- var CallbackType_Timeout = 3;
33
- var CallbackType_Interval = 4;
34
- var CallbackType_WebSocketOpen = 5;
35
- var CallbackType_WebSocketMessage = 6;
36
- var CallbackType_WebSocketError = 7;
37
- var CallbackType_WebSocketClose = 8;
38
-
39
- // src/wasm/wasi.ts
40
- var decoder = new TextDecoder();
41
- var encoder = new TextEncoder();
42
- var ZxWasiBridge = class {
43
- #alloc;
44
- #memory;
45
- #cb;
46
- #intervals = /* @__PURE__ */ new Map();
47
- // Cached memory view - invalidated when the WASM buffer grows.
48
- #memView = null;
49
- #memBuf = null;
50
- constructor(exports) {
51
- this.#memory = exports.memory;
52
- this.#alloc = exports.__zx_alloc;
53
- this.#cb = exports.__zx_cb;
54
- }
55
- #view() {
56
- const buf = this.#memory.buffer;
57
- if (buf !== this.#memBuf) {
58
- this.#memBuf = buf;
59
- this.#memView = new Uint8Array(buf);
60
- }
61
- return this.#memView;
62
- }
63
- #readString(ptr, len) {
64
- const start = ptr >>> 0;
65
- const length = len >>> 0;
66
- if (length === 0) return "";
67
- const view = this.#view();
68
- if (start + length > view.byteLength) return "";
69
- return decoder.decode(view.subarray(start, start + length));
70
- }
71
- #writeBytes(ptr, data) {
72
- const start = ptr >>> 0;
73
- const view = this.#view();
74
- if (start + data.length > view.byteLength) return;
75
- view.set(data, start);
76
- }
77
- #invoke(type, id, a = 0n, b = 0n, c = 0n) {
78
- this.#cb?.(type, id, a, b, c);
79
- }
80
- log(level, ptr, len) {
81
- const msg = decoder.decode(this.#view().subarray(ptr, ptr + len));
82
- switch (level) {
83
- case 0:
84
- console.error(msg);
85
- break;
86
- case 1:
87
- console.warn(msg);
88
- break;
89
- case 3:
90
- console.debug(msg);
91
- break;
92
- default:
93
- console.log(msg);
94
- break;
95
- }
96
- }
97
- fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
98
- const url = this.#readString(urlPtr, urlLen);
99
- const method = methodLen > 0 ? this.#readString(methodPtr, methodLen) : "GET";
100
- const headersJson = headersLen > 0 ? this.#readString(headersPtr, headersLen) : "{}";
101
- const body = bodyLen > 0 ? this.#view().subarray(bodyPtr, bodyPtr + bodyLen) : void 0;
102
- let headers = {};
103
- try {
104
- headers = JSON.parse(headersJson);
105
- } catch {
106
- for (const line of headersJson.split("\n")) {
107
- const i = line.indexOf(":");
108
- if (i > 0) headers[line.slice(0, i)] = line.slice(i + 1);
109
- }
110
- }
111
- const controller = new AbortController();
112
- const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
113
- fetch(url, {
114
- method,
115
- headers: Object.keys(headers).length > 0 ? headers : void 0,
116
- body: method !== "GET" && method !== "HEAD" ? body : void 0,
117
- signal: controller.signal
118
- }).then(async (res) => {
119
- if (timeout) clearTimeout(timeout);
120
- const bytes = new Uint8Array(await res.arrayBuffer());
121
- this.#notifyFetchComplete(fetchId, res.status, bytes, false);
122
- }).catch((err) => {
123
- if (timeout) clearTimeout(timeout);
124
- const msg = err.name === "AbortError" ? "Request timeout" : err.message ?? "Fetch failed";
125
- this.#notifyFetchComplete(fetchId, 0, msg, true);
126
- });
127
- }
128
- #notifyFetchComplete(fetchId, status, body, isError) {
129
- const encoded = typeof body === "string" ? encoder.encode(body) : body;
130
- const ptr = this.#alloc(encoded.length);
131
- this.#writeBytes(ptr, encoded);
132
- const type = isError ? CallbackType_FetchError : CallbackType_FetchSuccess;
133
- this.#invoke(type, fetchId, BigInt(status), BigInt(ptr), BigInt(encoded.length));
134
- }
135
- setTimeout(callbackId, delayMs) {
136
- setTimeout(() => this.#invoke(CallbackType_Timeout, callbackId), delayMs);
137
- }
138
- setInterval(callbackId, intervalMs) {
139
- const handle = setInterval(() => this.#invoke(CallbackType_Interval, callbackId), intervalMs);
140
- this.#intervals.set(callbackId, handle);
141
- }
142
- clearInterval(callbackId) {
143
- const handle = this.#intervals.get(callbackId);
144
- if (handle !== void 0) {
145
- clearInterval(handle);
146
- this.#intervals.delete(callbackId);
147
- }
148
- }
149
- /**
150
- * Create the WASI import object for WASM instantiation.
151
- *
152
- * Returns only the `__zx` namespace (log, fetch, timers).
153
- * Does NOT include jsz.importObject() - the server binary does not use jsz.
154
- */
155
- static createImportObject(bridgeRef) {
156
- return {
157
- __zx: {
158
- _log: (level, ptr, len) => {
159
- bridgeRef[0]?.log(level, ptr, len);
160
- },
161
- _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
162
- bridgeRef[0]?.fetchAsync(
163
- urlPtr,
164
- urlLen,
165
- methodPtr,
166
- methodLen,
167
- headersPtr,
168
- headersLen,
169
- bodyPtr,
170
- bodyLen,
171
- timeoutMs,
172
- fetchId
173
- );
174
- },
175
- _setTimeout: (callbackId, delayMs) => {
176
- bridgeRef[0]?.setTimeout(callbackId, delayMs);
177
- },
178
- _setInterval: (callbackId, intervalMs) => {
179
- bridgeRef[0]?.setInterval(callbackId, intervalMs);
180
- },
181
- _clearInterval: (callbackId) => {
182
- bridgeRef[0]?.clearInterval(callbackId);
183
- }
184
- }
185
- };
186
- }
187
- };
188
-
189
- // src/runtime/fetch.ts
190
- function createFetchImports(getMemory) {
191
- const encoder3 = new TextEncoder();
192
- const decoder3 = new TextDecoder();
193
- function readStr(ptr, len) {
194
- return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
195
- }
196
- function writeBytes2(buf_ptr, buf_max, data) {
197
- if (data.length > buf_max) return -2;
198
- new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
199
- return data.length;
200
- }
201
- function readBytes(ptr, len) {
202
- return new Uint8Array(getMemory().buffer, ptr, len);
203
- }
204
- function parseHeaders(headersJson) {
205
- let headers = {};
206
- try {
207
- headers = JSON.parse(headersJson);
208
- } catch {
209
- for (const line of headersJson.split("\n")) {
210
- const colonIdx = line.indexOf(":");
211
- if (colonIdx > 0) {
212
- headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
213
- }
214
- }
215
- }
216
- return headers;
217
- }
218
- async function doFetch(url_ptr, url_len, method_ptr, method_len, headers_ptr, headers_len, body_ptr, body_len, timeout_ms, status_out, buf_ptr, buf_max) {
219
- const url = readStr(url_ptr, url_len);
220
- const method = method_len > 0 ? readStr(method_ptr, method_len) : "GET";
221
- const headersJson = headers_len > 0 ? readStr(headers_ptr, headers_len) : "{}";
222
- const body = body_len > 0 ? readBytes(body_ptr, body_len) : void 0;
223
- const headers = parseHeaders(headersJson);
224
- const controller = new AbortController();
225
- const timeout = timeout_ms > 0 ? setTimeout(() => controller.abort(), timeout_ms) : null;
226
- try {
227
- const response = await fetch(url, {
228
- method,
229
- headers: Object.keys(headers).length > 0 ? headers : void 0,
230
- body: method !== "GET" && method !== "HEAD" ? body : void 0,
231
- signal: controller.signal
232
- });
233
- if (timeout) clearTimeout(timeout);
234
- new DataView(getMemory().buffer).setUint16(status_out, response.status, true);
235
- const bytes = new Uint8Array(await response.arrayBuffer());
236
- return writeBytes2(buf_ptr, buf_max, bytes);
237
- } catch (err) {
238
- if (timeout) clearTimeout(timeout);
239
- const msg = err instanceof Error ? err.message : String(err);
240
- console.error(`wasm fetch failed: ${url} (${msg})`);
241
- return -1;
242
- }
243
- }
244
- const Suspending = WebAssembly.Suspending;
245
- if (typeof Suspending !== "function") {
246
- return {
247
- fetch: (_url_ptr, _url_len, _method_ptr, _method_len, _headers_ptr, _headers_len, _body_ptr, _body_len, _timeout_ms, _status_out, _buf_ptr, _buf_max) => -1
248
- };
249
- }
250
- return {
251
- fetch: new Suspending(doFetch)
252
- };
253
- }
254
-
255
1
  // ../../vendor/jsz/js/src/zigjs.ts
256
2
  var NAN_PREFIX = 2146959360;
257
3
  var predefined = {
@@ -264,8 +10,8 @@ var predefined = {
264
10
  "runtime": 6
265
11
  };
266
12
  var PREDEFINED_ID_MAX = 6;
267
- var encoder2 = new TextEncoder();
268
- var decoder2 = new TextDecoder("utf-8");
13
+ var encoder = new TextEncoder();
14
+ var decoder = new TextDecoder("utf-8");
269
15
  var ZigJS = class {
270
16
  constructor() {
271
17
  /**
@@ -349,7 +95,7 @@ var ZigJS = class {
349
95
  * */
350
96
  valueStringLen(id) {
351
97
  const val = this.loadValue(id);
352
- const buf = encoder2.encode(val);
98
+ const buf = encoder.encode(val);
353
99
  return buf.byteLength;
354
100
  }
355
101
  /**
@@ -361,7 +107,7 @@ var ZigJS = class {
361
107
  const cap = max >>> 0;
362
108
  const val = this.loadValue(id);
363
109
  if (typeof val !== "string") return;
364
- const bytes = encoder2.encode(val);
110
+ const bytes = encoder.encode(val);
365
111
  if (bytes.byteLength > cap || bytes.length === 0) return;
366
112
  const buf = this.memory.buffer;
367
113
  if (dest + bytes.length > buf.byteLength) return;
@@ -497,31 +243,121 @@ var ZigJS = class {
497
243
  if (length === 0 || start + length > buf.byteLength) return "";
498
244
  const arr = new Uint8ClampedArray(buf, start, length);
499
245
  const data = arr.slice();
500
- return decoder2.decode(data);
246
+ return decoder.decode(data);
501
247
  }
502
248
  };
503
249
 
504
- // src/wasm/core.ts
505
- var jsz = new ZigJS();
506
- var tempRefBuffer = new ArrayBuffer(8);
507
- var tempRefView = new DataView(tempRefBuffer);
508
- function storeValueGetRef(val) {
509
- const originalMemory = jsz.memory;
510
- jsz.memory = { buffer: tempRefBuffer };
511
- jsz.storeValue(0, val);
512
- jsz.memory = originalMemory;
513
- return tempRefView.getBigUint64(0, true);
514
- }
515
- function loadValueFromRef(ref) {
516
- tempRefView.setBigUint64(0, ref, true);
517
- const originalMemory = jsz.memory;
518
- jsz.memory = { buffer: tempRefBuffer };
519
- const val = jsz.loadRef(0);
520
- jsz.memory = originalMemory;
521
- return val;
522
- }
523
- function releaseValueRef(ref) {
524
- tempRefView.setBigUint64(0, ref, true);
250
+ // src/runtime/fetch.ts
251
+ function createFetchImports(getMemory) {
252
+ const encoder3 = new TextEncoder();
253
+ const decoder3 = new TextDecoder();
254
+ function readStr2(ptr, len) {
255
+ return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
256
+ }
257
+ function writeBytes2(buf_ptr, buf_max, data) {
258
+ if (data.length > buf_max) return -2;
259
+ new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
260
+ return data.length;
261
+ }
262
+ function readBytes(ptr, len) {
263
+ return new Uint8Array(getMemory().buffer, ptr, len);
264
+ }
265
+ function parseHeaders(headersJson) {
266
+ let headers = {};
267
+ try {
268
+ headers = JSON.parse(headersJson);
269
+ } catch {
270
+ for (const line of headersJson.split("\n")) {
271
+ const colonIdx = line.indexOf(":");
272
+ if (colonIdx > 0) {
273
+ headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
274
+ }
275
+ }
276
+ }
277
+ return headers;
278
+ }
279
+ async function doFetch(url_ptr, url_len, method_ptr, method_len, headers_ptr, headers_len, body_ptr, body_len, timeout_ms, status_out, buf_ptr, buf_max) {
280
+ const url = readStr2(url_ptr, url_len);
281
+ const method = method_len > 0 ? readStr2(method_ptr, method_len) : "GET";
282
+ const headersJson = headers_len > 0 ? readStr2(headers_ptr, headers_len) : "{}";
283
+ const body = body_len > 0 ? readBytes(body_ptr, body_len) : void 0;
284
+ const headers = parseHeaders(headersJson);
285
+ const controller = new AbortController();
286
+ const timeout = timeout_ms > 0 ? setTimeout(() => controller.abort(), timeout_ms) : null;
287
+ try {
288
+ const response = await fetch(url, {
289
+ method,
290
+ headers: Object.keys(headers).length > 0 ? headers : void 0,
291
+ body: method !== "GET" && method !== "HEAD" ? body : void 0,
292
+ signal: controller.signal
293
+ });
294
+ if (timeout) clearTimeout(timeout);
295
+ new DataView(getMemory().buffer).setUint16(status_out, response.status, true);
296
+ const bytes = new Uint8Array(await response.arrayBuffer());
297
+ return writeBytes2(buf_ptr, buf_max, bytes);
298
+ } catch (err) {
299
+ if (timeout) clearTimeout(timeout);
300
+ const msg = err instanceof Error ? err.message : String(err);
301
+ console.error(`wasm fetch failed: ${url} (${msg})`);
302
+ return -1;
303
+ }
304
+ }
305
+ const Suspending2 = WebAssembly.Suspending;
306
+ if (typeof Suspending2 !== "function") {
307
+ return {
308
+ fetch: (_url_ptr, _url_len, _method_ptr, _method_len, _headers_ptr, _headers_len, _body_ptr, _body_len, _timeout_ms, _status_out, _buf_ptr, _buf_max) => -1
309
+ };
310
+ }
311
+ return {
312
+ fetch: new Suspending2(doFetch)
313
+ };
314
+ }
315
+
316
+ // src/wasm/constants.ts
317
+ var DOM_CMD_HEADER_SIZE = 8;
318
+ var DOM_CMD_RECORD_SIZE = 24;
319
+ var DomOp_CreateElement = 1;
320
+ var DomOp_CreateText = 2;
321
+ var DomOp_HydrateInsert = 3;
322
+ var DomOp_SetAttr = 4;
323
+ var DomOp_SetProp = 5;
324
+ var DomOp_RemoveAttr = 6;
325
+ var DomOp_SetNodeValue = 7;
326
+ var DomOp_SetInnerHtml = 8;
327
+ var DomOp_AppendChild = 9;
328
+ var DomOp_InsertBefore = 10;
329
+ var DomOp_RemoveChild = 11;
330
+ var DomOp_ReplaceChild = 12;
331
+ var CallbackType_FetchSuccess = 1;
332
+ var CallbackType_FetchError = 2;
333
+ var CallbackType_Timeout = 3;
334
+ var CallbackType_Interval = 4;
335
+ var CallbackType_WebSocketOpen = 5;
336
+ var CallbackType_WebSocketMessage = 6;
337
+ var CallbackType_WebSocketError = 7;
338
+ var CallbackType_WebSocketClose = 8;
339
+
340
+ // src/wasm/core.ts
341
+ var jsz = new ZigJS();
342
+ var tempRefBuffer = new ArrayBuffer(8);
343
+ var tempRefView = new DataView(tempRefBuffer);
344
+ function storeValueGetRef(val) {
345
+ const originalMemory = jsz.memory;
346
+ jsz.memory = { buffer: tempRefBuffer };
347
+ jsz.storeValue(0, val);
348
+ jsz.memory = originalMemory;
349
+ return tempRefView.getBigUint64(0, true);
350
+ }
351
+ function loadValueFromRef(ref) {
352
+ tempRefView.setBigUint64(0, ref, true);
353
+ const originalMemory = jsz.memory;
354
+ jsz.memory = { buffer: tempRefBuffer };
355
+ const val = jsz.loadRef(0);
356
+ jsz.memory = originalMemory;
357
+ return val;
358
+ }
359
+ function releaseValueRef(ref) {
360
+ tempRefView.setBigUint64(0, ref, true);
525
361
  if (!Number.isNaN(tempRefView.getFloat64(0, true))) return;
526
362
  const id = tempRefView.getUint32(0, true);
527
363
  if (id > 6) jsz.deleteValue(id);
@@ -760,1005 +596,239 @@ function bindWasmAlloc(allocRef, exports) {
760
596
  }
761
597
 
762
598
  // src/runtime/kv/extern.ts
599
+ var Suspending = WebAssembly.Suspending;
600
+ var jspi = typeof Suspending === "function";
601
+ var miss = jspi ? -1 : 0;
763
602
  function putOptions(ttlSeconds) {
764
603
  if (ttlSeconds < 60) return void 0;
765
604
  return { expirationTtl: ttlSeconds };
766
605
  }
606
+ function kvDel(binding, key) {
607
+ const b = binding;
608
+ return (b.del ?? b.delete).call(b, key);
609
+ }
767
610
  function isSyncKVNamespace(binding) {
768
- const candidate = binding;
769
- return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
611
+ return typeof binding.get === "function" && binding.get.constructor.name !== "AsyncFunction";
770
612
  }
771
- function createKVImports(bindings, getMemory, allocRef) {
772
- const encoder3 = new TextEncoder();
773
- const decoder3 = new TextDecoder();
774
- function readStr(ptr, len) {
775
- return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
776
- }
777
- function binding(ns) {
778
- return bindings[ns] ?? bindings["default"] ?? null;
613
+ function listOpts(prefix) {
614
+ return prefix.length > 0 ? { prefix } : void 0;
615
+ }
616
+ function maybeThen(r, f) {
617
+ return r instanceof Promise ? r.then(f) : f(r);
618
+ }
619
+ function readStr(getMemory, ptr, len) {
620
+ return textDecoder.decode(new Uint8Array(getMemory().buffer, ptr, len));
621
+ }
622
+ function resolve(bindings, ns) {
623
+ const b = bindings[ns] ?? bindings["default"] ?? null;
624
+ if (!b || jspi) return b;
625
+ return isSyncKVNamespace(b) ? b : null;
626
+ }
627
+ function encodeGet(getMemory, allocRef, value, out_ptr) {
628
+ if (value === null) return -1;
629
+ return writeBytesOut(getMemory, allocRef, out_ptr, textEncoder.encode(value));
630
+ }
631
+ function encodeList(getMemory, allocRef, names, out_ptr) {
632
+ if (names.length === 0) {
633
+ new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
634
+ return 0;
779
635
  }
780
- const Suspending = WebAssembly.Suspending;
781
- if (typeof Suspending !== "function") {
782
- let syncBinding2 = function(ns) {
783
- const candidate = binding(ns);
784
- return candidate && isSyncKVNamespace(candidate) ? candidate : null;
785
- };
786
- var syncBinding = syncBinding2;
787
- return {
788
- kv_get: (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
789
- const b = syncBinding2(readStr(ns_ptr, ns_len));
790
- if (!b) return -1;
791
- const value = b.getSync(readStr(key_ptr, key_len));
792
- if (value === null) return -1;
793
- return writeBytesOut(getMemory, allocRef, out_ptr, encoder3.encode(value));
794
- },
795
- kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
796
- const b = syncBinding2(readStr(ns_ptr, ns_len));
797
- if (!b) return 0;
798
- b.putSync(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
799
- return 0;
800
- },
801
- kv_delete: (ns_ptr, ns_len, key_ptr, key_len) => {
802
- const b = syncBinding2(readStr(ns_ptr, ns_len));
803
- if (!b) return 0;
804
- b.deleteSync(readStr(key_ptr, key_len));
805
- return 0;
806
- },
807
- kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, out_ptr) => {
808
- const b = syncBinding2(readStr(ns_ptr, ns_len));
809
- if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
810
- const prefix = readStr(pfx_ptr, pfx_len);
811
- const result = b.listSync(prefix.length > 0 ? { prefix } : void 0);
812
- return writeJsonOut(getMemory, allocRef, out_ptr, result.keys.map((k) => k.name));
813
- }
814
- };
636
+ return writeJsonOut(getMemory, allocRef, out_ptr, names);
637
+ }
638
+ function get(b, key, out_ptr, getMemory, allocRef) {
639
+ return maybeThen(b.get(key), (v) => encodeGet(getMemory, allocRef, v, out_ptr));
640
+ }
641
+ function put(b, key, val, ttl) {
642
+ return maybeThen(b.put(key, val, putOptions(ttl)), () => 0);
643
+ }
644
+ function del(b, key) {
645
+ return maybeThen(kvDel(b, key), () => 0);
646
+ }
647
+ function list(b, prefix, out_ptr, getMemory, allocRef) {
648
+ return maybeThen(
649
+ b.list(listOpts(prefix)),
650
+ (result) => encodeList(getMemory, allocRef, result.keys.map((k) => k.name), out_ptr)
651
+ );
652
+ }
653
+ function wrapImport(impl) {
654
+ if (!jspi) {
655
+ return ((...args) => {
656
+ const r = impl(...args);
657
+ if (r instanceof Promise) throw new Error("async kv binding requires JSPI");
658
+ return r;
659
+ });
815
660
  }
661
+ return new Suspending(impl);
662
+ }
663
+ function createKVImports(bindings, getMemory, allocRef) {
816
664
  return {
817
- kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
818
- const b = binding(readStr(ns_ptr, ns_len));
665
+ kv_get: wrapImport((ns_ptr, ns_len, key_ptr, key_len, out_ptr) => {
666
+ const b = resolve(bindings, readStr(getMemory, ns_ptr, ns_len));
819
667
  if (!b) return -1;
820
- const value = await b.get(readStr(key_ptr, key_len));
821
- if (value === null) return -1;
822
- return writeBytesOut(getMemory, allocRef, out_ptr, encoder3.encode(value));
668
+ return get(b, readStr(getMemory, key_ptr, key_len), out_ptr, getMemory, allocRef);
823
669
  }),
824
- kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
825
- const b = binding(readStr(ns_ptr, ns_len));
826
- if (!b) return -1;
827
- await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
828
- return 0;
670
+ kv_put: wrapImport((ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
671
+ const b = resolve(bindings, readStr(getMemory, ns_ptr, ns_len));
672
+ if (!b) return miss;
673
+ return put(
674
+ b,
675
+ readStr(getMemory, key_ptr, key_len),
676
+ readStr(getMemory, val_ptr, val_len),
677
+ ttl_seconds
678
+ );
829
679
  }),
830
- kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
831
- const b = binding(readStr(ns_ptr, ns_len));
832
- if (!b) return -1;
833
- await b.delete(readStr(key_ptr, key_len));
834
- return 0;
680
+ kv_delete: wrapImport((ns_ptr, ns_len, key_ptr, key_len) => {
681
+ const b = resolve(bindings, readStr(getMemory, ns_ptr, ns_len));
682
+ if (!b) return miss;
683
+ return del(b, readStr(getMemory, key_ptr, key_len));
835
684
  }),
836
- kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, out_ptr) => {
837
- const b = binding(readStr(ns_ptr, ns_len));
685
+ kv_list: wrapImport((ns_ptr, ns_len, pfx_ptr, pfx_len, out_ptr) => {
686
+ const b = resolve(bindings, readStr(getMemory, ns_ptr, ns_len));
838
687
  if (!b) return writeJsonOut(getMemory, allocRef, out_ptr, []);
839
- const prefix = readStr(prefix_ptr, prefix_len);
840
- const result = await b.list(prefix.length > 0 ? { prefix } : void 0);
841
- const names = result.keys.map((k) => k.name);
842
- if (names.length === 0) {
843
- new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
844
- return 0;
845
- }
846
- return writeJsonOut(getMemory, allocRef, out_ptr, names);
688
+ return list(b, readStr(getMemory, pfx_ptr, pfx_len), out_ptr, getMemory, allocRef);
847
689
  })
848
690
  };
849
691
  }
850
692
 
851
- // src/runtime/db/extern.ts
852
- function decodeBlob(base64) {
853
- const binary = atob(base64);
854
- const bytes = new Uint8Array(binary.length);
855
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
856
- return bytes;
857
- }
858
- function toDbValue(value) {
859
- switch (value.kind) {
860
- case "null":
861
- return null;
862
- case "integer":
863
- return value.integer;
864
- case "float":
865
- return value.float;
866
- case "text":
867
- return value.text;
868
- case "blob":
869
- return decodeBlob(value.blob);
870
- case "boolean":
871
- return value.boolean;
693
+ // src/runtime/kv/localstorage.ts
694
+ var namespace = "default";
695
+ var storagePrefix = "ziex-kv";
696
+ var namespacePrefix = `${storagePrefix}:${namespace}:`;
697
+ function storage() {
698
+ if (typeof localStorage === "undefined") {
699
+ throw new Error("localStorage is not available in this environment");
872
700
  }
701
+ return localStorage;
873
702
  }
874
- function toPositionalBindings(json) {
875
- switch (json.kind) {
876
- case "none":
877
- return [];
878
- case "positional":
879
- return json.values.map(toDbValue);
880
- case "named":
881
- throw new Error("named SQL bindings are not supported yet");
882
- }
703
+ function get2(key) {
704
+ return storage().getItem(`${storagePrefix}:${namespace}:${key}`);
883
705
  }
884
- function toWireValue(value) {
885
- if (value === null || value === void 0) return { kind: "null" };
886
- if (typeof value === "string") return { kind: "text", text: value };
887
- if (typeof value === "boolean") return { kind: "boolean", boolean: value };
888
- if (typeof value === "number") {
889
- return Number.isInteger(value) ? { kind: "integer", integer: value } : { kind: "float", float: value };
890
- }
891
- if (value instanceof ArrayBuffer) {
892
- const bytes = new Uint8Array(value);
893
- let binary = "";
894
- for (const byte of bytes) binary += String.fromCharCode(byte);
895
- return { kind: "blob", blob: btoa(binary) };
896
- }
897
- if (ArrayBuffer.isView(value)) {
898
- const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
899
- let binary = "";
900
- for (const byte of bytes) binary += String.fromCharCode(byte);
901
- return { kind: "blob", blob: btoa(binary) };
706
+ function put2(key, value) {
707
+ storage().setItem(`${storagePrefix}:${namespace}:${key}`, value);
708
+ }
709
+ function del2(key) {
710
+ storage().removeItem(`${storagePrefix}:${namespace}:${key}`);
711
+ }
712
+ function list2(options) {
713
+ const ls = storage();
714
+ const prefix = namespacePrefix + (options?.prefix ?? "");
715
+ const keys = [];
716
+ for (let i = 0; i < ls.length; i += 1) {
717
+ const key = ls.key(i);
718
+ if (!key || !key.startsWith(prefix)) continue;
719
+ keys.push({ name: key.slice(namespacePrefix.length) });
720
+ }
721
+ return { keys };
722
+ }
723
+
724
+ // src/runtime/kv/indexdb.ts
725
+ var databaseName = "ziex-kv";
726
+ var storeName = "kv";
727
+ var namespace2 = "default";
728
+ var dbPromise;
729
+ function openDb() {
730
+ if (!dbPromise) {
731
+ if (typeof indexedDB === "undefined") {
732
+ return Promise.reject(new Error("IndexedDB is not available in this environment"));
733
+ }
734
+ dbPromise = new Promise((resolve2, reject) => {
735
+ const request = indexedDB.open(databaseName, 1);
736
+ request.onupgradeneeded = () => {
737
+ const db = request.result;
738
+ if (!db.objectStoreNames.contains(storeName)) {
739
+ db.createObjectStore(storeName);
740
+ }
741
+ };
742
+ request.onsuccess = () => resolve2(request.result);
743
+ request.onerror = () => reject(request.error ?? new Error("Failed to open IndexedDB"));
744
+ });
902
745
  }
903
- return { kind: "text", text: String(value) };
746
+ return dbPromise;
904
747
  }
905
- function objectToWireRow(record) {
748
+ function requestToPromise(request) {
749
+ return new Promise((resolve2, reject) => {
750
+ request.onsuccess = () => resolve2(request.result);
751
+ request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
752
+ });
753
+ }
754
+ function transactionToPromise(transaction) {
755
+ return new Promise((resolve2, reject) => {
756
+ transaction.oncomplete = () => resolve2();
757
+ transaction.onabort = () => reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
758
+ transaction.onerror = () => reject(transaction.error ?? new Error("IndexedDB transaction failed"));
759
+ });
760
+ }
761
+ async function get3(key) {
762
+ const db = await openDb();
763
+ const tx = db.transaction(storeName, "readonly");
764
+ const value = await requestToPromise(tx.objectStore(storeName).get(`${namespace2}:${key}`));
765
+ await transactionToPromise(tx);
766
+ return typeof value === "string" ? value : null;
767
+ }
768
+ async function put3(key, value) {
769
+ const db = await openDb();
770
+ const tx = db.transaction(storeName, "readwrite");
771
+ tx.objectStore(storeName).put(value, `${namespace2}:${key}`);
772
+ await transactionToPromise(tx);
773
+ }
774
+ async function del3(key) {
775
+ const db = await openDb();
776
+ const tx = db.transaction(storeName, "readwrite");
777
+ tx.objectStore(storeName).delete(`${namespace2}:${key}`);
778
+ await transactionToPromise(tx);
779
+ }
780
+ async function list3(options) {
781
+ const db = await openDb();
782
+ const tx = db.transaction(storeName, "readonly");
783
+ const keys = await requestToPromise(tx.objectStore(storeName).getAllKeys());
784
+ await transactionToPromise(tx);
785
+ const prefix = `${namespace2}:${options?.prefix ?? ""}`;
906
786
  return {
907
- fields: Object.entries(record).map(([name, value]) => ({
908
- name,
909
- value: toWireValue(value)
910
- }))
787
+ keys: keys.filter((key) => typeof key === "string" && key.startsWith(prefix)).map((key) => ({ name: key.slice(namespace2.length + 1) }))
911
788
  };
912
789
  }
913
- function valuesToWireRows(rows) {
914
- return rows.map((row) => row.map((value) => toWireValue(value)));
790
+
791
+ // src/runtime/kv.ts
792
+ var hasJspi = typeof WebAssembly.Suspending === "function" && typeof WebAssembly.promising === "function";
793
+ function createBrowserKVBindings(options = {}) {
794
+ const namespace3 = options.namespace ?? "default";
795
+ return {
796
+ [namespace3]: hasJspi && !options.forceLocalStorage ? { get: get3, put: put3, del: del3, list: list3 } : { get: get2, put: put2, del: del2, list: list2 }
797
+ };
915
798
  }
916
- function createDbImports(bindings, getMemory, allocRef) {
917
- const decoder3 = new TextDecoder();
918
- function readStr(ptr, len) {
919
- return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
920
- }
921
- function binding(ns) {
922
- return bindings[ns] ?? bindings["default"] ?? null;
923
- }
924
- async function statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len) {
925
- const database = binding(readStr(ns_ptr, ns_len));
926
- if (!database) return null;
927
- const sql = readStr(sql_ptr, sql_len);
928
- const bindingsJson = JSON.parse(readStr(bindings_ptr, bindings_len));
929
- return database.prepare(sql).bind(...toPositionalBindings(bindingsJson));
930
- }
931
- const Suspending = WebAssembly.Suspending;
932
- if (typeof Suspending !== "function") {
933
- return {
934
- db_open: (_ns, _ns_len) => -1,
935
- db_run: (_a, _b, _c, _d, _e, _f, _g) => -1,
936
- db_get: (_a, _b, _c, _d, _e, _f, _g) => -1,
937
- db_all: (_a, _b, _c, _d, _e, _f, _g) => -1,
938
- db_values: (_a, _b, _c, _d, _e, _f, _g) => -1
939
- };
799
+
800
+ // src/runtime/kv/memory.ts
801
+ var store = /* @__PURE__ */ new Map();
802
+ async function get4(key) {
803
+ const entry = store.get(key);
804
+ if (!entry) return null;
805
+ const expiresAt = entry[1];
806
+ if (expiresAt !== void 0 && Date.now() >= expiresAt) {
807
+ store.delete(key);
808
+ return null;
809
+ }
810
+ return entry[0];
811
+ }
812
+ async function put4(key, value, options) {
813
+ let expiresAt;
814
+ if (options?.expiration !== void 0) {
815
+ expiresAt = options.expiration * 1e3;
816
+ } else if (options?.expirationTtl !== void 0) {
817
+ expiresAt = Date.now() + options.expirationTtl * 1e3;
818
+ }
819
+ store.set(key, [value, expiresAt]);
820
+ }
821
+ async function del4(key) {
822
+ store.delete(key);
823
+ }
824
+ async function list4(options) {
825
+ const keys = [];
826
+ for (const name of [...store.keys()]) {
827
+ if (options?.prefix && !name.startsWith(options.prefix)) continue;
828
+ if (await get4(name) !== null) keys.push({ name });
940
829
  }
941
- return {
942
- db_open: (ns_ptr, ns_len) => binding(readStr(ns_ptr, ns_len)) ? 0 : -1,
943
- db_run: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
944
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
945
- if (!stmt) return -1;
946
- const result = await stmt.run();
947
- return writeJsonOut(getMemory, allocRef, out_ptr, {
948
- last_insert_rowid: result.meta?.last_row_id ?? 0,
949
- changes: result.meta?.changes ?? 0
950
- });
951
- }),
952
- db_get: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
953
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
954
- if (!stmt) return -1;
955
- const row = await stmt.first();
956
- if (!row) {
957
- new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
958
- return 0;
959
- }
960
- return writeJsonOut(getMemory, allocRef, out_ptr, [objectToWireRow(row)]);
961
- }),
962
- db_all: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
963
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
964
- if (!stmt) return -1;
965
- const result = await stmt.all();
966
- const rows = (result.results ?? []).map(objectToWireRow);
967
- if (rows.length === 0) {
968
- new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
969
- return 0;
970
- }
971
- return writeJsonOut(getMemory, allocRef, out_ptr, rows);
972
- }),
973
- db_values: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
974
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
975
- if (!stmt) return -1;
976
- const rows = await stmt.raw();
977
- if (rows.length === 0) {
978
- new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
979
- return 0;
980
- }
981
- return writeJsonOut(getMemory, allocRef, out_ptr, valuesToWireRows(rows));
982
- })
983
- };
984
- }
985
-
986
- // src/runtime/wasi.ts
987
- var ProcExit = class extends Error {
988
- constructor(code) {
989
- super(`proc_exit(${code})`);
990
- this.code = code;
991
- }
992
- };
993
- function createWasiImports({
994
- request,
995
- stdinData,
996
- onStdout
997
- }) {
998
- const encoder3 = new TextEncoder();
999
- const url = new URL(request.url);
1000
- const argStrings = [
1001
- "wasm",
1002
- "--pathname",
1003
- url.pathname,
1004
- "--method",
1005
- request.method,
1006
- "--search",
1007
- url.search,
1008
- "--url",
1009
- url.href
1010
- ];
1011
- request.headers.forEach((value, name) => {
1012
- if (value) argStrings.push("--header", `${name}:${value}`);
1013
- });
1014
- const encodedArgs = argStrings.map((a) => encoder3.encode(a + "\0"));
1015
- const argBufSize = encodedArgs.reduce((s, a) => s + a.length, 0);
1016
- let wasmMemory = null;
1017
- const setMemory = (m2) => {
1018
- wasmMemory = m2;
1019
- };
1020
- const stdoutChunks = [];
1021
- let stderrMeta = "";
1022
- let stderrPartial = "";
1023
- const stderrDecoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
1024
- function processStderrChunk(chunk) {
1025
- const text = stderrDecoder.decode(chunk, { stream: true });
1026
- const lines = (stderrPartial + text).split("\n");
1027
- stderrPartial = lines.pop() ?? "";
1028
- for (const line of lines) {
1029
- if (line.startsWith("__ZIEX_META__:")) {
1030
- stderrMeta += line + "\n";
1031
- } else if (line.length > 0) {
1032
- console.error("[ziex]", line);
1033
- }
1034
- }
1035
- }
1036
- let stdinOffset = 0;
1037
- function v() {
1038
- return new DataView(wasmMemory.buffer);
1039
- }
1040
- function m() {
1041
- return new Uint8Array(wasmMemory.buffer);
1042
- }
1043
- const wasiImport = {
1044
- args_sizes_get(argc_ptr, argv_buf_size_ptr) {
1045
- v().setUint32(argc_ptr, encodedArgs.length, true);
1046
- v().setUint32(argv_buf_size_ptr, argBufSize, true);
1047
- return 0;
1048
- },
1049
- args_get(argv_ptr, argv_buf_ptr) {
1050
- const dv = v();
1051
- const mem = m();
1052
- let offset = argv_buf_ptr;
1053
- for (const arg of encodedArgs) {
1054
- dv.setUint32(argv_ptr, offset, true);
1055
- mem.set(arg, offset);
1056
- argv_ptr += 4;
1057
- offset += arg.length;
1058
- }
1059
- return 0;
1060
- },
1061
- environ_sizes_get(count_ptr, buf_size_ptr) {
1062
- v().setUint32(count_ptr, 0, true);
1063
- v().setUint32(buf_size_ptr, 0, true);
1064
- return 0;
1065
- },
1066
- environ_get(_environ_ptr, _environ_buf_ptr) {
1067
- return 0;
1068
- },
1069
- fd_write(fd, iovs_ptr, iovs_len, nwritten_ptr) {
1070
- const dv = v();
1071
- const mem = m();
1072
- let written = 0;
1073
- for (let i = 0; i < iovs_len; i++) {
1074
- const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
1075
- const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
1076
- const chunk = mem.slice(buf_ptr, buf_ptr + buf_len);
1077
- if (fd === 1) {
1078
- if (onStdout) onStdout(chunk);
1079
- else stdoutChunks.push(chunk);
1080
- } else if (fd === 2) processStderrChunk(chunk);
1081
- written += buf_len;
1082
- }
1083
- dv.setUint32(nwritten_ptr, written, true);
1084
- return 0;
1085
- },
1086
- fd_read(fd, iovs_ptr, iovs_len, nread_ptr) {
1087
- const dv = v();
1088
- const mem = m();
1089
- const stdin = stdinData ?? new Uint8Array(0);
1090
- let totalRead = 0;
1091
- for (let i = 0; i < iovs_len; i++) {
1092
- const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
1093
- const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
1094
- if (fd === 0 && stdinOffset < stdin.length) {
1095
- const toRead = Math.min(buf_len, stdin.length - stdinOffset);
1096
- mem.set(stdin.subarray(stdinOffset, stdinOffset + toRead), buf_ptr);
1097
- stdinOffset += toRead;
1098
- totalRead += toRead;
1099
- }
1100
- }
1101
- dv.setUint32(nread_ptr, totalRead, true);
1102
- return 0;
1103
- },
1104
- fd_fdstat_get(_fd, fdstat_ptr) {
1105
- const dv = v();
1106
- dv.setUint8(fdstat_ptr, 2);
1107
- dv.setUint8(fdstat_ptr + 1, 0);
1108
- dv.setUint16(fdstat_ptr + 2, 0, true);
1109
- dv.setUint32(fdstat_ptr + 4, 0, true);
1110
- dv.setBigUint64(fdstat_ptr + 8, 0n, true);
1111
- dv.setBigUint64(fdstat_ptr + 16, 0n, true);
1112
- return 0;
1113
- },
1114
- fd_prestat_get(_fd, _bufptr) {
1115
- return 8;
1116
- },
1117
- fd_prestat_dir_name(_fd, _path, _path_len) {
1118
- return 8;
1119
- },
1120
- fd_close(_fd) {
1121
- return 0;
1122
- },
1123
- fd_pread(_fd, _iovs, _iovs_len, _offset, nread_ptr) {
1124
- v().setUint32(nread_ptr, 0, true);
1125
- return 0;
1126
- },
1127
- fd_pwrite(_fd, _iovs, _iovs_len, _offset, nwritten_ptr) {
1128
- v().setUint32(nwritten_ptr, 0, true);
1129
- return 0;
1130
- },
1131
- fd_filestat_get(_fd, filestat_ptr) {
1132
- const dv = v();
1133
- dv.setBigUint64(filestat_ptr, 0n, true);
1134
- dv.setBigUint64(filestat_ptr + 8, 0n, true);
1135
- dv.setUint8(filestat_ptr + 16, 2);
1136
- dv.setBigUint64(filestat_ptr + 24, 1n, true);
1137
- dv.setBigUint64(filestat_ptr + 32, 0n, true);
1138
- dv.setBigUint64(filestat_ptr + 40, 0n, true);
1139
- dv.setBigUint64(filestat_ptr + 48, 0n, true);
1140
- dv.setBigUint64(filestat_ptr + 56, 0n, true);
1141
- return 0;
1142
- },
1143
- fd_filestat_set_size(_fd, _size) {
1144
- return 76;
1145
- },
1146
- fd_filestat_set_times(_fd, _atim, _mtim, _fst_flags) {
1147
- return 76;
1148
- },
1149
- fd_fdstat_set_flags(_fd, _flags) {
1150
- return 0;
1151
- },
1152
- fd_fdstat_set_rights(_fd, _rights_base, _rights_inheriting) {
1153
- return 0;
1154
- },
1155
- fd_sync(_fd) {
1156
- return 0;
1157
- },
1158
- fd_datasync(_fd) {
1159
- return 0;
1160
- },
1161
- fd_advise(_fd, _offset, _len, _advice) {
1162
- return 0;
1163
- },
1164
- fd_allocate(_fd, _offset, _len) {
1165
- return 76;
1166
- },
1167
- fd_tell(_fd, offset_ptr) {
1168
- v().setBigUint64(offset_ptr, 0n, true);
1169
- return 0;
1170
- },
1171
- fd_renumber(_from, _to) {
1172
- return 0;
1173
- },
1174
- path_filestat_set_times(_fd, _flags, _path, _path_len, _atim, _mtim, _fst_flags) {
1175
- return 76;
1176
- },
1177
- path_link(_old_fd, _old_flags, _old_path, _old_path_len, _new_fd, _new_path, _new_path_len) {
1178
- return 76;
1179
- },
1180
- path_symlink(_old_path, _old_path_len, _fd, _new_path, _new_path_len) {
1181
- return 76;
1182
- },
1183
- proc_raise(_sig) {
1184
- return 0;
1185
- },
1186
- sock_recv(_fd, _ri_data, _ri_data_len, _ri_flags, ro_datalen_ptr, ro_flags_ptr) {
1187
- v().setUint32(ro_datalen_ptr, 0, true);
1188
- v().setUint32(ro_flags_ptr, 0, true);
1189
- return 76;
1190
- },
1191
- sock_send(_fd, _si_data, _si_data_len, _si_flags, so_datalen_ptr) {
1192
- v().setUint32(so_datalen_ptr, 0, true);
1193
- return 76;
1194
- },
1195
- sock_shutdown(_fd, _how) {
1196
- return 76;
1197
- },
1198
- fd_seek(_fd, _offset, _whence, newoffset_ptr) {
1199
- v().setBigInt64(newoffset_ptr, 0n, true);
1200
- return 0;
1201
- },
1202
- proc_exit(code) {
1203
- throw new ProcExit(code);
1204
- },
1205
- sched_yield() {
1206
- return 0;
1207
- },
1208
- clock_time_get(_id, _precision, time_ptr) {
1209
- v().setBigUint64(time_ptr, BigInt(Date.now()) * 1000000n, true);
1210
- return 0;
1211
- },
1212
- clock_res_get(_id, res_ptr) {
1213
- v().setBigUint64(res_ptr, 1000000n, true);
1214
- return 0;
1215
- },
1216
- random_get(buf_ptr, buf_len) {
1217
- crypto.getRandomValues(new Uint8Array(wasmMemory.buffer, buf_ptr, buf_len));
1218
- return 0;
1219
- },
1220
- path_open(_fd, _dirflags, _path, _path_len, _oflags, _rights_base, _rights_inheriting, _fdflags, opened_fd_ptr) {
1221
- v().setInt32(opened_fd_ptr, -1, true);
1222
- return 76;
1223
- },
1224
- path_create_directory(_fd, _path, _path_len) {
1225
- return 76;
1226
- },
1227
- path_unlink_file(_fd, _path, _path_len) {
1228
- return 76;
1229
- },
1230
- path_remove_directory(_fd, _path, _path_len) {
1231
- return 76;
1232
- },
1233
- path_rename(_fd, _old_path, _old_path_len, _new_fd, _new_path, _new_path_len) {
1234
- return 76;
1235
- },
1236
- path_filestat_get(_fd, _flags, _path, _path_len, filestat_ptr) {
1237
- new Uint8Array(wasmMemory.buffer, filestat_ptr, 64).fill(0);
1238
- return 76;
1239
- },
1240
- path_readlink(_fd, _path, _path_len, _buf, _buf_len, nread_ptr) {
1241
- v().setUint32(nread_ptr, 0, true);
1242
- return 76;
1243
- },
1244
- fd_readdir(_fd, _buf, _buf_len, _cookie, bufused_ptr) {
1245
- v().setUint32(bufused_ptr, 0, true);
1246
- return 76;
1247
- },
1248
- // Stub for poll_oneoff - no blocking I/O in edge runtimes.
1249
- poll_oneoff(_in, _out, _nsubscriptions, nevents_ptr) {
1250
- v().setUint32(nevents_ptr, 0, true);
1251
- return 0;
1252
- }
1253
- };
1254
- function collectOutput() {
1255
- const remaining = stderrDecoder.decode(void 0, { stream: false });
1256
- const tail = stderrPartial + remaining;
1257
- if (tail.length > 0) {
1258
- if (tail.startsWith("__ZIEX_META__:")) stderrMeta += tail;
1259
- else console.error("[ziex]", tail);
1260
- stderrPartial = "";
1261
- }
1262
- return {
1263
- stdout: mergeUint8Arrays(stdoutChunks),
1264
- stderrText: stderrMeta
1265
- };
1266
- }
1267
- return { wasiImport, setMemory, collectOutput };
1268
- }
1269
- function mergeUint8Arrays(arrays) {
1270
- const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
1271
- const result = new Uint8Array(totalLen);
1272
- let offset = 0;
1273
- for (const arr of arrays) {
1274
- result.set(arr, offset);
1275
- offset += arr.length;
1276
- }
1277
- return result;
1278
- }
1279
-
1280
- // src/runtime/kv.ts
1281
- var kv_exports = {};
1282
- __export(kv_exports, {
1283
- createBrowserKVBindings: () => createBrowserKVBindings,
1284
- createIndexedDbKV: () => createIndexedDbKV,
1285
- createKVImports: () => createKVImports,
1286
- createLocalStorageKV: () => createLocalStorageKV,
1287
- createMemoryKV: () => createMemoryKV,
1288
- hasJSPI: () => hasJSPI
1289
- });
1290
-
1291
- // src/runtime/kv/memory.ts
1292
- function createMemoryKV() {
1293
- const store = /* @__PURE__ */ new Map();
1294
- function read(key) {
1295
- const entry = store.get(key);
1296
- if (!entry) return null;
1297
- const expiresAt = entry[1];
1298
- if (expiresAt !== void 0 && Date.now() >= expiresAt) {
1299
- store.delete(key);
1300
- return null;
1301
- }
1302
- return entry[0];
1303
- }
1304
- function write(key, value, options) {
1305
- let expiresAt;
1306
- if (options?.expiration !== void 0) {
1307
- expiresAt = options.expiration * 1e3;
1308
- } else if (options?.expirationTtl !== void 0) {
1309
- expiresAt = Date.now() + options.expirationTtl * 1e3;
1310
- }
1311
- store.set(key, [value, expiresAt]);
1312
- }
1313
- return {
1314
- async get(key) {
1315
- return read(key);
1316
- },
1317
- async put(key, value, options) {
1318
- write(key, value, options);
1319
- },
1320
- async delete(key) {
1321
- store.delete(key);
1322
- },
1323
- async list(options) {
1324
- const keys = [...store.keys()].filter((k) => {
1325
- if (options?.prefix && !k.startsWith(options.prefix)) return false;
1326
- return read(k) !== null;
1327
- }).map((name) => ({ name }));
1328
- return { keys };
1329
- }
1330
- };
1331
- }
1332
-
1333
- // src/runtime/kv/localstorage.ts
1334
- function getLocalStorage() {
1335
- if (typeof localStorage === "undefined") {
1336
- throw new Error("localStorage is not available in this environment");
1337
- }
1338
- return localStorage;
1339
- }
1340
- function createLocalStorageKV(options = {}) {
1341
- const storage = getLocalStorage();
1342
- const namespace = options.namespace ?? "default";
1343
- const storagePrefix = options.storagePrefix ?? "ziex-kv";
1344
- const scopedKey = (key) => `${storagePrefix}:${namespace}:${key}`;
1345
- const namespacePrefix = scopedKey("");
1346
- return {
1347
- getSync(key) {
1348
- return storage.getItem(scopedKey(key));
1349
- },
1350
- async get(key) {
1351
- return this.getSync(key);
1352
- },
1353
- putSync(key, value) {
1354
- storage.setItem(scopedKey(key), value);
1355
- },
1356
- async put(key, value) {
1357
- this.putSync(key, value);
1358
- },
1359
- deleteSync(key) {
1360
- storage.removeItem(scopedKey(key));
1361
- },
1362
- async delete(key) {
1363
- this.deleteSync(key);
1364
- },
1365
- listSync(options2) {
1366
- const prefix = namespacePrefix + (options2?.prefix ?? "");
1367
- const keys = [];
1368
- for (let i = 0; i < storage.length; i += 1) {
1369
- const key = storage.key(i);
1370
- if (!key || !key.startsWith(prefix)) continue;
1371
- keys.push({ name: key.slice(namespacePrefix.length) });
1372
- }
1373
- return { keys };
1374
- },
1375
- async list(options2) {
1376
- return this.listSync(options2);
1377
- }
1378
- };
1379
- }
1380
-
1381
- // src/runtime/kv/indexdb.ts
1382
- function getIndexedDb() {
1383
- if (typeof indexedDB === "undefined") {
1384
- throw new Error("IndexedDB is not available in this environment");
1385
- }
1386
- return indexedDB;
1387
- }
1388
- function requestToPromise(request) {
1389
- return new Promise((resolve, reject) => {
1390
- request.onsuccess = () => resolve(request.result);
1391
- request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
1392
- });
1393
- }
1394
- function transactionToPromise(transaction) {
1395
- return new Promise((resolve, reject) => {
1396
- transaction.oncomplete = () => resolve();
1397
- transaction.onabort = () => reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
1398
- transaction.onerror = () => reject(transaction.error ?? new Error("IndexedDB transaction failed"));
1399
- });
1400
- }
1401
- function createIndexedDbKV(options = {}) {
1402
- const databaseName = options.databaseName ?? "ziex-kv";
1403
- const storeName = options.storeName ?? "kv";
1404
- const namespace = options.namespace ?? "default";
1405
- const dbPromise = new Promise((resolve, reject) => {
1406
- const request = getIndexedDb().open(databaseName, 1);
1407
- request.onupgradeneeded = () => {
1408
- const db = request.result;
1409
- if (!db.objectStoreNames.contains(storeName)) {
1410
- db.createObjectStore(storeName);
1411
- }
1412
- };
1413
- request.onsuccess = () => resolve(request.result);
1414
- request.onerror = () => reject(request.error ?? new Error("Failed to open IndexedDB"));
1415
- });
1416
- const scopedKey = (key) => `${namespace}:${key}`;
1417
- return {
1418
- async get(key) {
1419
- const db = await dbPromise;
1420
- const tx = db.transaction(storeName, "readonly");
1421
- const store = tx.objectStore(storeName);
1422
- const value = await requestToPromise(store.get(scopedKey(key)));
1423
- await transactionToPromise(tx);
1424
- return typeof value === "string" ? value : null;
1425
- },
1426
- async put(key, value) {
1427
- const db = await dbPromise;
1428
- const tx = db.transaction(storeName, "readwrite");
1429
- tx.objectStore(storeName).put(value, scopedKey(key));
1430
- await transactionToPromise(tx);
1431
- },
1432
- async delete(key) {
1433
- const db = await dbPromise;
1434
- const tx = db.transaction(storeName, "readwrite");
1435
- tx.objectStore(storeName).delete(scopedKey(key));
1436
- await transactionToPromise(tx);
1437
- },
1438
- async list(options2) {
1439
- const db = await dbPromise;
1440
- const tx = db.transaction(storeName, "readonly");
1441
- const store = tx.objectStore(storeName);
1442
- const keys = await requestToPromise(store.getAllKeys());
1443
- await transactionToPromise(tx);
1444
- const prefix = scopedKey(options2?.prefix ?? "");
1445
- return {
1446
- keys: keys.filter((key) => typeof key === "string" && key.startsWith(prefix)).map((key) => ({ name: key.slice(namespace.length + 1) }))
1447
- };
1448
- }
1449
- };
1450
- }
1451
-
1452
- // src/runtime/kv.ts
1453
- function hasJSPI() {
1454
- return typeof WebAssembly.Suspending === "function" && typeof WebAssembly.promising === "function";
1455
- }
1456
- function createBrowserKVBindings(options = {}) {
1457
- const namespace = options.namespace ?? "default";
1458
- const isIndexedDb = hasJSPI() && !options.forceLocalStorage;
1459
- return {
1460
- [namespace]: isIndexedDb ? createIndexedDbKV(options) : createLocalStorageKV(options)
1461
- };
1462
- }
1463
-
1464
- // src/runtime/index.ts
1465
- function buildWsImports(Suspending, mem, decoder3, ws) {
1466
- const readStr = (ptr, len) => decoder3.decode(new Uint8Array(mem().buffer, ptr, len));
1467
- return {
1468
- ws_upgrade: () => {
1469
- ws.upgraded = true;
1470
- },
1471
- ws_write: (ptr, len) => {
1472
- const data = new Uint8Array(mem().buffer, ptr, len).slice();
1473
- if (!ws.server) {
1474
- ws.pendingWrites.push(data);
1475
- } else {
1476
- ws.server.send(data);
1477
- }
1478
- },
1479
- ws_close: (code, reason_ptr, reason_len) => {
1480
- ws.server?.close(code, decoder3.decode(new Uint8Array(mem().buffer, reason_ptr, reason_len)));
1481
- },
1482
- ws_recv: Suspending ? new Suspending(async (buf_ptr, buf_max) => {
1483
- if (ws._resolveFirstSuspend) {
1484
- const fn = ws._resolveFirstSuspend;
1485
- ws._resolveFirstSuspend = void 0;
1486
- fn();
1487
- }
1488
- const deliver = (bytes) => {
1489
- if (bytes === null) return -1;
1490
- const n = Math.min(bytes.length, buf_max);
1491
- new Uint8Array(mem().buffer, buf_ptr, n).set(bytes.subarray(0, n));
1492
- return n;
1493
- };
1494
- if (ws.messageQueue.length > 0) return deliver(ws.messageQueue.shift());
1495
- return new Promise((resolve) => {
1496
- ws.recvResolve = (bytes) => resolve(deliver(bytes));
1497
- });
1498
- }) : (_buf_ptr, _buf_max) => -1,
1499
- // Pub/sub - delegates to optional callbacks (real in DO, no-ops otherwise)
1500
- ws_subscribe: (ptr, len) => {
1501
- ws.subscribe?.(readStr(ptr, len));
1502
- },
1503
- ws_unsubscribe: (ptr, len) => {
1504
- ws.unsubscribe?.(readStr(ptr, len));
1505
- },
1506
- ws_publish: (topic_ptr, topic_len, data_ptr, data_len) => {
1507
- const topic = readStr(topic_ptr, topic_len);
1508
- const data = new Uint8Array(mem().buffer, data_ptr, data_len).slice();
1509
- return ws.publish?.(topic, data) ?? 0;
1510
- },
1511
- ws_is_subscribed: (ptr, len) => ws.isSubscribed?.(readStr(ptr, len)) ? 1 : 0
1512
- };
1513
- }
1514
- function attachWebSocket(ws) {
1515
- const WebSocketPairCtor = globalThis.WebSocketPair;
1516
- const pair = new WebSocketPairCtor();
1517
- const client = pair[0];
1518
- const server = pair[1];
1519
- ws.server = server;
1520
- server.accept();
1521
- for (const data of ws.pendingWrites) server.send(data);
1522
- ws.pendingWrites = [];
1523
- server.addEventListener("message", (event) => {
1524
- const data = typeof event.data === "string" ? new TextEncoder().encode(event.data) : new Uint8Array(event.data);
1525
- if (ws.recvResolve) {
1526
- const res = ws.recvResolve;
1527
- ws.recvResolve = null;
1528
- res(data);
1529
- } else {
1530
- ws.messageQueue.push(data);
1531
- }
1532
- });
1533
- server.addEventListener("close", () => {
1534
- if (ws.recvResolve) {
1535
- const res = ws.recvResolve;
1536
- ws.recvResolve = null;
1537
- res(null);
1538
- }
1539
- });
1540
- return { client };
1541
- }
1542
- function buildSysImports(jspi, Suspending) {
1543
- return {
1544
- sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {
1545
- }
1546
- };
1547
- }
1548
- function executeWasm(instance, jspi, Suspending, wsState) {
1549
- if (!jspi) {
1550
- try {
1551
- instance.exports._start();
1552
- } catch (e) {
1553
- if (!(e instanceof ProcExit)) throw e;
1554
- }
1555
- return Promise.resolve();
1556
- }
1557
- const start = WebAssembly.promising(instance.exports._start);
1558
- return start().catch((e) => {
1559
- if (e instanceof Error && e.message.startsWith("proc_exit")) return;
1560
- throw e;
1561
- }).finally(() => {
1562
- if (wsState.recvResolve) {
1563
- const res = wsState.recvResolve;
1564
- wsState.recvResolve = null;
1565
- res(null);
1566
- }
1567
- });
1568
- }
1569
- function parseZiexMeta(stderrText) {
1570
- const meta = { status: 200, headers: new Headers(), streaming: false };
1571
- const metaPrefix = "__ZIEX_META__:";
1572
- const metaLine = stderrText.split("\n").find((line) => line.startsWith(metaPrefix));
1573
- if (metaLine) {
1574
- try {
1575
- const parsed = JSON.parse(metaLine.slice(metaPrefix.length));
1576
- if (parsed.status) meta.status = parsed.status;
1577
- if (parsed.streaming === true) meta.streaming = true;
1578
- if (Array.isArray(parsed.headers)) {
1579
- for (const [name, value] of parsed.headers) {
1580
- meta.headers.append(name, value);
1581
- }
1582
- }
1583
- } catch {
1584
- }
1585
- }
1586
- return meta;
1587
- }
1588
- async function run({
1589
- request,
1590
- env,
1591
- ctx,
1592
- module,
1593
- kv: kvBindings,
1594
- db: dbBindings,
1595
- imports,
1596
- wasi,
1597
- websocket: doNamespace
1598
- }) {
1599
- if (doNamespace && request.headers.get("upgrade")?.toLowerCase() === "websocket") {
1600
- const id = doNamespace.idFromName(new URL(request.url).pathname);
1601
- return doNamespace.get(id).fetch(request);
1602
- }
1603
- const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : void 0;
1604
- const stdoutChunks = [];
1605
- let streamWriter = null;
1606
- const { wasiImport, setMemory, collectOutput } = createWasiImports({
1607
- request,
1608
- stdinData,
1609
- onStdout: (chunk) => {
1610
- if (streamWriter) void streamWriter.write(chunk);
1611
- else stdoutChunks.push(chunk);
1612
- }
1613
- });
1614
- let wasmMemory = null;
1615
- const mem = () => wasmMemory;
1616
- const bridgeRef = [null];
1617
- const allocRef = [null];
1618
- const Suspending = WebAssembly.Suspending;
1619
- const jspi = typeof Suspending === "function";
1620
- const wsState = {
1621
- upgraded: false,
1622
- server: null,
1623
- pendingWrites: [],
1624
- messageQueue: [],
1625
- recvResolve: null
1626
- };
1627
- const importObject = {
1628
- wasi_snapshot_preview1: { ...wasi?.wasiImport, ...wasiImport },
1629
- __zx_sys: buildSysImports(jspi, Suspending),
1630
- __zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder(), wsState),
1631
- __zx_net: createFetchImports(mem),
1632
- ...imports ? imports(mem) : {},
1633
- ...ZxWasiBridge.createImportObject(bridgeRef)
1634
- };
1635
- if (true) {
1636
- importObject.__zx_kv = createKVImports(
1637
- kvBindings ?? { default: createMemoryKV() },
1638
- mem,
1639
- allocRef
1640
- );
1641
- }
1642
- if (true) {
1643
- importObject.__zx_db = createDbImports(
1644
- dbBindings ?? {},
1645
- mem,
1646
- allocRef
1647
- );
1648
- }
1649
- const instance = new WebAssembly.Instance(module, importObject);
1650
- wasmMemory = instance.exports.memory;
1651
- setMemory(wasmMemory);
1652
- bridgeRef[0] = new ZxWasiBridge(instance.exports);
1653
- bindWasmAlloc(allocRef, instance.exports);
1654
- const wasmPromise = executeWasm(instance, jspi, Suspending, wsState);
1655
- if (wsState.upgraded) {
1656
- const server = attachWebSocket(wsState);
1657
- ctx?.waitUntil(wasmPromise);
1658
- return new Response(null, { status: 101, webSocket: server.client });
1659
- }
1660
- const { stderrText: earlyStderrText } = collectOutput();
1661
- const earlyMeta = parseZiexMeta(earlyStderrText);
1662
- if (earlyMeta.streaming) {
1663
- const { readable, writable } = new TransformStream();
1664
- streamWriter = writable.getWriter();
1665
- for (const chunk of stdoutChunks) void streamWriter.write(chunk);
1666
- stdoutChunks.length = 0;
1667
- void wasmPromise.finally(() => streamWriter?.close());
1668
- return new Response(readable, { status: earlyMeta.status, headers: earlyMeta.headers });
1669
- }
1670
- await wasmPromise;
1671
- const { stderrText } = collectOutput();
1672
- const meta = parseZiexMeta(stderrText);
1673
- const body = mergeUint8Arrays(stdoutChunks);
1674
- meta.headers.delete("transfer-encoding");
1675
- const nullBody = meta.status === 101 || meta.status === 204 || meta.status === 205 || meta.status === 304;
1676
- if (nullBody) {
1677
- meta.headers.delete("content-length");
1678
- return new Response(null, { status: meta.status, headers: meta.headers });
1679
- }
1680
- if (!meta.headers.has("content-length")) meta.headers.set("content-length", String(body.byteLength));
1681
- return new Response(body.buffer, { status: meta.status, headers: meta.headers });
1682
- }
1683
-
1684
- // src/app.ts
1685
- async function resolveModule(input) {
1686
- if (typeof input === "string") {
1687
- if (input.startsWith("http://") || input.startsWith("https://")) {
1688
- return WebAssembly.compileStreaming(fetch(input));
1689
- }
1690
- const url = input.startsWith("/") ? `file://${input}` : input;
1691
- return WebAssembly.compile(await fetch(url).then((r) => r.arrayBuffer()));
1692
- }
1693
- if (input instanceof URL) {
1694
- return WebAssembly.compileStreaming(fetch(input));
1695
- }
1696
- if (input instanceof Response) {
1697
- return WebAssembly.compileStreaming(input);
1698
- }
1699
- if (input instanceof ArrayBuffer) {
1700
- return WebAssembly.compile(input);
1701
- }
1702
- if (ArrayBuffer.isView(input)) {
1703
- return WebAssembly.compile(input.buffer);
1704
- }
1705
- return input;
1706
- }
1707
- var Ziex = class {
1708
- constructor(options) {
1709
- this.resolved = null;
1710
- /**
1711
- * Fetch handler called by the runtime on every request.
1712
- *
1713
- * Arrow function so `this` is always the class instance, even when the
1714
- * runtime extracts `fetch` from the exported object (e.g. Bun).
1715
- */
1716
- this.fetch = async (request, env, ctx) => {
1717
- const module = await this.getModule();
1718
- const { wasi, imports, websocket } = this.options;
1719
- return run({
1720
- request,
1721
- env,
1722
- ctx,
1723
- module,
1724
- wasi,
1725
- imports,
1726
- kv: this.resolveKV(env),
1727
- db: this.resolveDB(env),
1728
- websocket: websocket !== void 0 ? env[websocket] : void 0
1729
- });
1730
- };
1731
- this.options = options;
1732
- }
1733
- async getModule() {
1734
- if (!this.resolved) this.resolved = await resolveModule(this.options.module);
1735
- return this.resolved;
1736
- }
1737
- resolveKV(env) {
1738
- const { kv } = this.options;
1739
- if (kv === void 0) return void 0;
1740
- if (typeof kv === "object" && kv !== null) {
1741
- const result = {};
1742
- for (const [name, key] of Object.entries(kv)) {
1743
- result[name] = env[key];
1744
- }
1745
- return result;
1746
- }
1747
- return { default: env[kv] };
1748
- }
1749
- resolveDB(env) {
1750
- const { db } = this.options;
1751
- if (db === void 0) return void 0;
1752
- if (typeof db === "object" && db !== null) {
1753
- const result = {};
1754
- for (const [name, key] of Object.entries(db)) {
1755
- result[name] = env[key];
1756
- }
1757
- return result;
1758
- }
1759
- return { default: env[db] };
1760
- }
1761
- };
830
+ return { keys };
831
+ }
1762
832
 
1763
833
  // src/wasm/generated/tags.ts
1764
834
  var TAG_NAMES = [
@@ -1969,6 +1039,55 @@ var SVG_TAG_START_INDEX = 140;
1969
1039
  var CUSTOM_TAG_INDEX = 199;
1970
1040
 
1971
1041
  // src/wasm/dom_cmd.ts
1042
+ var BOOL_PROPS = /* @__PURE__ */ new Set([
1043
+ "checked",
1044
+ "selected",
1045
+ "muted",
1046
+ "defaultChecked",
1047
+ "indeterminate"
1048
+ ]);
1049
+ function enqueueAfterConnect(queue, el, kind) {
1050
+ for (let i = 0; i < queue.length; i++) {
1051
+ const job = queue[i];
1052
+ if (job.el === el && job.kind === kind) return;
1053
+ }
1054
+ queue.push({ el, kind });
1055
+ }
1056
+ function runAfterConnect(queue) {
1057
+ for (let i = 0; i < queue.length; i++) {
1058
+ const job = queue[i];
1059
+ if (!job.el.isConnected) continue;
1060
+ switch (job.kind) {
1061
+ case "focus": {
1062
+ if (typeof job.el.focus !== "function") break;
1063
+ try {
1064
+ job.el.focus({ preventScroll: true });
1065
+ } catch {
1066
+ job.el.focus();
1067
+ }
1068
+ break;
1069
+ }
1070
+ }
1071
+ }
1072
+ }
1073
+ function assignProp(el, name, val) {
1074
+ if (BOOL_PROPS.has(name)) {
1075
+ const on = val !== "false";
1076
+ el[name] = on;
1077
+ if (name === "defaultChecked" && "checked" in el) {
1078
+ el.checked = on;
1079
+ }
1080
+ return;
1081
+ }
1082
+ if (name === "defaultValue") {
1083
+ el.defaultValue = val;
1084
+ if (typeof el.value === "string" && (el.value === "" || el.value === el.defaultValue)) {
1085
+ el.value = val;
1086
+ }
1087
+ return;
1088
+ }
1089
+ el[name] = val;
1090
+ }
1972
1091
  function flushDomCmds(ptr, len, ctx) {
1973
1092
  const start = ptr >>> 0;
1974
1093
  const length = len >>> 0;
@@ -1980,6 +1099,7 @@ function flushDomCmds(ptr, len, ctx) {
1980
1099
  const recordsBytes = count * DOM_CMD_RECORD_SIZE;
1981
1100
  if (DOM_CMD_HEADER_SIZE + recordsBytes > length) return;
1982
1101
  const { domNodes: domNodes2, cleanupDomNodes: cleanupDomNodes2 } = ctx;
1102
+ const afterConnect = [];
1983
1103
  for (let i = 0; i < count; i++) {
1984
1104
  const off = DOM_CMD_HEADER_SIZE + i * DOM_CMD_RECORD_SIZE;
1985
1105
  const op = view.getUint8(off);
@@ -2011,266 +1131,963 @@ function flushDomCmds(ptr, len, ctx) {
2011
1131
  end.parentNode.insertBefore(child, end);
2012
1132
  break;
2013
1133
  }
2014
- case DomOp_SetAttr: {
2015
- domNodes2.get(p0)?.setAttribute(readString(p1, p2), readString(p3, p4));
2016
- break;
1134
+ case DomOp_SetAttr: {
1135
+ const el = domNodes2.get(p0);
1136
+ if (!el) break;
1137
+ const name = readString(p1, p2);
1138
+ const val = readString(p3, p4);
1139
+ el.setAttribute(name, val);
1140
+ if (name === "autofocus") {
1141
+ enqueueAfterConnect(afterConnect, el, "focus");
1142
+ }
1143
+ break;
1144
+ }
1145
+ case DomOp_SetProp: {
1146
+ const el = domNodes2.get(p0);
1147
+ if (el) assignProp(el, readString(p1, p2), readString(p3, p4));
1148
+ break;
1149
+ }
1150
+ case DomOp_RemoveAttr: {
1151
+ domNodes2.get(p0)?.removeAttribute(readString(p1, p2));
1152
+ break;
1153
+ }
1154
+ case DomOp_SetNodeValue: {
1155
+ const node = domNodes2.get(p0);
1156
+ if (node) node.nodeValue = readString(p1, p2);
1157
+ break;
1158
+ }
1159
+ case DomOp_SetInnerHtml: {
1160
+ const el = domNodes2.get(p0);
1161
+ if (el) el.innerHTML = readString(p1, p2);
1162
+ break;
1163
+ }
1164
+ case DomOp_AppendChild: {
1165
+ const parent = domNodes2.get(p0);
1166
+ const child = domNodes2.get(p1);
1167
+ if (parent && child) parent.appendChild(child);
1168
+ break;
1169
+ }
1170
+ case DomOp_InsertBefore: {
1171
+ const parent = domNodes2.get(p0);
1172
+ const child = domNodes2.get(p1);
1173
+ const refNode = domNodes2.get(p2) ?? null;
1174
+ if (parent && child) parent.insertBefore(child, refNode);
1175
+ break;
1176
+ }
1177
+ case DomOp_RemoveChild: {
1178
+ const parent = domNodes2.get(p0);
1179
+ const child = domNodes2.get(p1);
1180
+ if (parent && child) {
1181
+ parent.removeChild(child);
1182
+ cleanupDomNodes2(child);
1183
+ }
1184
+ break;
1185
+ }
1186
+ case DomOp_ReplaceChild: {
1187
+ const parent = domNodes2.get(p0);
1188
+ const newChild = domNodes2.get(p1);
1189
+ const oldChild = domNodes2.get(p2);
1190
+ if (parent && newChild && oldChild) {
1191
+ parent.replaceChild(newChild, oldChild);
1192
+ cleanupDomNodes2(oldChild);
1193
+ }
1194
+ break;
1195
+ }
1196
+ default:
1197
+ break;
1198
+ }
1199
+ }
1200
+ runAfterConnect(afterConnect);
1201
+ }
1202
+
1203
+ // src/wasm/generated/events.ts
1204
+ var DELEGATED_EVENTS = [
1205
+ "click",
1206
+ "dblclick",
1207
+ "input",
1208
+ "change",
1209
+ "submit",
1210
+ "focusin",
1211
+ "focusout",
1212
+ "keydown",
1213
+ "keyup",
1214
+ "keypress",
1215
+ "mouseenter",
1216
+ "mouseleave",
1217
+ "mousedown",
1218
+ "mouseup",
1219
+ "mousemove",
1220
+ "touchstart",
1221
+ "touchend",
1222
+ "touchmove",
1223
+ "scroll",
1224
+ "wheel",
1225
+ "pointerdown",
1226
+ "pointermove",
1227
+ "pointerup",
1228
+ "pointercancel",
1229
+ "pointerenter",
1230
+ "pointerleave",
1231
+ "lostpointercapture"
1232
+ ];
1233
+
1234
+ // src/wasm/generated/event_bits.ts
1235
+ var HIGH_FREQ_EVENT_BITS = 3031040;
1236
+
1237
+ // src/wasm/index.ts
1238
+ var ZxBridge = class extends ZxBridgeCore {
1239
+ #websockets = /* @__PURE__ */ new Map();
1240
+ #eventbridge;
1241
+ #eventbridgeAsync;
1242
+ constructor(exports) {
1243
+ super(exports);
1244
+ this.#eventbridge = exports.__zx_eventbridge;
1245
+ this.#eventbridgeAsync = wrapPromisingExport(
1246
+ exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
1247
+ );
1248
+ }
1249
+ hasEventHandler(velementId, eventTypeId) {
1250
+ return !!((eventHandlersPresent.get(velementId) ?? 0) & 1 << eventTypeId);
1251
+ }
1252
+ eventMaySuspend(velementId, eventTypeId) {
1253
+ return !!((eventHandlersSuspend.get(velementId) ?? 0) & 1 << eventTypeId);
1254
+ }
1255
+ setEventHandlerMode(velementId, eventTypeId, maySuspend) {
1256
+ const bit = 1 << eventTypeId;
1257
+ const present = (eventHandlersPresent.get(velementId) ?? 0) | bit;
1258
+ eventHandlersPresent.set(velementId, present);
1259
+ const suspendBits = eventHandlersSuspend.get(velementId) ?? 0;
1260
+ const nextSuspend = maySuspend ? suspendBits | bit : suspendBits & ~bit;
1261
+ if (nextSuspend === 0) eventHandlersSuspend.delete(velementId);
1262
+ else eventHandlersSuspend.set(velementId, nextSuspend);
1263
+ ensureDelegatedListener(eventTypeId);
1264
+ }
1265
+ clearEventHandlerModes(velementId) {
1266
+ const present = eventHandlersPresent.get(velementId) ?? 0;
1267
+ eventHandlersPresent.delete(velementId);
1268
+ eventHandlersSuspend.delete(velementId);
1269
+ for (let bits = present & HIGH_FREQ_EVENT_BITS; bits !== 0; bits &= bits - 1) {
1270
+ maybeRemoveHighFreqListener(31 - Math.clz32(bits));
1271
+ }
1272
+ }
1273
+ /** Submit a form action with bound-state round-trip. */
1274
+ submitFormActionAsync(form, actionId, statesJson, fetchId) {
1275
+ const formData = new FormData(form);
1276
+ formData.append("__$states", statesJson);
1277
+ fetch(window.location.href, {
1278
+ method: "POST",
1279
+ // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
1280
+ headers: { "x-action": String(actionId >>> 0) },
1281
+ body: formData
1282
+ }).then(async (response) => {
1283
+ const text = await response.text();
1284
+ this._notifyFetchComplete(fetchId, response.status, text, false);
1285
+ }).catch((error) => {
1286
+ const msg = error instanceof Error ? error.message : "Fetch failed";
1287
+ this._notifyFetchComplete(fetchId, 0, msg, true);
1288
+ });
1289
+ }
1290
+ /**
1291
+ * Create and connect a WebSocket.
1292
+ * Completes via `__zx_cb(ws_open|ws_message|ws_error|ws_close, ...)`.
1293
+ */
1294
+ wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
1295
+ const url = readString(urlPtr, urlLen);
1296
+ const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
1297
+ const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
1298
+ try {
1299
+ const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
1300
+ ws.binaryType = "arraybuffer";
1301
+ ws.onopen = () => {
1302
+ const protocol = ws.protocol || "";
1303
+ const [ptr, len] = this._writeStringToWasm(protocol);
1304
+ this._invoke(CallbackType_WebSocketOpen, wsId, BigInt(ptr), BigInt(len));
1305
+ };
1306
+ ws.onmessage = (event) => {
1307
+ const isBinary = event.data instanceof ArrayBuffer;
1308
+ const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
1309
+ const [ptr, len] = this.writeBytesToWasm(data);
1310
+ this._invoke(CallbackType_WebSocketMessage, wsId, BigInt(ptr), BigInt(len), BigInt(isBinary ? 1 : 0));
1311
+ };
1312
+ ws.onerror = (_event) => {
1313
+ const [ptr, len] = this._writeStringToWasm("WebSocket error");
1314
+ this._invoke(CallbackType_WebSocketError, wsId, BigInt(ptr), BigInt(len));
1315
+ };
1316
+ ws.onclose = (event) => {
1317
+ const reason = event.reason || "";
1318
+ const [ptr, len] = this._writeStringToWasm(reason);
1319
+ const c = BigInt(len) | BigInt(event.wasClean ? 1 : 0) << 32n;
1320
+ this._invoke(CallbackType_WebSocketClose, wsId, BigInt(event.code), BigInt(ptr), c);
1321
+ this.#websockets.delete(wsId);
1322
+ };
1323
+ this.#websockets.set(wsId, ws);
1324
+ } catch (error) {
1325
+ const msg = error instanceof Error ? error.message : "WebSocket connection failed";
1326
+ const [ptr, len] = this._writeStringToWasm(msg);
1327
+ this._invoke(CallbackType_WebSocketError, wsId, BigInt(ptr), BigInt(len));
1328
+ }
1329
+ }
1330
+ /** Send data over WebSocket */
1331
+ wsSend(wsId, dataPtr, dataLen, isBinary) {
1332
+ const ws = this.#websockets.get(wsId);
1333
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
1334
+ const memory = getMemoryView();
1335
+ const start = dataPtr >>> 0;
1336
+ const length = dataLen >>> 0;
1337
+ if (start + length > memory.byteLength) return;
1338
+ if (isBinary) {
1339
+ ws.send(memory.slice(start, start + length));
1340
+ } else {
1341
+ ws.send(textDecoder.decode(memory.subarray(start, start + length)));
1342
+ }
1343
+ }
1344
+ /** Close WebSocket connection */
1345
+ wsClose(wsId, code, reasonPtr, reasonLen) {
1346
+ const ws = this.#websockets.get(wsId);
1347
+ if (!ws) return;
1348
+ const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : void 0;
1349
+ try {
1350
+ if (reason) ws.close(code, reason);
1351
+ else ws.close(code);
1352
+ } catch {
1353
+ ws.close();
1354
+ }
1355
+ }
1356
+ dispose() {
1357
+ super.dispose();
1358
+ eventHandlersPresent.clear();
1359
+ eventHandlersSuspend.clear();
1360
+ for (const ws of this.#websockets.values()) {
1361
+ try {
1362
+ ws.close();
1363
+ } catch {
1364
+ }
1365
+ }
1366
+ this.#websockets.clear();
1367
+ }
1368
+ /**
1369
+ * Dispatch to WASM for one vnode. Caller owns `eventRef` lifetime
1370
+ * (store once per bubble, release after sync/async work completes).
1371
+ */
1372
+ eventbridge(velementId, eventTypeId, eventRef) {
1373
+ const id = BigInt(velementId >>> 0);
1374
+ if (this.eventMaySuspend(velementId, eventTypeId)) {
1375
+ return invokeWasmExport(this.#eventbridgeAsync, id, eventTypeId, eventRef);
1376
+ }
1377
+ invokeWasmExport(this.#eventbridge, id, eventTypeId, eventRef);
1378
+ }
1379
+ /** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
1380
+ static createImportObject(bridgeRef) {
1381
+ return {
1382
+ ...jsz.importObject(),
1383
+ __zx_net: createFetchImports(() => {
1384
+ if (!jsz.memory) throw new Error("WASM memory is not ready");
1385
+ return jsz.memory;
1386
+ }),
1387
+ __zx: {
1388
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
1389
+ _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
1390
+ bridgeRef[0]?.setEventHandlerMode(Number(vnodeId), eventTypeId, maySuspend !== 0);
1391
+ },
1392
+ _clearEventHandlerModes: (vnodeId) => {
1393
+ bridgeRef[0]?.clearEventHandlerModes(Number(vnodeId));
1394
+ },
1395
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
1396
+ bridgeRef[0]?.fetchAsync(
1397
+ urlPtr,
1398
+ urlLen,
1399
+ methodPtr,
1400
+ methodLen,
1401
+ headersPtr,
1402
+ headersLen,
1403
+ bodyPtr,
1404
+ bodyLen,
1405
+ timeoutMs,
1406
+ fetchId
1407
+ );
1408
+ },
1409
+ _setTimeout: (callbackId, delayMs) => {
1410
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
1411
+ },
1412
+ _setInterval: (callbackId, intervalMs) => {
1413
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
1414
+ },
1415
+ _clearInterval: (callbackId) => {
1416
+ bridgeRef[0]?.clearInterval(callbackId);
1417
+ },
1418
+ // WebSocket API
1419
+ _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
1420
+ bridgeRef[0]?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
1421
+ },
1422
+ _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
1423
+ bridgeRef[0]?.wsSend(wsId, dataPtr, dataLen, isBinary);
1424
+ },
1425
+ _wsClose: (wsId, code, reasonPtr, reasonLen) => {
1426
+ bridgeRef[0]?.wsClose(wsId, code, reasonPtr, reasonLen);
1427
+ },
1428
+ _flush: (ptr, len) => {
1429
+ flushDomCmds(ptr, len, {
1430
+ domNodes,
1431
+ cleanupDomNodes
1432
+ });
1433
+ },
1434
+ _getLocationHref: (bufPtr, bufLen) => {
1435
+ const bytes = textEncoder.encode(window.location.href);
1436
+ const len = Math.min(bytes.length, bufLen);
1437
+ writeBytes(bufPtr, bytes.subarray(0, len));
1438
+ return len;
1439
+ },
1440
+ _getFormData: (eventRef, outPtrAddr) => {
1441
+ const event = loadValueFromRef(eventRef);
1442
+ const el = event?.target;
1443
+ const form = el instanceof HTMLFormElement ? el : el?.closest?.("form") ?? null;
1444
+ if (!form) return 0;
1445
+ const entries = [];
1446
+ for (const [k, v] of new FormData(form).entries()) {
1447
+ entries.push(k, String(v));
1448
+ }
1449
+ const bytes = textEncoder.encode(JSON.stringify(entries));
1450
+ const [ptr, len] = bridgeRef[0].writeBytesToWasm(bytes);
1451
+ new DataView(jsz.memory.buffer).setUint32(outPtrAddr, ptr, true);
1452
+ return len;
1453
+ },
1454
+ _submitFormAction: (vnodeId, actionId) => {
1455
+ const form = domNodes.get(Number(vnodeId));
1456
+ if (!form || !(form instanceof HTMLFormElement)) return;
1457
+ const formData = new FormData(form);
1458
+ fetch(window.location.href, {
1459
+ method: "POST",
1460
+ // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
1461
+ headers: { "x-action": String(actionId >>> 0) },
1462
+ body: formData
1463
+ }).catch(() => {
1464
+ });
1465
+ },
1466
+ _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
1467
+ const form = domNodes.get(Number(vnodeId));
1468
+ if (!form || !(form instanceof HTMLFormElement)) return;
1469
+ const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
1470
+ bridgeRef[0]?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1471
+ },
1472
+ _formReset: (vnodeId) => {
1473
+ const form = domNodes.get(Number(vnodeId));
1474
+ if (form instanceof HTMLFormElement) form.reset();
1475
+ }
1476
+ }
1477
+ };
1478
+ }
1479
+ };
1480
+ var domNodes = /* @__PURE__ */ new Map();
1481
+ var eventHandlersPresent = /* @__PURE__ */ new Map();
1482
+ var eventHandlersSuspend = /* @__PURE__ */ new Map();
1483
+ function cleanupDomNodes(node) {
1484
+ const stack = [node];
1485
+ let highFreqBits = 0;
1486
+ while (stack.length > 0) {
1487
+ const n = stack.pop();
1488
+ const ref = n.__zx_ref;
1489
+ if (typeof ref === "number") {
1490
+ const present = eventHandlersPresent.get(ref);
1491
+ if (present !== void 0) {
1492
+ highFreqBits |= present;
1493
+ eventHandlersPresent.delete(ref);
1494
+ eventHandlersSuspend.delete(ref);
2017
1495
  }
2018
- case DomOp_SetProp: {
2019
- const el = domNodes2.get(p0);
2020
- if (el) {
2021
- const name = readString(p1, p2);
2022
- const val = readString(p3, p4);
2023
- if (name === "checked" || name === "selected" || name === "muted") {
2024
- el[name] = val !== "false";
2025
- } else {
2026
- el[name] = val;
2027
- }
1496
+ domNodes.delete(ref);
1497
+ }
1498
+ const children = n.childNodes;
1499
+ for (let i = 0; i < children.length; i++) stack.push(children[i]);
1500
+ }
1501
+ for (let bits = highFreqBits & HIGH_FREQ_EVENT_BITS; bits !== 0; bits &= bits - 1) {
1502
+ maybeRemoveHighFreqListener(31 - Math.clz32(bits));
1503
+ }
1504
+ }
1505
+ var delegationState = null;
1506
+ function makeDelegatedListener(bridge, eventTypeId) {
1507
+ return (event) => {
1508
+ let eventRef;
1509
+ const pending = [];
1510
+ let target = event.target;
1511
+ while (target && target !== document.body) {
1512
+ const zxRef = target.__zx_ref;
1513
+ if (typeof zxRef === "number" && bridge.hasEventHandler(zxRef, eventTypeId)) {
1514
+ if (eventRef === void 0) eventRef = storeValueGetRef(event);
1515
+ const result = bridge.eventbridge(zxRef, eventTypeId, eventRef);
1516
+ if (result && typeof result.then === "function") {
1517
+ pending.push(result);
2028
1518
  }
2029
- break;
1519
+ if (event.cancelBubble) break;
2030
1520
  }
2031
- case DomOp_RemoveAttr: {
2032
- domNodes2.get(p0)?.removeAttribute(readString(p1, p2));
2033
- break;
1521
+ target = target.parentElement;
1522
+ }
1523
+ if (eventRef !== void 0) {
1524
+ const ref = eventRef;
1525
+ if (pending.length > 0) {
1526
+ Promise.all(pending).finally(() => releaseValueRef(ref));
1527
+ } else {
1528
+ releaseValueRef(ref);
1529
+ }
1530
+ }
1531
+ };
1532
+ }
1533
+ function ensureDelegatedListener(eventTypeId) {
1534
+ const state = delegationState;
1535
+ if (!state || state.attached.has(eventTypeId)) return;
1536
+ const domType = DELEGATED_EVENTS[eventTypeId];
1537
+ if (!domType) return;
1538
+ const passive = domType.startsWith("touch") || domType === "scroll";
1539
+ const options = { passive };
1540
+ const listener = makeDelegatedListener(state.bridge, eventTypeId);
1541
+ state.root.addEventListener(domType, listener, options);
1542
+ state.attached.set(eventTypeId, { listener, options });
1543
+ }
1544
+ function anyHandlerForType(eventTypeId) {
1545
+ const bit = 1 << eventTypeId;
1546
+ for (const mask of eventHandlersPresent.values()) {
1547
+ if (mask & bit) return true;
1548
+ }
1549
+ return false;
1550
+ }
1551
+ function maybeRemoveHighFreqListener(eventTypeId) {
1552
+ if ((HIGH_FREQ_EVENT_BITS & 1 << eventTypeId) === 0) return;
1553
+ if (anyHandlerForType(eventTypeId)) return;
1554
+ const state = delegationState;
1555
+ if (!state) return;
1556
+ const entry = state.attached.get(eventTypeId);
1557
+ if (!entry) return;
1558
+ const domType = DELEGATED_EVENTS[eventTypeId];
1559
+ state.root.removeEventListener(domType, entry.listener, entry.options);
1560
+ state.attached.delete(eventTypeId);
1561
+ }
1562
+
1563
+ // src/runtime/db/extern.ts
1564
+ function decodeBlob(base64) {
1565
+ const binary = atob(base64);
1566
+ const bytes = new Uint8Array(binary.length);
1567
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
1568
+ return bytes;
1569
+ }
1570
+ function toDbValue(value) {
1571
+ switch (value.kind) {
1572
+ case "null":
1573
+ return null;
1574
+ case "integer":
1575
+ return value.integer;
1576
+ case "float":
1577
+ return value.float;
1578
+ case "text":
1579
+ return value.text;
1580
+ case "blob":
1581
+ return decodeBlob(value.blob);
1582
+ case "boolean":
1583
+ return value.boolean;
1584
+ }
1585
+ }
1586
+ function toPositionalBindings(json) {
1587
+ switch (json.kind) {
1588
+ case "none":
1589
+ return [];
1590
+ case "positional":
1591
+ return json.values.map(toDbValue);
1592
+ case "named":
1593
+ throw new Error("named SQL bindings are not supported yet");
1594
+ }
1595
+ }
1596
+ function toWireValue(value) {
1597
+ if (value === null || value === void 0) return { kind: "null" };
1598
+ if (typeof value === "string") return { kind: "text", text: value };
1599
+ if (typeof value === "boolean") return { kind: "boolean", boolean: value };
1600
+ if (typeof value === "number") {
1601
+ return Number.isInteger(value) ? { kind: "integer", integer: value } : { kind: "float", float: value };
1602
+ }
1603
+ if (value instanceof ArrayBuffer) {
1604
+ const bytes = new Uint8Array(value);
1605
+ let binary = "";
1606
+ for (const byte of bytes) binary += String.fromCharCode(byte);
1607
+ return { kind: "blob", blob: btoa(binary) };
1608
+ }
1609
+ if (ArrayBuffer.isView(value)) {
1610
+ const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1611
+ let binary = "";
1612
+ for (const byte of bytes) binary += String.fromCharCode(byte);
1613
+ return { kind: "blob", blob: btoa(binary) };
1614
+ }
1615
+ return { kind: "text", text: String(value) };
1616
+ }
1617
+ function objectToWireRow(record) {
1618
+ return {
1619
+ fields: Object.entries(record).map(([name, value]) => ({
1620
+ name,
1621
+ value: toWireValue(value)
1622
+ }))
1623
+ };
1624
+ }
1625
+ function valuesToWireRows(rows) {
1626
+ return rows.map((row) => row.map((value) => toWireValue(value)));
1627
+ }
1628
+ function createDbImports(bindings, getMemory, allocRef) {
1629
+ const decoder3 = new TextDecoder();
1630
+ function readStr2(ptr, len) {
1631
+ return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
1632
+ }
1633
+ function binding(ns) {
1634
+ return bindings[ns] ?? bindings["default"] ?? null;
1635
+ }
1636
+ async function statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len) {
1637
+ const database = binding(readStr2(ns_ptr, ns_len));
1638
+ if (!database) return null;
1639
+ const sql = readStr2(sql_ptr, sql_len);
1640
+ const bindingsJson = JSON.parse(readStr2(bindings_ptr, bindings_len));
1641
+ return database.prepare(sql).bind(...toPositionalBindings(bindingsJson));
1642
+ }
1643
+ const Suspending2 = WebAssembly.Suspending;
1644
+ if (typeof Suspending2 !== "function") {
1645
+ return {
1646
+ db_open: (_ns, _ns_len) => -1,
1647
+ db_run: (_a, _b, _c, _d, _e, _f, _g) => -1,
1648
+ db_get: (_a, _b, _c, _d, _e, _f, _g) => -1,
1649
+ db_all: (_a, _b, _c, _d, _e, _f, _g) => -1,
1650
+ db_values: (_a, _b, _c, _d, _e, _f, _g) => -1
1651
+ };
1652
+ }
1653
+ return {
1654
+ db_open: (ns_ptr, ns_len) => binding(readStr2(ns_ptr, ns_len)) ? 0 : -1,
1655
+ db_run: new Suspending2(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
1656
+ const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
1657
+ if (!stmt) return -1;
1658
+ const result = await stmt.run();
1659
+ return writeJsonOut(getMemory, allocRef, out_ptr, {
1660
+ last_insert_rowid: result.meta?.last_row_id ?? 0,
1661
+ changes: result.meta?.changes ?? 0
1662
+ });
1663
+ }),
1664
+ db_get: new Suspending2(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
1665
+ const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
1666
+ if (!stmt) return -1;
1667
+ const row = await stmt.first();
1668
+ if (!row) {
1669
+ new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
1670
+ return 0;
2034
1671
  }
2035
- case DomOp_SetNodeValue: {
2036
- const node = domNodes2.get(p0);
2037
- if (node) node.nodeValue = readString(p1, p2);
2038
- break;
1672
+ return writeJsonOut(getMemory, allocRef, out_ptr, [objectToWireRow(row)]);
1673
+ }),
1674
+ db_all: new Suspending2(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
1675
+ const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
1676
+ if (!stmt) return -1;
1677
+ const result = await stmt.all();
1678
+ const rows = (result.results ?? []).map(objectToWireRow);
1679
+ if (rows.length === 0) {
1680
+ new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
1681
+ return 0;
2039
1682
  }
2040
- case DomOp_SetInnerHtml: {
2041
- const el = domNodes2.get(p0);
2042
- if (el) el.innerHTML = readString(p1, p2);
2043
- break;
1683
+ return writeJsonOut(getMemory, allocRef, out_ptr, rows);
1684
+ }),
1685
+ db_values: new Suspending2(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
1686
+ const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
1687
+ if (!stmt) return -1;
1688
+ const rows = await stmt.raw();
1689
+ if (rows.length === 0) {
1690
+ new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
1691
+ return 0;
2044
1692
  }
2045
- case DomOp_AppendChild: {
2046
- const parent = domNodes2.get(p0);
2047
- const child = domNodes2.get(p1);
2048
- if (parent && child) parent.appendChild(child);
2049
- break;
1693
+ return writeJsonOut(getMemory, allocRef, out_ptr, valuesToWireRows(rows));
1694
+ })
1695
+ };
1696
+ }
1697
+
1698
+ // src/runtime/wasi.ts
1699
+ var ProcExit = class extends Error {
1700
+ constructor(code) {
1701
+ super(`proc_exit(${code})`);
1702
+ this.code = code;
1703
+ }
1704
+ };
1705
+ function createWasiImports({
1706
+ request,
1707
+ stdinData
1708
+ }) {
1709
+ const encoder3 = new TextEncoder();
1710
+ const url = new URL(request.url);
1711
+ const argStrings = [
1712
+ "wasm",
1713
+ "--pathname",
1714
+ url.pathname,
1715
+ "--method",
1716
+ request.method,
1717
+ "--search",
1718
+ url.search,
1719
+ "--url",
1720
+ url.href
1721
+ ];
1722
+ request.headers.forEach((value, name) => {
1723
+ if (value) argStrings.push("--header", `${name}:${value}`);
1724
+ });
1725
+ const encodedArgs = argStrings.map((a) => encoder3.encode(a + "\0"));
1726
+ const argBufSize = encodedArgs.reduce((s, a) => s + a.length, 0);
1727
+ let wasmMemory = null;
1728
+ const setMemory = (m2) => {
1729
+ wasmMemory = m2;
1730
+ };
1731
+ let stderrPartial = "";
1732
+ const stderrDecoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
1733
+ function processStderrChunk(chunk) {
1734
+ const text = stderrDecoder.decode(chunk, { stream: true });
1735
+ const lines = (stderrPartial + text).split("\n");
1736
+ stderrPartial = lines.pop() ?? "";
1737
+ for (const line of lines) {
1738
+ if (line.length > 0) {
1739
+ console.error("[ziex]", line);
2050
1740
  }
2051
- case DomOp_InsertBefore: {
2052
- const parent = domNodes2.get(p0);
2053
- const child = domNodes2.get(p1);
2054
- const refNode = domNodes2.get(p2) ?? null;
2055
- if (parent && child) parent.insertBefore(child, refNode);
2056
- break;
1741
+ }
1742
+ }
1743
+ let stdinOffset = 0;
1744
+ function v() {
1745
+ return new DataView(wasmMemory.buffer);
1746
+ }
1747
+ function m() {
1748
+ return new Uint8Array(wasmMemory.buffer);
1749
+ }
1750
+ const wasiImport = {
1751
+ args_sizes_get(argc_ptr, argv_buf_size_ptr) {
1752
+ v().setUint32(argc_ptr, encodedArgs.length, true);
1753
+ v().setUint32(argv_buf_size_ptr, argBufSize, true);
1754
+ return 0;
1755
+ },
1756
+ args_get(argv_ptr, argv_buf_ptr) {
1757
+ const dv = v();
1758
+ const mem = m();
1759
+ let offset = argv_buf_ptr;
1760
+ for (const arg of encodedArgs) {
1761
+ dv.setUint32(argv_ptr, offset, true);
1762
+ mem.set(arg, offset);
1763
+ argv_ptr += 4;
1764
+ offset += arg.length;
2057
1765
  }
2058
- case DomOp_RemoveChild: {
2059
- const parent = domNodes2.get(p0);
2060
- const child = domNodes2.get(p1);
2061
- if (parent && child) {
2062
- parent.removeChild(child);
2063
- cleanupDomNodes2(child);
2064
- }
2065
- break;
1766
+ return 0;
1767
+ },
1768
+ environ_sizes_get(count_ptr, buf_size_ptr) {
1769
+ v().setUint32(count_ptr, 0, true);
1770
+ v().setUint32(buf_size_ptr, 0, true);
1771
+ return 0;
1772
+ },
1773
+ environ_get(_environ_ptr, _environ_buf_ptr) {
1774
+ return 0;
1775
+ },
1776
+ fd_write(fd, iovs_ptr, iovs_len, nwritten_ptr) {
1777
+ const dv = v();
1778
+ const mem = m();
1779
+ let written = 0;
1780
+ for (let i = 0; i < iovs_len; i++) {
1781
+ const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
1782
+ const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
1783
+ const chunk = mem.slice(buf_ptr, buf_ptr + buf_len);
1784
+ if (fd === 2) processStderrChunk(chunk);
1785
+ written += buf_len;
2066
1786
  }
2067
- case DomOp_ReplaceChild: {
2068
- const parent = domNodes2.get(p0);
2069
- const newChild = domNodes2.get(p1);
2070
- const oldChild = domNodes2.get(p2);
2071
- if (parent && newChild && oldChild) {
2072
- parent.replaceChild(newChild, oldChild);
2073
- cleanupDomNodes2(oldChild);
1787
+ dv.setUint32(nwritten_ptr, written, true);
1788
+ return 0;
1789
+ },
1790
+ fd_read(fd, iovs_ptr, iovs_len, nread_ptr) {
1791
+ const dv = v();
1792
+ const mem = m();
1793
+ const stdin = stdinData ?? new Uint8Array(0);
1794
+ let totalRead = 0;
1795
+ for (let i = 0; i < iovs_len; i++) {
1796
+ const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
1797
+ const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
1798
+ if (fd === 0 && stdinOffset < stdin.length) {
1799
+ const toRead = Math.min(buf_len, stdin.length - stdinOffset);
1800
+ mem.set(stdin.subarray(stdinOffset, stdinOffset + toRead), buf_ptr);
1801
+ stdinOffset += toRead;
1802
+ totalRead += toRead;
2074
1803
  }
2075
- break;
2076
1804
  }
2077
- default:
2078
- break;
1805
+ dv.setUint32(nread_ptr, totalRead, true);
1806
+ return 0;
1807
+ },
1808
+ fd_fdstat_get(_fd, fdstat_ptr) {
1809
+ const dv = v();
1810
+ dv.setUint8(fdstat_ptr, 2);
1811
+ dv.setUint8(fdstat_ptr + 1, 0);
1812
+ dv.setUint16(fdstat_ptr + 2, 0, true);
1813
+ dv.setUint32(fdstat_ptr + 4, 0, true);
1814
+ dv.setBigUint64(fdstat_ptr + 8, 0n, true);
1815
+ dv.setBigUint64(fdstat_ptr + 16, 0n, true);
1816
+ return 0;
1817
+ },
1818
+ fd_prestat_get(_fd, _bufptr) {
1819
+ return 8;
1820
+ },
1821
+ fd_prestat_dir_name(_fd, _path, _path_len) {
1822
+ return 8;
1823
+ },
1824
+ fd_close(_fd) {
1825
+ return 0;
1826
+ },
1827
+ fd_pread(_fd, _iovs, _iovs_len, _offset, nread_ptr) {
1828
+ v().setUint32(nread_ptr, 0, true);
1829
+ return 0;
1830
+ },
1831
+ fd_pwrite(_fd, _iovs, _iovs_len, _offset, nwritten_ptr) {
1832
+ v().setUint32(nwritten_ptr, 0, true);
1833
+ return 0;
1834
+ },
1835
+ fd_filestat_get(_fd, filestat_ptr) {
1836
+ const dv = v();
1837
+ dv.setBigUint64(filestat_ptr, 0n, true);
1838
+ dv.setBigUint64(filestat_ptr + 8, 0n, true);
1839
+ dv.setUint8(filestat_ptr + 16, 2);
1840
+ dv.setBigUint64(filestat_ptr + 24, 1n, true);
1841
+ dv.setBigUint64(filestat_ptr + 32, 0n, true);
1842
+ dv.setBigUint64(filestat_ptr + 40, 0n, true);
1843
+ dv.setBigUint64(filestat_ptr + 48, 0n, true);
1844
+ dv.setBigUint64(filestat_ptr + 56, 0n, true);
1845
+ return 0;
1846
+ },
1847
+ fd_filestat_set_size(_fd, _size) {
1848
+ return 76;
1849
+ },
1850
+ fd_filestat_set_times(_fd, _atim, _mtim, _fst_flags) {
1851
+ return 76;
1852
+ },
1853
+ fd_fdstat_set_flags(_fd, _flags) {
1854
+ return 0;
1855
+ },
1856
+ fd_fdstat_set_rights(_fd, _rights_base, _rights_inheriting) {
1857
+ return 0;
1858
+ },
1859
+ fd_sync(_fd) {
1860
+ return 0;
1861
+ },
1862
+ fd_datasync(_fd) {
1863
+ return 0;
1864
+ },
1865
+ fd_advise(_fd, _offset, _len, _advice) {
1866
+ return 0;
1867
+ },
1868
+ fd_allocate(_fd, _offset, _len) {
1869
+ return 76;
1870
+ },
1871
+ fd_tell(_fd, offset_ptr) {
1872
+ v().setBigUint64(offset_ptr, 0n, true);
1873
+ return 0;
1874
+ },
1875
+ fd_renumber(_from, _to) {
1876
+ return 0;
1877
+ },
1878
+ path_filestat_set_times(_fd, _flags, _path, _path_len, _atim, _mtim, _fst_flags) {
1879
+ return 76;
1880
+ },
1881
+ path_link(_old_fd, _old_flags, _old_path, _old_path_len, _new_fd, _new_path, _new_path_len) {
1882
+ return 76;
1883
+ },
1884
+ path_symlink(_old_path, _old_path_len, _fd, _new_path, _new_path_len) {
1885
+ return 76;
1886
+ },
1887
+ proc_raise(_sig) {
1888
+ return 0;
1889
+ },
1890
+ sock_recv(_fd, _ri_data, _ri_data_len, _ri_flags, ro_datalen_ptr, ro_flags_ptr) {
1891
+ v().setUint32(ro_datalen_ptr, 0, true);
1892
+ v().setUint32(ro_flags_ptr, 0, true);
1893
+ return 76;
1894
+ },
1895
+ sock_send(_fd, _si_data, _si_data_len, _si_flags, so_datalen_ptr) {
1896
+ v().setUint32(so_datalen_ptr, 0, true);
1897
+ return 76;
1898
+ },
1899
+ sock_shutdown(_fd, _how) {
1900
+ return 76;
1901
+ },
1902
+ fd_seek(_fd, _offset, _whence, newoffset_ptr) {
1903
+ v().setBigInt64(newoffset_ptr, 0n, true);
1904
+ return 0;
1905
+ },
1906
+ proc_exit(code) {
1907
+ throw new ProcExit(code);
1908
+ },
1909
+ sched_yield() {
1910
+ return 0;
1911
+ },
1912
+ clock_time_get(_id, _precision, time_ptr) {
1913
+ v().setBigUint64(time_ptr, BigInt(Date.now()) * 1000000n, true);
1914
+ return 0;
1915
+ },
1916
+ clock_res_get(_id, res_ptr) {
1917
+ v().setBigUint64(res_ptr, 1000000n, true);
1918
+ return 0;
1919
+ },
1920
+ random_get(buf_ptr, buf_len) {
1921
+ crypto.getRandomValues(new Uint8Array(wasmMemory.buffer, buf_ptr, buf_len));
1922
+ return 0;
1923
+ },
1924
+ path_open(_fd, _dirflags, _path, _path_len, _oflags, _rights_base, _rights_inheriting, _fdflags, opened_fd_ptr) {
1925
+ v().setInt32(opened_fd_ptr, -1, true);
1926
+ return 76;
1927
+ },
1928
+ path_create_directory(_fd, _path, _path_len) {
1929
+ return 76;
1930
+ },
1931
+ path_unlink_file(_fd, _path, _path_len) {
1932
+ return 76;
1933
+ },
1934
+ path_remove_directory(_fd, _path, _path_len) {
1935
+ return 76;
1936
+ },
1937
+ path_rename(_fd, _old_path, _old_path_len, _new_fd, _new_path, _new_path_len) {
1938
+ return 76;
1939
+ },
1940
+ path_filestat_get(_fd, _flags, _path, _path_len, filestat_ptr) {
1941
+ new Uint8Array(wasmMemory.buffer, filestat_ptr, 64).fill(0);
1942
+ return 76;
1943
+ },
1944
+ path_readlink(_fd, _path, _path_len, _buf, _buf_len, nread_ptr) {
1945
+ v().setUint32(nread_ptr, 0, true);
1946
+ return 76;
1947
+ },
1948
+ fd_readdir(_fd, _buf, _buf_len, _cookie, bufused_ptr) {
1949
+ v().setUint32(bufused_ptr, 0, true);
1950
+ return 76;
1951
+ },
1952
+ poll_oneoff(_in, _out, _nsubscriptions, nevents_ptr) {
1953
+ v().setUint32(nevents_ptr, 0, true);
1954
+ return 0;
2079
1955
  }
1956
+ };
1957
+ return { wasiImport, setMemory };
1958
+ }
1959
+ function mergeUint8Arrays(arrays) {
1960
+ const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
1961
+ const result = new Uint8Array(totalLen);
1962
+ let offset = 0;
1963
+ for (const arr of arrays) {
1964
+ result.set(arr, offset);
1965
+ offset += arr.length;
2080
1966
  }
1967
+ return result;
2081
1968
  }
2082
1969
 
2083
- // src/wasm/generated/events.ts
2084
- var DELEGATED_EVENTS = [
2085
- "click",
2086
- "dblclick",
2087
- "input",
2088
- "change",
2089
- "submit",
2090
- "focusin",
2091
- "focusout",
2092
- "keydown",
2093
- "keyup",
2094
- "keypress",
2095
- "mouseenter",
2096
- "mouseleave",
2097
- "mousedown",
2098
- "mouseup",
2099
- "mousemove",
2100
- "touchstart",
2101
- "touchend",
2102
- "touchmove",
2103
- "scroll",
2104
- "wheel",
2105
- "pointerdown",
2106
- "pointermove",
2107
- "pointerup",
2108
- "pointercancel",
2109
- "pointerenter",
2110
- "pointerleave",
2111
- "lostpointercapture"
2112
- ];
2113
-
2114
- // src/wasm/generated/event_bits.ts
2115
- var HIGH_FREQ_EVENT_BITS = 3031040;
2116
-
2117
- // src/wasm/index.ts
2118
- var ZxBridge = class extends ZxBridgeCore {
2119
- #websockets = /* @__PURE__ */ new Map();
2120
- #eventbridge;
2121
- #eventbridgeAsync;
1970
+ // src/wasm/wasi.ts
1971
+ var decoder2 = new TextDecoder();
1972
+ var encoder2 = new TextEncoder();
1973
+ var ZxWasiBridge = class {
1974
+ #alloc;
1975
+ #memory;
1976
+ #cb;
1977
+ #intervals = /* @__PURE__ */ new Map();
1978
+ // Cached memory view - invalidated when the WASM buffer grows.
1979
+ #memView = null;
1980
+ #memBuf = null;
2122
1981
  constructor(exports) {
2123
- super(exports);
2124
- this.#eventbridge = exports.__zx_eventbridge;
2125
- this.#eventbridgeAsync = wrapPromisingExport(
2126
- exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
2127
- );
2128
- }
2129
- hasEventHandler(velementId, eventTypeId) {
2130
- return !!((eventHandlersPresent.get(velementId) ?? 0) & 1 << eventTypeId);
2131
- }
2132
- eventMaySuspend(velementId, eventTypeId) {
2133
- return !!((eventHandlersSuspend.get(velementId) ?? 0) & 1 << eventTypeId);
2134
- }
2135
- setEventHandlerMode(velementId, eventTypeId, maySuspend) {
2136
- const bit = 1 << eventTypeId;
2137
- const present = (eventHandlersPresent.get(velementId) ?? 0) | bit;
2138
- eventHandlersPresent.set(velementId, present);
2139
- const suspendBits = eventHandlersSuspend.get(velementId) ?? 0;
2140
- const nextSuspend = maySuspend ? suspendBits | bit : suspendBits & ~bit;
2141
- if (nextSuspend === 0) eventHandlersSuspend.delete(velementId);
2142
- else eventHandlersSuspend.set(velementId, nextSuspend);
2143
- ensureDelegatedListener(eventTypeId);
2144
- }
2145
- clearEventHandlerModes(velementId) {
2146
- const present = eventHandlersPresent.get(velementId) ?? 0;
2147
- eventHandlersPresent.delete(velementId);
2148
- eventHandlersSuspend.delete(velementId);
2149
- for (let bits = present & HIGH_FREQ_EVENT_BITS; bits !== 0; bits &= bits - 1) {
2150
- maybeRemoveHighFreqListener(31 - Math.clz32(bits));
2151
- }
2152
- }
2153
- /** Submit a form action with bound-state round-trip. */
2154
- submitFormActionAsync(form, actionId, statesJson, fetchId) {
2155
- const formData = new FormData(form);
2156
- formData.append("__$states", statesJson);
2157
- fetch(window.location.href, {
2158
- method: "POST",
2159
- // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
2160
- headers: { "x-action": String(actionId >>> 0) },
2161
- body: formData
2162
- }).then(async (response) => {
2163
- const text = await response.text();
2164
- this._notifyFetchComplete(fetchId, response.status, text, false);
2165
- }).catch((error) => {
2166
- const msg = error instanceof Error ? error.message : "Fetch failed";
2167
- this._notifyFetchComplete(fetchId, 0, msg, true);
2168
- });
1982
+ this.#memory = exports.memory;
1983
+ this.#alloc = exports.__zx_alloc;
1984
+ this.#cb = exports.__zx_cb;
2169
1985
  }
2170
- /**
2171
- * Create and connect a WebSocket.
2172
- * Completes via `__zx_cb(ws_open|ws_message|ws_error|ws_close, ...)`.
2173
- */
2174
- wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
2175
- const url = readString(urlPtr, urlLen);
2176
- const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
2177
- const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
2178
- try {
2179
- const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
2180
- ws.binaryType = "arraybuffer";
2181
- ws.onopen = () => {
2182
- const protocol = ws.protocol || "";
2183
- const [ptr, len] = this._writeStringToWasm(protocol);
2184
- this._invoke(CallbackType_WebSocketOpen, wsId, BigInt(ptr), BigInt(len));
2185
- };
2186
- ws.onmessage = (event) => {
2187
- const isBinary = event.data instanceof ArrayBuffer;
2188
- const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
2189
- const [ptr, len] = this.writeBytesToWasm(data);
2190
- this._invoke(CallbackType_WebSocketMessage, wsId, BigInt(ptr), BigInt(len), BigInt(isBinary ? 1 : 0));
2191
- };
2192
- ws.onerror = (_event) => {
2193
- const [ptr, len] = this._writeStringToWasm("WebSocket error");
2194
- this._invoke(CallbackType_WebSocketError, wsId, BigInt(ptr), BigInt(len));
2195
- };
2196
- ws.onclose = (event) => {
2197
- const reason = event.reason || "";
2198
- const [ptr, len] = this._writeStringToWasm(reason);
2199
- const c = BigInt(len) | BigInt(event.wasClean ? 1 : 0) << 32n;
2200
- this._invoke(CallbackType_WebSocketClose, wsId, BigInt(event.code), BigInt(ptr), c);
2201
- this.#websockets.delete(wsId);
2202
- };
2203
- this.#websockets.set(wsId, ws);
2204
- } catch (error) {
2205
- const msg = error instanceof Error ? error.message : "WebSocket connection failed";
2206
- const [ptr, len] = this._writeStringToWasm(msg);
2207
- this._invoke(CallbackType_WebSocketError, wsId, BigInt(ptr), BigInt(len));
1986
+ #view() {
1987
+ const buf = this.#memory.buffer;
1988
+ if (buf !== this.#memBuf) {
1989
+ this.#memBuf = buf;
1990
+ this.#memView = new Uint8Array(buf);
2208
1991
  }
1992
+ return this.#memView;
2209
1993
  }
2210
- /** Send data over WebSocket */
2211
- wsSend(wsId, dataPtr, dataLen, isBinary) {
2212
- const ws = this.#websockets.get(wsId);
2213
- if (!ws || ws.readyState !== WebSocket.OPEN) return;
2214
- const memory = getMemoryView();
2215
- const start = dataPtr >>> 0;
2216
- const length = dataLen >>> 0;
2217
- if (start + length > memory.byteLength) return;
2218
- if (isBinary) {
2219
- ws.send(memory.slice(start, start + length));
2220
- } else {
2221
- ws.send(textDecoder.decode(memory.subarray(start, start + length)));
1994
+ #readString(ptr, len) {
1995
+ const start = ptr >>> 0;
1996
+ const length = len >>> 0;
1997
+ if (length === 0) return "";
1998
+ const view = this.#view();
1999
+ if (start + length > view.byteLength) return "";
2000
+ return decoder2.decode(view.subarray(start, start + length));
2001
+ }
2002
+ #writeBytes(ptr, data) {
2003
+ const start = ptr >>> 0;
2004
+ const view = this.#view();
2005
+ if (start + data.length > view.byteLength) return;
2006
+ view.set(data, start);
2007
+ }
2008
+ #invoke(type, id, a = 0n, b = 0n, c = 0n) {
2009
+ this.#cb?.(type, id, a, b, c);
2010
+ }
2011
+ log(level, ptr, len) {
2012
+ const msg = decoder2.decode(this.#view().subarray(ptr, ptr + len));
2013
+ switch (level) {
2014
+ case 0:
2015
+ console.error(msg);
2016
+ break;
2017
+ case 1:
2018
+ console.warn(msg);
2019
+ break;
2020
+ case 3:
2021
+ console.debug(msg);
2022
+ break;
2023
+ default:
2024
+ console.log(msg);
2025
+ break;
2222
2026
  }
2223
2027
  }
2224
- /** Close WebSocket connection */
2225
- wsClose(wsId, code, reasonPtr, reasonLen) {
2226
- const ws = this.#websockets.get(wsId);
2227
- if (!ws) return;
2228
- const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : void 0;
2028
+ fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
2029
+ const url = this.#readString(urlPtr, urlLen);
2030
+ const method = methodLen > 0 ? this.#readString(methodPtr, methodLen) : "GET";
2031
+ const headersJson = headersLen > 0 ? this.#readString(headersPtr, headersLen) : "{}";
2032
+ const body = bodyLen > 0 ? this.#view().subarray(bodyPtr, bodyPtr + bodyLen) : void 0;
2033
+ let headers = {};
2229
2034
  try {
2230
- if (reason) ws.close(code, reason);
2231
- else ws.close(code);
2035
+ headers = JSON.parse(headersJson);
2232
2036
  } catch {
2233
- ws.close();
2037
+ for (const line of headersJson.split("\n")) {
2038
+ const i = line.indexOf(":");
2039
+ if (i > 0) headers[line.slice(0, i)] = line.slice(i + 1);
2040
+ }
2234
2041
  }
2042
+ const controller = new AbortController();
2043
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
2044
+ fetch(url, {
2045
+ method,
2046
+ headers: Object.keys(headers).length > 0 ? headers : void 0,
2047
+ body: method !== "GET" && method !== "HEAD" ? body : void 0,
2048
+ signal: controller.signal
2049
+ }).then(async (res) => {
2050
+ if (timeout) clearTimeout(timeout);
2051
+ const bytes = new Uint8Array(await res.arrayBuffer());
2052
+ this.#notifyFetchComplete(fetchId, res.status, bytes, false);
2053
+ }).catch((err) => {
2054
+ if (timeout) clearTimeout(timeout);
2055
+ const msg = err.name === "AbortError" ? "Request timeout" : err.message ?? "Fetch failed";
2056
+ this.#notifyFetchComplete(fetchId, 0, msg, true);
2057
+ });
2235
2058
  }
2236
- dispose() {
2237
- super.dispose();
2238
- eventHandlersPresent.clear();
2239
- eventHandlersSuspend.clear();
2240
- for (const ws of this.#websockets.values()) {
2241
- try {
2242
- ws.close();
2243
- } catch {
2244
- }
2059
+ #notifyFetchComplete(fetchId, status, body, isError) {
2060
+ const encoded = typeof body === "string" ? encoder2.encode(body) : body;
2061
+ const ptr = this.#alloc(encoded.length);
2062
+ this.#writeBytes(ptr, encoded);
2063
+ const type = isError ? CallbackType_FetchError : CallbackType_FetchSuccess;
2064
+ this.#invoke(type, fetchId, BigInt(status), BigInt(ptr), BigInt(encoded.length));
2065
+ }
2066
+ setTimeout(callbackId, delayMs) {
2067
+ setTimeout(() => this.#invoke(CallbackType_Timeout, callbackId), delayMs);
2068
+ }
2069
+ setInterval(callbackId, intervalMs) {
2070
+ const handle = setInterval(() => this.#invoke(CallbackType_Interval, callbackId), intervalMs);
2071
+ this.#intervals.set(callbackId, handle);
2072
+ }
2073
+ clearInterval(callbackId) {
2074
+ const handle = this.#intervals.get(callbackId);
2075
+ if (handle !== void 0) {
2076
+ clearInterval(handle);
2077
+ this.#intervals.delete(callbackId);
2245
2078
  }
2246
- this.#websockets.clear();
2247
2079
  }
2248
2080
  /**
2249
- * Dispatch to WASM for one vnode. Caller owns `eventRef` lifetime
2250
- * (store once per bubble, release after sync/async work completes).
2081
+ * Create the WASI import object for WASM instantiation.
2082
+ *
2083
+ * Returns only the `__zx` namespace (log, fetch, timers).
2084
+ * Does NOT include jsz.importObject() - the server binary does not use jsz.
2251
2085
  */
2252
- eventbridge(velementId, eventTypeId, eventRef) {
2253
- const id = BigInt(velementId >>> 0);
2254
- if (this.eventMaySuspend(velementId, eventTypeId)) {
2255
- return invokeWasmExport(this.#eventbridgeAsync, id, eventTypeId, eventRef);
2256
- }
2257
- invokeWasmExport(this.#eventbridge, id, eventTypeId, eventRef);
2258
- }
2259
- /** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
2260
2086
  static createImportObject(bridgeRef) {
2261
2087
  return {
2262
- ...jsz.importObject(),
2263
- __zx_net: createFetchImports(() => {
2264
- if (!jsz.memory) throw new Error("WASM memory is not ready");
2265
- return jsz.memory;
2266
- }),
2267
2088
  __zx: {
2268
- _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
2269
- _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
2270
- bridgeRef[0]?.setEventHandlerMode(Number(vnodeId), eventTypeId, maySuspend !== 0);
2271
- },
2272
- _clearEventHandlerModes: (vnodeId) => {
2273
- bridgeRef[0]?.clearEventHandlerModes(Number(vnodeId));
2089
+ _log: (level, ptr, len) => {
2090
+ bridgeRef[0]?.log(level, ptr, len);
2274
2091
  },
2275
2092
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
2276
2093
  bridgeRef[0]?.fetchAsync(
@@ -2294,188 +2111,330 @@ var ZxBridge = class extends ZxBridgeCore {
2294
2111
  },
2295
2112
  _clearInterval: (callbackId) => {
2296
2113
  bridgeRef[0]?.clearInterval(callbackId);
2297
- },
2298
- // WebSocket API
2299
- _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
2300
- bridgeRef[0]?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
2301
- },
2302
- _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
2303
- bridgeRef[0]?.wsSend(wsId, dataPtr, dataLen, isBinary);
2304
- },
2305
- _wsClose: (wsId, code, reasonPtr, reasonLen) => {
2306
- bridgeRef[0]?.wsClose(wsId, code, reasonPtr, reasonLen);
2307
- },
2308
- _flush: (ptr, len) => {
2309
- flushDomCmds(ptr, len, {
2310
- domNodes,
2311
- cleanupDomNodes
2312
- });
2313
- },
2314
- _getLocationHref: (bufPtr, bufLen) => {
2315
- const bytes = textEncoder.encode(window.location.href);
2316
- const len = Math.min(bytes.length, bufLen);
2317
- writeBytes(bufPtr, bytes.subarray(0, len));
2318
- return len;
2319
- },
2320
- _getFormData: (eventRef, outPtrAddr) => {
2321
- const event = loadValueFromRef(eventRef);
2322
- const el = event?.target;
2323
- const form = el instanceof HTMLFormElement ? el : el?.closest?.("form") ?? null;
2324
- if (!form) return 0;
2325
- const entries = [];
2326
- for (const [k, v] of new FormData(form).entries()) {
2327
- entries.push(k, String(v));
2328
- }
2329
- const bytes = textEncoder.encode(JSON.stringify(entries));
2330
- const [ptr, len] = bridgeRef[0].writeBytesToWasm(bytes);
2331
- new DataView(jsz.memory.buffer).setUint32(outPtrAddr, ptr, true);
2332
- return len;
2333
- },
2334
- _submitFormAction: (vnodeId, actionId) => {
2335
- const form = domNodes.get(Number(vnodeId));
2336
- if (!form || !(form instanceof HTMLFormElement)) return;
2337
- const formData = new FormData(form);
2338
- fetch(window.location.href, {
2339
- method: "POST",
2340
- // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
2341
- headers: { "x-action": String(actionId >>> 0) },
2342
- body: formData
2343
- }).catch(() => {
2344
- });
2345
- },
2346
- _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
2347
- const form = domNodes.get(Number(vnodeId));
2348
- if (!form || !(form instanceof HTMLFormElement)) return;
2349
- const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
2350
- bridgeRef[0]?.submitFormActionAsync(form, actionId, statesJson, fetchId);
2351
2114
  }
2352
2115
  }
2353
2116
  };
2354
2117
  }
2355
2118
  };
2356
- var domNodes = /* @__PURE__ */ new Map();
2357
- var eventHandlersPresent = /* @__PURE__ */ new Map();
2358
- var eventHandlersSuspend = /* @__PURE__ */ new Map();
2359
- function cleanupDomNodes(node) {
2360
- const stack = [node];
2361
- let highFreqBits = 0;
2362
- while (stack.length > 0) {
2363
- const n = stack.pop();
2364
- const ref = n.__zx_ref;
2365
- if (typeof ref === "number") {
2366
- const present = eventHandlersPresent.get(ref);
2367
- if (present !== void 0) {
2368
- highFreqBits |= present;
2369
- eventHandlersPresent.delete(ref);
2370
- eventHandlersSuspend.delete(ref);
2119
+
2120
+ // src/runtime/index.ts
2121
+ function buildHttpImports(mem, http) {
2122
+ const decoder3 = new TextDecoder();
2123
+ return {
2124
+ commit: (status, meta_ptr, meta_len) => {
2125
+ http.status = status >>> 0;
2126
+ http.committed = true;
2127
+ http.headers = new Headers();
2128
+ http.streaming = false;
2129
+ if (meta_len > 0) {
2130
+ try {
2131
+ const raw = decoder3.decode(new Uint8Array(mem().buffer, meta_ptr >>> 0, meta_len >>> 0));
2132
+ const parsed = JSON.parse(raw);
2133
+ if (parsed.streaming === true) http.streaming = true;
2134
+ if (Array.isArray(parsed.headers)) {
2135
+ for (const [name, value] of parsed.headers) {
2136
+ http.headers.append(name, value);
2137
+ }
2138
+ }
2139
+ } catch {
2140
+ }
2371
2141
  }
2372
- domNodes.delete(ref);
2142
+ },
2143
+ write: (ptr, len) => {
2144
+ if (len <= 0) return;
2145
+ const chunk = new Uint8Array(mem().buffer, ptr >>> 0, len >>> 0).slice();
2146
+ if (http.streamWriter) void http.streamWriter.write(chunk);
2147
+ else http.bodyChunks.push(chunk);
2148
+ },
2149
+ end: () => {
2150
+ http.ended = true;
2151
+ if (http.streamWriter) {
2152
+ void http.streamWriter.close();
2153
+ http.streamWriter = null;
2154
+ }
2155
+ }
2156
+ };
2157
+ }
2158
+ function buildWsImports(Suspending2, mem, decoder3, ws) {
2159
+ const readStr2 = (ptr, len) => decoder3.decode(new Uint8Array(mem().buffer, ptr, len));
2160
+ return {
2161
+ ws_upgrade: () => {
2162
+ ws.upgraded = true;
2163
+ },
2164
+ ws_write: (ptr, len) => {
2165
+ const data = new Uint8Array(mem().buffer, ptr, len).slice();
2166
+ if (!ws.server) {
2167
+ ws.pendingWrites.push(data);
2168
+ } else {
2169
+ ws.server.send(data);
2170
+ }
2171
+ },
2172
+ ws_close: (code, reason_ptr, reason_len) => {
2173
+ ws.server?.close(code, decoder3.decode(new Uint8Array(mem().buffer, reason_ptr, reason_len)));
2174
+ },
2175
+ ws_recv: Suspending2 ? new Suspending2(async (buf_ptr, buf_max) => {
2176
+ if (ws._resolveFirstSuspend) {
2177
+ const fn = ws._resolveFirstSuspend;
2178
+ ws._resolveFirstSuspend = void 0;
2179
+ fn();
2180
+ }
2181
+ const deliver = (bytes) => {
2182
+ if (bytes === null) return -1;
2183
+ const n = Math.min(bytes.length, buf_max);
2184
+ new Uint8Array(mem().buffer, buf_ptr, n).set(bytes.subarray(0, n));
2185
+ return n;
2186
+ };
2187
+ if (ws.messageQueue.length > 0) return deliver(ws.messageQueue.shift());
2188
+ return new Promise((resolve2) => {
2189
+ ws.recvResolve = (bytes) => resolve2(deliver(bytes));
2190
+ });
2191
+ }) : (_buf_ptr, _buf_max) => -1,
2192
+ // Pub/sub - delegates to optional callbacks (real in DO, no-ops otherwise)
2193
+ ws_subscribe: (ptr, len) => {
2194
+ ws.subscribe?.(readStr2(ptr, len));
2195
+ },
2196
+ ws_unsubscribe: (ptr, len) => {
2197
+ ws.unsubscribe?.(readStr2(ptr, len));
2198
+ },
2199
+ ws_publish: (topic_ptr, topic_len, data_ptr, data_len) => {
2200
+ const topic = readStr2(topic_ptr, topic_len);
2201
+ const data = new Uint8Array(mem().buffer, data_ptr, data_len).slice();
2202
+ return ws.publish?.(topic, data) ?? 0;
2203
+ },
2204
+ ws_is_subscribed: (ptr, len) => ws.isSubscribed?.(readStr2(ptr, len)) ? 1 : 0
2205
+ };
2206
+ }
2207
+ function attachWebSocket(ws) {
2208
+ const WebSocketPairCtor = globalThis.WebSocketPair;
2209
+ const pair = new WebSocketPairCtor();
2210
+ const client = pair[0];
2211
+ const server = pair[1];
2212
+ ws.server = server;
2213
+ server.accept();
2214
+ for (const data of ws.pendingWrites) server.send(data);
2215
+ ws.pendingWrites = [];
2216
+ server.addEventListener("message", (event) => {
2217
+ const data = typeof event.data === "string" ? new TextEncoder().encode(event.data) : new Uint8Array(event.data);
2218
+ if (ws.recvResolve) {
2219
+ const res = ws.recvResolve;
2220
+ ws.recvResolve = null;
2221
+ res(data);
2222
+ } else {
2223
+ ws.messageQueue.push(data);
2224
+ }
2225
+ });
2226
+ server.addEventListener("close", () => {
2227
+ if (ws.recvResolve) {
2228
+ const res = ws.recvResolve;
2229
+ ws.recvResolve = null;
2230
+ res(null);
2373
2231
  }
2374
- const children = n.childNodes;
2375
- for (let i = 0; i < children.length; i++) stack.push(children[i]);
2376
- }
2377
- for (let bits = highFreqBits & HIGH_FREQ_EVENT_BITS; bits !== 0; bits &= bits - 1) {
2378
- maybeRemoveHighFreqListener(31 - Math.clz32(bits));
2379
- }
2232
+ });
2233
+ return { client };
2380
2234
  }
2381
- var delegationState = null;
2382
- function makeDelegatedListener(bridge, eventTypeId) {
2383
- return (event) => {
2384
- let eventRef;
2385
- const pending = [];
2386
- let target = event.target;
2387
- while (target && target !== document.body) {
2388
- const zxRef = target.__zx_ref;
2389
- if (typeof zxRef === "number" && bridge.hasEventHandler(zxRef, eventTypeId)) {
2390
- if (eventRef === void 0) eventRef = storeValueGetRef(event);
2391
- const result = bridge.eventbridge(zxRef, eventTypeId, eventRef);
2392
- if (result && typeof result.then === "function") {
2393
- pending.push(result);
2394
- }
2395
- if (event.cancelBubble) break;
2396
- }
2397
- target = target.parentElement;
2398
- }
2399
- if (eventRef !== void 0) {
2400
- const ref = eventRef;
2401
- if (pending.length > 0) {
2402
- Promise.all(pending).finally(() => releaseValueRef(ref));
2403
- } else {
2404
- releaseValueRef(ref);
2405
- }
2235
+ function buildSysImports(jspi2, Suspending2) {
2236
+ return {
2237
+ sleep_ms: jspi2 ? new Suspending2(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {
2406
2238
  }
2407
2239
  };
2408
2240
  }
2409
- function ensureDelegatedListener(eventTypeId) {
2410
- const state = delegationState;
2411
- if (!state || state.attached.has(eventTypeId)) return;
2412
- const domType = DELEGATED_EVENTS[eventTypeId];
2413
- if (!domType) return;
2414
- const passive = domType.startsWith("touch") || domType === "scroll";
2415
- const options = { passive };
2416
- const listener = makeDelegatedListener(state.bridge, eventTypeId);
2417
- state.root.addEventListener(domType, listener, options);
2418
- state.attached.set(eventTypeId, { listener, options });
2419
- }
2420
- function anyHandlerForType(eventTypeId) {
2421
- const bit = 1 << eventTypeId;
2422
- for (const mask of eventHandlersPresent.values()) {
2423
- if (mask & bit) return true;
2241
+ function executeWasm(instance, jspi2, Suspending2, wsState) {
2242
+ if (!jspi2) {
2243
+ try {
2244
+ instance.exports._start();
2245
+ } catch (e) {
2246
+ if (!(e instanceof ProcExit)) throw e;
2247
+ }
2248
+ return Promise.resolve();
2424
2249
  }
2425
- return false;
2250
+ const start = WebAssembly.promising(instance.exports._start);
2251
+ return start().catch((e) => {
2252
+ if (e instanceof Error && e.message.startsWith("proc_exit")) return;
2253
+ throw e;
2254
+ }).finally(() => {
2255
+ if (wsState.recvResolve) {
2256
+ const res = wsState.recvResolve;
2257
+ wsState.recvResolve = null;
2258
+ res(null);
2259
+ }
2260
+ });
2426
2261
  }
2427
- function maybeRemoveHighFreqListener(eventTypeId) {
2428
- if ((HIGH_FREQ_EVENT_BITS & 1 << eventTypeId) === 0) return;
2429
- if (anyHandlerForType(eventTypeId)) return;
2430
- const state = delegationState;
2431
- if (!state) return;
2432
- const entry = state.attached.get(eventTypeId);
2433
- if (!entry) return;
2434
- const domType = DELEGATED_EVENTS[eventTypeId];
2435
- state.root.removeEventListener(domType, entry.listener, entry.options);
2436
- state.attached.delete(eventTypeId);
2262
+ async function run({
2263
+ request,
2264
+ env,
2265
+ ctx,
2266
+ module,
2267
+ kv: kvBindings,
2268
+ db: dbBindings,
2269
+ imports,
2270
+ wasi,
2271
+ sticky
2272
+ }) {
2273
+ if (sticky && request.headers.get("upgrade")?.toLowerCase() === "websocket") {
2274
+ const id = sticky.idFromName(new URL(request.url).pathname);
2275
+ return sticky.get(id).fetch(request);
2276
+ }
2277
+ const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : void 0;
2278
+ const httpState = {
2279
+ committed: false,
2280
+ ended: false,
2281
+ status: 200,
2282
+ streaming: false,
2283
+ headers: new Headers(),
2284
+ bodyChunks: [],
2285
+ streamWriter: null
2286
+ };
2287
+ const { wasiImport, setMemory } = createWasiImports({
2288
+ request,
2289
+ stdinData
2290
+ });
2291
+ let wasmMemory = null;
2292
+ const mem = () => wasmMemory;
2293
+ const bridgeRef = [null];
2294
+ const allocRef = [null];
2295
+ const Suspending2 = WebAssembly.Suspending;
2296
+ const jspi2 = typeof Suspending2 === "function";
2297
+ const wsState = {
2298
+ upgraded: false,
2299
+ server: null,
2300
+ pendingWrites: [],
2301
+ messageQueue: [],
2302
+ recvResolve: null
2303
+ };
2304
+ const importObject = {
2305
+ wasi_snapshot_preview1: { ...wasi?.wasiImport, ...wasiImport },
2306
+ __zx_sys: buildSysImports(jspi2, Suspending2),
2307
+ __zx_ws: buildWsImports(jspi2 ? Suspending2 : null, mem, new TextDecoder(), wsState),
2308
+ __zx_http: buildHttpImports(mem, httpState),
2309
+ __zx_net: createFetchImports(mem),
2310
+ ...imports ? imports(mem) : {},
2311
+ ...ZxWasiBridge.createImportObject(bridgeRef)
2312
+ };
2313
+ if (true) {
2314
+ importObject.__zx_kv = createKVImports(
2315
+ kvBindings ?? { default: { get: get4, put: put4, del: del4, list: list4 } },
2316
+ mem,
2317
+ allocRef
2318
+ );
2319
+ }
2320
+ if (true) {
2321
+ importObject.__zx_db = createDbImports(
2322
+ dbBindings ?? {},
2323
+ mem,
2324
+ allocRef
2325
+ );
2326
+ }
2327
+ const instance = new WebAssembly.Instance(module, importObject);
2328
+ wasmMemory = instance.exports.memory;
2329
+ setMemory(wasmMemory);
2330
+ bridgeRef[0] = new ZxWasiBridge(instance.exports);
2331
+ bindWasmAlloc(allocRef, instance.exports);
2332
+ const wasmPromise = executeWasm(instance, jspi2, Suspending2, wsState);
2333
+ if (wsState.upgraded) {
2334
+ const server = attachWebSocket(wsState);
2335
+ ctx?.waitUntil(wasmPromise);
2336
+ return new Response(null, { status: 101, webSocket: server.client });
2337
+ }
2338
+ if (httpState.committed && httpState.streaming) {
2339
+ const { readable, writable } = new TransformStream();
2340
+ httpState.streamWriter = writable.getWriter();
2341
+ for (const chunk of httpState.bodyChunks) void httpState.streamWriter.write(chunk);
2342
+ httpState.bodyChunks.length = 0;
2343
+ void wasmPromise.finally(() => {
2344
+ if (httpState.streamWriter) {
2345
+ void httpState.streamWriter.close();
2346
+ httpState.streamWriter = null;
2347
+ }
2348
+ });
2349
+ return new Response(readable, { status: httpState.status, headers: httpState.headers });
2350
+ }
2351
+ await wasmPromise;
2352
+ const status = httpState.status;
2353
+ const headers = httpState.headers;
2354
+ headers.delete("transfer-encoding");
2355
+ const nullBody = status === 101 || status === 204 || status === 205 || status === 304;
2356
+ if (nullBody) {
2357
+ headers.delete("content-length");
2358
+ return new Response(null, { status, headers });
2359
+ }
2360
+ const body = mergeUint8Arrays(httpState.bodyChunks);
2361
+ if (!headers.has("content-length")) headers.set("content-length", String(body.byteLength));
2362
+ return new Response(body.buffer, { status, headers });
2437
2363
  }
2438
2364
 
2439
- // src/platforms/cloudflare/do.ts
2440
- function createWebSocketDO(module, options) {
2441
- return class ZxWebSocketDO {
2365
+ // src/platforms/cloudflare/stateful.ts
2366
+ var textDecoder2 = new TextDecoder();
2367
+ function deliverToWasm(conn, data) {
2368
+ if (conn.recvResolve) {
2369
+ const res = conn.recvResolve;
2370
+ conn.recvResolve = null;
2371
+ res(data);
2372
+ return;
2373
+ }
2374
+ if (data) conn.messageQueue.push(data);
2375
+ }
2376
+ function attachWebSocketPair(ws) {
2377
+ const WebSocketPairCtor = globalThis.WebSocketPair;
2378
+ const pair = new WebSocketPairCtor();
2379
+ const [client, server] = Object.values(pair);
2380
+ ws.server = server;
2381
+ server.accept();
2382
+ const pending = ws.pendingWrites;
2383
+ ws.pendingWrites = [];
2384
+ queueMicrotask(() => {
2385
+ for (const data of pending) {
2386
+ try {
2387
+ server.send(textDecoder2.decode(data));
2388
+ } catch {
2389
+ }
2390
+ }
2391
+ });
2392
+ server.addEventListener("message", (event) => {
2393
+ const data = typeof event.data === "string" ? new TextEncoder().encode(event.data) : new Uint8Array(event.data);
2394
+ deliverToWasm(ws, data);
2395
+ });
2396
+ server.addEventListener("close", () => {
2397
+ deliverToWasm(ws, null);
2398
+ });
2399
+ return client;
2400
+ }
2401
+ function createStatefulFetch(module, options) {
2402
+ return class StatefulFetch {
2442
2403
  constructor(state, env) {
2443
- /** All active connections in this room, keyed by their server-side WebSocket. */
2444
2404
  this.connections = /* @__PURE__ */ new Map();
2445
- this.doState = state;
2405
+ this.state = state;
2446
2406
  this.env = env;
2447
2407
  }
2448
2408
  async fetch(request) {
2449
- const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : void 0;
2409
+ const isUpgrade = request.headers.get("upgrade")?.toLowerCase() === "websocket";
2410
+ const stdinData = !isUpgrade && request.body ? new Uint8Array(await request.arrayBuffer()) : void 0;
2450
2411
  const { wasiImport, setMemory } = createWasiImports({ request, stdinData });
2451
2412
  let wasmMemory = null;
2452
2413
  const mem = () => wasmMemory;
2453
2414
  const bridgeRef = [null];
2454
2415
  const bridgeImports = ZxBridge.createImportObject(bridgeRef);
2455
- const Suspending = WebAssembly.Suspending;
2456
- const jspi = typeof Suspending === "function";
2416
+ const Suspending2 = WebAssembly.Suspending;
2417
+ const jspi2 = typeof Suspending2 === "function";
2418
+ if (!jspi2) {
2419
+ return new Response("Sticky WebSocket fetch requires WebAssembly JSPI", { status: 501 });
2420
+ }
2457
2421
  const decoder3 = new TextDecoder();
2458
- let _resolveFirstSuspend;
2459
- const firstSuspendPromise = new Promise((resolve) => {
2460
- _resolveFirstSuspend = resolve;
2461
- });
2462
- let wasmExited = false;
2463
2422
  const connState = {
2464
2423
  upgraded: false,
2465
2424
  server: null,
2466
2425
  pendingWrites: [],
2467
2426
  messageQueue: [],
2468
2427
  recvResolve: null,
2469
- _resolveFirstSuspend,
2470
2428
  topics: /* @__PURE__ */ new Set(),
2471
2429
  subscribe: (topic) => connState.topics.add(topic),
2472
2430
  unsubscribe: (topic) => connState.topics.delete(topic),
2473
2431
  publish: (topic, data) => {
2474
2432
  let count = 0;
2475
- for (const [ws, conn] of this.connections) {
2433
+ const text = textDecoder2.decode(data);
2434
+ for (const [sock, conn] of this.connections) {
2476
2435
  if (conn.topics.has(topic)) {
2477
2436
  try {
2478
- ws.send(data);
2437
+ sock.send(text);
2479
2438
  count++;
2480
2439
  } catch {
2481
2440
  }
@@ -2490,10 +2449,20 @@ function createWebSocketDO(module, options) {
2490
2449
  isSubscribed: (topic) => connState.topics.has(topic)
2491
2450
  };
2492
2451
  const sysImports = {
2493
- sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {
2494
- }
2452
+ sleep_ms: new Suspending2(
2453
+ async (ms) => new Promise((r) => setTimeout(r, ms))
2454
+ )
2455
+ };
2456
+ const wsImports = buildWsImports(Suspending2, mem, decoder3, connState);
2457
+ const httpState = {
2458
+ committed: false,
2459
+ ended: false,
2460
+ status: 200,
2461
+ streaming: false,
2462
+ headers: new Headers(),
2463
+ bodyChunks: [],
2464
+ streamWriter: null
2495
2465
  };
2496
- const wsImports = buildWsImports(jspi ? Suspending : null, mem, decoder3, connState);
2497
2466
  const kvBindings = options?.kv?.(this.env);
2498
2467
  const dbBindings = options?.db?.(this.env);
2499
2468
  const allocRef = [null];
@@ -2501,23 +2470,20 @@ function createWebSocketDO(module, options) {
2501
2470
  wasi_snapshot_preview1: wasiImport,
2502
2471
  __zx_sys: sysImports,
2503
2472
  __zx_ws: wsImports,
2473
+ __zx_http: buildHttpImports(mem, httpState),
2504
2474
  __zx_net: createFetchImports(mem),
2505
2475
  ...options?.imports ? options.imports(mem) : {},
2506
2476
  ...bridgeImports
2507
2477
  };
2508
2478
  if (true) {
2509
2479
  importObject.__zx_kv = createKVImports(
2510
- kvBindings ?? { default: createMemoryKV() },
2480
+ kvBindings ?? { default: { get: get4, put: put4, del: del4, list: list4 } },
2511
2481
  mem,
2512
2482
  allocRef
2513
2483
  );
2514
2484
  }
2515
2485
  if (true) {
2516
- importObject.__zx_db = createDbImports(
2517
- dbBindings ?? {},
2518
- mem,
2519
- allocRef
2520
- );
2486
+ importObject.__zx_db = createDbImports(dbBindings ?? {}, mem, allocRef);
2521
2487
  }
2522
2488
  const instance = new WebAssembly.Instance(module, importObject);
2523
2489
  wasmMemory = instance.exports.memory;
@@ -2526,31 +2492,142 @@ function createWebSocketDO(module, options) {
2526
2492
  bindWasmAlloc(allocRef, instance.exports);
2527
2493
  const start = WebAssembly.promising(instance.exports._start);
2528
2494
  const wasmPromise = start().catch((e) => {
2529
- wasmExited = true;
2530
2495
  if (e instanceof Error && e.message.startsWith("proc_exit")) return;
2531
- console.error("[ZxWebSocketDO] WASM error:", e);
2496
+ console.error("[StatefulFetch] WASM error:", e);
2532
2497
  }).finally(() => {
2533
2498
  if (connState.server) this.connections.delete(connState.server);
2534
- if (connState.recvResolve) {
2535
- const res = connState.recvResolve;
2536
- connState.recvResolve = null;
2537
- res(null);
2538
- }
2499
+ deliverToWasm(connState, null);
2539
2500
  });
2540
- await Promise.race([firstSuspendPromise, wasmPromise]);
2541
- if (!connState.upgraded || wasmExited) {
2501
+ if (!connState.upgraded) {
2502
+ await wasmPromise;
2542
2503
  return new Response("WebSocket upgrade expected", { status: 426 });
2543
2504
  }
2544
- const { client } = attachWebSocket(connState);
2505
+ const client = attachWebSocketPair(connState);
2545
2506
  this.connections.set(connState.server, connState);
2546
- this.doState.waitUntil(wasmPromise);
2507
+ this.state.waitUntil(wasmPromise);
2547
2508
  return new Response(null, { status: 101, webSocket: client });
2548
2509
  }
2549
2510
  };
2550
2511
  }
2512
+
2513
+ // src/app.ts
2514
+ async function resolveModule(input) {
2515
+ if (typeof input === "string") {
2516
+ if (input.startsWith("http://") || input.startsWith("https://")) {
2517
+ return WebAssembly.compileStreaming(fetch(input));
2518
+ }
2519
+ const url = input.startsWith("/") ? `file://${input}` : input;
2520
+ return WebAssembly.compile(await fetch(url).then((r) => r.arrayBuffer()));
2521
+ }
2522
+ if (input instanceof URL) {
2523
+ return WebAssembly.compileStreaming(fetch(input));
2524
+ }
2525
+ if (input instanceof Response) {
2526
+ return WebAssembly.compileStreaming(input);
2527
+ }
2528
+ if (input instanceof ArrayBuffer) {
2529
+ return WebAssembly.compile(input);
2530
+ }
2531
+ if (ArrayBuffer.isView(input)) {
2532
+ return WebAssembly.compile(input.buffer);
2533
+ }
2534
+ return input;
2535
+ }
2536
+ var Ziex = class {
2537
+ constructor(options) {
2538
+ this.resolved = null;
2539
+ /**
2540
+ * Fetch handler called by the runtime on every request.
2541
+ *
2542
+ * Arrow function so `this` is always the class instance, even when the
2543
+ * runtime extracts `fetch` from the exported object (e.g. Bun).
2544
+ */
2545
+ this.fetch = async (request, env, ctx) => {
2546
+ const module = await this.getModule();
2547
+ const { wasi, imports, sticky } = this.options;
2548
+ return run({
2549
+ request,
2550
+ env,
2551
+ ctx,
2552
+ module,
2553
+ wasi,
2554
+ imports,
2555
+ kv: this.resolveKV(env),
2556
+ db: this.resolveDB(env),
2557
+ sticky: sticky !== void 0 ? env[sticky] : void 0
2558
+ });
2559
+ };
2560
+ this.options = options;
2561
+ }
2562
+ async getModule() {
2563
+ if (!this.resolved) this.resolved = await resolveModule(this.options.module);
2564
+ return this.resolved;
2565
+ }
2566
+ /**
2567
+ * Enable sticky upgrade forwarding and return host config for platform adapters
2568
+ * (e.g. Cloudflare {@linkcode stateful}).
2569
+ *
2570
+ * Requires `options.module` to already be a compiled `WebAssembly.Module`.
2571
+ */
2572
+ stickyHost(binding) {
2573
+ this.options.sticky = binding;
2574
+ const mod = this.options.module;
2575
+ if (mod instanceof ArrayBuffer || ArrayBuffer.isView(mod) || mod instanceof Response || mod instanceof URL || typeof mod === "string") {
2576
+ throw new Error(
2577
+ 'sticky handlers require a compiled WebAssembly.Module (e.g. `import module from "./app.wasm"` under wrangler)'
2578
+ );
2579
+ }
2580
+ return {
2581
+ module: mod,
2582
+ imports: this.options.imports,
2583
+ kv: (env) => this.resolveKV(env),
2584
+ db: (env) => this.resolveDB(env)
2585
+ };
2586
+ }
2587
+ resolveKV(env) {
2588
+ const { kv } = this.options;
2589
+ if (kv === void 0) return void 0;
2590
+ if (typeof kv === "object" && kv !== null) {
2591
+ const result = {};
2592
+ for (const [name, key] of Object.entries(kv)) {
2593
+ result[name] = env[key];
2594
+ }
2595
+ return result;
2596
+ }
2597
+ return { default: env[kv] };
2598
+ }
2599
+ resolveDB(env) {
2600
+ const { db } = this.options;
2601
+ if (db === void 0) return void 0;
2602
+ if (typeof db === "object" && db !== null) {
2603
+ const result = {};
2604
+ for (const [name, key] of Object.entries(db)) {
2605
+ result[name] = env[key];
2606
+ }
2607
+ return result;
2608
+ }
2609
+ return { default: env[db] };
2610
+ }
2611
+ };
2612
+
2613
+ // src/platforms/cloudflare/app.ts
2614
+ function stateful(app, options) {
2615
+ const host = app.stickyHost(options.binding);
2616
+ return createStatefulFetch(host.module, {
2617
+ kv: (env) => host.kv(env) ?? { default: { get: get4, put: put4, del: del4, list: list4 } },
2618
+ db: (env) => host.db(env) ?? {},
2619
+ imports: host.imports
2620
+ });
2621
+ }
2551
2622
  export {
2552
2623
  Ziex,
2553
- createWebSocketDO,
2554
- kv_exports as kv,
2555
- runtime_exports as worker
2624
+ createBrowserKVBindings,
2625
+ createKVImports,
2626
+ del4 as del,
2627
+ get4 as get,
2628
+ hasJspi,
2629
+ list4 as list,
2630
+ put4 as put,
2631
+ resolveModule,
2632
+ stateful
2556
2633
  };