ziex 0.1.0-dev.1259 → 0.1.0-dev.1360

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 (35) hide show
  1. package/README.md +20 -24
  2. package/cloudflare/index.js +101 -15
  3. package/index.js +78 -4
  4. package/package.json +2 -2
  5. package/pkg/ziex/src/fetch.d.ts +5 -0
  6. package/{wasm → pkg/ziex/src/wasm}/core.d.ts +2 -2
  7. package/{wasm → pkg/ziex/src/wasm}/index.d.ts +2 -1
  8. package/vendor/jsz/js/src/index.d.ts +1 -0
  9. package/vendor/jsz/js/src/zigjs.d.ts +107 -0
  10. package/wasm/index.js +92 -11
  11. package/wasm/init.dev.js +1310 -0
  12. package/wasm/init.js +3 -1229
  13. /package/{app.d.ts → pkg/ziex/src/app.d.ts} +0 -0
  14. /package/{aws-lambda → pkg/ziex/src/aws-lambda}/index.d.ts +0 -0
  15. /package/{browser → pkg/ziex/src/browser}/kv.d.ts +0 -0
  16. /package/{cloudflare → pkg/ziex/src/cloudflare}/app.d.ts +0 -0
  17. /package/{cloudflare → pkg/ziex/src/cloudflare}/db.d.ts +0 -0
  18. /package/{cloudflare → pkg/ziex/src/cloudflare}/do.d.ts +0 -0
  19. /package/{cloudflare → pkg/ziex/src/cloudflare}/index.d.ts +0 -0
  20. /package/{cloudflare → pkg/ziex/src/cloudflare}/kv.d.ts +0 -0
  21. /package/{cloudflare → pkg/ziex/src/cloudflare}/worker.d.ts +0 -0
  22. /package/{db.d.ts → pkg/ziex/src/db.d.ts} +0 -0
  23. /package/{index.d.ts → pkg/ziex/src/index.d.ts} +0 -0
  24. /package/{kv.d.ts → pkg/ziex/src/kv.d.ts} +0 -0
  25. /package/{react → pkg/ziex/src/react}/dom.d.ts +0 -0
  26. /package/{react → pkg/ziex/src/react}/index.d.ts +0 -0
  27. /package/{react → pkg/ziex/src/react}/types.d.ts +0 -0
  28. /package/{runtime.d.ts → pkg/ziex/src/runtime.d.ts} +0 -0
  29. /package/{vercel → pkg/ziex/src/vercel}/index.d.ts +0 -0
  30. /package/{wasi.d.ts → pkg/ziex/src/wasi.d.ts} +0 -0
  31. /package/{wasm → pkg/ziex/src/wasm}/dom.d.ts +0 -0
  32. /package/{wasm → pkg/ziex/src/wasm}/init.d.ts +0 -0
  33. /package/{wasm → pkg/ziex/src/wasm}/types.d.ts +0 -0
  34. /package/{wasm → pkg/ziex/src/wasm}/wasi.d.ts +0 -0
  35. /package/{zx.d.ts → pkg/ziex/src/zx.d.ts} +0 -0
package/README.md CHANGED
@@ -8,37 +8,29 @@ Ziex combines the power and performance of Zig with the expressiveness and simpl
8
8
 
9
9
  **[Documentation →](https://ziex.dev/learn)**
10
10
 
11
-
12
11
  > **Note:** Most of the API and syntax are finalized and stable, and server-side rendering (SSR) features are production-ready, Ziex continues to evolve with ongoing improvements to client-side rendering and state management, see the [roadmap](#roadmap). You can start using the documented features today, as they are stable and unlikely to change. Areas still under development are not yet documented and will be added as they mature. See [versions](#versions) for Zig and Ziex versions compatibility.
13
12
 
14
-
15
13
  ## Getting Started
16
14
 
17
15
  ### 1. Installing CLI (optional)
18
16
 
19
- macOS/Linux
20
17
  ```bash
18
+ # macOS/Linux
21
19
  curl -fsSL https://ziex.dev/install | bash
22
- ```
23
- Windows
24
- ```
20
+
21
+ # Windows
25
22
  powershell -c "irm ziex.dev/install.ps1 | iex"
26
23
  ```
27
24
 
25
+
28
26
  ### 2. Initializing Project
27
+
29
28
  ```powershell
30
29
  zx init
31
30
  # or
32
31
  npm init ziex
33
32
  ```
34
33
 
35
- ### 3. Running Project
36
- ```powershell
37
- zx dev
38
- # or
39
- npm run dev
40
- ```
41
-
42
34
  You will need [compatible](#versions) Zig version when using zx CLI or you can use the `Node` template from `npm init ziex`
43
35
 
44
36
  Read [Getting Started →](https://ziex.dev/learn) for more details.
@@ -159,6 +151,7 @@ const zx = @import("zx");
159
151
  </details>
160
152
 
161
153
  ## Features
154
+
162
155
  - **Declarative UI**: Declarative UI components using with full access to Zig's control flow.
163
156
  - **Full-Stack Capabilities**: Build both frontend and backend of web application.
164
157
  - **Fast**: Significantly faster at SSR than many other frameworks.
@@ -170,24 +163,27 @@ const zx = @import("zx");
170
163
  - **Developer Tooling**: CLI, hot reload, and editor extensions for the best DX.
171
164
 
172
165
  ## Versions
173
- | Zig | Ziex | Branch | Status |
174
- |-------------|---------------------|-------------------|----------------|
175
- | `0.17.x` | | `zig-0.17` | Development |
176
- | `0.16.x` | `0.1.0-dev.1068`-* | `main` | **Latest** |
177
- | `0.15.x` | `0.1.0-dev-1050` | `zig-0.15` | Latest (`Zig 0.15.x`) |
178
166
 
167
+ | Zig | Ziex | Branch | Status |
168
+ | -------- | --------------------------------------------------------------------------------- | ---------- | ----------- |
169
+ | `0.17.x` | | `main` | Development |
170
+ | `0.16.x` | [`0.1.0-dev.1259`](https://github.com/ziex-dev/ziex/releases/tag/v0.1.0-dev.1259) | `zig-0.16` | **Latest** |
171
+ | `0.15.x` | [`0.1.0-dev-1050`](https://github.com/ziex-dev/ziex/releases/tag/v0.1.0-dev.1050) | `zig-0.15` | Outdated |
179
172
 
180
173
  ## Roadmap
181
- [Ziex 0.1.0](https://github.com/ziex-dev/ziex/milestone/2) is targeted after `Zig 0.17.0` release. You can see the [roadmap](https://github.com/ziex-dev/ziex/milestone) to learn more.
182
174
 
183
- `0.1.0` release will indicate that Ziex is production ready with all majore features fully baked and will receive patch releases for bug fixes.
175
+ [Ziex 0.1.0](https://github.com/ziex-dev/ziex/milestone/2) is planned for release after `Zig 0.17.0` is available. You can view the [roadmap](https://github.com/ziex-dev/ziex/milestones) to learn more.
176
+
177
+ The [`0.1.0`](https://github.com/ziex-dev/ziex/milestone/2) release will indicate that Ziex is production-ready, with all major features fully implemented, and will receive patch releases for bug fixes.
178
+
179
+ The [`1.0.0`](https://github.com/ziex-dev/ziex/milestone/6) release will signify long-term support for that major version, receiving bug fixes and minor updates.
184
180
 
185
181
  ## Editor Support
186
182
 
187
- * [VSCode](https://marketplace.visualstudio.com/items?itemName=ziex.ziex)/[VSCode Forks](https://open-vsx.org/extension/ziex/ziex)
188
- * [Neovim](/ide/neovim/)
189
- * [Helix](/ide/helix/)
190
- * [Zed](/ide/zed/)
183
+ - [VSCode](https://marketplace.visualstudio.com/items?itemName=ziex.ziex)/[VSCode Forks](https://open-vsx.org/extension/ziex/ziex)
184
+ - [Neovim](/ide/neovim/)
185
+ - [Helix](/ide/helix/)
186
+ - [Zed](/ide/zed/)
191
187
 
192
188
  ## Community
193
189
 
@@ -193,6 +193,76 @@ class ZigJS {
193
193
  return decoder.decode(data);
194
194
  }
195
195
  }
196
+ // src/fetch.ts
197
+ function createFetchImports(getMemory) {
198
+ const encoder2 = new TextEncoder;
199
+ const decoder2 = new TextDecoder;
200
+ function readStr(ptr, len) {
201
+ return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
202
+ }
203
+ function writeBytes(buf_ptr, buf_max, data) {
204
+ if (data.length > buf_max)
205
+ return -2;
206
+ new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
207
+ return data.length;
208
+ }
209
+ function readBytes(ptr, len) {
210
+ return new Uint8Array(getMemory().buffer, ptr, len);
211
+ }
212
+ function parseHeaders(headersJson) {
213
+ let headers = {};
214
+ try {
215
+ headers = JSON.parse(headersJson);
216
+ } catch {
217
+ for (const line of headersJson.split(`
218
+ `)) {
219
+ const colonIdx = line.indexOf(":");
220
+ if (colonIdx > 0) {
221
+ headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
222
+ }
223
+ }
224
+ }
225
+ return headers;
226
+ }
227
+ async function doFetch(url_ptr, url_len, method_ptr, method_len, headers_ptr, headers_len, body_ptr, body_len, timeout_ms, status_out, buf_ptr, buf_max) {
228
+ const url = readStr(url_ptr, url_len);
229
+ const method = method_len > 0 ? readStr(method_ptr, method_len) : "GET";
230
+ const headersJson = headers_len > 0 ? readStr(headers_ptr, headers_len) : "{}";
231
+ const body = body_len > 0 ? readBytes(body_ptr, body_len) : undefined;
232
+ const headers = parseHeaders(headersJson);
233
+ const controller = new AbortController;
234
+ const timeout = timeout_ms > 0 ? setTimeout(() => controller.abort(), timeout_ms) : null;
235
+ try {
236
+ const response = await fetch(url, {
237
+ method,
238
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
239
+ body: method !== "GET" && method !== "HEAD" ? body : undefined,
240
+ signal: controller.signal
241
+ });
242
+ if (timeout)
243
+ clearTimeout(timeout);
244
+ new DataView(getMemory().buffer).setUint16(status_out, response.status, true);
245
+ const bytes = new Uint8Array(await response.arrayBuffer());
246
+ return writeBytes(buf_ptr, buf_max, bytes);
247
+ } catch (err) {
248
+ if (timeout)
249
+ clearTimeout(timeout);
250
+ const msg = err instanceof Error ? err.message : String(err);
251
+ console.error(`wasm fetch failed: ${url} (${msg})`);
252
+ return -1;
253
+ }
254
+ }
255
+ const Suspending = WebAssembly.Suspending;
256
+ if (typeof Suspending !== "function") {
257
+ return {
258
+ fetch: (_url_ptr, _url_len, _method_ptr, _method_len, _headers_ptr, _headers_len, _body_ptr, _body_len, _timeout_ms, _status_out, _buf_ptr, _buf_max) => -1
259
+ };
260
+ }
261
+ return {
262
+ fetch: new Suspending(doFetch)
263
+ };
264
+ }
265
+
196
266
  // src/wasm/core.ts
197
267
  var CallbackType = {
198
268
  Event: 0,
@@ -291,7 +361,7 @@ class ZxBridgeCore {
291
361
  const url = readString(urlPtr, urlLen);
292
362
  const method = methodLen > 0 ? readString(methodPtr, methodLen) : "GET";
293
363
  const headersJson = headersLen > 0 ? readString(headersPtr, headersLen) : "{}";
294
- const body = bodyLen > 0 ? readString(bodyPtr, bodyLen) : undefined;
364
+ const body = bodyLen > 0 ? getMemoryView().subarray(bodyPtr, bodyPtr + bodyLen) : undefined;
295
365
  let headers = {};
296
366
  try {
297
367
  headers = JSON.parse(headersJson);
@@ -315,8 +385,8 @@ class ZxBridgeCore {
315
385
  fetch(url, fetchOptions).then(async (response) => {
316
386
  if (timeout)
317
387
  clearTimeout(timeout);
318
- const text = await response.text();
319
- this._notifyFetchComplete(fetchId, response.status, text, false);
388
+ const bytes = new Uint8Array(await response.arrayBuffer());
389
+ this._notifyFetchComplete(fetchId, response.status, bytes, false);
320
390
  }).catch((error) => {
321
391
  if (timeout)
322
392
  clearTimeout(timeout);
@@ -327,7 +397,7 @@ class ZxBridgeCore {
327
397
  }
328
398
  _notifyFetchComplete(fetchId, statusCode, body, isError) {
329
399
  const handler = this.#fetchCompleteHandler;
330
- const encoded = textEncoder.encode(body);
400
+ const encoded = typeof body === "string" ? textEncoder.encode(body) : body;
331
401
  const ptr = this._alloc(encoded.length);
332
402
  writeBytes(ptr, encoded);
333
403
  invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
@@ -384,6 +454,11 @@ class ZxBridgeCore {
384
454
  static createImportObject(bridgeRef) {
385
455
  return {
386
456
  ...jsz.importObject(),
457
+ __zx_net: createFetchImports(() => {
458
+ if (!jsz.memory)
459
+ throw new Error("WASM memory is not ready");
460
+ return jsz.memory;
461
+ }),
387
462
  __zx: {
388
463
  _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
389
464
  _fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
@@ -682,12 +757,12 @@ class ZxBridge extends ZxBridgeCore {
682
757
  clearEventHandlerModes(velementId) {
683
758
  eventHandlerModes.delete(velementId);
684
759
  }
685
- submitFormActionAsync(form, statesJson, fetchId) {
760
+ submitFormActionAsync(form, actionId, statesJson, fetchId) {
686
761
  const formData = new FormData(form);
687
762
  formData.append("__$states", statesJson);
688
763
  fetch(window.location.href, {
689
764
  method: "POST",
690
- headers: { "X-ZX-Action": "1" },
765
+ headers: { "x-action": String(actionId >>> 0) },
691
766
  body: formData
692
767
  }).then(async (response) => {
693
768
  const text = await response.text();
@@ -793,6 +868,11 @@ class ZxBridge extends ZxBridgeCore {
793
868
  static createImportObject(bridgeRef) {
794
869
  return {
795
870
  ...jsz.importObject(),
871
+ __zx_net: createFetchImports(() => {
872
+ if (!jsz.memory)
873
+ throw new Error("WASM memory is not ready");
874
+ return jsz.memory;
875
+ }),
796
876
  __zx: {
797
877
  _log: (level, ptr, len) => ZxBridgeCore.log(level, ptr, len),
798
878
  _setEventHandlerMode: (vnodeId, eventTypeId, maySuspend) => {
@@ -911,23 +991,23 @@ class ZxBridge extends ZxBridgeCore {
911
991
  writeBytes(bufPtr, bytes.subarray(0, len));
912
992
  return len;
913
993
  },
914
- _submitFormAction: (vnodeId) => {
994
+ _submitFormAction: (vnodeId, actionId) => {
915
995
  const form = domNodes.get(vnodeId);
916
996
  if (!form || !(form instanceof HTMLFormElement))
917
997
  return;
918
998
  const formData = new FormData(form);
919
999
  fetch(window.location.href, {
920
1000
  method: "POST",
921
- headers: { "X-ZX-Action": "1" },
1001
+ headers: { "x-action": String(actionId >>> 0) },
922
1002
  body: formData
923
1003
  }).catch(() => {});
924
1004
  },
925
- _submitFormActionAsync: (vnodeId, statesPtr, statesLen, fetchId) => {
1005
+ _submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
926
1006
  const form = domNodes.get(vnodeId);
927
1007
  if (!form || !(form instanceof HTMLFormElement))
928
1008
  return;
929
1009
  const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
930
- bridgeRef.current?.submitFormActionAsync(form, statesJson, fetchId);
1010
+ bridgeRef.current?.submitFormActionAsync(form, actionId, statesJson, fetchId);
931
1011
  }
932
1012
  }
933
1013
  };
@@ -1259,7 +1339,8 @@ async function init(options = {}) {
1259
1339
  domNodes.clear();
1260
1340
  }
1261
1341
  };
1262
- registerDevReinit(normalizedOptions);
1342
+ if (true)
1343
+ registerDevReinit(normalizedOptions);
1263
1344
  return { source, bridge };
1264
1345
  }
1265
1346
 
@@ -1324,7 +1405,7 @@ class ZxWasiBridge {
1324
1405
  const url = this.#readString(urlPtr, urlLen);
1325
1406
  const method = methodLen > 0 ? this.#readString(methodPtr, methodLen) : "GET";
1326
1407
  const headersJson = headersLen > 0 ? this.#readString(headersPtr, headersLen) : "{}";
1327
- const body = bodyLen > 0 ? this.#readString(bodyPtr, bodyLen) : undefined;
1408
+ const body = bodyLen > 0 ? this.#view().subarray(bodyPtr, bodyPtr + bodyLen) : undefined;
1328
1409
  let headers = {};
1329
1410
  try {
1330
1411
  headers = JSON.parse(headersJson);
@@ -1346,7 +1427,8 @@ class ZxWasiBridge {
1346
1427
  }).then(async (res) => {
1347
1428
  if (timeout)
1348
1429
  clearTimeout(timeout);
1349
- this.#notifyFetchComplete(fetchId, res.status, await res.text(), false);
1430
+ const bytes = new Uint8Array(await res.arrayBuffer());
1431
+ this.#notifyFetchComplete(fetchId, res.status, bytes, false);
1350
1432
  }).catch((err) => {
1351
1433
  if (timeout)
1352
1434
  clearTimeout(timeout);
@@ -1355,7 +1437,7 @@ class ZxWasiBridge {
1355
1437
  });
1356
1438
  }
1357
1439
  #notifyFetchComplete(fetchId, status, body, isError) {
1358
- const encoded = encoder2.encode(body);
1440
+ const encoded = typeof body === "string" ? encoder2.encode(body) : body;
1359
1441
  const ptr = this.#alloc(encoded.length);
1360
1442
  this.#writeBytes(ptr, encoded);
1361
1443
  this.#fetchCompleteHandler(fetchId, status, ptr, encoded.length, isError ? 1 : 0);
@@ -1562,7 +1644,9 @@ function createWasiImports({
1562
1644
  "--method",
1563
1645
  request.method,
1564
1646
  "--search",
1565
- url.search
1647
+ url.search,
1648
+ "--url",
1649
+ url.href
1566
1650
  ];
1567
1651
  request.headers.forEach((value, name) => {
1568
1652
  if (value)
@@ -2015,6 +2099,7 @@ async function run({
2015
2099
  __zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder, wsState),
2016
2100
  __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
2017
2101
  __zx_db: createD1Imports(dbBindings ?? {}, mem),
2102
+ __zx_net: createFetchImports(mem),
2018
2103
  ...imports ? imports(mem) : {},
2019
2104
  ...ZxWasiBridge.createImportObject(bridgeRef)
2020
2105
  });
@@ -2189,6 +2274,7 @@ function createWebSocketDO(module, options) {
2189
2274
  __zx_ws: wsImports,
2190
2275
  __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
2191
2276
  __zx_db: createD1Imports(dbBindings ?? {}, mem),
2277
+ __zx_net: createFetchImports(mem),
2192
2278
  ...options?.imports ? options.imports(mem) : {},
2193
2279
  ...bridgeImports
2194
2280
  });
package/index.js CHANGED
@@ -74,7 +74,7 @@ class ZxWasiBridge {
74
74
  const url = this.#readString(urlPtr, urlLen);
75
75
  const method = methodLen > 0 ? this.#readString(methodPtr, methodLen) : "GET";
76
76
  const headersJson = headersLen > 0 ? this.#readString(headersPtr, headersLen) : "{}";
77
- const body = bodyLen > 0 ? this.#readString(bodyPtr, bodyLen) : undefined;
77
+ const body = bodyLen > 0 ? this.#view().subarray(bodyPtr, bodyPtr + bodyLen) : undefined;
78
78
  let headers = {};
79
79
  try {
80
80
  headers = JSON.parse(headersJson);
@@ -96,7 +96,8 @@ class ZxWasiBridge {
96
96
  }).then(async (res) => {
97
97
  if (timeout)
98
98
  clearTimeout(timeout);
99
- this.#notifyFetchComplete(fetchId, res.status, await res.text(), false);
99
+ const bytes = new Uint8Array(await res.arrayBuffer());
100
+ this.#notifyFetchComplete(fetchId, res.status, bytes, false);
100
101
  }).catch((err) => {
101
102
  if (timeout)
102
103
  clearTimeout(timeout);
@@ -105,7 +106,7 @@ class ZxWasiBridge {
105
106
  });
106
107
  }
107
108
  #notifyFetchComplete(fetchId, status, body, isError) {
108
- const encoded = encoder.encode(body);
109
+ const encoded = typeof body === "string" ? encoder.encode(body) : body;
109
110
  const ptr = this.#alloc(encoded.length);
110
111
  this.#writeBytes(ptr, encoded);
111
112
  this.#fetchCompleteHandler(fetchId, status, ptr, encoded.length, isError ? 1 : 0);
@@ -265,6 +266,76 @@ function createKVImports(bindings, getMemory) {
265
266
  };
266
267
  }
267
268
 
269
+ // src/fetch.ts
270
+ function createFetchImports(getMemory) {
271
+ const encoder2 = new TextEncoder;
272
+ const decoder2 = new TextDecoder;
273
+ function readStr(ptr, len) {
274
+ return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
275
+ }
276
+ function writeBytes(buf_ptr, buf_max, data) {
277
+ if (data.length > buf_max)
278
+ return -2;
279
+ new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
280
+ return data.length;
281
+ }
282
+ function readBytes(ptr, len) {
283
+ return new Uint8Array(getMemory().buffer, ptr, len);
284
+ }
285
+ function parseHeaders(headersJson) {
286
+ let headers = {};
287
+ try {
288
+ headers = JSON.parse(headersJson);
289
+ } catch {
290
+ for (const line of headersJson.split(`
291
+ `)) {
292
+ const colonIdx = line.indexOf(":");
293
+ if (colonIdx > 0) {
294
+ headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
295
+ }
296
+ }
297
+ }
298
+ return headers;
299
+ }
300
+ async function doFetch(url_ptr, url_len, method_ptr, method_len, headers_ptr, headers_len, body_ptr, body_len, timeout_ms, status_out, buf_ptr, buf_max) {
301
+ const url = readStr(url_ptr, url_len);
302
+ const method = method_len > 0 ? readStr(method_ptr, method_len) : "GET";
303
+ const headersJson = headers_len > 0 ? readStr(headers_ptr, headers_len) : "{}";
304
+ const body = body_len > 0 ? readBytes(body_ptr, body_len) : undefined;
305
+ const headers = parseHeaders(headersJson);
306
+ const controller = new AbortController;
307
+ const timeout = timeout_ms > 0 ? setTimeout(() => controller.abort(), timeout_ms) : null;
308
+ try {
309
+ const response = await fetch(url, {
310
+ method,
311
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
312
+ body: method !== "GET" && method !== "HEAD" ? body : undefined,
313
+ signal: controller.signal
314
+ });
315
+ if (timeout)
316
+ clearTimeout(timeout);
317
+ new DataView(getMemory().buffer).setUint16(status_out, response.status, true);
318
+ const bytes = new Uint8Array(await response.arrayBuffer());
319
+ return writeBytes(buf_ptr, buf_max, bytes);
320
+ } catch (err) {
321
+ if (timeout)
322
+ clearTimeout(timeout);
323
+ const msg = err instanceof Error ? err.message : String(err);
324
+ console.error(`wasm fetch failed: ${url} (${msg})`);
325
+ return -1;
326
+ }
327
+ }
328
+ const Suspending = WebAssembly.Suspending;
329
+ if (typeof Suspending !== "function") {
330
+ return {
331
+ fetch: (_url_ptr, _url_len, _method_ptr, _method_len, _headers_ptr, _headers_len, _body_ptr, _body_len, _timeout_ms, _status_out, _buf_ptr, _buf_max) => -1
332
+ };
333
+ }
334
+ return {
335
+ fetch: new Suspending(doFetch)
336
+ };
337
+ }
338
+
268
339
  // src/db.ts
269
340
  function decodeBlob(base64) {
270
341
  const binary = atob(base64);
@@ -430,7 +501,9 @@ function createWasiImports({
430
501
  "--method",
431
502
  request.method,
432
503
  "--search",
433
- url.search
504
+ url.search,
505
+ "--url",
506
+ url.href
434
507
  ];
435
508
  request.headers.forEach((value, name) => {
436
509
  if (value)
@@ -883,6 +956,7 @@ async function run({
883
956
  __zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder, wsState),
884
957
  __zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
885
958
  __zx_db: createD1Imports(dbBindings ?? {}, mem),
959
+ __zx_net: createFetchImports(mem),
886
960
  ...imports ? imports(mem) : {},
887
961
  ...ZxWasiBridge.createImportObject(bridgeRef)
888
962
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ziex",
3
- "version": "0.1.0-dev.1259",
3
+ "version": "0.1.0-dev.1360",
4
4
  "description": "Ziex is a framework for building web applications with Zig.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -37,7 +37,7 @@
37
37
  "license": "MIT",
38
38
  "scripts": {},
39
39
  "dependencies": {
40
- "@ziex/cli": "0.1.0-dev.1259"
40
+ "@ziex/cli": "0.1.0-dev.1360"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "react": {
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Create a `fetch` import object for blocking WASM fetch via JSPI.
3
+ * When JSPI is unavailable the import always returns -1 (network error).
4
+ */
5
+ export declare function createFetchImports(getMemory: () => WebAssembly.Memory): Record<string, unknown>;
@@ -49,8 +49,8 @@ export declare class ZxBridgeCore {
49
49
  * Calls __zx_fetch_complete when done.
50
50
  */
51
51
  fetchAsync(urlPtr: number, urlLen: number, methodPtr: number, methodLen: number, headersPtr: number, headersLen: number, bodyPtr: number, bodyLen: number, timeoutMs: number, fetchId: bigint): void;
52
- /** Notify WASM that a fetch completed */
53
- protected _notifyFetchComplete(fetchId: bigint, statusCode: number, body: string, isError: boolean): void;
52
+ /** Notify WASM that a fetch completed. `body` is raw bytes on success, text on error. */
53
+ protected _notifyFetchComplete(fetchId: bigint, statusCode: number, body: string | Uint8Array, isError: boolean): void;
54
54
  /** Set a timeout and callback when it fires */
55
55
  setTimeout(callbackId: bigint, delayMs: number): void;
56
56
  /** Set an interval and callback each time it fires */
@@ -14,7 +14,7 @@ export declare class ZxBridge extends ZxBridgeCore {
14
14
  setEventHandlerMode(velementId: bigint, eventTypeId: number, maySuspend: boolean): void;
15
15
  clearEventHandlerModes(velementId: bigint): void;
16
16
  /** Submit a form action with bound-state round-trip. */
17
- submitFormActionAsync(form: HTMLFormElement, statesJson: string, fetchId: bigint): void;
17
+ submitFormActionAsync(form: HTMLFormElement, actionId: number, statesJson: string, fetchId: bigint): void;
18
18
  /**
19
19
  * Create and connect a WebSocket.
20
20
  * Calls __zx_ws_onopen, __zx_ws_onmessage, __zx_ws_onerror, __zx_ws_onclose.
@@ -58,6 +58,7 @@ export declare function init(options?: InitOptions): Promise<{
58
58
  bridge: ZxBridge;
59
59
  }>;
60
60
  declare global {
61
+ const __DEV__: boolean;
61
62
  interface HTMLElement {
62
63
  __zx_ref?: number;
63
64
  }
@@ -0,0 +1 @@
1
+ export * from './zigjs';
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Predefined references.
3
+ * */
4
+ export declare const predefined: {
5
+ nan: number;
6
+ null: number;
7
+ true: number;
8
+ false: number;
9
+ undefined: number;
10
+ globalThis: number;
11
+ runtime: number;
12
+ };
13
+ /**
14
+ * The main state.
15
+ * */
16
+ export declare class ZigJS {
17
+ /**
18
+ * Set this to the memory of your WebAssembly instance prior to making
19
+ * any Wasm calls that might interface with JS.
20
+ *
21
+ * We have to use a Memory object directly (rather than an ArrayBuffer)
22
+ * so that we can always access memory even if it is resized. Otherwise,
23
+ * a resize could detach the array buffer.
24
+ * */
25
+ memory?: WebAssembly.Memory;
26
+ /**
27
+ * The values, indexed by ID (number). Duplicate values can be in this
28
+ * if they are loaded multiple times. That just acts as duplicate references.
29
+ * */
30
+ private values;
31
+ /**
32
+ * When a value is removed from the values array, its ID is put
33
+ * in the pool so that we can use it next. This avoids fragmentation in
34
+ * our array keys.
35
+ * */
36
+ private idPool;
37
+ /**
38
+ * Returns the import object that should be merged with your import
39
+ * object when instantiating your wasm instance. This injects the required
40
+ * functions into the wasm environment.
41
+ * */
42
+ importObject(): ImportObject;
43
+ /**
44
+ * Get a value from the JS environment.
45
+ * */
46
+ protected valueGet(out: number, id: number, ptr: number, len: number): void;
47
+ /**
48
+ * Set a value on an object.
49
+ * */
50
+ protected valueSet(id: number, ptr: number, len: number, refAddr: number): void;
51
+ /**
52
+ * Dereference a value, allowing the JS environment to potentially GC it.
53
+ * */
54
+ protected valueDeinit(id: number): void;
55
+ /**
56
+ * Create an empty object.
57
+ * */
58
+ protected valueObjectCreate(out: number): void;
59
+ /**
60
+ * Creates a string on the JS side from a UTF-8 encoded string in wasm memory.
61
+ * */
62
+ protected valueStringCreate(out: number, ptr: number, len: number): void;
63
+ /**
64
+ * Returns the length of the string given by id.
65
+ * */
66
+ protected valueStringLen(id: number): number;
67
+ /**
68
+ * Copy the string at id "id" into the shared memory at ptr.
69
+ * */
70
+ protected valueStringCopy(id: number, ptr: number, max: number): void;
71
+ /**
72
+ * Call a constructor given by id.
73
+ * */
74
+ protected valueNew(out: number, id: number, argsAddr: number, argsLen: number): void;
75
+ /**
76
+ * Call a function given by id.
77
+ * */
78
+ protected funcApply(out: number, id: number, thisRefAddr: number, argsAddr: number, argsLen: number): void;
79
+ /**
80
+ * This can be used to load a value given by an ID. A WASM function
81
+ * might return a value as an ID. This can be used to retrieve it.
82
+ * */
83
+ loadValue(id: number): any;
84
+ /**
85
+ * This removes the value from the values list and returns it. This
86
+ * will not remove predefined values but can still be used to retrieve
87
+ * them.
88
+ * */
89
+ deleteValue(id: number): any;
90
+ loadRef(refAddr: number): any;
91
+ loadRefId(refAddr: number): number;
92
+ storeValue(out: number, val: any): void;
93
+ loadString(ptr: number, len: number): string;
94
+ }
95
+ export interface ImportObject {
96
+ "zig-js": {
97
+ valueGet: (out: number, id: number, ptr: number, len: number) => void;
98
+ valueSet: (id: number, ptr: number, len: number, valueRef: number) => void;
99
+ valueObjectCreate: (out: number) => void;
100
+ valueStringCreate: (out: number, ptr: number, len: number) => void;
101
+ valueStringLen: (id: number) => number;
102
+ valueStringCopy: (id: number, ptr: number, max: number) => void;
103
+ valueDeinit: (id: number) => void;
104
+ valueNew: (out: number, funcId: number, argsPtr: number, argsLen: number) => void;
105
+ funcApply: (out: number, funcId: number, thisRef: number, argsPtr: number, argsLen: number) => void;
106
+ };
107
+ }