ziex 0.1.0-dev.1389 → 0.1.0-dev.1466

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +4 -1
  2. package/app.d.ts +6 -6
  3. package/build.zig.zon +1 -1
  4. package/index.js +490 -174
  5. package/package.json +7 -5
  6. package/{aws-lambda → platforms/aws-lambda}/index.js +1 -1
  7. package/platforms/cloudflare/app.d.ts +2 -0
  8. package/platforms/cloudflare/db.d.ts +6 -0
  9. package/{cloudflare → platforms/cloudflare}/do.d.ts +5 -5
  10. package/platforms/cloudflare/index.d.ts +4 -0
  11. package/{cloudflare → platforms/cloudflare}/index.js +1959 -1532
  12. package/platforms/cloudflare/kv.d.ts +5 -0
  13. package/platforms/cloudflare/worker.d.ts +3 -0
  14. package/{vercel → platforms/vercel}/index.js +1 -1
  15. package/runtime/db/extern.d.ts +38 -0
  16. package/runtime/db/sqlite.d.ts +7 -0
  17. package/runtime/db.d.ts +3 -0
  18. package/runtime/db.js +419 -0
  19. package/{fetch.d.ts → runtime/fetch.d.ts} +1 -1
  20. package/{runtime.d.ts → runtime/index.d.ts} +6 -15
  21. package/runtime/kv/extern.d.ts +11 -0
  22. package/runtime/kv/indexdb.d.ts +7 -0
  23. package/runtime/kv/localstorage.d.ts +6 -0
  24. package/runtime/kv/memory.d.ts +6 -0
  25. package/runtime/kv.d.ts +45 -0
  26. package/runtime/kv.js +543 -0
  27. package/wasm/constants.d.ts +33 -0
  28. package/wasm/core.d.ts +23 -33
  29. package/wasm/dom_cmd.d.ts +15 -0
  30. package/wasm/generated/event_bits.d.ts +2 -0
  31. package/wasm/generated/events.d.ts +1 -0
  32. package/wasm/generated/tag_indices.d.ts +2 -0
  33. package/wasm/generated/tags.d.ts +1 -0
  34. package/wasm/index.d.ts +15 -13
  35. package/wasm/index.js +911 -676
  36. package/wasm/init.dev.js +895 -674
  37. package/wasm/init.js +3 -3
  38. package/wasm/wasi.d.ts +1 -5
  39. package/browser/kv.d.ts +0 -13
  40. package/cloudflare/app.d.ts +0 -2
  41. package/cloudflare/db.d.ts +0 -2
  42. package/cloudflare/index.d.ts +0 -4
  43. package/cloudflare/kv.d.ts +0 -2
  44. package/cloudflare/worker.d.ts +0 -3
  45. package/db.d.ts +0 -22
  46. package/kv.d.ts +0 -42
  47. /package/{aws-lambda → platforms/aws-lambda}/index.d.ts +0 -0
  48. /package/{vercel → platforms/vercel}/index.d.ts +0 -0
  49. /package/{wasi.d.ts → runtime/wasi.d.ts} +0 -0
@@ -4,7 +4,7 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
- // src/runtime.ts
7
+ // src/runtime/index.ts
8
8
  var runtime_exports = {};
9
9
  __export(runtime_exports, {
10
10
  attachWebSocket: () => attachWebSocket,
@@ -12,12 +12,35 @@ __export(runtime_exports, {
12
12
  run: () => run
13
13
  });
14
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
+
15
39
  // src/wasm/wasi.ts
16
40
  var decoder = new TextDecoder();
17
41
  var encoder = new TextEncoder();
18
42
  var ZxWasiBridge = class {
19
43
  #alloc;
20
- #fetchCompleteHandler;
21
44
  #memory;
22
45
  #cb;
23
46
  #intervals = /* @__PURE__ */ new Map();
@@ -27,7 +50,6 @@ var ZxWasiBridge = class {
27
50
  constructor(exports) {
28
51
  this.#memory = exports.memory;
29
52
  this.#alloc = exports.__zx_alloc;
30
- this.#fetchCompleteHandler = exports.__zx_fetch_complete;
31
53
  this.#cb = exports.__zx_cb;
32
54
  }
33
55
  #view() {
@@ -39,10 +61,21 @@ var ZxWasiBridge = class {
39
61
  return this.#memView;
40
62
  }
41
63
  #readString(ptr, len) {
42
- return decoder.decode(this.#view().subarray(ptr, 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));
43
70
  }
44
71
  #writeBytes(ptr, data) {
45
- this.#view().set(data, ptr);
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);
46
79
  }
47
80
  log(level, ptr, len) {
48
81
  const msg = decoder.decode(this.#view().subarray(ptr, ptr + len));
@@ -96,13 +129,14 @@ var ZxWasiBridge = class {
96
129
  const encoded = typeof body === "string" ? encoder.encode(body) : body;
97
130
  const ptr = this.#alloc(encoded.length);
98
131
  this.#writeBytes(ptr, encoded);
99
- this.#fetchCompleteHandler(fetchId, status, ptr, encoded.length, isError ? 1 : 0);
132
+ const type = isError ? CallbackType_FetchError : CallbackType_FetchSuccess;
133
+ this.#invoke(type, fetchId, BigInt(status), BigInt(ptr), BigInt(encoded.length));
100
134
  }
101
135
  setTimeout(callbackId, delayMs) {
102
- setTimeout(() => this.#cb?.(3, callbackId, 0n), delayMs);
136
+ setTimeout(() => this.#invoke(CallbackType_Timeout, callbackId), delayMs);
103
137
  }
104
138
  setInterval(callbackId, intervalMs) {
105
- const handle = setInterval(() => this.#cb?.(4, callbackId, 0n), intervalMs);
139
+ const handle = setInterval(() => this.#invoke(CallbackType_Interval, callbackId), intervalMs);
106
140
  this.#intervals.set(callbackId, handle);
107
141
  }
108
142
  clearInterval(callbackId) {
@@ -122,10 +156,10 @@ var ZxWasiBridge = class {
122
156
  return {
123
157
  __zx: {
124
158
  _log: (level, ptr, len) => {
125
- bridgeRef.current?.log(level, ptr, len);
159
+ bridgeRef[0]?.log(level, ptr, len);
126
160
  },
127
161
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
128
- bridgeRef.current?.fetchAsync(
162
+ bridgeRef[0]?.fetchAsync(
129
163
  urlPtr,
130
164
  urlLen,
131
165
  methodPtr,
@@ -139,153 +173,20 @@ var ZxWasiBridge = class {
139
173
  );
140
174
  },
141
175
  _setTimeout: (callbackId, delayMs) => {
142
- bridgeRef.current?.setTimeout(callbackId, delayMs);
176
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
143
177
  },
144
178
  _setInterval: (callbackId, intervalMs) => {
145
- bridgeRef.current?.setInterval(callbackId, intervalMs);
179
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
146
180
  },
147
181
  _clearInterval: (callbackId) => {
148
- bridgeRef.current?.clearInterval(callbackId);
182
+ bridgeRef[0]?.clearInterval(callbackId);
149
183
  }
150
184
  }
151
185
  };
152
186
  }
153
187
  };
154
188
 
155
- // src/kv.ts
156
- var kv_exports = {};
157
- __export(kv_exports, {
158
- createKVImports: () => createKVImports,
159
- createMemoryKV: () => createMemoryKV
160
- });
161
- function putOptions(ttlSeconds) {
162
- if (ttlSeconds < 60) return void 0;
163
- return { expirationTtl: ttlSeconds };
164
- }
165
- function createMemoryKV() {
166
- const store = /* @__PURE__ */ new Map();
167
- function read(key) {
168
- const entry = store.get(key);
169
- if (!entry) return null;
170
- if (entry.expiresAt !== void 0 && Date.now() >= entry.expiresAt) {
171
- store.delete(key);
172
- return null;
173
- }
174
- return entry.value;
175
- }
176
- function write(key, value, options) {
177
- let expiresAt;
178
- if (options?.expiration !== void 0) {
179
- expiresAt = options.expiration * 1e3;
180
- } else if (options?.expirationTtl !== void 0) {
181
- expiresAt = Date.now() + options.expirationTtl * 1e3;
182
- }
183
- store.set(key, { value, expiresAt });
184
- }
185
- return {
186
- async get(key) {
187
- return read(key);
188
- },
189
- async put(key, value, options) {
190
- write(key, value, options);
191
- },
192
- async delete(key) {
193
- store.delete(key);
194
- },
195
- async list(options) {
196
- const keys = [...store.keys()].filter((k) => {
197
- if (options?.prefix && !k.startsWith(options.prefix)) return false;
198
- return read(k) !== null;
199
- }).map((name) => ({ name }));
200
- return { keys };
201
- }
202
- };
203
- }
204
- function isSyncKVNamespace(binding) {
205
- const candidate = binding;
206
- return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
207
- }
208
- function createKVImports(bindings, getMemory) {
209
- const encoder3 = new TextEncoder();
210
- const decoder3 = new TextDecoder();
211
- function readStr(ptr, len) {
212
- return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
213
- }
214
- function writeBytes2(buf_ptr, buf_max, data) {
215
- if (data.length > buf_max) return -2;
216
- new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
217
- return data.length;
218
- }
219
- function binding(ns) {
220
- return bindings[ns] ?? bindings["default"] ?? null;
221
- }
222
- const Suspending = WebAssembly.Suspending;
223
- if (typeof Suspending !== "function") {
224
- let syncBinding2 = function(ns) {
225
- const candidate = binding(ns);
226
- return candidate && isSyncKVNamespace(candidate) ? candidate : null;
227
- };
228
- var syncBinding = syncBinding2;
229
- return {
230
- kv_get: (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
231
- const b = syncBinding2(readStr(ns_ptr, ns_len));
232
- if (!b) return -1;
233
- const value = b.getSync(readStr(key_ptr, key_len));
234
- if (value === null) return -1;
235
- return writeBytes2(buf_ptr, buf_max, encoder3.encode(value));
236
- },
237
- kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
238
- const b = syncBinding2(readStr(ns_ptr, ns_len));
239
- if (!b) return 0;
240
- b.putSync(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
241
- return 0;
242
- },
243
- kv_delete: (ns_ptr, ns_len, key_ptr, key_len) => {
244
- const b = syncBinding2(readStr(ns_ptr, ns_len));
245
- if (!b) return 0;
246
- b.deleteSync(readStr(key_ptr, key_len));
247
- return 0;
248
- },
249
- kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, buf_ptr, buf_max) => {
250
- const b = syncBinding2(readStr(ns_ptr, ns_len));
251
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"));
252
- const prefix = readStr(pfx_ptr, pfx_len);
253
- const result = b.listSync(prefix.length > 0 ? { prefix } : void 0);
254
- return writeBytes2(buf_ptr, buf_max, encoder3.encode(JSON.stringify(result.keys.map((k) => k.name))));
255
- }
256
- };
257
- }
258
- return {
259
- kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
260
- const b = binding(readStr(ns_ptr, ns_len));
261
- if (!b) return -1;
262
- const value = await b.get(readStr(key_ptr, key_len));
263
- if (value === null) return -1;
264
- return writeBytes2(buf_ptr, buf_max, encoder3.encode(value));
265
- }),
266
- kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
267
- const b = binding(readStr(ns_ptr, ns_len));
268
- if (!b) return -1;
269
- await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
270
- return 0;
271
- }),
272
- kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
273
- const b = binding(readStr(ns_ptr, ns_len));
274
- if (!b) return -1;
275
- await b.delete(readStr(key_ptr, key_len));
276
- return 0;
277
- }),
278
- kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
279
- const b = binding(readStr(ns_ptr, ns_len));
280
- if (!b) return writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"));
281
- const prefix = readStr(prefix_ptr, prefix_len);
282
- const result = await b.list(prefix.length > 0 ? { prefix } : void 0);
283
- return writeBytes2(buf_ptr, buf_max, encoder3.encode(JSON.stringify(result.keys.map((k) => k.name))));
284
- })
285
- };
286
- }
287
-
288
- // src/fetch.ts
189
+ // src/runtime/fetch.ts
289
190
  function createFetchImports(getMemory) {
290
191
  const encoder3 = new TextEncoder();
291
192
  const decoder3 = new TextDecoder();
@@ -351,1475 +252,1515 @@ function createFetchImports(getMemory) {
351
252
  };
352
253
  }
353
254
 
354
- // src/db.ts
355
- function decodeBlob(base64) {
356
- const binary = atob(base64);
357
- const bytes = new Uint8Array(binary.length);
358
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
359
- return bytes;
360
- }
361
- function toD1Value(value) {
362
- switch (value.kind) {
363
- case "null":
364
- return null;
365
- case "integer":
366
- return value.integer;
367
- case "float":
368
- return value.float;
369
- case "text":
370
- return value.text;
371
- case "blob":
372
- return decodeBlob(value.blob);
373
- case "boolean":
374
- return value.boolean;
255
+ // ../../vendor/jsz/js/src/zigjs.ts
256
+ var NAN_PREFIX = 2146959360;
257
+ var predefined = {
258
+ "nan": 0,
259
+ "null": 1,
260
+ "true": 2,
261
+ "false": 3,
262
+ "undefined": 4,
263
+ "globalThis": 5,
264
+ "runtime": 6
265
+ };
266
+ var PREDEFINED_ID_MAX = 6;
267
+ var encoder2 = new TextEncoder();
268
+ var decoder2 = new TextDecoder("utf-8");
269
+ var ZigJS = class {
270
+ constructor() {
271
+ /**
272
+ * The values, indexed by ID (number). Duplicate values can be in this
273
+ * if they are loaded multiple times. That just acts as duplicate references.
274
+ * */
275
+ this.values = [NaN, null, true, false, void 0, globalThis, this];
276
+ /**
277
+ * When a value is removed from the values array, its ID is put
278
+ * in the pool so that we can use it next. This avoids fragmentation in
279
+ * our array keys.
280
+ * */
281
+ this.idPool = [];
375
282
  }
376
- }
377
- function toPositionalBindings(json) {
378
- switch (json.kind) {
379
- case "none":
380
- return [];
381
- case "positional":
382
- return json.values.map(toD1Value);
383
- case "named":
384
- throw new Error("Cloudflare D1 adapter does not support named bindings yet");
283
+ /**
284
+ * Returns the import object that should be merged with your import
285
+ * object when instantiating your wasm instance. This injects the required
286
+ * functions into the wasm environment.
287
+ * */
288
+ importObject() {
289
+ return {
290
+ "zig-js": {
291
+ valueGet: this.valueGet.bind(this),
292
+ valueSet: this.valueSet.bind(this),
293
+ valueDeinit: this.valueDeinit.bind(this),
294
+ valueObjectCreate: this.valueObjectCreate.bind(this),
295
+ valueStringCreate: this.valueStringCreate.bind(this),
296
+ valueStringLen: this.valueStringLen.bind(this),
297
+ valueStringCopy: this.valueStringCopy.bind(this),
298
+ valueNew: this.valueNew.bind(this),
299
+ funcApply: this.funcApply.bind(this)
300
+ }
301
+ };
385
302
  }
386
- }
387
- function toWireValue(value) {
388
- if (value === null || value === void 0) return { kind: "null" };
389
- if (typeof value === "string") return { kind: "text", text: value };
390
- if (typeof value === "boolean") return { kind: "boolean", boolean: value };
391
- if (typeof value === "number") {
392
- return Number.isInteger(value) ? { kind: "integer", integer: value } : { kind: "float", float: value };
303
+ /**
304
+ * Get a value from the JS environment.
305
+ * */
306
+ valueGet(out, id, ptr, len) {
307
+ const val = this.loadValue(id);
308
+ if (val === null || val === void 0 || typeof val !== "object" && typeof val !== "function") {
309
+ this.storeValue(out, void 0);
310
+ return;
311
+ }
312
+ const str = this.loadString(ptr, len);
313
+ const result = Reflect.get(val, str);
314
+ this.storeValue(out, result);
393
315
  }
394
- if (value instanceof ArrayBuffer) {
395
- const bytes = new Uint8Array(value);
396
- let binary = "";
397
- for (const byte of bytes) binary += String.fromCharCode(byte);
398
- return { kind: "blob", blob: btoa(binary) };
316
+ /**
317
+ * Set a value on an object.
318
+ * */
319
+ valueSet(id, ptr, len, refAddr) {
320
+ const obj = this.loadValue(id);
321
+ const str = this.loadString(ptr, len);
322
+ const val = this.loadRef(refAddr);
323
+ Reflect.set(obj, str, val);
399
324
  }
400
- if (ArrayBuffer.isView(value)) {
401
- const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
402
- let binary = "";
403
- for (const byte of bytes) binary += String.fromCharCode(byte);
404
- return { kind: "blob", blob: btoa(binary) };
325
+ /**
326
+ * Dereference a value, allowing the JS environment to potentially GC it.
327
+ * */
328
+ valueDeinit(id) {
329
+ if (id > PREDEFINED_ID_MAX) {
330
+ this.values[id] = null;
331
+ this.idPool.push(id);
332
+ }
405
333
  }
406
- return { kind: "text", text: String(value) };
407
- }
408
- function objectToWireRow(record) {
409
- return {
410
- fields: Object.entries(record).map(([name, value]) => ({
411
- name,
412
- value: toWireValue(value)
413
- }))
414
- };
415
- }
416
- function valuesToWireRows(rows) {
417
- return rows.map((row) => row.map((value) => toWireValue(value)));
418
- }
419
- function createD1Imports(bindings, getMemory) {
420
- const encoder3 = new TextEncoder();
421
- const decoder3 = new TextDecoder();
422
- function readStr(ptr, len) {
423
- return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
334
+ /**
335
+ * Create an empty object.
336
+ * */
337
+ valueObjectCreate(out) {
338
+ this.storeValue(out, new Object());
424
339
  }
425
- function writeJson(buf_ptr, buf_max, value) {
426
- const data = encoder3.encode(JSON.stringify(value));
427
- if (data.length > buf_max) return -2;
428
- new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
429
- return data.length;
340
+ /**
341
+ * Creates a string on the JS side from a UTF-8 encoded string in wasm memory.
342
+ * */
343
+ valueStringCreate(out, ptr, len) {
344
+ const str = this.loadString(ptr, len);
345
+ this.storeValue(out, str);
430
346
  }
431
- function binding(ns) {
432
- return bindings[ns] ?? bindings["default"] ?? null;
347
+ /**
348
+ * Returns the length of the string given by id.
349
+ * */
350
+ valueStringLen(id) {
351
+ const val = this.loadValue(id);
352
+ const buf = encoder2.encode(val);
353
+ return buf.byteLength;
433
354
  }
434
- async function statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len) {
435
- const database = binding(readStr(ns_ptr, ns_len));
436
- if (!database) return null;
437
- const sql = readStr(sql_ptr, sql_len);
438
- const bindingsJson = JSON.parse(readStr(bindings_ptr, bindings_len));
439
- return database.prepare(sql).bind(...toPositionalBindings(bindingsJson));
355
+ /**
356
+ * Copy the string at id "id" into the shared memory at ptr.
357
+ * */
358
+ valueStringCopy(id, ptr, max) {
359
+ if (this.memory == null) return;
360
+ const dest = ptr >>> 0;
361
+ const cap = max >>> 0;
362
+ const val = this.loadValue(id);
363
+ if (typeof val !== "string") return;
364
+ const bytes = encoder2.encode(val);
365
+ if (bytes.byteLength > cap || bytes.length === 0) return;
366
+ const buf = this.memory.buffer;
367
+ if (dest + bytes.length > buf.byteLength) return;
368
+ new Uint8Array(buf, dest, bytes.length).set(bytes);
440
369
  }
441
- const Suspending = WebAssembly.Suspending;
442
- if (typeof Suspending !== "function") {
443
- return {
444
- db_open: (_ns, _ns_len) => -1,
445
- db_run: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
446
- db_get: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
447
- db_all: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
448
- db_values: (_a, _b, _c, _d, _e, _f, _g, _h) => -1
449
- };
370
+ /**
371
+ * Call a constructor given by id.
372
+ * */
373
+ valueNew(out, id, argsAddr, argsLen) {
374
+ const fn = this.loadValue(id);
375
+ const args = [];
376
+ const base = argsAddr >>> 0;
377
+ const count = argsLen >>> 0;
378
+ for (let i = 0; i < count; i++) {
379
+ args.push(this.loadRef(base + i * 8));
380
+ }
381
+ const result = Reflect.construct(fn, args);
382
+ this.storeValue(out, result);
450
383
  }
451
- return {
452
- db_open: (ns_ptr, ns_len) => binding(readStr(ns_ptr, ns_len)) ? 0 : -1,
453
- db_run: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
454
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
455
- if (!stmt) return -1;
456
- const result = await stmt.run();
457
- return writeJson(buf_ptr, buf_max, {
458
- last_insert_rowid: result.meta?.last_row_id ?? 0,
459
- changes: result.meta?.changes ?? 0
460
- });
461
- }),
462
- db_get: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
463
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
464
- if (!stmt) return -1;
465
- const row = await stmt.first();
466
- if (!row) return 0;
467
- return writeJson(buf_ptr, buf_max, [objectToWireRow(row)]);
468
- }),
469
- db_all: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
470
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
471
- if (!stmt) return -1;
472
- const result = await stmt.all();
473
- return writeJson(buf_ptr, buf_max, (result.results ?? []).map(objectToWireRow));
474
- }),
475
- db_values: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
476
- const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
477
- if (!stmt) return -1;
478
- const rows = await stmt.raw();
479
- return writeJson(buf_ptr, buf_max, valuesToWireRows(rows));
480
- })
481
- };
482
- }
483
-
484
- // src/wasi.ts
485
- var ProcExit = class extends Error {
486
- constructor(code) {
487
- super(`proc_exit(${code})`);
488
- this.code = code;
384
+ /**
385
+ * Call a function given by id.
386
+ * */
387
+ funcApply(out, id, thisRefAddr, argsAddr, argsLen) {
388
+ const fn = this.loadValue(id);
389
+ const thisVal = this.loadRef(thisRefAddr >>> 0);
390
+ const args = [];
391
+ const base = argsAddr >>> 0;
392
+ const count = argsLen >>> 0;
393
+ for (let i = 0; i < count; i++) {
394
+ args.push(this.loadRef(base + i * 8));
395
+ }
396
+ if (typeof fn !== "function") {
397
+ this.storeValue(out, void 0);
398
+ return;
399
+ }
400
+ try {
401
+ const result = Reflect.apply(fn, thisVal, args);
402
+ this.storeValue(out, result);
403
+ } catch {
404
+ this.storeValue(out, void 0);
405
+ }
489
406
  }
490
- };
491
- function createWasiImports({
492
- request,
493
- stdinData,
494
- onStdout
495
- }) {
496
- const encoder3 = new TextEncoder();
497
- const url = new URL(request.url);
498
- const argStrings = [
499
- "wasm",
500
- "--pathname",
501
- url.pathname,
502
- "--method",
503
- request.method,
504
- "--search",
505
- url.search,
506
- "--url",
507
- url.href
508
- ];
509
- request.headers.forEach((value, name) => {
510
- if (value) argStrings.push("--header", `${name}:${value}`);
511
- });
512
- const encodedArgs = argStrings.map((a) => encoder3.encode(a + "\0"));
513
- const argBufSize = encodedArgs.reduce((s, a) => s + a.length, 0);
514
- let wasmMemory = null;
515
- const setMemory = (m2) => {
516
- wasmMemory = m2;
517
- };
518
- const stdoutChunks = [];
519
- let stderrMeta = "";
520
- let stderrPartial = "";
521
- const stderrDecoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
522
- function processStderrChunk(chunk) {
523
- const text = stderrDecoder.decode(chunk, { stream: true });
524
- const lines = (stderrPartial + text).split("\n");
525
- stderrPartial = lines.pop() ?? "";
526
- for (const line of lines) {
527
- if (line.startsWith("__ZIEX_META__:")) {
528
- stderrMeta += line + "\n";
529
- } else if (line.length > 0) {
530
- console.error("[ziex]", line);
407
+ /**
408
+ * This can be used to load a value given by an ID. A WASM function
409
+ * might return a value as an ID. This can be used to retrieve it.
410
+ * */
411
+ loadValue(id) {
412
+ return this.values[id];
413
+ }
414
+ /**
415
+ * This removes the value from the values list and returns it. This
416
+ * will not remove predefined values but can still be used to retrieve
417
+ * them.
418
+ * */
419
+ deleteValue(id) {
420
+ const val = this.values[id];
421
+ this.valueDeinit(id);
422
+ return val;
423
+ }
424
+ loadRef(refAddr) {
425
+ if (this.memory == null) return;
426
+ const addr = refAddr >>> 0;
427
+ const view = new DataView(this.memory.buffer);
428
+ const floatVal = view.getFloat64(addr, true);
429
+ if (!isNaN(floatVal)) return floatVal;
430
+ const id = this.loadRefId(addr);
431
+ return this.values[id];
432
+ }
433
+ loadRefId(refAddr) {
434
+ if (this.memory == null) return 0;
435
+ return new DataView(this.memory.buffer).getUint32(refAddr >>> 0, true);
436
+ }
437
+ storeValue(out, val) {
438
+ if (this.memory == null) return;
439
+ const view = new DataView(this.memory.buffer);
440
+ out = out >>> 0;
441
+ if (typeof val === "number") {
442
+ if (isNaN(val)) {
443
+ view.setUint32(out, predefined.nan, true);
444
+ view.setUint32(out + 4, NAN_PREFIX, true);
445
+ } else {
446
+ view.setFloat64(out, val, true);
531
447
  }
448
+ return;
449
+ }
450
+ if (val === null) {
451
+ view.setUint32(out, predefined.null, true);
452
+ view.setUint32(out + 4, NAN_PREFIX, true);
453
+ return;
454
+ }
455
+ if (val === void 0) {
456
+ view.setUint32(out, predefined.undefined, true);
457
+ view.setUint32(out + 4, NAN_PREFIX, true);
458
+ return;
459
+ }
460
+ if (typeof val === "boolean") {
461
+ view.setUint32(out, val ? predefined.true : predefined.false, true);
462
+ view.setUint32(out + 4, NAN_PREFIX, true);
463
+ return;
464
+ }
465
+ if (typeof val === "bigint") {
466
+ view.setFloat64(out, Number(val), true);
467
+ return;
468
+ }
469
+ let id = this.idPool.pop();
470
+ if (id === void 0) {
471
+ id = this.values.length;
472
+ }
473
+ this.values[id] = val;
474
+ let typeId = 0;
475
+ switch (typeof val) {
476
+ case "object":
477
+ typeId = 1;
478
+ break;
479
+ case "string":
480
+ typeId = 2;
481
+ break;
482
+ case "symbol":
483
+ typeId = 3;
484
+ break;
485
+ case "function":
486
+ typeId = 4;
487
+ break;
532
488
  }
489
+ view.setUint32(out, Number(id), true);
490
+ view.setUint32(out + 4, NAN_PREFIX | typeId, true);
533
491
  }
534
- let stdinOffset = 0;
535
- function v() {
536
- return new DataView(wasmMemory.buffer);
492
+ loadString(ptr, len) {
493
+ if (this.memory == null) return "";
494
+ const start = ptr >>> 0;
495
+ const length = Number(len) >>> 0;
496
+ const buf = this.memory.buffer;
497
+ if (length === 0 || start + length > buf.byteLength) return "";
498
+ const arr = new Uint8ClampedArray(buf, start, length);
499
+ const data = arr.slice();
500
+ return decoder2.decode(data);
537
501
  }
538
- function m() {
539
- return new Uint8Array(wasmMemory.buffer);
502
+ };
503
+
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);
525
+ if (!Number.isNaN(tempRefView.getFloat64(0, true))) return;
526
+ const id = tempRefView.getUint32(0, true);
527
+ if (id > 6) jsz.deleteValue(id);
528
+ }
529
+ var textDecoder = new TextDecoder();
530
+ var textEncoder = new TextEncoder();
531
+ var memoryView = null;
532
+ var memoryBuffer = null;
533
+ function getMemoryView() {
534
+ const buf = jsz.memory.buffer;
535
+ if (buf !== memoryBuffer) {
536
+ memoryBuffer = buf;
537
+ memoryView = new Uint8Array(buf);
540
538
  }
541
- const wasiImport = {
542
- args_sizes_get(argc_ptr, argv_buf_size_ptr) {
543
- v().setUint32(argc_ptr, encodedArgs.length, true);
544
- v().setUint32(argv_buf_size_ptr, argBufSize, true);
545
- return 0;
546
- },
547
- args_get(argv_ptr, argv_buf_ptr) {
548
- const dv = v();
549
- const mem = m();
550
- let offset = argv_buf_ptr;
551
- for (const arg of encodedArgs) {
552
- dv.setUint32(argv_ptr, offset, true);
553
- mem.set(arg, offset);
554
- argv_ptr += 4;
555
- offset += arg.length;
556
- }
557
- return 0;
558
- },
559
- environ_sizes_get(count_ptr, buf_size_ptr) {
560
- v().setUint32(count_ptr, 0, true);
561
- v().setUint32(buf_size_ptr, 0, true);
562
- return 0;
563
- },
564
- environ_get(_environ_ptr, _environ_buf_ptr) {
565
- return 0;
566
- },
567
- fd_write(fd, iovs_ptr, iovs_len, nwritten_ptr) {
568
- const dv = v();
569
- const mem = m();
570
- let written = 0;
571
- for (let i = 0; i < iovs_len; i++) {
572
- const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
573
- const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
574
- const chunk = mem.slice(buf_ptr, buf_ptr + buf_len);
575
- if (fd === 1) {
576
- if (onStdout) onStdout(chunk);
577
- else stdoutChunks.push(chunk);
578
- } else if (fd === 2) processStderrChunk(chunk);
579
- written += buf_len;
580
- }
581
- dv.setUint32(nwritten_ptr, written, true);
582
- return 0;
583
- },
584
- fd_read(fd, iovs_ptr, iovs_len, nread_ptr) {
585
- const dv = v();
586
- const mem = m();
587
- const stdin = stdinData ?? new Uint8Array(0);
588
- let totalRead = 0;
589
- for (let i = 0; i < iovs_len; i++) {
590
- const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
591
- const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
592
- if (fd === 0 && stdinOffset < stdin.length) {
593
- const toRead = Math.min(buf_len, stdin.length - stdinOffset);
594
- mem.set(stdin.subarray(stdinOffset, stdinOffset + toRead), buf_ptr);
595
- stdinOffset += toRead;
596
- totalRead += toRead;
539
+ return memoryView;
540
+ }
541
+ function readString(ptr, len) {
542
+ const start = ptr >>> 0;
543
+ const length = len >>> 0;
544
+ if (length === 0) return "";
545
+ const view = getMemoryView();
546
+ if (start + length > view.byteLength) return "";
547
+ return textDecoder.decode(view.subarray(start, start + length));
548
+ }
549
+ function writeBytes(ptr, data) {
550
+ const start = ptr >>> 0;
551
+ const view = getMemoryView();
552
+ if (start + data.length > view.byteLength) return;
553
+ view.set(data, start);
554
+ }
555
+ function wrapPromisingExport(fn) {
556
+ if (!fn) return void 0;
557
+ const promising = WebAssembly.promising;
558
+ if (typeof promising !== "function") return fn;
559
+ return promising(fn);
560
+ }
561
+ function invokeWasmExport(fn, ...args) {
562
+ if (!fn) return;
563
+ const result = fn(...args);
564
+ if (result && typeof result.then === "function") {
565
+ void result.then(void 0, (error) => {
566
+ console.error(error);
567
+ });
568
+ }
569
+ }
570
+ var ZxBridgeCore = class _ZxBridgeCore {
571
+ #intervals = /* @__PURE__ */ new Map();
572
+ #handler;
573
+ constructor(exports) {
574
+ this._alloc = exports.__zx_alloc;
575
+ this.#handler = wrapPromisingExport(exports.__zx_cb);
576
+ if (!this.#handler) {
577
+ console.warn("__zx_cb not exported from WASM");
578
+ }
579
+ if (exports.memory) jsz.memory = exports.memory;
580
+ }
581
+ /** Invoke the unified callback handler */
582
+ _invoke(type, id, a = 0n, b = 0n, c = 0n) {
583
+ const handler = this.#handler;
584
+ if (!handler) {
585
+ console.warn("__zx_cb not exported from WASM");
586
+ return;
587
+ }
588
+ invokeWasmExport(handler, type, id, a, b, c);
589
+ }
590
+ /**
591
+ * Async fetch with full options support.
592
+ * Completes via `__zx_cb(fetch_success|fetch_error, ...)`.
593
+ */
594
+ fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
595
+ const url = readString(urlPtr, urlLen);
596
+ const method = methodLen > 0 ? readString(methodPtr, methodLen) : "GET";
597
+ const headersJson = headersLen > 0 ? readString(headersPtr, headersLen) : "{}";
598
+ const body = bodyLen > 0 ? getMemoryView().subarray(bodyPtr, bodyPtr + bodyLen) : void 0;
599
+ let headers = {};
600
+ try {
601
+ headers = JSON.parse(headersJson);
602
+ } catch {
603
+ for (const line of headersJson.split("\n")) {
604
+ const colonIdx = line.indexOf(":");
605
+ if (colonIdx > 0) {
606
+ headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
597
607
  }
598
608
  }
599
- dv.setUint32(nread_ptr, totalRead, true);
600
- return 0;
601
- },
602
- fd_fdstat_get(_fd, fdstat_ptr) {
603
- const dv = v();
604
- dv.setUint8(fdstat_ptr, 2);
605
- dv.setUint8(fdstat_ptr + 1, 0);
606
- dv.setUint16(fdstat_ptr + 2, 0, true);
607
- dv.setUint32(fdstat_ptr + 4, 0, true);
608
- dv.setBigUint64(fdstat_ptr + 8, 0n, true);
609
- dv.setBigUint64(fdstat_ptr + 16, 0n, true);
610
- return 0;
611
- },
612
- fd_prestat_get(_fd, _bufptr) {
613
- return 8;
614
- },
615
- fd_prestat_dir_name(_fd, _path, _path_len) {
616
- return 8;
617
- },
618
- fd_close(_fd) {
619
- return 0;
620
- },
621
- fd_pread(_fd, _iovs, _iovs_len, _offset, nread_ptr) {
622
- v().setUint32(nread_ptr, 0, true);
623
- return 0;
624
- },
625
- fd_pwrite(_fd, _iovs, _iovs_len, _offset, nwritten_ptr) {
626
- v().setUint32(nwritten_ptr, 0, true);
627
- return 0;
628
- },
629
- fd_filestat_get(_fd, filestat_ptr) {
630
- const dv = v();
631
- dv.setBigUint64(filestat_ptr, 0n, true);
632
- dv.setBigUint64(filestat_ptr + 8, 0n, true);
633
- dv.setUint8(filestat_ptr + 16, 2);
634
- dv.setBigUint64(filestat_ptr + 24, 1n, true);
635
- dv.setBigUint64(filestat_ptr + 32, 0n, true);
636
- dv.setBigUint64(filestat_ptr + 40, 0n, true);
637
- dv.setBigUint64(filestat_ptr + 48, 0n, true);
638
- dv.setBigUint64(filestat_ptr + 56, 0n, true);
639
- return 0;
640
- },
641
- fd_filestat_set_size(_fd, _size) {
642
- return 76;
643
- },
644
- fd_filestat_set_times(_fd, _atim, _mtim, _fst_flags) {
645
- return 76;
646
- },
647
- fd_fdstat_set_flags(_fd, _flags) {
648
- return 0;
649
- },
650
- fd_fdstat_set_rights(_fd, _rights_base, _rights_inheriting) {
651
- return 0;
652
- },
653
- fd_sync(_fd) {
654
- return 0;
655
- },
656
- fd_datasync(_fd) {
657
- return 0;
658
- },
659
- fd_advise(_fd, _offset, _len, _advice) {
660
- return 0;
661
- },
662
- fd_allocate(_fd, _offset, _len) {
663
- return 76;
664
- },
665
- fd_tell(_fd, offset_ptr) {
666
- v().setBigUint64(offset_ptr, 0n, true);
667
- return 0;
668
- },
669
- fd_renumber(_from, _to) {
670
- return 0;
671
- },
672
- path_filestat_set_times(_fd, _flags, _path, _path_len, _atim, _mtim, _fst_flags) {
673
- return 76;
674
- },
675
- path_link(_old_fd, _old_flags, _old_path, _old_path_len, _new_fd, _new_path, _new_path_len) {
676
- return 76;
677
- },
678
- path_symlink(_old_path, _old_path_len, _fd, _new_path, _new_path_len) {
679
- return 76;
680
- },
681
- proc_raise(_sig) {
682
- return 0;
683
- },
684
- sock_recv(_fd, _ri_data, _ri_data_len, _ri_flags, ro_datalen_ptr, ro_flags_ptr) {
685
- v().setUint32(ro_datalen_ptr, 0, true);
686
- v().setUint32(ro_flags_ptr, 0, true);
687
- return 76;
688
- },
689
- sock_send(_fd, _si_data, _si_data_len, _si_flags, so_datalen_ptr) {
690
- v().setUint32(so_datalen_ptr, 0, true);
691
- return 76;
692
- },
693
- sock_shutdown(_fd, _how) {
694
- return 76;
695
- },
696
- fd_seek(_fd, _offset, _whence, newoffset_ptr) {
697
- v().setBigInt64(newoffset_ptr, 0n, true);
698
- return 0;
699
- },
700
- proc_exit(code) {
701
- throw new ProcExit(code);
702
- },
703
- sched_yield() {
704
- return 0;
705
- },
706
- clock_time_get(_id, _precision, time_ptr) {
707
- v().setBigUint64(time_ptr, BigInt(Date.now()) * 1000000n, true);
708
- return 0;
709
- },
710
- clock_res_get(_id, res_ptr) {
711
- v().setBigUint64(res_ptr, 1000000n, true);
712
- return 0;
713
- },
714
- random_get(buf_ptr, buf_len) {
715
- crypto.getRandomValues(new Uint8Array(wasmMemory.buffer, buf_ptr, buf_len));
716
- return 0;
717
- },
718
- path_open(_fd, _dirflags, _path, _path_len, _oflags, _rights_base, _rights_inheriting, _fdflags, opened_fd_ptr) {
719
- v().setInt32(opened_fd_ptr, -1, true);
720
- return 76;
721
- },
722
- path_create_directory(_fd, _path, _path_len) {
723
- return 76;
724
- },
725
- path_unlink_file(_fd, _path, _path_len) {
726
- return 76;
727
- },
728
- path_remove_directory(_fd, _path, _path_len) {
729
- return 76;
730
- },
731
- path_rename(_fd, _old_path, _old_path_len, _new_fd, _new_path, _new_path_len) {
732
- return 76;
733
- },
734
- path_filestat_get(_fd, _flags, _path, _path_len, filestat_ptr) {
735
- new Uint8Array(wasmMemory.buffer, filestat_ptr, 64).fill(0);
736
- return 76;
737
- },
738
- path_readlink(_fd, _path, _path_len, _buf, _buf_len, nread_ptr) {
739
- v().setUint32(nread_ptr, 0, true);
740
- return 76;
741
- },
742
- fd_readdir(_fd, _buf, _buf_len, _cookie, bufused_ptr) {
743
- v().setUint32(bufused_ptr, 0, true);
744
- return 76;
745
- },
746
- // Stub for poll_oneoff - no blocking I/O in edge runtimes.
747
- poll_oneoff(_in, _out, _nsubscriptions, nevents_ptr) {
748
- v().setUint32(nevents_ptr, 0, true);
749
- return 0;
750
- }
751
- };
752
- function collectOutput() {
753
- const remaining = stderrDecoder.decode(void 0, { stream: false });
754
- const tail = stderrPartial + remaining;
755
- if (tail.length > 0) {
756
- if (tail.startsWith("__ZIEX_META__:")) stderrMeta += tail;
757
- else console.error("[ziex]", tail);
758
- stderrPartial = "";
759
609
  }
760
- return {
761
- stdout: mergeUint8Arrays(stdoutChunks),
762
- stderrText: stderrMeta
610
+ const controller = new AbortController();
611
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
612
+ const fetchOptions = {
613
+ method,
614
+ headers: Object.keys(headers).length > 0 ? headers : void 0,
615
+ body: method !== "GET" && method !== "HEAD" ? body : void 0,
616
+ signal: controller.signal
763
617
  };
618
+ fetch(url, fetchOptions).then(async (response) => {
619
+ if (timeout) clearTimeout(timeout);
620
+ const bytes = new Uint8Array(await response.arrayBuffer());
621
+ this._notifyFetchComplete(fetchId, response.status, bytes, false);
622
+ }).catch((error) => {
623
+ if (timeout) clearTimeout(timeout);
624
+ const isAbort = error.name === "AbortError";
625
+ const errorMsg = isAbort ? "Request timeout" : error.message ?? "Fetch failed";
626
+ this._notifyFetchComplete(fetchId, 0, errorMsg, true);
627
+ });
764
628
  }
765
- return { wasiImport, setMemory, collectOutput };
766
- }
767
- function mergeUint8Arrays(arrays) {
768
- const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
769
- const result = new Uint8Array(totalLen);
770
- let offset = 0;
771
- for (const arr of arrays) {
772
- result.set(arr, offset);
773
- offset += arr.length;
629
+ /** Notify WASM that a fetch completed. `body` is raw bytes on success, text on error. */
630
+ _notifyFetchComplete(fetchId, statusCode, body, isError) {
631
+ const encoded = typeof body === "string" ? textEncoder.encode(body) : body;
632
+ const ptr = this._alloc(encoded.length) >>> 0;
633
+ if (!ptr && encoded.length > 0) return;
634
+ writeBytes(ptr, encoded);
635
+ const type = isError ? CallbackType_FetchError : CallbackType_FetchSuccess;
636
+ this._invoke(type, fetchId, BigInt(statusCode), BigInt(ptr), BigInt(encoded.length));
774
637
  }
775
- return result;
776
- }
777
-
778
- // src/runtime.ts
779
- function buildWsImports(Suspending, mem, decoder3, ws) {
780
- const readStr = (ptr, len) => decoder3.decode(new Uint8Array(mem().buffer, ptr, len));
781
- return {
782
- ws_upgrade: () => {
783
- ws.upgraded = true;
784
- },
785
- ws_write: (ptr, len) => {
786
- const data = new Uint8Array(mem().buffer, ptr, len).slice();
787
- if (!ws.server) {
788
- ws.pendingWrites.push(data);
789
- } else {
790
- ws.server.send(data);
791
- }
792
- },
793
- ws_close: (code, reason_ptr, reason_len) => {
794
- ws.server?.close(code, decoder3.decode(new Uint8Array(mem().buffer, reason_ptr, reason_len)));
795
- },
796
- ws_recv: Suspending ? new Suspending(async (buf_ptr, buf_max) => {
797
- if (ws._resolveFirstSuspend) {
798
- const fn = ws._resolveFirstSuspend;
799
- ws._resolveFirstSuspend = void 0;
800
- fn();
801
- }
802
- const deliver = (bytes) => {
803
- if (bytes === null) return -1;
804
- const n = Math.min(bytes.length, buf_max);
805
- new Uint8Array(mem().buffer, buf_ptr, n).set(bytes.subarray(0, n));
806
- return n;
807
- };
808
- if (ws.messageQueue.length > 0) return deliver(ws.messageQueue.shift());
809
- return new Promise((resolve) => {
810
- ws.recvResolve = (bytes) => resolve(deliver(bytes));
811
- });
812
- }) : (_buf_ptr, _buf_max) => -1,
813
- // Pub/sub - delegates to optional callbacks (real in DO, no-ops otherwise)
814
- ws_subscribe: (ptr, len) => {
815
- ws.subscribe?.(readStr(ptr, len));
816
- },
817
- ws_unsubscribe: (ptr, len) => {
818
- ws.unsubscribe?.(readStr(ptr, len));
819
- },
820
- ws_publish: (topic_ptr, topic_len, data_ptr, data_len) => {
821
- const topic = readStr(topic_ptr, topic_len);
822
- const data = new Uint8Array(mem().buffer, data_ptr, data_len).slice();
823
- return ws.publish?.(topic, data) ?? 0;
824
- },
825
- ws_is_subscribed: (ptr, len) => ws.isSubscribed?.(readStr(ptr, len)) ? 1 : 0
826
- };
827
- }
828
- function attachWebSocket(ws) {
829
- const WebSocketPairCtor = globalThis.WebSocketPair;
830
- const pair = new WebSocketPairCtor();
831
- const client = pair[0];
832
- const server = pair[1];
833
- ws.server = server;
834
- server.accept();
835
- for (const data of ws.pendingWrites) server.send(data);
836
- ws.pendingWrites = [];
837
- server.addEventListener("message", (event) => {
838
- const data = typeof event.data === "string" ? new TextEncoder().encode(event.data) : new Uint8Array(event.data);
839
- if (ws.recvResolve) {
840
- const res = ws.recvResolve;
841
- ws.recvResolve = null;
842
- res(data);
843
- } else {
844
- ws.messageQueue.push(data);
845
- }
846
- });
847
- server.addEventListener("close", () => {
848
- if (ws.recvResolve) {
849
- const res = ws.recvResolve;
850
- ws.recvResolve = null;
851
- res(null);
852
- }
853
- });
854
- return { client };
855
- }
856
- function buildSysImports(jspi, Suspending) {
857
- return {
858
- sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {
638
+ /** Set a timeout and callback when it fires */
639
+ setTimeout(callbackId, delayMs) {
640
+ setTimeout(() => {
641
+ this._invoke(CallbackType_Timeout, callbackId);
642
+ }, delayMs);
643
+ }
644
+ /** Set an interval and callback each time it fires */
645
+ setInterval(callbackId, intervalMs) {
646
+ const handle = setInterval(() => {
647
+ this._invoke(CallbackType_Interval, callbackId);
648
+ }, intervalMs);
649
+ this.#intervals.set(callbackId, handle);
650
+ }
651
+ /** Clear an interval */
652
+ clearInterval(callbackId) {
653
+ const handle = this.#intervals.get(callbackId);
654
+ if (handle !== void 0) {
655
+ clearInterval(handle);
656
+ this.#intervals.delete(callbackId);
859
657
  }
860
- };
861
- }
862
- function executeWasm(instance, jspi, Suspending, wsState) {
863
- if (!jspi) {
864
- try {
865
- instance.exports._start();
866
- } catch (e) {
867
- if (!(e instanceof ProcExit)) throw e;
658
+ }
659
+ dispose() {
660
+ for (const handle of this.#intervals.values()) {
661
+ clearInterval(handle);
868
662
  }
869
- return Promise.resolve();
663
+ this.#intervals.clear();
870
664
  }
871
- const start = WebAssembly.promising(instance.exports._start);
872
- return start().catch((e) => {
873
- if (e instanceof Error && e.message.startsWith("proc_exit")) return;
874
- throw e;
875
- }).finally(() => {
876
- if (wsState.recvResolve) {
877
- const res = wsState.recvResolve;
878
- wsState.recvResolve = null;
879
- res(null);
665
+ /** Write a string to WASM memory, returning `[ptr, len]`. */
666
+ _writeStringToWasm(str) {
667
+ return this.writeBytesToWasm(textEncoder.encode(str));
668
+ }
669
+ writeBytesToWasm(data) {
670
+ if (data.length === 0) return [0, 0];
671
+ const ptr = this._alloc(data.length) >>> 0;
672
+ if (!ptr) return [0, 0];
673
+ writeBytes(ptr, data);
674
+ return [ptr, data.length];
675
+ }
676
+ /** Log a message from WASM at the given level (0=error, 1=warn, 2=info, 3=debug) */
677
+ static log(level, ptr, len) {
678
+ const start = ptr >>> 0;
679
+ const length = len >>> 0;
680
+ const view = getMemoryView();
681
+ if (start + length > view.byteLength) return;
682
+ const msg = textDecoder.decode(view.subarray(start, start + length));
683
+ switch (level) {
684
+ case 0:
685
+ console.error(msg);
686
+ break;
687
+ case 1:
688
+ console.warn(msg);
689
+ break;
690
+ case 3:
691
+ console.debug(msg);
692
+ break;
693
+ default:
694
+ console.log(msg);
695
+ break;
880
696
  }
881
- });
882
- }
883
- function parseZiexMeta(stderrText) {
884
- const meta = { status: 200, headers: new Headers(), streaming: false };
885
- const metaPrefix = "__ZIEX_META__:";
886
- const metaLine = stderrText.split("\n").find((line) => line.startsWith(metaPrefix));
887
- if (metaLine) {
888
- try {
889
- const parsed = JSON.parse(metaLine.slice(metaPrefix.length));
890
- if (parsed.status) meta.status = parsed.status;
891
- if (parsed.streaming === true) meta.streaming = true;
892
- if (Array.isArray(parsed.headers)) {
893
- for (const [name, value] of parsed.headers) {
894
- meta.headers.append(name, value);
697
+ }
698
+ /**
699
+ * Create the core import object for WASM instantiation.
700
+ * Includes only environment-agnostic bindings: log, fetch, and timers.
701
+ * Use ZxBridge.createImportObject (from wasm/index.ts) in browser contexts
702
+ * to additionally include DOM and WebSocket bindings.
703
+ */
704
+ static createImportObject(bridgeRef) {
705
+ return {
706
+ ...jsz.importObject(),
707
+ __zx_net: createFetchImports(() => {
708
+ if (!jsz.memory) throw new Error("WASM memory is not ready");
709
+ return jsz.memory;
710
+ }),
711
+ __zx: {
712
+ _log: (level, ptr, len) => _ZxBridgeCore.log(level, ptr, len),
713
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
714
+ bridgeRef[0]?.fetchAsync(
715
+ urlPtr,
716
+ urlLen,
717
+ methodPtr,
718
+ methodLen,
719
+ headersPtr,
720
+ headersLen,
721
+ bodyPtr,
722
+ bodyLen,
723
+ timeoutMs,
724
+ fetchId
725
+ );
726
+ },
727
+ _setTimeout: (callbackId, delayMs) => {
728
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
729
+ },
730
+ _setInterval: (callbackId, intervalMs) => {
731
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
732
+ },
733
+ _clearInterval: (callbackId) => {
734
+ bridgeRef[0]?.clearInterval(callbackId);
895
735
  }
896
736
  }
897
- } catch {
898
- }
737
+ };
899
738
  }
900
- return meta;
739
+ };
740
+ function writeBytesOut(getMemory, allocRef, outPtrAddr, data) {
741
+ if (data.length === 0) {
742
+ new DataView(getMemory().buffer).setUint32(outPtrAddr, 0, true);
743
+ return 0;
744
+ }
745
+ const alloc = allocRef[0];
746
+ if (!alloc) return -1;
747
+ const ptr = alloc(data.length) >>> 0;
748
+ if (!ptr) return -1;
749
+ const buffer = getMemory().buffer;
750
+ if (ptr + data.length > buffer.byteLength) return -1;
751
+ new Uint8Array(buffer, ptr, data.length).set(data);
752
+ new DataView(buffer).setUint32(outPtrAddr >>> 0, ptr, true);
753
+ return data.length;
901
754
  }
902
- async function run({
903
- request,
904
- env,
905
- ctx,
906
- module,
907
- kv: kvBindings,
908
- db: dbBindings,
909
- imports,
910
- wasi,
911
- websocket: doNamespace
912
- }) {
913
- if (doNamespace && request.headers.get("upgrade")?.toLowerCase() === "websocket") {
914
- const id = doNamespace.idFromName(new URL(request.url).pathname);
915
- return doNamespace.get(id).fetch(request);
916
- }
917
- const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : void 0;
918
- const stdoutChunks = [];
919
- let streamWriter = null;
920
- const { wasiImport, setMemory, collectOutput } = createWasiImports({
921
- request,
922
- stdinData,
923
- onStdout: (chunk) => {
924
- if (streamWriter) void streamWriter.write(chunk);
925
- else stdoutChunks.push(chunk);
926
- }
927
- });
928
- let wasmMemory = null;
929
- const mem = () => wasmMemory;
930
- const bridgeRef = { current: null };
931
- const Suspending = WebAssembly.Suspending;
932
- const jspi = typeof Suspending === "function";
933
- const wsState = {
934
- upgraded: false,
935
- server: null,
936
- pendingWrites: [],
937
- messageQueue: [],
938
- recvResolve: null
939
- };
940
- const instance = new WebAssembly.Instance(module, {
941
- wasi_snapshot_preview1: { ...wasi?.wasiImport, ...wasiImport },
942
- __zx_sys: buildSysImports(jspi, Suspending),
943
- __zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder(), wsState),
944
- __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
945
- __zx_db: createD1Imports(dbBindings ?? {}, mem),
946
- __zx_net: createFetchImports(mem),
947
- ...imports ? imports(mem) : {},
948
- ...ZxWasiBridge.createImportObject(bridgeRef)
949
- });
950
- wasmMemory = instance.exports.memory;
951
- setMemory(wasmMemory);
952
- bridgeRef.current = new ZxWasiBridge(instance.exports);
953
- const wasmPromise = executeWasm(instance, jspi, Suspending, wsState);
954
- if (wsState.upgraded) {
955
- const server = attachWebSocket(wsState);
956
- ctx?.waitUntil(wasmPromise);
957
- return new Response(null, { status: 101, webSocket: server.client });
755
+ function writeJsonOut(getMemory, allocRef, outPtrAddr, value) {
756
+ return writeBytesOut(getMemory, allocRef, outPtrAddr, textEncoder.encode(JSON.stringify(value)));
757
+ }
758
+ function bindWasmAlloc(allocRef, exports) {
759
+ allocRef[0] = exports.__zx_alloc;
760
+ }
761
+
762
+ // src/runtime/kv/extern.ts
763
+ function putOptions(ttlSeconds) {
764
+ if (ttlSeconds < 60) return void 0;
765
+ return { expirationTtl: ttlSeconds };
766
+ }
767
+ 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";
770
+ }
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));
958
776
  }
959
- const { stderrText: earlyStderrText } = collectOutput();
960
- const earlyMeta = parseZiexMeta(earlyStderrText);
961
- if (earlyMeta.streaming) {
962
- const { readable, writable } = new TransformStream();
963
- streamWriter = writable.getWriter();
964
- for (const chunk of stdoutChunks) void streamWriter.write(chunk);
965
- stdoutChunks.length = 0;
966
- void wasmPromise.finally(() => streamWriter?.close());
967
- return new Response(readable, { status: earlyMeta.status, headers: earlyMeta.headers });
777
+ function binding(ns) {
778
+ return bindings[ns] ?? bindings["default"] ?? null;
968
779
  }
969
- await wasmPromise;
970
- const { stderrText } = collectOutput();
971
- const meta = parseZiexMeta(stderrText);
972
- const body = mergeUint8Arrays(stdoutChunks);
973
- meta.headers.delete("transfer-encoding");
974
- const nullBody = meta.status === 101 || meta.status === 204 || meta.status === 205 || meta.status === 304;
975
- if (nullBody) {
976
- meta.headers.delete("content-length");
977
- return new Response(null, { status: meta.status, headers: meta.headers });
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
+ };
978
815
  }
979
- if (!meta.headers.has("content-length")) meta.headers.set("content-length", String(body.byteLength));
980
- return new Response(body.buffer, { status: meta.status, headers: meta.headers });
816
+ 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));
819
+ 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));
823
+ }),
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;
829
+ }),
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;
835
+ }),
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));
838
+ 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);
847
+ })
848
+ };
981
849
  }
982
850
 
983
- // src/app.ts
984
- async function resolveModule(input) {
985
- if (typeof input === "string") {
986
- if (input.startsWith("http://") || input.startsWith("https://")) {
987
- return WebAssembly.compileStreaming(fetch(input));
988
- }
989
- const url = input.startsWith("/") ? `file://${input}` : input;
990
- return WebAssembly.compile(await fetch(url).then((r) => r.arrayBuffer()));
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;
991
872
  }
992
- if (input instanceof URL) {
993
- return WebAssembly.compileStreaming(fetch(input));
873
+ }
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");
994
882
  }
995
- if (input instanceof Response) {
996
- return WebAssembly.compileStreaming(input);
883
+ }
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 };
997
890
  }
998
- if (input instanceof ArrayBuffer) {
999
- return WebAssembly.compile(input);
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) };
1000
896
  }
1001
- if (ArrayBuffer.isView(input)) {
1002
- return WebAssembly.compile(input.buffer);
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) };
1003
902
  }
1004
- return input;
903
+ return { kind: "text", text: String(value) };
1005
904
  }
1006
- var Ziex = class {
1007
- constructor(options) {
1008
- this.resolved = null;
1009
- /**
1010
- * Fetch handler called by the runtime on every request.
1011
- *
1012
- * Arrow function so `this` is always the class instance, even when the
1013
- * runtime extracts `fetch` from the exported object (e.g. Bun).
1014
- */
1015
- this.fetch = async (request, env, ctx) => {
1016
- const module = await this.getModule();
1017
- const { wasi, imports, websocket } = this.options;
1018
- return run({
1019
- request,
1020
- env,
1021
- ctx,
1022
- module,
1023
- wasi,
1024
- imports,
1025
- kv: this.resolveKV(env),
1026
- db: this.resolveDB(env),
1027
- websocket: websocket !== void 0 ? env[websocket] : void 0
1028
- });
1029
- };
1030
- this.options = options;
1031
- }
1032
- async getModule() {
1033
- if (!this.resolved) this.resolved = await resolveModule(this.options.module);
1034
- return this.resolved;
1035
- }
1036
- resolveKV(env) {
1037
- const { kv } = this.options;
1038
- if (kv === void 0) return void 0;
1039
- if (typeof kv === "object" && kv !== null) {
1040
- const result = {};
1041
- for (const [name, key] of Object.entries(kv)) {
1042
- result[name] = env[key];
1043
- }
1044
- return result;
1045
- }
1046
- return { default: env[kv] };
905
+ function objectToWireRow(record) {
906
+ return {
907
+ fields: Object.entries(record).map(([name, value]) => ({
908
+ name,
909
+ value: toWireValue(value)
910
+ }))
911
+ };
912
+ }
913
+ function valuesToWireRows(rows) {
914
+ return rows.map((row) => row.map((value) => toWireValue(value)));
915
+ }
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));
1047
920
  }
1048
- resolveDB(env) {
1049
- const { db } = this.options;
1050
- if (db === void 0) return void 0;
1051
- if (typeof db === "object" && db !== null) {
1052
- const result = {};
1053
- for (const [name, key] of Object.entries(db)) {
1054
- result[name] = env[key];
1055
- }
1056
- return result;
1057
- }
1058
- return { default: env[db] };
921
+ function binding(ns) {
922
+ return bindings[ns] ?? bindings["default"] ?? null;
1059
923
  }
1060
- };
1061
-
1062
- // ../../vendor/jsz/js/src/zigjs.ts
1063
- var NAN_PREFIX = 2146959360;
1064
- var predefined = {
1065
- "nan": 0,
1066
- "null": 1,
1067
- "true": 2,
1068
- "false": 3,
1069
- "undefined": 4,
1070
- "globalThis": 5,
1071
- "runtime": 6
1072
- };
1073
- var PREDEFINED_ID_MAX = 6;
1074
- var encoder2 = new TextEncoder();
1075
- var decoder2 = new TextDecoder("utf-8");
1076
- var ZigJS = class {
1077
- constructor() {
1078
- /**
1079
- * The values, indexed by ID (number). Duplicate values can be in this
1080
- * if they are loaded multiple times. That just acts as duplicate references.
1081
- * */
1082
- this.values = [NaN, null, true, false, void 0, globalThis, this];
1083
- /**
1084
- * When a value is removed from the values array, its ID is put
1085
- * in the pool so that we can use it next. This avoids fragmentation in
1086
- * our array keys.
1087
- * */
1088
- this.idPool = [];
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));
1089
930
  }
1090
- /**
1091
- * Returns the import object that should be merged with your import
1092
- * object when instantiating your wasm instance. This injects the required
1093
- * functions into the wasm environment.
1094
- * */
1095
- importObject() {
931
+ const Suspending = WebAssembly.Suspending;
932
+ if (typeof Suspending !== "function") {
1096
933
  return {
1097
- "zig-js": {
1098
- valueGet: this.valueGet.bind(this),
1099
- valueSet: this.valueSet.bind(this),
1100
- valueDeinit: this.valueDeinit.bind(this),
1101
- valueObjectCreate: this.valueObjectCreate.bind(this),
1102
- valueStringCreate: this.valueStringCreate.bind(this),
1103
- valueStringLen: this.valueStringLen.bind(this),
1104
- valueStringCopy: this.valueStringCopy.bind(this),
1105
- valueNew: this.valueNew.bind(this),
1106
- funcApply: this.funcApply.bind(this)
1107
- }
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
1108
939
  };
1109
940
  }
1110
- /**
1111
- * Get a value from the JS environment.
1112
- * */
1113
- valueGet(out, id, ptr, len) {
1114
- const val = this.loadValue(id);
1115
- const str = this.loadString(ptr, len);
1116
- const result = Reflect.get(val, str);
1117
- this.storeValue(out, result);
1118
- }
1119
- /**
1120
- * Set a value on an object.
1121
- * */
1122
- valueSet(id, ptr, len, refAddr) {
1123
- const obj = this.loadValue(id);
1124
- const str = this.loadString(ptr, len);
1125
- const val = this.loadRef(refAddr);
1126
- Reflect.set(obj, str, val);
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;
1127
991
  }
1128
- /**
1129
- * Dereference a value, allowing the JS environment to potentially GC it.
1130
- * */
1131
- valueDeinit(id) {
1132
- if (id > PREDEFINED_ID_MAX) {
1133
- this.values[id] = null;
1134
- this.idPool.push(id);
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
+ }
1135
1034
  }
1136
1035
  }
1137
- /**
1138
- * Create an empty object.
1139
- * */
1140
- valueObjectCreate(out) {
1141
- this.storeValue(out, new Object());
1142
- }
1143
- /**
1144
- * Creates a string on the JS side from a UTF-8 encoded string in wasm memory.
1145
- * */
1146
- valueStringCreate(out, ptr, len) {
1147
- const str = this.loadString(ptr, len);
1148
- this.storeValue(out, str);
1149
- }
1150
- /**
1151
- * Returns the length of the string given by id.
1152
- * */
1153
- valueStringLen(id) {
1154
- const val = this.loadValue(id);
1155
- const buf = encoder2.encode(val);
1156
- return buf.byteLength;
1036
+ let stdinOffset = 0;
1037
+ function v() {
1038
+ return new DataView(wasmMemory.buffer);
1157
1039
  }
1158
- /**
1159
- * Copy the string at id "id" into the shared memory at ptr.
1160
- * */
1161
- valueStringCopy(id, ptr, max) {
1162
- if (this.memory == null) return;
1163
- const val = this.loadValue(id);
1164
- const bytes = encoder2.encode(val);
1165
- if (bytes.byteLength > max) return;
1166
- if (bytes.length === 0) return;
1167
- new Uint8Array(this.memory.buffer, ptr, bytes.length).set(bytes);
1040
+ function m() {
1041
+ return new Uint8Array(wasmMemory.buffer);
1168
1042
  }
1169
- /**
1170
- * Call a constructor given by id.
1171
- * */
1172
- valueNew(out, id, argsAddr, argsLen) {
1173
- const fn = this.loadValue(id);
1174
- const args = [];
1175
- for (let i = 0; i < argsLen; i++) {
1176
- args.push(this.loadRef(argsAddr + i * 8));
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;
1177
1252
  }
1178
- const result = Reflect.construct(fn, args);
1179
- this.storeValue(out, result);
1180
- }
1181
- /**
1182
- * Call a function given by id.
1183
- * */
1184
- funcApply(out, id, thisRefAddr, argsAddr, argsLen) {
1185
- const fn = this.loadValue(id);
1186
- const thisVal = this.loadRef(thisRefAddr);
1187
- const args = [];
1188
- for (let i = 0; i < argsLen; i++) {
1189
- args.push(this.loadRef(argsAddr + i * 8));
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 = "";
1190
1261
  }
1191
- const result = Reflect.apply(fn, thisVal, args);
1192
- this.storeValue(out, result);
1262
+ return {
1263
+ stdout: mergeUint8Arrays(stdoutChunks),
1264
+ stderrText: stderrMeta
1265
+ };
1193
1266
  }
1194
- /**
1195
- * This can be used to load a value given by an ID. A WASM function
1196
- * might return a value as an ID. This can be used to retrieve it.
1197
- * */
1198
- loadValue(id) {
1199
- return this.values[id];
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;
1200
1276
  }
1201
- /**
1202
- * This removes the value from the values list and returns it. This
1203
- * will not remove predefined values but can still be used to retrieve
1204
- * them.
1205
- * */
1206
- deleteValue(id) {
1207
- const val = this.values[id];
1208
- this.valueDeinit(id);
1209
- return val;
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];
1210
1303
  }
1211
- loadRef(refAddr) {
1212
- if (this.memory == null) return;
1213
- const view = new DataView(this.memory.buffer);
1214
- const floatVal = view.getFloat64(refAddr, true);
1215
- if (!isNaN(floatVal)) return floatVal;
1216
- const id = this.loadRefId(refAddr);
1217
- return this.values[id];
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]);
1218
1312
  }
1219
- loadRefId(refAddr) {
1220
- if (this.memory == null) return 0;
1221
- return new DataView(this.memory.buffer).getUint32(refAddr, true);
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");
1222
1337
  }
1223
- storeValue(out, val) {
1224
- if (this.memory == null) return;
1225
- const view = new DataView(this.memory.buffer);
1226
- if (typeof val === "number") {
1227
- if (isNaN(val)) {
1228
- view.setUint32(out, predefined.nan, true);
1229
- view.setUint32(out + 4, NAN_PREFIX, true);
1230
- } else {
1231
- view.setFloat64(out, val, true);
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) });
1232
1372
  }
1233
- return;
1234
- }
1235
- if (val === null) {
1236
- view.setUint32(out, predefined.null, true);
1237
- view.setUint32(out + 4, NAN_PREFIX, true);
1238
- return;
1239
- }
1240
- if (val === void 0) {
1241
- view.setUint32(out, predefined.undefined, true);
1242
- view.setUint32(out + 4, NAN_PREFIX, true);
1243
- return;
1244
- }
1245
- if (typeof val === "boolean") {
1246
- view.setUint32(out, val ? predefined.true : predefined.false, true);
1247
- view.setUint32(out + 4, NAN_PREFIX, true);
1248
- return;
1249
- }
1250
- if (typeof val === "bigint") {
1251
- view.setFloat64(out, Number(val), true);
1252
- return;
1253
- }
1254
- let id = this.idPool.pop();
1255
- if (id === void 0) {
1256
- id = this.values.length;
1257
- }
1258
- this.values[id] = val;
1259
- let typeId = 0;
1260
- switch (typeof val) {
1261
- case "object":
1262
- typeId = 1;
1263
- break;
1264
- case "string":
1265
- typeId = 2;
1266
- break;
1267
- case "symbol":
1268
- typeId = 3;
1269
- break;
1270
- case "function":
1271
- typeId = 4;
1272
- break;
1373
+ return { keys };
1374
+ },
1375
+ async list(options2) {
1376
+ return this.listSync(options2);
1273
1377
  }
1274
- view.setUint32(out, Number(id), true);
1275
- view.setUint32(out + 4, NAN_PREFIX | typeId, true);
1276
- }
1277
- loadString(ptr, len) {
1278
- if (this.memory == null) return "";
1279
- const arr = new Uint8ClampedArray(this.memory.buffer, ptr, Number(len));
1280
- const data = arr.slice();
1281
- return decoder2.decode(data);
1282
- }
1283
- };
1284
-
1285
- // src/wasm/core.ts
1286
- var CallbackType = {
1287
- Event: 0,
1288
- FetchSuccess: 1,
1289
- FetchError: 2,
1290
- Timeout: 3,
1291
- Interval: 4,
1292
- WebSocketOpen: 5,
1293
- WebSocketMessage: 6,
1294
- WebSocketError: 7,
1295
- WebSocketClose: 8
1296
- };
1297
- var jsz = new ZigJS();
1298
- var tempRefBuffer = new ArrayBuffer(8);
1299
- var tempRefView = new DataView(tempRefBuffer);
1300
- function storeValueGetRef(val) {
1301
- const originalMemory = jsz.memory;
1302
- jsz.memory = { buffer: tempRefBuffer };
1303
- jsz.storeValue(0, val);
1304
- jsz.memory = originalMemory;
1305
- return tempRefView.getBigUint64(0, true);
1378
+ };
1306
1379
  }
1307
- var textDecoder = new TextDecoder();
1308
- var textEncoder = new TextEncoder();
1309
- var memoryView = null;
1310
- var memoryBuffer = null;
1311
- function getMemoryView() {
1312
- const buf = jsz.memory.buffer;
1313
- if (buf !== memoryBuffer) {
1314
- memoryBuffer = buf;
1315
- memoryView = new Uint8Array(buf);
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");
1316
1385
  }
1317
- return memoryView;
1386
+ return indexedDB;
1318
1387
  }
1319
- var stringCache = /* @__PURE__ */ new Map();
1320
- function stringCacheKey(ptr, len) {
1321
- return ptr * 65536 + len;
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
+ });
1322
1393
  }
1323
- function readString(ptr, len) {
1324
- const key = stringCacheKey(ptr, len);
1325
- const cached = stringCache.get(key);
1326
- if (cached !== void 0) return cached;
1327
- const str = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
1328
- stringCache.set(key, str);
1329
- return str;
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
+ });
1330
1400
  }
1331
- function writeBytes(ptr, data) {
1332
- getMemoryView().set(data, ptr);
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
+ };
1333
1513
  }
1334
- function wrapPromisingExport(fn) {
1335
- if (!fn) return void 0;
1336
- const promising = WebAssembly.promising;
1337
- if (typeof promising !== "function") return fn;
1338
- return promising(fn);
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 };
1339
1541
  }
1340
- function invokeWasmExport(fn, ...args) {
1341
- if (!fn) return;
1342
- const result = fn(...args);
1343
- if (result && typeof result.then === "function") {
1344
- void result.then(void 0, (error) => {
1345
- console.error(error);
1346
- });
1347
- }
1542
+ function buildSysImports(jspi, Suspending) {
1543
+ return {
1544
+ sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {
1545
+ }
1546
+ };
1348
1547
  }
1349
- var ZxBridgeCore = class _ZxBridgeCore {
1350
- #intervals = /* @__PURE__ */ new Map();
1351
- #handler;
1352
- #fetchCompleteHandler;
1353
- constructor(exports) {
1354
- this._alloc = exports.__zx_alloc;
1355
- this.#handler = wrapPromisingExport(exports.__zx_cb);
1356
- const fetchCompleteHandler = wrapPromisingExport(exports.__zx_fetch_complete);
1357
- if (!fetchCompleteHandler) {
1358
- throw new Error("__zx_fetch_complete not exported from WASM");
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;
1359
1554
  }
1360
- this.#fetchCompleteHandler = fetchCompleteHandler;
1361
- if (exports.memory) jsz.memory = exports.memory;
1555
+ return Promise.resolve();
1362
1556
  }
1363
- /** Invoke the unified callback handler */
1364
- #invoke(type, id, data) {
1365
- const handler = this.#handler;
1366
- if (!handler) {
1367
- console.warn("__zx_cb not exported from WASM");
1368
- return;
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);
1369
1566
  }
1370
- const dataRef = storeValueGetRef(data);
1371
- invokeWasmExport(handler, type, id, dataRef);
1372
- }
1373
- /**
1374
- * Async fetch with full options support.
1375
- * Calls __zx_fetch_complete when done.
1376
- */
1377
- fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
1378
- const url = readString(urlPtr, urlLen);
1379
- const method = methodLen > 0 ? readString(methodPtr, methodLen) : "GET";
1380
- const headersJson = headersLen > 0 ? readString(headersPtr, headersLen) : "{}";
1381
- const body = bodyLen > 0 ? getMemoryView().subarray(bodyPtr, bodyPtr + bodyLen) : void 0;
1382
- let headers = {};
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) {
1383
1574
  try {
1384
- headers = JSON.parse(headersJson);
1385
- } catch {
1386
- for (const line of headersJson.split("\n")) {
1387
- const colonIdx = line.indexOf(":");
1388
- if (colonIdx > 0) {
1389
- headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
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);
1390
1581
  }
1391
1582
  }
1583
+ } catch {
1392
1584
  }
1393
- const controller = new AbortController();
1394
- const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
1395
- const fetchOptions = {
1396
- method,
1397
- headers: Object.keys(headers).length > 0 ? headers : void 0,
1398
- body: method !== "GET" && method !== "HEAD" ? body : void 0,
1399
- signal: controller.signal
1400
- };
1401
- fetch(url, fetchOptions).then(async (response) => {
1402
- if (timeout) clearTimeout(timeout);
1403
- const bytes = new Uint8Array(await response.arrayBuffer());
1404
- this._notifyFetchComplete(fetchId, response.status, bytes, false);
1405
- }).catch((error) => {
1406
- if (timeout) clearTimeout(timeout);
1407
- const isAbort = error.name === "AbortError";
1408
- const errorMsg = isAbort ? "Request timeout" : error.message ?? "Fetch failed";
1409
- this._notifyFetchComplete(fetchId, 0, errorMsg, true);
1410
- });
1411
- }
1412
- /** Notify WASM that a fetch completed. `body` is raw bytes on success, text on error. */
1413
- _notifyFetchComplete(fetchId, statusCode, body, isError) {
1414
- const handler = this.#fetchCompleteHandler;
1415
- const encoded = typeof body === "string" ? textEncoder.encode(body) : body;
1416
- const ptr = this._alloc(encoded.length);
1417
- writeBytes(ptr, encoded);
1418
- invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
1419
- }
1420
- /** Set a timeout and callback when it fires */
1421
- setTimeout(callbackId, delayMs) {
1422
- setTimeout(() => {
1423
- this.#invoke(CallbackType.Timeout, callbackId, null);
1424
- }, delayMs);
1425
- }
1426
- /** Set an interval and callback each time it fires */
1427
- setInterval(callbackId, intervalMs) {
1428
- const handle = setInterval(() => {
1429
- this.#invoke(CallbackType.Interval, callbackId, null);
1430
- }, intervalMs);
1431
- this.#intervals.set(callbackId, handle);
1432
- }
1433
- /** Clear an interval */
1434
- clearInterval(callbackId) {
1435
- const handle = this.#intervals.get(callbackId);
1436
- if (handle !== void 0) {
1437
- clearInterval(handle);
1438
- this.#intervals.delete(callbackId);
1439
- }
1440
- }
1441
- dispose() {
1442
- for (const handle of this.#intervals.values()) {
1443
- clearInterval(handle);
1444
- }
1445
- this.#intervals.clear();
1446
- }
1447
- /** Write a string to WASM memory, returning pointer and length */
1448
- _writeStringToWasm(str) {
1449
- return this._writeBytesToWasm(textEncoder.encode(str));
1450
1585
  }
1451
- _writeBytesToWasm(data) {
1452
- const ptr = this._alloc(data.length);
1453
- writeBytes(ptr, data);
1454
- return { ptr, len: data.length };
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);
1455
1602
  }
1456
- /** Log a message from WASM at the given level (0=error, 1=warn, 2=info, 3=debug) */
1457
- static log(level, ptr, len) {
1458
- const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
1459
- switch (level) {
1460
- case 0:
1461
- console.error(msg);
1462
- break;
1463
- case 1:
1464
- console.warn(msg);
1465
- break;
1466
- case 3:
1467
- console.debug(msg);
1468
- break;
1469
- default:
1470
- console.log(msg);
1471
- break;
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);
1472
1612
  }
1473
- }
1474
- /**
1475
- * Create the core import object for WASM instantiation.
1476
- * Includes only environment-agnostic bindings: log, fetch, and timers.
1477
- * Use ZxBridge.createImportObject (from wasm/index.ts) in browser contexts
1478
- * to additionally include DOM and WebSocket bindings.
1479
- */
1480
- static createImportObject(bridgeRef) {
1481
- return {
1482
- ...jsz.importObject(),
1483
- __zx_net: createFetchImports(() => {
1484
- if (!jsz.memory) throw new Error("WASM memory is not ready");
1485
- return jsz.memory;
1486
- }),
1487
- __zx: {
1488
- _log: (level, ptr, len) => _ZxBridgeCore.log(level, ptr, len),
1489
- _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
1490
- bridgeRef.current?.fetchAsync(
1491
- urlPtr,
1492
- urlLen,
1493
- methodPtr,
1494
- methodLen,
1495
- headersPtr,
1496
- headersLen,
1497
- bodyPtr,
1498
- bodyLen,
1499
- timeoutMs,
1500
- fetchId
1501
- );
1502
- },
1503
- _setTimeout: (callbackId, delayMs) => {
1504
- bridgeRef.current?.setTimeout(callbackId, delayMs);
1505
- },
1506
- _setInterval: (callbackId, intervalMs) => {
1507
- bridgeRef.current?.setInterval(callbackId, intervalMs);
1508
- },
1509
- _clearInterval: (callbackId) => {
1510
- bridgeRef.current?.clearInterval(callbackId);
1511
- }
1512
- }
1513
- };
1514
- }
1515
- };
1516
-
1517
- // src/wasm/index.ts
1518
- var ZxBridge = class extends ZxBridgeCore {
1519
- #websockets = /* @__PURE__ */ new Map();
1520
- #wsOnOpenHandler;
1521
- #wsOnMessageHandler;
1522
- #wsOnErrorHandler;
1523
- #wsOnCloseHandler;
1524
- #eventbridge;
1525
- #eventbridgeAsync;
1526
- constructor(exports) {
1527
- super(exports);
1528
- this.#wsOnOpenHandler = wrapPromisingExport(exports.__zx_ws_onopen);
1529
- this.#wsOnMessageHandler = wrapPromisingExport(exports.__zx_ws_onmessage);
1530
- this.#wsOnErrorHandler = wrapPromisingExport(exports.__zx_ws_onerror);
1531
- this.#wsOnCloseHandler = wrapPromisingExport(exports.__zx_ws_onclose);
1532
- this.#eventbridge = exports.__zx_eventbridge;
1533
- this.#eventbridgeAsync = wrapPromisingExport(
1534
- exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
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
1535
1640
  );
1536
1641
  }
1537
- eventMaySuspend(velementId, eventTypeId) {
1538
- return !!((eventHandlerModes.get(velementId) ?? 0) & 1 << eventTypeId);
1642
+ if (true) {
1643
+ importObject.__zx_db = createDbImports(
1644
+ dbBindings ?? {},
1645
+ mem,
1646
+ allocRef
1647
+ );
1539
1648
  }
1540
- setEventHandlerMode(velementId, eventTypeId, maySuspend) {
1541
- const bit = 1 << eventTypeId;
1542
- const current = eventHandlerModes.get(velementId) ?? 0;
1543
- const next = maySuspend ? current | bit : current & ~bit;
1544
- if (next === 0) eventHandlerModes.delete(velementId);
1545
- else eventHandlerModes.set(velementId, next);
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 });
1546
1659
  }
1547
- clearEventHandlerModes(velementId) {
1548
- eventHandlerModes.delete(velementId);
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 });
1549
1669
  }
1550
- /** Submit a form action with bound-state round-trip. */
1551
- submitFormActionAsync(form, actionId, statesJson, fetchId) {
1552
- const formData = new FormData(form);
1553
- formData.append("__$states", statesJson);
1554
- fetch(window.location.href, {
1555
- method: "POST",
1556
- // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
1557
- headers: { "x-action": String(actionId >>> 0) },
1558
- body: formData
1559
- }).then(async (response) => {
1560
- const text = await response.text();
1561
- this._notifyFetchComplete(fetchId, response.status, text, false);
1562
- }).catch((error) => {
1563
- const msg = error instanceof Error ? error.message : "Fetch failed";
1564
- this._notifyFetchComplete(fetchId, 0, msg, true);
1565
- });
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 });
1566
1679
  }
1567
- /**
1568
- * Create and connect a WebSocket.
1569
- * Calls __zx_ws_onopen, __zx_ws_onmessage, __zx_ws_onerror, __zx_ws_onclose.
1570
- */
1571
- wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
1572
- const url = readString(urlPtr, urlLen);
1573
- const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
1574
- const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
1575
- try {
1576
- const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
1577
- ws.binaryType = "arraybuffer";
1578
- ws.onopen = () => {
1579
- const handler = this.#wsOnOpenHandler;
1580
- if (!handler) return;
1581
- const protocol = ws.protocol || "";
1582
- const { ptr, len } = this._writeStringToWasm(protocol);
1583
- invokeWasmExport(handler, wsId, ptr, len);
1584
- };
1585
- ws.onmessage = (event) => {
1586
- const handler = this.#wsOnMessageHandler;
1587
- if (!handler) return;
1588
- const isBinary = event.data instanceof ArrayBuffer;
1589
- const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
1590
- const { ptr, len } = this._writeBytesToWasm(data);
1591
- invokeWasmExport(handler, wsId, ptr, len, isBinary ? 1 : 0);
1592
- };
1593
- ws.onerror = (_event) => {
1594
- const handler = this.#wsOnErrorHandler;
1595
- if (!handler) return;
1596
- const { ptr, len } = this._writeStringToWasm("WebSocket error");
1597
- invokeWasmExport(handler, wsId, ptr, len);
1598
- };
1599
- ws.onclose = (event) => {
1600
- const handler = this.#wsOnCloseHandler;
1601
- if (!handler) return;
1602
- const reason = event.reason || "";
1603
- const { ptr, len } = this._writeStringToWasm(reason);
1604
- invokeWasmExport(handler, wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
1605
- this.#websockets.delete(wsId);
1606
- };
1607
- this.#websockets.set(wsId, ws);
1608
- } catch (error) {
1609
- const handler = this.#wsOnErrorHandler;
1610
- if (handler) {
1611
- const msg = error instanceof Error ? error.message : "WebSocket connection failed";
1612
- const { ptr, len } = this._writeStringToWasm(msg);
1613
- invokeWasmExport(handler, wsId, ptr, len);
1614
- }
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));
1615
1689
  }
1690
+ const url = input.startsWith("/") ? `file://${input}` : input;
1691
+ return WebAssembly.compile(await fetch(url).then((r) => r.arrayBuffer()));
1616
1692
  }
1617
- /** Send data over WebSocket */
1618
- wsSend(wsId, dataPtr, dataLen, isBinary) {
1619
- const ws = this.#websockets.get(wsId);
1620
- if (!ws || ws.readyState !== WebSocket.OPEN) return;
1621
- const memory = getMemoryView();
1622
- if (isBinary) {
1623
- ws.send(memory.slice(dataPtr, dataPtr + dataLen));
1624
- } else {
1625
- ws.send(textDecoder.decode(memory.subarray(dataPtr, dataPtr + dataLen)));
1626
- }
1693
+ if (input instanceof URL) {
1694
+ return WebAssembly.compileStreaming(fetch(input));
1627
1695
  }
1628
- /** Close WebSocket connection */
1629
- wsClose(wsId, code, reasonPtr, reasonLen) {
1630
- const ws = this.#websockets.get(wsId);
1631
- if (!ws) return;
1632
- const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : void 0;
1633
- try {
1634
- if (reason) ws.close(code, reason);
1635
- else ws.close(code);
1636
- } catch {
1637
- ws.close();
1638
- }
1696
+ if (input instanceof Response) {
1697
+ return WebAssembly.compileStreaming(input);
1639
1698
  }
1640
- dispose() {
1641
- super.dispose();
1642
- eventHandlerModes.clear();
1643
- for (const ws of this.#websockets.values()) {
1644
- try {
1645
- ws.close();
1646
- } catch {
1647
- }
1648
- }
1649
- this.#websockets.clear();
1699
+ if (input instanceof ArrayBuffer) {
1700
+ return WebAssembly.compile(input);
1650
1701
  }
1651
- /** Handle a DOM event (called by event delegation) */
1652
- eventbridge(velementId, eventTypeId, event) {
1653
- const eventRef = storeValueGetRef(event);
1654
- if (this.eventMaySuspend(velementId, eventTypeId)) {
1655
- invokeWasmExport(this.#eventbridgeAsync, velementId, eventTypeId, eventRef);
1656
- return;
1657
- }
1658
- invokeWasmExport(this.#eventbridge, velementId, eventTypeId, eventRef);
1702
+ if (ArrayBuffer.isView(input)) {
1703
+ return WebAssembly.compile(input.buffer);
1659
1704
  }
1660
- /** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
1661
- static createImportObject(bridgeRef) {
1662
- return {
1663
- ...jsz.importObject(),
1664
- __zx_net: createFetchImports(() => {
1665
- if (!jsz.memory) throw new Error("WASM memory is not ready");
1666
- return jsz.memory;
1667
- }),
1668
- __zx: {
1669
- _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
1670
- _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
1671
- bridgeRef.current?.setEventHandlerMode(vnodeId, eventTypeId, maySuspend !== 0);
1672
- },
1673
- _clearEventHandlerModes: (vnodeId) => {
1674
- bridgeRef.current?.clearEventHandlerModes(vnodeId);
1675
- },
1676
- _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
1677
- bridgeRef.current?.fetchAsync(
1678
- urlPtr,
1679
- urlLen,
1680
- methodPtr,
1681
- methodLen,
1682
- headersPtr,
1683
- headersLen,
1684
- bodyPtr,
1685
- bodyLen,
1686
- timeoutMs,
1687
- fetchId
1688
- );
1689
- },
1690
- _setTimeout: (callbackId, delayMs) => {
1691
- bridgeRef.current?.setTimeout(callbackId, delayMs);
1692
- },
1693
- _setInterval: (callbackId, intervalMs) => {
1694
- bridgeRef.current?.setInterval(callbackId, intervalMs);
1695
- },
1696
- _clearInterval: (callbackId) => {
1697
- bridgeRef.current?.clearInterval(callbackId);
1698
- },
1699
- // WebSocket API
1700
- _wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
1701
- bridgeRef.current?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
1702
- },
1703
- _wsSend: (wsId, dataPtr, dataLen, isBinary) => {
1704
- bridgeRef.current?.wsSend(wsId, dataPtr, dataLen, isBinary);
1705
- },
1706
- _wsClose: (wsId, code, reasonPtr, reasonLen) => {
1707
- bridgeRef.current?.wsClose(wsId, code, reasonPtr, reasonLen);
1708
- },
1709
- _ce: (id, vnodeId) => {
1710
- const tagName = TAG_NAMES[id];
1711
- const el = id >= SVG_TAG_START_INDEX ? document.createElementNS("http://www.w3.org/2000/svg", tagName) : document.createElement(tagName);
1712
- el.__zx_ref = Number(vnodeId);
1713
- domNodes.set(vnodeId, el);
1714
- return storeValueGetRef(el);
1715
- },
1716
- _ct: (ptr, len, vnodeId) => {
1717
- const text = readString(ptr, len);
1718
- const node = document.createTextNode(text);
1719
- node.__zx_ref = Number(vnodeId);
1720
- domNodes.set(vnodeId, node);
1721
- return storeValueGetRef(node);
1722
- },
1723
- _sa: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
1724
- domNodes.get(vnodeId)?.setAttribute(readString(namePtr, nameLen), readString(valPtr, valLen));
1725
- },
1726
- _sp: (vnodeId, namePtr, nameLen, valPtr, valLen) => {
1727
- const el = domNodes.get(vnodeId);
1728
- if (el) {
1729
- const name = readString(namePtr, nameLen);
1730
- const val = readString(valPtr, valLen);
1731
- if (name === "checked" || name === "selected" || name === "muted") {
1732
- el[name] = val !== "false";
1733
- } else {
1734
- el[name] = val;
1735
- }
1736
- }
1737
- },
1738
- _ra: (vnodeId, namePtr, nameLen) => {
1739
- domNodes.get(vnodeId)?.removeAttribute(readString(namePtr, nameLen));
1740
- },
1741
- _snv: (vnodeId, ptr, len) => {
1742
- const node = domNodes.get(vnodeId);
1743
- if (node) node.nodeValue = readString(ptr, len);
1744
- },
1745
- _srh: (vnodeId, ptr, len) => {
1746
- const el = domNodes.get(vnodeId);
1747
- if (el) el.innerHTML = readString(ptr, len);
1748
- },
1749
- _ac: (parentId, childId) => {
1750
- const parent = domNodes.get(parentId);
1751
- const child = domNodes.get(childId);
1752
- if (parent && child) parent.appendChild(child);
1753
- },
1754
- _ib: (parentId, childId, refId) => {
1755
- const parent = domNodes.get(parentId);
1756
- const child = domNodes.get(childId);
1757
- const ref = domNodes.get(refId) ?? null;
1758
- if (parent && child) parent.insertBefore(child, ref);
1759
- },
1760
- _rc: (parentId, childId) => {
1761
- const parent = domNodes.get(parentId);
1762
- const child = domNodes.get(childId);
1763
- if (parent && child) {
1764
- parent.removeChild(child);
1765
- cleanupDomNodes(child);
1766
- }
1767
- },
1768
- _rpc: (parentId, newId, oldId) => {
1769
- const parent = domNodes.get(parentId);
1770
- const newChild = domNodes.get(newId);
1771
- const oldChild = domNodes.get(oldId);
1772
- if (parent && newChild && oldChild) {
1773
- parent.replaceChild(newChild, oldChild);
1774
- cleanupDomNodes(oldChild);
1775
- }
1776
- },
1777
- _getLocationHref: (bufPtr, bufLen) => {
1778
- const bytes = textEncoder.encode(window.location.href);
1779
- const len = Math.min(bytes.length, bufLen);
1780
- writeBytes(bufPtr, bytes.subarray(0, len));
1781
- return len;
1782
- },
1783
- _getFormData: (vnodeId, bufPtr, bufLen) => {
1784
- const form = domNodes.get(vnodeId);
1785
- if (!form || !(form instanceof HTMLFormElement)) return 0;
1786
- const formData = new FormData(form);
1787
- const urlEncoded = new URLSearchParams(formData).toString();
1788
- const bytes = textEncoder.encode(urlEncoded);
1789
- const len = Math.min(bytes.length, bufLen);
1790
- writeBytes(bufPtr, bytes.subarray(0, len));
1791
- return len;
1792
- },
1793
- _submitFormAction: (vnodeId, actionId) => {
1794
- const form = domNodes.get(vnodeId);
1795
- if (!form || !(form instanceof HTMLFormElement)) return;
1796
- const formData = new FormData(form);
1797
- fetch(window.location.href, {
1798
- method: "POST",
1799
- // `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
1800
- headers: { "x-action": String(actionId >>> 0) },
1801
- body: formData
1802
- }).catch(() => {
1803
- });
1804
- },
1805
- _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
1806
- const form = domNodes.get(vnodeId);
1807
- if (!form || !(form instanceof HTMLFormElement)) return;
1808
- const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
1809
- bridgeRef.current?.submitFormActionAsync(form, actionId, statesJson, fetchId);
1810
- }
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];
1811
1744
  }
1812
- };
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] };
1813
1760
  }
1814
1761
  };
1815
- var domNodes = /* @__PURE__ */ new Map();
1816
- function cleanupDomNodes(node) {
1817
- const ref = node.__zx_ref;
1818
- if (ref !== void 0) domNodes.delete(BigInt(ref));
1819
- const children = node.childNodes;
1820
- for (let i = 0; i < children.length; i++) cleanupDomNodes(children[i]);
1821
- }
1822
- var SVG_TAG_START_INDEX = 140;
1762
+
1763
+ // src/wasm/generated/tags.ts
1823
1764
  var TAG_NAMES = [
1824
1765
  "aside",
1825
1766
  "fragment",
@@ -1961,7 +1902,6 @@ var TAG_NAMES = [
1961
1902
  "strike",
1962
1903
  "tt",
1963
1904
  "xmp",
1964
- // SVG Tags
1965
1905
  "animate",
1966
1906
  "animateMotion",
1967
1907
  "animateTransform",
@@ -2020,11 +1960,483 @@ var TAG_NAMES = [
2020
1960
  "textPath",
2021
1961
  "tspan",
2022
1962
  "use",
2023
- "view"
1963
+ "view",
1964
+ "custom"
1965
+ ];
1966
+
1967
+ // src/wasm/generated/tag_indices.ts
1968
+ var SVG_TAG_START_INDEX = 140;
1969
+ var CUSTOM_TAG_INDEX = 199;
1970
+
1971
+ // src/wasm/dom_cmd.ts
1972
+ function flushDomCmds(ptr, len, ctx) {
1973
+ const start = ptr >>> 0;
1974
+ const length = len >>> 0;
1975
+ if (length < DOM_CMD_HEADER_SIZE) return;
1976
+ const mem = getMemoryView();
1977
+ if (start + length > mem.byteLength) return;
1978
+ const view = new DataView(mem.buffer, mem.byteOffset + start, length);
1979
+ const count = view.getUint32(0, true);
1980
+ const recordsBytes = count * DOM_CMD_RECORD_SIZE;
1981
+ if (DOM_CMD_HEADER_SIZE + recordsBytes > length) return;
1982
+ const { domNodes: domNodes2, cleanupDomNodes: cleanupDomNodes2 } = ctx;
1983
+ for (let i = 0; i < count; i++) {
1984
+ const off = DOM_CMD_HEADER_SIZE + i * DOM_CMD_RECORD_SIZE;
1985
+ const op = view.getUint8(off);
1986
+ const p0 = view.getUint32(off + 4, true);
1987
+ const p1 = view.getUint32(off + 8, true);
1988
+ const p2 = view.getUint32(off + 12, true);
1989
+ const p3 = view.getUint32(off + 16, true);
1990
+ const p4 = view.getUint32(off + 20, true);
1991
+ switch (op) {
1992
+ case DomOp_CreateElement: {
1993
+ const isCustom = p0 === CUSTOM_TAG_INDEX;
1994
+ const tagName = isCustom ? readString(p2, p3) : TAG_NAMES[p0];
1995
+ const el = !isCustom && p0 >= SVG_TAG_START_INDEX ? document.createElementNS("http://www.w3.org/2000/svg", tagName) : document.createElement(tagName);
1996
+ el.__zx_ref = p1;
1997
+ domNodes2.set(p1, el);
1998
+ break;
1999
+ }
2000
+ case DomOp_CreateText: {
2001
+ const node = document.createTextNode(readString(p0, p1));
2002
+ node.__zx_ref = p2;
2003
+ domNodes2.set(p2, node);
2004
+ break;
2005
+ }
2006
+ case DomOp_HydrateInsert: {
2007
+ const child = domNodes2.get(p0);
2008
+ const ref = BigInt(p1) | BigInt(p2) << 32n;
2009
+ const end = loadValueFromRef(ref);
2010
+ if (!child || !end?.parentNode) break;
2011
+ end.parentNode.insertBefore(child, end);
2012
+ break;
2013
+ }
2014
+ case DomOp_SetAttr: {
2015
+ domNodes2.get(p0)?.setAttribute(readString(p1, p2), readString(p3, p4));
2016
+ break;
2017
+ }
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
+ }
2028
+ }
2029
+ break;
2030
+ }
2031
+ case DomOp_RemoveAttr: {
2032
+ domNodes2.get(p0)?.removeAttribute(readString(p1, p2));
2033
+ break;
2034
+ }
2035
+ case DomOp_SetNodeValue: {
2036
+ const node = domNodes2.get(p0);
2037
+ if (node) node.nodeValue = readString(p1, p2);
2038
+ break;
2039
+ }
2040
+ case DomOp_SetInnerHtml: {
2041
+ const el = domNodes2.get(p0);
2042
+ if (el) el.innerHTML = readString(p1, p2);
2043
+ break;
2044
+ }
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;
2050
+ }
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;
2057
+ }
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;
2066
+ }
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);
2074
+ }
2075
+ break;
2076
+ }
2077
+ default:
2078
+ break;
2079
+ }
2080
+ }
2081
+ }
2082
+
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"
2024
2112
  ];
2025
- var eventHandlerModes = /* @__PURE__ */ new Map();
2026
2113
 
2027
- // src/cloudflare/do.ts
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;
2122
+ 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
+ });
2169
+ }
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));
2208
+ }
2209
+ }
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)));
2222
+ }
2223
+ }
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;
2229
+ try {
2230
+ if (reason) ws.close(code, reason);
2231
+ else ws.close(code);
2232
+ } catch {
2233
+ ws.close();
2234
+ }
2235
+ }
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
+ }
2245
+ }
2246
+ this.#websockets.clear();
2247
+ }
2248
+ /**
2249
+ * Dispatch to WASM for one vnode. Caller owns `eventRef` lifetime
2250
+ * (store once per bubble, release after sync/async work completes).
2251
+ */
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
+ static createImportObject(bridgeRef) {
2261
+ 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
+ __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));
2274
+ },
2275
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
2276
+ bridgeRef[0]?.fetchAsync(
2277
+ urlPtr,
2278
+ urlLen,
2279
+ methodPtr,
2280
+ methodLen,
2281
+ headersPtr,
2282
+ headersLen,
2283
+ bodyPtr,
2284
+ bodyLen,
2285
+ timeoutMs,
2286
+ fetchId
2287
+ );
2288
+ },
2289
+ _setTimeout: (callbackId, delayMs) => {
2290
+ bridgeRef[0]?.setTimeout(callbackId, delayMs);
2291
+ },
2292
+ _setInterval: (callbackId, intervalMs) => {
2293
+ bridgeRef[0]?.setInterval(callbackId, intervalMs);
2294
+ },
2295
+ _clearInterval: (callbackId) => {
2296
+ 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
+ }
2352
+ }
2353
+ };
2354
+ }
2355
+ };
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);
2371
+ }
2372
+ domNodes.delete(ref);
2373
+ }
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
+ }
2380
+ }
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
+ }
2406
+ }
2407
+ };
2408
+ }
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;
2424
+ }
2425
+ return false;
2426
+ }
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);
2437
+ }
2438
+
2439
+ // src/platforms/cloudflare/do.ts
2028
2440
  function createWebSocketDO(module, options) {
2029
2441
  return class ZxWebSocketDO {
2030
2442
  constructor(state, env) {
@@ -2038,7 +2450,7 @@ function createWebSocketDO(module, options) {
2038
2450
  const { wasiImport, setMemory } = createWasiImports({ request, stdinData });
2039
2451
  let wasmMemory = null;
2040
2452
  const mem = () => wasmMemory;
2041
- const bridgeRef = { current: null };
2453
+ const bridgeRef = [null];
2042
2454
  const bridgeImports = ZxBridge.createImportObject(bridgeRef);
2043
2455
  const Suspending = WebAssembly.Suspending;
2044
2456
  const jspi = typeof Suspending === "function";
@@ -2084,19 +2496,34 @@ function createWebSocketDO(module, options) {
2084
2496
  const wsImports = buildWsImports(jspi ? Suspending : null, mem, decoder3, connState);
2085
2497
  const kvBindings = options?.kv?.(this.env);
2086
2498
  const dbBindings = options?.db?.(this.env);
2087
- const instance = new WebAssembly.Instance(module, {
2499
+ const allocRef = [null];
2500
+ const importObject = {
2088
2501
  wasi_snapshot_preview1: wasiImport,
2089
2502
  __zx_sys: sysImports,
2090
2503
  __zx_ws: wsImports,
2091
- __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
2092
- __zx_db: createD1Imports(dbBindings ?? {}, mem),
2093
2504
  __zx_net: createFetchImports(mem),
2094
2505
  ...options?.imports ? options.imports(mem) : {},
2095
2506
  ...bridgeImports
2096
- });
2507
+ };
2508
+ if (true) {
2509
+ importObject.__zx_kv = createKVImports(
2510
+ kvBindings ?? { default: createMemoryKV() },
2511
+ mem,
2512
+ allocRef
2513
+ );
2514
+ }
2515
+ if (true) {
2516
+ importObject.__zx_db = createDbImports(
2517
+ dbBindings ?? {},
2518
+ mem,
2519
+ allocRef
2520
+ );
2521
+ }
2522
+ const instance = new WebAssembly.Instance(module, importObject);
2097
2523
  wasmMemory = instance.exports.memory;
2098
2524
  setMemory(wasmMemory);
2099
- bridgeRef.current = new ZxBridge(instance.exports);
2525
+ bridgeRef[0] = new ZxBridge(instance.exports);
2526
+ bindWasmAlloc(allocRef, instance.exports);
2100
2527
  const start = WebAssembly.promising(instance.exports._start);
2101
2528
  const wasmPromise = start().catch((e) => {
2102
2529
  wasmExited = true;