ziex 0.1.0-dev.787 → 0.1.0-dev.804

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -178,7 +178,7 @@ class ZigJS {
178
178
  return decoder.decode(data);
179
179
  }
180
180
  }
181
- // src/wasm/index.ts
181
+ // src/wasm/core.ts
182
182
  var CallbackType = {
183
183
  Event: 0,
184
184
  FetchSuccess: 1,
@@ -229,25 +229,17 @@ function writeBytes(ptr, data) {
229
229
  getMemoryView().set(data, ptr);
230
230
  }
231
231
 
232
- class ZxBridge {
232
+ class ZxBridgeCore {
233
233
  #intervals = new Map;
234
- #websockets = new Map;
235
- #alloc;
234
+ _alloc;
236
235
  #handler;
237
236
  #fetchCompleteHandler;
238
- #wsOnOpenHandler;
239
- #wsOnMessageHandler;
240
- #wsOnErrorHandler;
241
- #wsOnCloseHandler;
242
237
  constructor(exports) {
243
- this.#alloc = exports.__zx_alloc;
238
+ this._alloc = exports.__zx_alloc;
244
239
  this.#handler = exports.__zx_cb;
245
240
  this.#fetchCompleteHandler = exports.__zx_fetch_complete;
246
- this.#wsOnOpenHandler = exports.__zx_ws_onopen;
247
- this.#wsOnMessageHandler = exports.__zx_ws_onmessage;
248
- this.#wsOnErrorHandler = exports.__zx_ws_onerror;
249
- this.#wsOnCloseHandler = exports.__zx_ws_onclose;
250
- this.#eventbridge = exports.__zx_eventbridge;
241
+ if (exports.memory)
242
+ jsz.memory = exports.memory;
251
243
  }
252
244
  #invoke(type, id, data) {
253
245
  const handler = this.#handler;
@@ -287,37 +279,22 @@ class ZxBridge {
287
279
  if (timeout)
288
280
  clearTimeout(timeout);
289
281
  const text = await response.text();
290
- this.#notifyFetchComplete(fetchId, response.status, text, false);
282
+ this._notifyFetchComplete(fetchId, response.status, text, false);
291
283
  }).catch((error) => {
292
284
  if (timeout)
293
285
  clearTimeout(timeout);
294
286
  const isAbort = error.name === "AbortError";
295
287
  const errorMsg = isAbort ? "Request timeout" : error.message ?? "Fetch failed";
296
- this.#notifyFetchComplete(fetchId, 0, errorMsg, true);
288
+ this._notifyFetchComplete(fetchId, 0, errorMsg, true);
297
289
  });
298
290
  }
299
- #notifyFetchComplete(fetchId, statusCode, body, isError) {
291
+ _notifyFetchComplete(fetchId, statusCode, body, isError) {
300
292
  const handler = this.#fetchCompleteHandler;
301
293
  const encoded = textEncoder.encode(body);
302
- const ptr = this.#alloc(encoded.length);
294
+ const ptr = this._alloc(encoded.length);
303
295
  writeBytes(ptr, encoded);
304
296
  handler(fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
305
297
  }
306
- submitFormActionAsync(form, statesJson, fetchId) {
307
- const formData = new FormData(form);
308
- formData.append("__zx_states", statesJson);
309
- fetch(window.location.href, {
310
- method: "POST",
311
- headers: { "X-ZX-Action": "1" },
312
- body: formData
313
- }).then(async (response) => {
314
- const text = await response.text();
315
- this.#notifyFetchComplete(fetchId, response.status, text, false);
316
- }).catch((error) => {
317
- const msg = error instanceof Error ? error.message : "Fetch failed";
318
- this.#notifyFetchComplete(fetchId, 0, msg, true);
319
- });
320
- }
321
298
  setTimeout(callbackId, delayMs) {
322
299
  setTimeout(() => {
323
300
  this.#invoke(CallbackType.Timeout, callbackId, null);
@@ -336,6 +313,83 @@ class ZxBridge {
336
313
  this.#intervals.delete(callbackId);
337
314
  }
338
315
  }
316
+ _writeStringToWasm(str) {
317
+ return this._writeBytesToWasm(textEncoder.encode(str));
318
+ }
319
+ _writeBytesToWasm(data) {
320
+ const ptr = this._alloc(data.length);
321
+ writeBytes(ptr, data);
322
+ return { ptr, len: data.length };
323
+ }
324
+ static log(level, ptr, len) {
325
+ const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
326
+ switch (level) {
327
+ case 0:
328
+ console.error(msg);
329
+ break;
330
+ case 1:
331
+ console.warn(msg);
332
+ break;
333
+ case 3:
334
+ console.debug(msg);
335
+ break;
336
+ default:
337
+ console.log(msg);
338
+ break;
339
+ }
340
+ }
341
+ static createImportObject(bridgeRef) {
342
+ return {
343
+ ...jsz.importObject(),
344
+ __zx: {
345
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
346
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
347
+ bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
348
+ },
349
+ _setTimeout: (callbackId, delayMs) => {
350
+ bridgeRef.current?.setTimeout(callbackId, delayMs);
351
+ },
352
+ _setInterval: (callbackId, intervalMs) => {
353
+ bridgeRef.current?.setInterval(callbackId, intervalMs);
354
+ },
355
+ _clearInterval: (callbackId) => {
356
+ bridgeRef.current?.clearInterval(callbackId);
357
+ }
358
+ }
359
+ };
360
+ }
361
+ }
362
+ // src/wasm/index.ts
363
+ class ZxBridge extends ZxBridgeCore {
364
+ #websockets = new Map;
365
+ #wsOnOpenHandler;
366
+ #wsOnMessageHandler;
367
+ #wsOnErrorHandler;
368
+ #wsOnCloseHandler;
369
+ #eventbridge;
370
+ constructor(exports) {
371
+ super(exports);
372
+ this.#wsOnOpenHandler = exports.__zx_ws_onopen;
373
+ this.#wsOnMessageHandler = exports.__zx_ws_onmessage;
374
+ this.#wsOnErrorHandler = exports.__zx_ws_onerror;
375
+ this.#wsOnCloseHandler = exports.__zx_ws_onclose;
376
+ this.#eventbridge = exports.__zx_eventbridge;
377
+ }
378
+ submitFormActionAsync(form, statesJson, fetchId) {
379
+ const formData = new FormData(form);
380
+ formData.append("__zx_states", statesJson);
381
+ fetch(window.location.href, {
382
+ method: "POST",
383
+ headers: { "X-ZX-Action": "1" },
384
+ body: formData
385
+ }).then(async (response) => {
386
+ const text = await response.text();
387
+ this._notifyFetchComplete(fetchId, response.status, text, false);
388
+ }).catch((error) => {
389
+ const msg = error instanceof Error ? error.message : "Fetch failed";
390
+ this._notifyFetchComplete(fetchId, 0, msg, true);
391
+ });
392
+ }
339
393
  wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
340
394
  const url = readString(urlPtr, urlLen);
341
395
  const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
@@ -348,7 +402,7 @@ class ZxBridge {
348
402
  if (!handler)
349
403
  return;
350
404
  const protocol = ws.protocol || "";
351
- const { ptr, len } = this.#writeStringToWasm(protocol);
405
+ const { ptr, len } = this._writeStringToWasm(protocol);
352
406
  handler(wsId, ptr, len);
353
407
  };
354
408
  ws.onmessage = (event) => {
@@ -356,21 +410,15 @@ class ZxBridge {
356
410
  if (!handler)
357
411
  return;
358
412
  const isBinary = event.data instanceof ArrayBuffer;
359
- let data;
360
- if (isBinary) {
361
- data = new Uint8Array(event.data);
362
- } else {
363
- data = textEncoder.encode(event.data);
364
- }
365
- const { ptr, len } = this.#writeBytesToWasm(data);
413
+ const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
414
+ const { ptr, len } = this._writeBytesToWasm(data);
366
415
  handler(wsId, ptr, len, isBinary ? 1 : 0);
367
416
  };
368
- ws.onerror = (event) => {
417
+ ws.onerror = (_event) => {
369
418
  const handler = this.#wsOnErrorHandler;
370
419
  if (!handler)
371
420
  return;
372
- const msg = "WebSocket error";
373
- const { ptr, len } = this.#writeStringToWasm(msg);
421
+ const { ptr, len } = this._writeStringToWasm("WebSocket error");
374
422
  handler(wsId, ptr, len);
375
423
  };
376
424
  ws.onclose = (event) => {
@@ -378,7 +426,7 @@ class ZxBridge {
378
426
  if (!handler)
379
427
  return;
380
428
  const reason = event.reason || "";
381
- const { ptr, len } = this.#writeStringToWasm(reason);
429
+ const { ptr, len } = this._writeStringToWasm(reason);
382
430
  handler(wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
383
431
  this.#websockets.delete(wsId);
384
432
  };
@@ -387,7 +435,7 @@ class ZxBridge {
387
435
  const handler = this.#wsOnErrorHandler;
388
436
  if (handler) {
389
437
  const msg = error instanceof Error ? error.message : "WebSocket connection failed";
390
- const { ptr, len } = this.#writeStringToWasm(msg);
438
+ const { ptr, len } = this._writeStringToWasm(msg);
391
439
  handler(wsId, ptr, len);
392
440
  }
393
441
  }
@@ -409,25 +457,14 @@ class ZxBridge {
409
457
  return;
410
458
  const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : undefined;
411
459
  try {
412
- if (reason) {
460
+ if (reason)
413
461
  ws.close(code, reason);
414
- } else {
462
+ else
415
463
  ws.close(code);
416
- }
417
464
  } catch {
418
465
  ws.close();
419
466
  }
420
467
  }
421
- #writeStringToWasm(str) {
422
- const encoded = textEncoder.encode(str);
423
- return this.#writeBytesToWasm(encoded);
424
- }
425
- #writeBytesToWasm(data) {
426
- const ptr = this.#alloc(data.length);
427
- writeBytes(ptr, data);
428
- return { ptr, len: data.length };
429
- }
430
- #eventbridge;
431
468
  eventbridge(velementId, eventTypeId, event) {
432
469
  if (!this.#eventbridge)
433
470
  return;
@@ -438,6 +475,7 @@ class ZxBridge {
438
475
  return {
439
476
  ...jsz.importObject(),
440
477
  __zx: {
478
+ _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
441
479
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
442
480
  bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
443
481
  },
@@ -842,16 +880,141 @@ async function init(options = {}) {
842
880
  return { source, bridge };
843
881
  }
844
882
 
845
- // src/cloudflare/worker.ts
846
- var exports_worker = {};
847
- __export(exports_worker, {
883
+ // src/runtime.ts
884
+ var exports_runtime = {};
885
+ __export(exports_runtime, {
848
886
  run: () => run,
849
- respond: () => respond,
850
- prepare: () => prepare,
851
- createWebSocketDO: () => createWebSocketDO
887
+ buildWsImports: () => buildWsImports,
888
+ attachWebSocket: () => attachWebSocket
852
889
  });
853
890
 
854
- // src/cloudflare/kv.ts
891
+ // src/wasm/wasi.ts
892
+ var decoder2 = new TextDecoder;
893
+ var encoder2 = new TextEncoder;
894
+
895
+ class ZxWasiBridge {
896
+ #alloc;
897
+ #fetchCompleteHandler;
898
+ #memory;
899
+ #cb;
900
+ #intervals = new Map;
901
+ #memView = null;
902
+ #memBuf = null;
903
+ constructor(exports) {
904
+ this.#memory = exports.memory;
905
+ this.#alloc = exports.__zx_alloc;
906
+ this.#fetchCompleteHandler = exports.__zx_fetch_complete;
907
+ this.#cb = exports.__zx_cb;
908
+ }
909
+ #view() {
910
+ const buf = this.#memory.buffer;
911
+ if (buf !== this.#memBuf) {
912
+ this.#memBuf = buf;
913
+ this.#memView = new Uint8Array(buf);
914
+ }
915
+ return this.#memView;
916
+ }
917
+ #readString(ptr, len) {
918
+ return decoder2.decode(this.#view().subarray(ptr, ptr + len));
919
+ }
920
+ #writeBytes(ptr, data) {
921
+ this.#view().set(data, ptr);
922
+ }
923
+ log(level, ptr, len) {
924
+ const msg = decoder2.decode(this.#view().subarray(ptr, ptr + len));
925
+ switch (level) {
926
+ case 0:
927
+ console.error(msg);
928
+ break;
929
+ case 1:
930
+ console.warn(msg);
931
+ break;
932
+ case 3:
933
+ console.debug(msg);
934
+ break;
935
+ default:
936
+ console.log(msg);
937
+ break;
938
+ }
939
+ }
940
+ fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
941
+ const url = this.#readString(urlPtr, urlLen);
942
+ const method = methodLen > 0 ? this.#readString(methodPtr, methodLen) : "GET";
943
+ const headersJson = headersLen > 0 ? this.#readString(headersPtr, headersLen) : "{}";
944
+ const body = bodyLen > 0 ? this.#readString(bodyPtr, bodyLen) : undefined;
945
+ let headers = {};
946
+ try {
947
+ headers = JSON.parse(headersJson);
948
+ } catch {
949
+ for (const line of headersJson.split(`
950
+ `)) {
951
+ const i = line.indexOf(":");
952
+ if (i > 0)
953
+ headers[line.slice(0, i)] = line.slice(i + 1);
954
+ }
955
+ }
956
+ const controller = new AbortController;
957
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
958
+ fetch(url, {
959
+ method,
960
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
961
+ body: method !== "GET" && method !== "HEAD" ? body : undefined,
962
+ signal: controller.signal
963
+ }).then(async (res) => {
964
+ if (timeout)
965
+ clearTimeout(timeout);
966
+ this.#notifyFetchComplete(fetchId, res.status, await res.text(), false);
967
+ }).catch((err) => {
968
+ if (timeout)
969
+ clearTimeout(timeout);
970
+ const msg = err.name === "AbortError" ? "Request timeout" : err.message ?? "Fetch failed";
971
+ this.#notifyFetchComplete(fetchId, 0, msg, true);
972
+ });
973
+ }
974
+ #notifyFetchComplete(fetchId, status, body, isError) {
975
+ const encoded = encoder2.encode(body);
976
+ const ptr = this.#alloc(encoded.length);
977
+ this.#writeBytes(ptr, encoded);
978
+ this.#fetchCompleteHandler(fetchId, status, ptr, encoded.length, isError ? 1 : 0);
979
+ }
980
+ setTimeout(callbackId, delayMs) {
981
+ setTimeout(() => this.#cb?.(3, callbackId, 0n), delayMs);
982
+ }
983
+ setInterval(callbackId, intervalMs) {
984
+ const handle = setInterval(() => this.#cb?.(4, callbackId, 0n), intervalMs);
985
+ this.#intervals.set(callbackId, handle);
986
+ }
987
+ clearInterval(callbackId) {
988
+ const handle = this.#intervals.get(callbackId);
989
+ if (handle !== undefined) {
990
+ clearInterval(handle);
991
+ this.#intervals.delete(callbackId);
992
+ }
993
+ }
994
+ static createImportObject(bridgeRef) {
995
+ return {
996
+ __zx: {
997
+ _log: (level, ptr, len) => {
998
+ bridgeRef.current?.log(level, ptr, len);
999
+ },
1000
+ _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
1001
+ bridgeRef.current?.fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId);
1002
+ },
1003
+ _setTimeout: (callbackId, delayMs) => {
1004
+ bridgeRef.current?.setTimeout(callbackId, delayMs);
1005
+ },
1006
+ _setInterval: (callbackId, intervalMs) => {
1007
+ bridgeRef.current?.setInterval(callbackId, intervalMs);
1008
+ },
1009
+ _clearInterval: (callbackId) => {
1010
+ bridgeRef.current?.clearInterval(callbackId);
1011
+ }
1012
+ }
1013
+ };
1014
+ }
1015
+ }
1016
+
1017
+ // src/kv.ts
855
1018
  var exports_kv = {};
856
1019
  __export(exports_kv, {
857
1020
  createMemoryKV: () => createMemoryKV,
@@ -876,10 +1039,10 @@ function createMemoryKV() {
876
1039
  };
877
1040
  }
878
1041
  function createKVImports(bindings, getMemory) {
879
- const encoder2 = new TextEncoder;
880
- const decoder2 = new TextDecoder;
1042
+ const encoder3 = new TextEncoder;
1043
+ const decoder3 = new TextDecoder;
881
1044
  function readStr(ptr, len) {
882
- return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
1045
+ return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
883
1046
  }
884
1047
  function writeBytes2(buf_ptr, buf_max, data) {
885
1048
  if (data.length > buf_max)
@@ -896,7 +1059,7 @@ function createKVImports(bindings, getMemory) {
896
1059
  kv_get: (_ns, _nsLen, _key, _keyLen, _buf, _max) => -1,
897
1060
  kv_put: (_ns, _nsLen, _key, _keyLen, _val, _valLen) => 0,
898
1061
  kv_delete: (_ns, _nsLen, _key, _keyLen) => 0,
899
- kv_list: (_ns, _nsLen, _pfx, _pfxLen, buf_ptr, buf_max) => writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"))
1062
+ kv_list: (_ns, _nsLen, _pfx, _pfxLen, buf_ptr, buf_max) => writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"))
900
1063
  };
901
1064
  }
902
1065
  return {
@@ -907,7 +1070,7 @@ function createKVImports(bindings, getMemory) {
907
1070
  const value = await b.get(readStr(key_ptr, key_len));
908
1071
  if (value === null)
909
1072
  return -1;
910
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
1073
+ return writeBytes2(buf_ptr, buf_max, encoder3.encode(value));
911
1074
  }),
912
1075
  kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len) => {
913
1076
  const b = binding(readStr(ns_ptr, ns_len));
@@ -926,15 +1089,15 @@ function createKVImports(bindings, getMemory) {
926
1089
  kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
927
1090
  const b = binding(readStr(ns_ptr, ns_len));
928
1091
  if (!b)
929
- return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
1092
+ return writeBytes2(buf_ptr, buf_max, encoder3.encode("[]"));
930
1093
  const prefix = readStr(prefix_ptr, prefix_len);
931
1094
  const result = await b.list(prefix.length > 0 ? { prefix } : undefined);
932
- return writeBytes2(buf_ptr, buf_max, encoder2.encode(JSON.stringify(result.keys.map((k) => k.name))));
1095
+ return writeBytes2(buf_ptr, buf_max, encoder3.encode(JSON.stringify(result.keys.map((k) => k.name))));
933
1096
  })
934
1097
  };
935
1098
  }
936
1099
 
937
- // src/cloudflare/worker.ts
1100
+ // src/wasi.ts
938
1101
  class ProcExit extends Error {
939
1102
  code;
940
1103
  constructor(code) {
@@ -947,8 +1110,7 @@ function createWasiImports({
947
1110
  stdinData,
948
1111
  onStdout
949
1112
  }) {
950
- const encoder2 = new TextEncoder;
951
- const decoder2 = new TextDecoder;
1113
+ const encoder3 = new TextEncoder;
952
1114
  const url = new URL(request.url);
953
1115
  const argStrings = [
954
1116
  "wasm",
@@ -963,14 +1125,30 @@ function createWasiImports({
963
1125
  if (value)
964
1126
  argStrings.push("--header", `${name}:${value}`);
965
1127
  });
966
- const encodedArgs = argStrings.map((a) => encoder2.encode(a + "\x00"));
1128
+ const encodedArgs = argStrings.map((a) => encoder3.encode(a + "\x00"));
967
1129
  const argBufSize = encodedArgs.reduce((s, a) => s + a.length, 0);
968
1130
  let wasmMemory = null;
969
1131
  const setMemory = (m2) => {
970
1132
  wasmMemory = m2;
971
1133
  };
972
1134
  const stdoutChunks = [];
973
- const stderrChunks = [];
1135
+ let stderrMeta = "";
1136
+ let stderrPartial = "";
1137
+ const stderrDecoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
1138
+ function processStderrChunk(chunk) {
1139
+ const text = stderrDecoder.decode(chunk, { stream: true });
1140
+ const lines = (stderrPartial + text).split(`
1141
+ `);
1142
+ stderrPartial = lines.pop() ?? "";
1143
+ for (const line of lines) {
1144
+ if (line.startsWith("__EDGE_META__:")) {
1145
+ stderrMeta += line + `
1146
+ `;
1147
+ } else if (line.length > 0) {
1148
+ console.error("[ziex]", line);
1149
+ }
1150
+ }
1151
+ }
974
1152
  let stdinOffset = 0;
975
1153
  function v() {
976
1154
  return new DataView(wasmMemory.buffer);
@@ -1018,7 +1196,7 @@ function createWasiImports({
1018
1196
  else
1019
1197
  stdoutChunks.push(chunk);
1020
1198
  } else if (fd === 2)
1021
- stderrChunks.push(chunk);
1199
+ processStderrChunk(chunk);
1022
1200
  written += buf_len;
1023
1201
  }
1024
1202
  dv.setUint32(nwritten_ptr, written, true);
@@ -1133,106 +1311,36 @@ function createWasiImports({
1133
1311
  }
1134
1312
  };
1135
1313
  function collectOutput() {
1314
+ const remaining = stderrDecoder.decode(undefined, { stream: false });
1315
+ const tail = stderrPartial + remaining;
1316
+ if (tail.length > 0) {
1317
+ if (tail.startsWith("__EDGE_META__:"))
1318
+ stderrMeta += tail;
1319
+ else
1320
+ console.error("[ziex]", tail);
1321
+ stderrPartial = "";
1322
+ }
1136
1323
  return {
1137
1324
  stdout: mergeUint8Arrays(stdoutChunks),
1138
- stderrText: decoder2.decode(mergeUint8Arrays(stderrChunks))
1325
+ stderrText: stderrMeta
1139
1326
  };
1140
1327
  }
1141
1328
  return { wasiImport, setMemory, collectOutput };
1142
1329
  }
1143
- async function run({
1144
- request,
1145
- env,
1146
- ctx,
1147
- module,
1148
- kv: kvBindings,
1149
- imports,
1150
- wasi,
1151
- websocket: doNamespace
1152
- }) {
1153
- if (doNamespace && request.headers.get("upgrade")?.toLowerCase() === "websocket") {
1154
- const id = doNamespace.idFromName(new URL(request.url).pathname);
1155
- return doNamespace.get(id).fetch(request);
1156
- }
1157
- const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : undefined;
1158
- const { readable, writable } = new TransformStream;
1159
- const stdoutWriter = writable.getWriter();
1160
- const { wasiImport, setMemory, collectOutput } = createWasiImports({
1161
- request,
1162
- stdinData,
1163
- onStdout: (chunk) => {
1164
- stdoutWriter.write(chunk);
1165
- }
1166
- });
1167
- let wasmMemory = null;
1168
- const mem = () => wasmMemory;
1169
- const bridgeRef = { current: null };
1170
- const bridgeImports = ZxBridge.createImportObject(bridgeRef);
1171
- const decoder2 = new TextDecoder;
1172
- const Suspending = WebAssembly.Suspending;
1173
- const jspi = typeof Suspending === "function";
1174
- const sysImports = {
1175
- sleep_ms: jspi ? new Suspending(async (ms) => new Promise((resolve) => setTimeout(resolve, ms))) : (_ms) => {}
1176
- };
1177
- const wsState = {
1178
- upgraded: false,
1179
- server: null,
1180
- pendingWrites: [],
1181
- messageQueue: [],
1182
- recvResolve: null
1183
- };
1184
- const wsImports = buildWsImports(jspi ? Suspending : null, mem, decoder2, wsState);
1185
- const instance = new WebAssembly.Instance(module, {
1186
- wasi_snapshot_preview1: { ...wasi?.wasiImport, ...wasiImport },
1187
- __zx_sys: sysImports,
1188
- __zx_ws: wsImports,
1189
- __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
1190
- ...imports ? imports(mem) : {},
1191
- ...bridgeImports
1192
- });
1193
- wasmMemory = instance.exports.memory;
1194
- setMemory(wasmMemory);
1195
- const bridge = new ZxBridge(instance.exports);
1196
- bridgeRef.current = bridge;
1197
- let wasmPromise;
1198
- if (jspi) {
1199
- const start = WebAssembly.promising(instance.exports._start);
1200
- wasmPromise = start().catch((e) => {
1201
- if (e instanceof Error && e.message.startsWith("proc_exit"))
1202
- return;
1203
- throw e;
1204
- }).finally(() => {
1205
- stdoutWriter.close();
1206
- if (wsState.recvResolve) {
1207
- const res = wsState.recvResolve;
1208
- wsState.recvResolve = null;
1209
- res(null);
1210
- }
1211
- });
1212
- } else {
1213
- try {
1214
- instance.exports._start();
1215
- } catch (e) {
1216
- if (!(e instanceof ProcExit))
1217
- throw e;
1218
- }
1219
- stdoutWriter.close();
1220
- wasmPromise = Promise.resolve();
1221
- }
1222
- if (wsState.upgraded) {
1223
- const server = attachWebSocket(wsState);
1224
- ctx?.waitUntil(wasmPromise);
1225
- return new Response(null, { status: 101, webSocket: server.client });
1330
+ function mergeUint8Arrays(arrays) {
1331
+ const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
1332
+ const result = new Uint8Array(totalLen);
1333
+ let offset = 0;
1334
+ for (const arr of arrays) {
1335
+ result.set(arr, offset);
1336
+ offset += arr.length;
1226
1337
  }
1227
- const { stderrText } = collectOutput();
1228
- const meta = parseEdgeMeta(stderrText);
1229
- return new Response(readable, {
1230
- status: meta.status,
1231
- headers: meta.headers
1232
- });
1338
+ return result;
1233
1339
  }
1234
- function buildWsImports(Suspending, mem, decoder2, ws) {
1235
- const readStr = (ptr, len) => decoder2.decode(new Uint8Array(mem().buffer, ptr, len));
1340
+
1341
+ // src/runtime.ts
1342
+ function buildWsImports(Suspending, mem, decoder3, ws) {
1343
+ const readStr = (ptr, len) => decoder3.decode(new Uint8Array(mem().buffer, ptr, len));
1236
1344
  return {
1237
1345
  ws_upgrade: () => {
1238
1346
  ws.upgraded = true;
@@ -1246,7 +1354,7 @@ function buildWsImports(Suspending, mem, decoder2, ws) {
1246
1354
  }
1247
1355
  },
1248
1356
  ws_close: (code, reason_ptr, reason_len) => {
1249
- ws.server?.close(code, decoder2.decode(new Uint8Array(mem().buffer, reason_ptr, reason_len)));
1357
+ ws.server?.close(code, decoder3.decode(new Uint8Array(mem().buffer, reason_ptr, reason_len)));
1250
1358
  },
1251
1359
  ws_recv: Suspending ? new Suspending(async (buf_ptr, buf_max) => {
1252
1360
  if (ws._resolveFirstSuspend) {
@@ -1310,6 +1418,193 @@ function attachWebSocket(ws) {
1310
1418
  });
1311
1419
  return { client };
1312
1420
  }
1421
+ function buildSysImports(jspi, Suspending) {
1422
+ return {
1423
+ sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {}
1424
+ };
1425
+ }
1426
+ function executeWasm(instance, jspi, Suspending, wsState) {
1427
+ if (!jspi) {
1428
+ try {
1429
+ instance.exports._start();
1430
+ } catch (e) {
1431
+ if (!(e instanceof ProcExit))
1432
+ throw e;
1433
+ }
1434
+ return Promise.resolve();
1435
+ }
1436
+ const start = WebAssembly.promising(instance.exports._start);
1437
+ return start().catch((e) => {
1438
+ if (e instanceof Error && e.message.startsWith("proc_exit"))
1439
+ return;
1440
+ throw e;
1441
+ }).finally(() => {
1442
+ if (wsState.recvResolve) {
1443
+ const res = wsState.recvResolve;
1444
+ wsState.recvResolve = null;
1445
+ res(null);
1446
+ }
1447
+ });
1448
+ }
1449
+ function parseEdgeMeta(stderrText) {
1450
+ const meta = { status: 200, headers: new Headers, streaming: false };
1451
+ const metaPrefix = "__EDGE_META__:";
1452
+ const metaLine = stderrText.split(`
1453
+ `).find((line) => line.startsWith(metaPrefix));
1454
+ if (metaLine) {
1455
+ try {
1456
+ const parsed = JSON.parse(metaLine.slice(metaPrefix.length));
1457
+ if (parsed.status)
1458
+ meta.status = parsed.status;
1459
+ if (parsed.streaming === true)
1460
+ meta.streaming = true;
1461
+ if (Array.isArray(parsed.headers)) {
1462
+ for (const [name, value] of parsed.headers) {
1463
+ meta.headers.append(name, value);
1464
+ }
1465
+ }
1466
+ } catch {}
1467
+ }
1468
+ return meta;
1469
+ }
1470
+ async function run({
1471
+ request,
1472
+ env,
1473
+ ctx,
1474
+ module,
1475
+ kv: kvBindings,
1476
+ imports,
1477
+ wasi,
1478
+ websocket: doNamespace
1479
+ }) {
1480
+ if (doNamespace && request.headers.get("upgrade")?.toLowerCase() === "websocket") {
1481
+ const id = doNamespace.idFromName(new URL(request.url).pathname);
1482
+ return doNamespace.get(id).fetch(request);
1483
+ }
1484
+ const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : undefined;
1485
+ const stdoutChunks = [];
1486
+ let streamWriter = null;
1487
+ const { wasiImport, setMemory, collectOutput } = createWasiImports({
1488
+ request,
1489
+ stdinData,
1490
+ onStdout: (chunk) => {
1491
+ if (streamWriter)
1492
+ streamWriter.write(chunk);
1493
+ else
1494
+ stdoutChunks.push(chunk);
1495
+ }
1496
+ });
1497
+ let wasmMemory = null;
1498
+ const mem = () => wasmMemory;
1499
+ const bridgeRef = { current: null };
1500
+ const Suspending = WebAssembly.Suspending;
1501
+ const jspi = typeof Suspending === "function";
1502
+ const wsState = {
1503
+ upgraded: false,
1504
+ server: null,
1505
+ pendingWrites: [],
1506
+ messageQueue: [],
1507
+ recvResolve: null
1508
+ };
1509
+ const instance = new WebAssembly.Instance(module, {
1510
+ wasi_snapshot_preview1: { ...wasi?.wasiImport, ...wasiImport },
1511
+ __zx_sys: buildSysImports(jspi, Suspending),
1512
+ __zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder, wsState),
1513
+ __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
1514
+ ...imports ? imports(mem) : {},
1515
+ ...ZxWasiBridge.createImportObject(bridgeRef)
1516
+ });
1517
+ wasmMemory = instance.exports.memory;
1518
+ setMemory(wasmMemory);
1519
+ bridgeRef.current = new ZxWasiBridge(instance.exports);
1520
+ const wasmPromise = executeWasm(instance, jspi, Suspending, wsState);
1521
+ if (wsState.upgraded) {
1522
+ const server = attachWebSocket(wsState);
1523
+ ctx?.waitUntil(wasmPromise);
1524
+ return new Response(null, { status: 101, webSocket: server.client });
1525
+ }
1526
+ const { stderrText } = collectOutput();
1527
+ const meta = parseEdgeMeta(stderrText);
1528
+ if (meta.streaming) {
1529
+ const { readable, writable } = new TransformStream;
1530
+ streamWriter = writable.getWriter();
1531
+ for (const chunk of stdoutChunks)
1532
+ streamWriter.write(chunk);
1533
+ stdoutChunks.length = 0;
1534
+ wasmPromise.finally(() => streamWriter?.close());
1535
+ return new Response(readable, { status: meta.status, headers: meta.headers });
1536
+ }
1537
+ await wasmPromise;
1538
+ const body = mergeUint8Arrays(stdoutChunks);
1539
+ meta.headers.delete("transfer-encoding");
1540
+ if (!meta.headers.has("content-length"))
1541
+ meta.headers.set("content-length", String(body.byteLength));
1542
+ return new Response(body.buffer, { status: meta.status, headers: meta.headers });
1543
+ }
1544
+ // src/app.ts
1545
+ async function resolveModule(input) {
1546
+ if (typeof input === "string") {
1547
+ if (input.startsWith("http://") || input.startsWith("https://")) {
1548
+ return WebAssembly.compileStreaming(fetch(input));
1549
+ }
1550
+ const url = input.startsWith("/") ? `file://${input}` : input;
1551
+ return WebAssembly.compile(await fetch(url).then((r) => r.arrayBuffer()));
1552
+ }
1553
+ if (input instanceof URL) {
1554
+ return WebAssembly.compileStreaming(fetch(input));
1555
+ }
1556
+ if (input instanceof Response) {
1557
+ return WebAssembly.compileStreaming(input);
1558
+ }
1559
+ if (input instanceof ArrayBuffer) {
1560
+ return WebAssembly.compile(input);
1561
+ }
1562
+ if (ArrayBuffer.isView(input)) {
1563
+ return WebAssembly.compile(input.buffer);
1564
+ }
1565
+ return input;
1566
+ }
1567
+
1568
+ class Ziex {
1569
+ options;
1570
+ resolved = null;
1571
+ constructor(options) {
1572
+ this.options = options;
1573
+ }
1574
+ async getModule() {
1575
+ if (!this.resolved)
1576
+ this.resolved = await resolveModule(this.options.module);
1577
+ return this.resolved;
1578
+ }
1579
+ resolveKV(env) {
1580
+ const { kv } = this.options;
1581
+ if (kv === undefined)
1582
+ return;
1583
+ if (typeof kv === "object" && kv !== null) {
1584
+ const result = {};
1585
+ for (const [name, key] of Object.entries(kv)) {
1586
+ result[name] = env[key];
1587
+ }
1588
+ return result;
1589
+ }
1590
+ return { default: env[kv] };
1591
+ }
1592
+ fetch = async (request, env, ctx) => {
1593
+ const module = await this.getModule();
1594
+ const { wasi, imports, websocket } = this.options;
1595
+ return run({
1596
+ request,
1597
+ env,
1598
+ ctx,
1599
+ module,
1600
+ wasi,
1601
+ imports,
1602
+ kv: this.resolveKV(env),
1603
+ websocket: websocket !== undefined ? env[websocket] : undefined
1604
+ });
1605
+ };
1606
+ }
1607
+ // src/cloudflare/do.ts
1313
1608
  function createWebSocketDO(module, options) {
1314
1609
  return class ZxWebSocketDO {
1315
1610
  doState;
@@ -1328,7 +1623,7 @@ function createWebSocketDO(module, options) {
1328
1623
  const bridgeImports = ZxBridge.createImportObject(bridgeRef);
1329
1624
  const Suspending = WebAssembly.Suspending;
1330
1625
  const jspi = typeof Suspending === "function";
1331
- const decoder2 = new TextDecoder;
1626
+ const decoder3 = new TextDecoder;
1332
1627
  let _resolveFirstSuspend;
1333
1628
  const firstSuspendPromise = new Promise((resolve) => {
1334
1629
  _resolveFirstSuspend = resolve;
@@ -1365,7 +1660,7 @@ function createWebSocketDO(module, options) {
1365
1660
  const sysImports = {
1366
1661
  sleep_ms: jspi ? new Suspending(async (ms) => new Promise((r) => setTimeout(r, ms))) : (_ms) => {}
1367
1662
  };
1368
- const wsImports = buildWsImports(jspi ? Suspending : null, mem, decoder2, connState);
1663
+ const wsImports = buildWsImports(jspi ? Suspending : null, mem, decoder3, connState);
1369
1664
  const kvBindings = options?.kv?.(this.env);
1370
1665
  const instance = new WebAssembly.Instance(module, {
1371
1666
  wasi_snapshot_preview1: wasiImport,
@@ -1404,109 +1699,8 @@ function createWebSocketDO(module, options) {
1404
1699
  }
1405
1700
  };
1406
1701
  }
1407
- function parseEdgeMeta(stderrText) {
1408
- const meta = { status: 200, headers: new Headers };
1409
- const metaPrefix = "__EDGE_META__:";
1410
- const metaLine = stderrText.split(`
1411
- `).find((line) => line.startsWith(metaPrefix));
1412
- if (metaLine) {
1413
- try {
1414
- const parsed = JSON.parse(metaLine.slice(metaPrefix.length));
1415
- if (parsed.status)
1416
- meta.status = parsed.status;
1417
- if (Array.isArray(parsed.headers)) {
1418
- for (const [name, value] of parsed.headers) {
1419
- meta.headers.append(name, value);
1420
- }
1421
- }
1422
- } catch {}
1423
- }
1424
- return meta;
1425
- }
1426
- function mergeUint8Arrays(arrays) {
1427
- const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
1428
- const result = new Uint8Array(totalLen);
1429
- let offset = 0;
1430
- for (const arr of arrays) {
1431
- result.set(arr, offset);
1432
- offset += arr.length;
1433
- }
1434
- return result;
1435
- }
1436
- async function collectStream(readable, chunks) {
1437
- const reader = readable.getReader();
1438
- while (true) {
1439
- const { done, value } = await reader.read();
1440
- if (done)
1441
- break;
1442
- if (value)
1443
- chunks.push(value);
1444
- }
1445
- }
1446
- function prepare({
1447
- request,
1448
- env,
1449
- ctx
1450
- }) {
1451
- const stdout = new TransformStream;
1452
- const stderr = new TransformStream;
1453
- const url = new URL(request.url);
1454
- const args = [
1455
- "--pathname",
1456
- url.pathname,
1457
- "--method",
1458
- request.method,
1459
- "--search",
1460
- url.search
1461
- ];
1462
- request.headers.forEach((value, name) => {
1463
- args.push("--header", `${name}:${value}`);
1464
- });
1465
- const stdin = request.body ?? undefined;
1466
- return { args, stdout, stderr, stdin };
1467
- }
1468
- async function respond({
1469
- exec,
1470
- stdout,
1471
- stderr
1472
- }) {
1473
- const stdoutChunks = [];
1474
- const stderrChunks = [];
1475
- const stderrReadable = stderr instanceof ReadableStream ? stderr : stderr.readable;
1476
- await Promise.all([
1477
- exec,
1478
- collectStream(stdout.readable, stdoutChunks),
1479
- collectStream(stderrReadable, stderrChunks)
1480
- ]);
1481
- const stderrText = new TextDecoder().decode(mergeUint8Arrays(stderrChunks));
1482
- const meta = parseEdgeMeta(stderrText);
1483
- return new Response(mergeUint8Arrays(stdoutChunks).buffer, {
1484
- status: meta.status,
1485
- headers: meta.headers
1486
- });
1487
- }
1488
- // src/cloudflare/app.ts
1489
- class Ziex {
1490
- options;
1491
- constructor(options) {
1492
- this.options = options;
1493
- }
1494
- fetch(request, env, ctx) {
1495
- const { module, wasi, imports, kv, websocket } = this.options;
1496
- return run({
1497
- request,
1498
- env,
1499
- ctx,
1500
- module,
1501
- wasi,
1502
- imports,
1503
- kv: kv?.(env),
1504
- websocket: websocket?.(env)
1505
- });
1506
- }
1507
- }
1508
1702
  export {
1509
- exports_worker as worker,
1703
+ exports_runtime as worker,
1510
1704
  exports_kv as kv,
1511
1705
  createWebSocketDO,
1512
1706
  Ziex