diff --git a/.gitignore b/.gitignore
index 10e1fd84..d1c96cf2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,6 @@ target
!tests/**/*.wasm
examples/*.toml
.DS_Store
-.wws
\ No newline at end of file
+.wws
+**/zig-cache
+**/zig-out
\ No newline at end of file
diff --git a/README.md b/README.md
index c71c3540..87cdbebc 100644
--- a/README.md
+++ b/README.md
@@ -99,7 +99,7 @@ Wasm Workers Server focuses on simplicity. We want you to run workers (written i
| Go | ✅ | No | [#95](https://github.com/vmware-labs/wasm-workers-server/issues/95) |
| Ruby | ✅ | [Yes](https://workers.wasmlabs.dev/docs/languages/ruby#installation) | [#63](https://github.com/vmware-labs/wasm-workers-server/issues/63) |
| Python | ✅ | [Yes](https://workers.wasmlabs.dev/docs/languages/python#installation) | [#63](https://github.com/vmware-labs/wasm-workers-server/issues/63) |
-| Zig | 🚧 | No | [#144](https://github.com/vmware-labs/wasm-workers-server/issues/144) |
+| Zig | ✅ | No | [#144](https://github.com/vmware-labs/wasm-workers-server/issues/144) |
| PHP | 🚧 | No | [#100](https://github.com/vmware-labs/wasm-workers-server/issues/100) |
To get more information about multi-language support in Wasm Workers Server, [check our documentation](https://workers.wasmlabs.dev/docs/languages/introduction).
diff --git a/docs/docs/features/all.md b/docs/docs/features/all.md
index 7b9b120a..c2a9ff66 100644
--- a/docs/docs/features/all.md
+++ b/docs/docs/features/all.md
@@ -36,3 +36,4 @@ The following table shows the language compatibility for the different worker fu
| Go | ✅ | ✅ | ✅ | ✅ | ✅ |
| Ruby | ✅ | ✅ | ✅ | ✅ | ❌ |
| Python | ✅ | ✅ | ✅ | ✅ | ❌ |
+| Zig | ✅ | ❌ | ✅ | ✅ | ❌ |
diff --git a/docs/docs/features/dynamic-routes.md b/docs/docs/features/dynamic-routes.md
index 41ea9872..7c0724b9 100644
--- a/docs/docs/features/dynamic-routes.md
+++ b/docs/docs/features/dynamic-routes.md
@@ -27,6 +27,7 @@ Check these guides to understand how to read parameters in the different support
* [Dynamic routes in Python](../languages/python.md#dynamic-routes)
* [Dynamic routes in Ruby](../languages/ruby.md#dynamic-routes)
* [Dynamic routes in Go](../languages/go.md#dynamic-routes)
+* [Dynamic routes in Zig](../languages/zig.md#dynamic-routes)
## Dynamic routes and folders
@@ -64,3 +65,4 @@ In this case, the `./[resource]/[id]/show.js` worker replies to URLs like `/arti
| Go | ✅ |
| Ruby | ✅ |
| Python | ✅ |
+| Zig | ✅ |
diff --git a/docs/docs/features/environment-variables.md b/docs/docs/features/environment-variables.md
index aeefefc5..fea3fdfd 100644
--- a/docs/docs/features/environment-variables.md
+++ b/docs/docs/features/environment-variables.md
@@ -50,3 +50,4 @@ This feature allows you to configure environment variables dynamically.
| Go | ✅ |
| Ruby | ✅ |
| Python | ✅ |
+| Zig | ❌ |
diff --git a/docs/docs/features/http-requests.md b/docs/docs/features/http-requests.md
index 30695083..d1abda7a 100644
--- a/docs/docs/features/http-requests.md
+++ b/docs/docs/features/http-requests.md
@@ -44,3 +44,4 @@ Check these guides to perform HTTP requests in the different supported languages
| Go | ✅ |
| Ruby | ❌ |
| Python | ❌ |
+| Zig | ❌ |
diff --git a/docs/docs/features/key-value.md b/docs/docs/features/key-value.md
index de2bf483..b46e40bb 100644
--- a/docs/docs/features/key-value.md
+++ b/docs/docs/features/key-value.md
@@ -21,6 +21,7 @@ The worker may access all the data and perform changes over it. Then, a new K/V
* [Add a K/V store to Python workers](../languages/python.md#add-a-key--value-store)
* [Add a K/V store to Ruby workers](../languages/ruby.md#add-a-key--value-store)
* [Add a K/V store to Go workers](../languages/go.md#add-a-key--value-store)
+* [Add a K/V store to Zig workers](../languages/zig.md#add-a-key--value-store)
## Limitations
@@ -35,3 +36,4 @@ A known limitation of the snapshot approach is the data override when concurrent
| Go | ✅ |
| Ruby | ✅ |
| Python | ✅ |
+| Zig | ✅ |
diff --git a/docs/docs/features/mount-folders.md b/docs/docs/features/mount-folders.md
index 10b169be..12f1c1d2 100644
--- a/docs/docs/features/mount-folders.md
+++ b/docs/docs/features/mount-folders.md
@@ -49,3 +49,4 @@ Note that those folders may include files that `wws` recognizes as workers (like
| Go | ✅ |
| Ruby | ✅ |
| Python | ✅ |
+| Zig | ✅ |
diff --git a/docs/docs/languages/zig.md b/docs/docs/languages/zig.md
new file mode 100644
index 00000000..c1a97eed
--- /dev/null
+++ b/docs/docs/languages/zig.md
@@ -0,0 +1,345 @@
+---
+sidebar_position: 6
+---
+
+# Zig
+
+Zig workers are tested with Zig version `0.11.0`. Then, they are loaded by Wasm Workers Server and start processing requests.
+
+## Your first Zig worker
+
+The recommended way to implement workers is by using the `worker.ServeFunc` function.
+
+In this example, the worker will get a request and print all the related information.
+
+1. Create a new Zig project:
+
+ ```shell-session
+ zig init-exe
+ ```
+
+2. Add Wasm Workers Server Zig dependency
+
+ At this point in time Zigs Package manager is not yet available. We will therefore clone the repository to make the library locally available.
+
+ ```shell-session
+ mkdir lib
+ wget -O ./lib/worker.zig https://raw.githubusercontent.com/vmware-labs/wasm-workers-server/main/kits/zig/worker/worker.zig
+ ```
+
+3. Edit the `src/main.zig` to match the following contents:
+
+ ```c title="worker.zig"
+ const std = @import("std");
+ const worker = @import("worker");
+
+ fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+ _ = r;
+
+ _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
+ _ = &resp.writeAll("hello from zig");
+ }
+
+ pub fn main() !void {
+ worker.ServeFunc(requestFn);
+ }
+ ```
+
+4. Additionally, you can now go further add all the information from the received `worker.Request`:
+
+ ```c title="worker.zig"
+ const std = @import("std");
+ const worker = @import("worker");
+
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ const allocator = arena.allocator();
+
+ fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+ std.debug.print("Hello from function\n", .{ });
+
+ // // TODO: prepare to read request body and send it back
+ std.debug.print("+++ doing payload \n", .{ });
+
+ var payload: []const u8 = "";
+ var reqBody = r.data;
+
+ if (reqBody.len == 0) {
+ payload = "-";
+ } else {
+ payload = reqBody;
+ }
+
+ const s =
+ \\
+ \\
+ \\Wasm Workers Server
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\Hello from Wasm Workers Server 👋
+ \\Replying to {s}
+ \\Method: {s}
+ \\User Agent: {s}
+ \\Payload: {s}
+ \\
+ \\This page was generated by a Zig⚡️ file running in WebAssembly.
+ \\
+ \\
+ \\
+ ;
+
+ var body = std.fmt.allocPrint(allocator, s, .{ r.url.path, r.method, "-", payload }) catch undefined;
+
+ _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
+ _ = &resp.writeAll(body);
+ }
+
+ pub fn main() !void {
+ worker.ServeFunc(requestFn);
+ }
+ ```
+
+5. Compile the project
+
+ ```shell-session
+ zig build-exe src/main.zig \
+ --name worker \
+ -mexec-model=reactor \
+ -target wasm32-wasi \
+ --mod worker::lib/worker.zig \
+ --deps worker
+ ```
+
+ You can also use a build script to build the project with a simple `zig build`, please find some inspiration in our [zig examples](https://github.com/vmware-labs/wasm-workers-server/tree/main/examples/).
+
+6. Run your worker with `wws`. If you didn't download the `wws` server yet, check our [Getting Started](../get-started/quickstart.md) guide.
+
+ ```shell-session
+ wws .
+
+ ⚙️ Loading routes from: .
+ 🗺 Detected routes:
+ - http://127.0.0.1:8080/worker
+ => worker.wasm (name: default)
+ 🚀 Start serving requests at http://127.0.0.1:8080
+ ```
+
+7. Finally, open in your browser.
+
+## Add a Key / Value store
+
+Wasm Workers allows you to add a Key / Value store to your workers. Read more information about this feature in the [Key / Value store](../features/key-value.md) section.
+
+To add a KV store to your worker, follow these steps:
+
+1. Create a new Zig project:
+
+ ```shell-session
+ zig init-exe
+ ```
+
+2. Add Wasm Workers Server Zig dependency
+
+ At this point in time Zigs Package manager is not yet available. We will therefore clone the repository to make the library locally available.
+
+ ```shell-session
+ mkdir lib
+ wget -O ./lib/worker.zig https://raw.githubusercontent.com/vmware-labs/wasm-workers-server/main/kits/zig/worker/worker.zig ./lib
+ ```
+
+1. Edit `src/main.zig` file with the following contents:
+
+ ```c title="main.zig"
+ const std = @import("std");
+ const worker = @import("worker");
+
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ const allocator = arena.allocator();
+
+ fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+ var cache = r.context.cache;
+ var counter: i32 = 0;
+
+ var v = cache.getOrPut("counter") catch undefined;
+
+ if (!v.found_existing) {
+ v.value_ptr.* = "0";
+ } else {
+ var counterValue = v.value_ptr.*;
+ var num = std.fmt.parseInt(i32, counterValue, 10) catch undefined;
+ counter = num + 1;
+ var num_s = std.fmt.allocPrint(allocator, "{d}", .{ counter }) catch undefined;
+ _ = cache.put("counter", num_s) catch undefined;
+ }
+
+ const s =
+ \\
+ \\
+ \\
+ \\Wasm Workers Server - KV example
+ \\
+ \\
+ \\
+ \\
+ \\Key / Value store in Zig
+ \\Counter: {d}
+ \\This page was generated by a Zig⚡️ file running in WebAssembly.
+ \\
+ ;
+
+ var body = std.fmt.allocPrint(allocator, s, .{ counter }) catch undefined; // add useragent
+
+ _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
+ _ = &resp.writeAll(body);
+ }
+
+ pub fn main() !void {
+ worker.ServeFunc(requestFn);
+ }
+ ```
+
+5. Compile the project
+
+ ```shell-session
+ zig build-exe src/main.zig \
+ --name worker-kv \
+ -mexec-model=reactor \
+ -target wasm32-wasi \
+ --mod worker::lib/worker.zig \
+ --deps worker
+ ```
+
+ You can also use a build script to build the project with a simple `zig build`, please find some inspiration in our [zig examples](https://github.com/vmware-labs/wasm-workers-server/tree/main/examples/).
+
+1. Create a `worker-kv.toml` file with the following content. Note the name of the TOML file must match the name of the worker. In this case we have `worker-kv.wasm` and `worker-kv.toml` in the same folder:
+
+ ```toml title="worker-kv.toml"
+ name = "workerkv"
+ version = "1"
+
+ [data]
+ [data.kv]
+ namespace = "workerkv"
+ ```
+
+1. Run your worker with `wws`. If you didn't download the `wws` server yet, check our [Getting Started](../get-started/quickstart.md) guide.
+
+ ```shell-session
+ wws .
+
+ ⚙️ Loading routes from: .
+ 🗺 Detected routes:
+ - http://127.0.0.1:8080/worker-kv
+ => worker-kv.wasm (name: default)
+ 🚀 Start serving requests at http://127.0.0.1:8080
+ ```
+
+1. Finally, open in your browser.
+
+
+## Dynamic routes
+
+You can define [dynamic routes by adding route parameters to your worker files](../features/dynamic-routes.md) (like `[id].wasm`). To read them in Zig, follow these steps:
+
+1. Use the `worker.ParamsKey` context value to read in the passed in parameters:
+
+ ```c title="main.zig"
+ const std = @import("std");
+ const worker = @import("worker");
+
+ fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+ var params = r.context.params;
+
+ ...
+ }
+ ```
+
+2. Then, you can read the values as follows:
+
+ ```c title="main.zig"
+ const std = @import("std");
+ const worker = @import("worker");
+
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ const allocator = arena.allocator();
+
+ fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+ var params = r.context.params;
+
+ var id: []const u8 = "the value is not available";
+
+ var v = params.get("id");
+
+ if (v) |val| {
+ id = val;
+ }
+
+ const s =
+ \\Hey! The parameter is: {s}
+ ;
+
+ var body = std.fmt.allocPrint(allocator, s, .{ id }) catch undefined; // add useragent
+
+ _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
+ _ = &resp.writeAll(body);
+ }
+
+ pub fn main() !void {
+ worker.ServeFunc(requestFn);
+ }
+ ```
+
+3. Compile the project
+
+ ```shell-session
+ zig build-exe src/main.zig \
+ --name "[id]" \
+ -mexec-model=reactor \
+ -target wasm32-wasi \
+ --mod worker::lib/worker.zig \
+ --deps worker
+ ```
+
+ You can also use a build script to build the project with a simple `zig build`, please find some inspiration in our [zig examples](https://github.com/vmware-labs/wasm-workers-server/tree/main/examples/).
+
+4. Run your worker with `wws`. If you didn't download the `wws` server yet, check our [Getting Started](../get-started/quickstart.md) guide.
+
+ ```shell-session
+ wws .
+
+ ⚙️ Loading routes from: .
+ 🗺 Detected routes:
+ - http://127.0.0.1:8080/[id]
+ => worker-kv.wasm (name: default)
+ 🚀 Start serving requests at http://127.0.0.1:8080
+ ```
+
+5. Finally, open in your browser.
+
+## Other examples
+
+Find other examples in the [`/examples` directory](https://github.com/vmware-labs/wasm-workers-server/tree/main/examples/) of wasm-workers-server repository.
+
+## Contributors
+
+The Zig kit was originally authored by Christoph Voigt ([@voigt](https://github.com/voigt)).
+
+## Feature compatibility
+
+[Workers' features](../features/all.md) that are available in Zig:
+
+| [K/V Store](../features/key-value.md) | [Environment Variables](../features/environment-variables.md) | [Dynamic Routes](../features/dynamic-routes.md) | [Folders](../features/mount-folders.md) | [HTTP Requests](../features/http-requests.md) |
+| --- | --- | --- | --- | --- |
+| ✅ | ❌ | ✅ | ❓ | ❌ |
diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css
index 08b1d584..2b079819 100644
--- a/docs/src/css/custom.css
+++ b/docs/src/css/custom.css
@@ -104,3 +104,7 @@ a.menu__link[href*="languages/rust"]::before {
a.menu__link[href*="languages/go"]::before {
background-image: url(/img/languages/go.svg);
}
+
+a.menu__link[href*="languages/zig"]::before {
+ background-image: url(/img/languages/zig.svg);
+}
diff --git a/docs/static/img/languages/zig.svg b/docs/static/img/languages/zig.svg
new file mode 100644
index 00000000..defec920
--- /dev/null
+++ b/docs/static/img/languages/zig.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/README.md b/examples/README.md
index bfcfc0c1..5794dde8 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -16,3 +16,4 @@ Every example includes a `README.md` file with all the instructions.
* [Python documentation](https://workers.wasmlabs.dev/docs/languages/python)
* [Ruby documentation](https://workers.wasmlabs.dev/docs/languages/ruby)
* [Go documentation](https://workers.wasmlabs.dev/docs/languages/go)
+* [Zig documentation](https://workers.wasmlabs.dev/docs/languages/zig)
diff --git a/examples/zig-basic/README.md b/examples/zig-basic/README.md
new file mode 100644
index 00000000..c6f1305e
--- /dev/null
+++ b/examples/zig-basic/README.md
@@ -0,0 +1,32 @@
+# Basic example
+
+Compile a Zig worker to WebAssembly and run it in Wasm Workers Server.
+
+## Prerequisites
+
+* Wasm Workers Server (wws):
+
+ ```shell-session
+ curl -fsSL https://workers.wasmlabs.dev/install | bash
+ ```
+
+* [Zig](https://ziglang.org/download/) `0.11.0`
+
+## Build
+
+All specific build confiugrations are in `build.zig` file.
+
+```shell-session
+zig build
+```
+
+## Run
+
+```shell-session
+wws ./zig-out/bin/
+```
+
+## Resources
+
+* [Zig documentation](https://workers.wasmlabs.dev/docs/languages/zig)
+* [Announcing Zig support for Wasm Workers Server](https://wasmlabs.dev/articles/Zig-support-on-wasm-workers-server/)
diff --git a/examples/zig-basic/build.zig b/examples/zig-basic/build.zig
new file mode 100644
index 00000000..a59f70d6
--- /dev/null
+++ b/examples/zig-basic/build.zig
@@ -0,0 +1,26 @@
+const std = @import("std");
+
+const examples = [1][]const u8{ "basic" };
+
+pub fn build(b: *std.Build) !void {
+ const target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = "wasm32-wasi" });
+ const optimize = b.standardOptimizeOption(.{});
+
+ const worker_module = b.createModule(.{
+ .source_file = .{ .path = "../../kits/zig/worker/src/worker.zig" },
+ });
+
+ inline for (examples) |example| {
+ const exe = b.addExecutable(.{
+ .name = example,
+ .root_source_file = .{ .path = "src/" ++ example ++ ".zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+
+ exe.wasi_exec_model = .reactor;
+ exe.addModule("worker", worker_module);
+
+ b.installArtifact(exe);
+ }
+}
diff --git a/examples/zig-basic/src/basic.zig b/examples/zig-basic/src/basic.zig
new file mode 100644
index 00000000..77268184
--- /dev/null
+++ b/examples/zig-basic/src/basic.zig
@@ -0,0 +1,57 @@
+const std = @import("std");
+const worker = @import("worker");
+
+var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+const allocator = arena.allocator();
+
+fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+
+ var payload: []const u8 = "";
+ var reqBody = r.body;
+
+ if (reqBody.len == 0) {
+ payload = "-";
+ } else {
+ payload = reqBody;
+ }
+
+ const s =
+ \\
+ \\
+ \\Wasm Workers Server
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\
+ \\Hello from Wasm Workers Server 👋
+ \\Replying to {s}
+ \\Method: {s}
+ \\User Agent: {s}
+ \\Payload: {s}
+ \\
+ \\This page was generated by a Zig⚡️ file running in WebAssembly.
+ \\
+ \\
+ \\
+ ;
+
+ var body = std.fmt.allocPrint(allocator, s, .{ r.url.path, r.method, "-", payload }) catch undefined; // add useragent
+
+ _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
+ _ = &resp.writeAll(body);
+}
+
+pub fn main() !void {
+ worker.ServeFunc(requestFn);
+}
diff --git a/examples/zig-kv/README.md b/examples/zig-kv/README.md
new file mode 100644
index 00000000..2230a277
--- /dev/null
+++ b/examples/zig-kv/README.md
@@ -0,0 +1,33 @@
+# Key/Value example
+
+Compile a Zig worker to WebAssembly and run it in Wasm Workers Server.
+
+## Prerequisites
+
+* Wasm Workers Server (wws):
+
+ ```shell-session
+ curl -fsSL https://workers.wasmlabs.dev/install | bash
+ ```
+
+* [Zig](https://ziglang.org/download/) `0.11.0`
+
+## Build
+
+All specific build confiugrations are in `build.zig` file.
+
+```shell-session
+zig build
+```
+
+## Run
+
+```shell-session
+wws ./zig-out/bin/
+```
+
+## Resources
+
+* [Key / Value store](https://workers.wasmlabs.dev/docs/features/key-value)
+* [Zig documentation](https://workers.wasmlabs.dev/docs/languages/zig)
+* [Announcing Zig support for Wasm Workers Server](https://wasmlabs.dev/articles/Zig-support-on-wasm-workers-server/)
diff --git a/examples/zig-kv/build.zig b/examples/zig-kv/build.zig
new file mode 100644
index 00000000..8f5b624a
--- /dev/null
+++ b/examples/zig-kv/build.zig
@@ -0,0 +1,26 @@
+const std = @import("std");
+
+const examples = [1][]const u8{ "worker-kv" };
+
+pub fn build(b: *std.Build) !void {
+ const target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = "wasm32-wasi" });
+ const optimize = b.standardOptimizeOption(.{});
+
+ const worker_module = b.createModule(.{
+ .source_file = .{ .path = "../../kits/zig/worker/src/worker.zig" },
+ });
+
+ inline for (examples) |example| {
+ const exe = b.addExecutable(.{
+ .name = example,
+ .root_source_file = .{ .path = "src/" ++ example ++ ".zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+
+ exe.wasi_exec_model = .reactor;
+ exe.addModule("worker", worker_module);
+
+ b.installArtifact(exe);
+ }
+}
diff --git a/examples/zig-kv/src/worker-kv.zig b/examples/zig-kv/src/worker-kv.zig
new file mode 100644
index 00000000..3f1bcd78
--- /dev/null
+++ b/examples/zig-kv/src/worker-kv.zig
@@ -0,0 +1,46 @@
+const std = @import("std");
+const worker = @import("worker");
+
+var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+const allocator = arena.allocator();
+
+fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+ var cache = r.context.cache;
+ var counter: i32 = 0;
+
+ var v = cache.getOrPut("counter") catch undefined;
+
+ if (!v.found_existing) {
+ v.value_ptr.* = "0";
+ } else {
+ var counterValue = v.value_ptr.*;
+ var num = std.fmt.parseInt(i32, counterValue, 10) catch undefined;
+ counter = num + 1;
+ var num_s = std.fmt.allocPrint(allocator, "{d}", .{ counter }) catch undefined;
+ _ = cache.put("counter", num_s) catch undefined;
+ }
+
+ const s =
+ \\
+ \\
+ \\
+ \\Wasm Workers Server - KV example
+ \\
+ \\
+ \\
+ \\
+ \\Key / Value store in Zig
+ \\Counter: {d}
+ \\This page was generated by a Zig⚡️ file running in WebAssembly.
+ \\
+ ;
+
+ var body = std.fmt.allocPrint(allocator, s, .{ counter }) catch undefined; // add useragent
+
+ _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
+ _ = &resp.writeAll(body);
+}
+
+pub fn main() !void {
+ worker.ServeFunc(requestFn);
+}
diff --git a/examples/zig-kv/zig-out/bin/worker-kv.toml b/examples/zig-kv/zig-out/bin/worker-kv.toml
new file mode 100644
index 00000000..d1987525
--- /dev/null
+++ b/examples/zig-kv/zig-out/bin/worker-kv.toml
@@ -0,0 +1,6 @@
+name = "workerkv"
+version = "1"
+
+[data]
+[data.kv]
+namespace = "workerkv"
\ No newline at end of file
diff --git a/examples/zig-params/README.md b/examples/zig-params/README.md
new file mode 100644
index 00000000..220ee921
--- /dev/null
+++ b/examples/zig-params/README.md
@@ -0,0 +1,33 @@
+# Params example
+
+Compile a Zig worker to WebAssembly and run it in Wasm Workers Server.
+
+## Prerequisites
+
+* Wasm Workers Server (wws):
+
+ ```shell-session
+ curl -fsSL https://workers.wasmlabs.dev/install | bash
+ ```
+
+* [Zig](https://ziglang.org/download/) `0.11.0`
+
+## Build
+
+All specific build confiugrations are in `build.zig` file.
+
+```shell-session
+zig build
+```
+
+## Run
+
+```shell-session
+wws ./zig-out/bin/
+```
+
+## Resources
+
+* [Dynamic routes](https://workers.wasmlabs.dev/docs/features/dynamic-routes)
+* [Zig documentation](https://workers.wasmlabs.dev/docs/languages/zig)
+* [Announcing Zig support for Wasm Workers Server](https://wasmlabs.dev/articles/Zig-support-on-wasm-workers-server/)
diff --git a/examples/zig-params/build.zig b/examples/zig-params/build.zig
new file mode 100644
index 00000000..657dc469
--- /dev/null
+++ b/examples/zig-params/build.zig
@@ -0,0 +1,26 @@
+const std = @import("std");
+
+const examples = [1][]const u8{ "worker-params" };
+
+pub fn build(b: *std.Build) !void {
+ const target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = "wasm32-wasi" });
+ const optimize = b.standardOptimizeOption(.{});
+
+ const worker_module = b.createModule(.{
+ .source_file = .{ .path = "../../kits/zig/worker/src/worker.zig" },
+ });
+
+ inline for (examples) |example| {
+ const exe = b.addExecutable(.{
+ .name = example,
+ .root_source_file = .{ .path = "src/" ++ example ++ ".zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+
+ exe.wasi_exec_model = .reactor;
+ exe.addModule("worker", worker_module);
+
+ b.installArtifact(exe);
+ }
+}
diff --git a/examples/zig-params/src/worker-params.zig b/examples/zig-params/src/worker-params.zig
new file mode 100644
index 00000000..a571d28b
--- /dev/null
+++ b/examples/zig-params/src/worker-params.zig
@@ -0,0 +1,30 @@
+const std = @import("std");
+const worker = @import("worker");
+
+var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+const allocator = arena.allocator();
+
+fn requestFn(resp: *worker.Response, r: *worker.Request) void {
+ var params = r.context.params;
+
+ var id: []const u8 = "the value is not available";
+
+ var v = params.get("id");
+
+ if (v) |val| {
+ id = val;
+ }
+
+ const s =
+ \\Hey! The parameter is: {s}
+ ;
+
+ var body = std.fmt.allocPrint(allocator, s, .{ id }) catch undefined; // add useragent
+
+ _ = &resp.headers.append("x-generated-by", "wasm-workers-server");
+ _ = &resp.writeAll(body);
+}
+
+pub fn main() !void {
+ worker.ServeFunc(requestFn);
+}
diff --git a/kits/zig/worker/README.md b/kits/zig/worker/README.md
new file mode 100644
index 00000000..403fd470
--- /dev/null
+++ b/kits/zig/worker/README.md
@@ -0,0 +1,49 @@
+# Zig kit
+
+This folder contains the Zig kit or SDK for Wasm Workers Server. Currently, it uses the regular STDIN / STDOUT approach to receive the request and provide the response.
+
+> *Note: this assumes Zig `0.11.0`*
+
+## Build
+
+To build all examples in ./examples
+
+```shell-session
+$ zig build -Dtarget="wasm32-wasi"
+```
+
+To build a specific example:
+
+```shell-session
+$ zig build-exe examples/.zig -target wasm32-wasi
+```
+
+## Testing
+
+At `./kits/zig/worker` execute:
+
+```shell-session
+$ zig build -Dtarget="wasm32-wasi"
+$ wws ./zig-out/bin/
+```
+
+## sockaddr issue
+
+Using `http.Server.Response` was unsuccessful and lead to following error:
+
+```
+$ worker git:(144_-_add_support_for_zig) ✗ zig build -Dtarget="wasm32-wasi"
+zig build-exe main Debug wasm32-wasi: error: the following command failed with 1 compilation errors:
+/Users/c.voigt/.asdf/installs/zig/0.11.0/zig build-exe /Users/c.voigt/go/src/github.com/voigt/wasm-workers-server/kits/zig/worker/examples/main.zig --cache-dir /Users/c.voigt/go/src/github.com/voigt/wasm-workers-server/kits/zig/worker/zig-cache --global-cache-dir /Users/c.voigt/.cache/zig --name main -target wasm32-wasi -mcpu generic --mod worker::/Users/c.voigt/go/src/github.com/voigt/wasm-workers-server/kits/zig/worker/src/worker.zig --deps worker --listen=-
+Build Summary: 6/9 steps succeeded; 1 failed (disable with --summary none)
+install transitive failure
+└─ install main transitive failure
+ └─ zig build-exe main Debug wasm32-wasi 1 errors
+/Users/c.voigt/.asdf/installs/zig/0.11.0/lib/std/os.zig:182:28: error: root struct of file 'os.wasi' has no member named 'sockaddr'
+pub const sockaddr = system.sockaddr;
+ ~~~~~~^~~~~~~~~
+referenced by:
+ Address: /Users/c.voigt/.asdf/installs/zig/0.11.0/lib/std/net.zig:18:12
+ Address: /Users/c.voigt/.asdf/installs/zig/0.11.0/lib/std/net.zig:17:28
+ remaining reference traces hidden; use '-freference-trace' to see all reference traces
+```
\ No newline at end of file
diff --git a/kits/zig/worker/src/worker.zig b/kits/zig/worker/src/worker.zig
new file mode 100644
index 00000000..197e1be3
--- /dev/null
+++ b/kits/zig/worker/src/worker.zig
@@ -0,0 +1,261 @@
+const std = @import("std");
+const io = std.io;
+const http = std.http;
+
+var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+const allocator = arena.allocator();
+
+pub var cache = std.StringHashMap([]const u8).init(allocator);
+pub var params = std.StringHashMap([]const u8).init(allocator);
+
+pub const Request = struct {
+ url: std.Uri,
+ method: []const u8, // TODO: change to http.Method enum
+ headers: http.Headers,
+ body: []const u8,
+ context: Context,
+};
+
+pub const Response = struct {
+ body: []const u8,
+ headers: http.Headers,
+ request: Request,
+
+ pub fn writeAll(res: *Response, data: []const u8) !u32 {
+ res.body = data;
+ return res.body.len;
+ }
+};
+
+// Note: as Zig does not support multiple return types, we use this struct
+// to wrap both the request and the output to keep code a bit more clean
+const RequestAndOutput = struct {
+ request: Request,
+ output: Output,
+};
+
+pub const Input = struct {
+ url: []const u8,
+ method: []const u8,
+ headers: std.StringArrayHashMap([]const u8),
+ body: []const u8,
+};
+
+pub const Output = struct {
+ data: []const u8,
+ headers: std.StringArrayHashMap([]const u8),
+ status: u16,
+ base64: bool,
+
+ httpHeader: http.Headers,
+
+ const Self = @This();
+
+ pub fn init() Self {
+ return .{
+ .data = "",
+ .headers = std.StringArrayHashMap([]const u8).init(allocator),
+ .status = 0,
+ .base64 = false,
+ .httpHeader = http.Headers.init(allocator),
+ };
+ }
+
+ pub fn header(self: *Self) http.Headers {
+ if (self.httpHeader == undefined) {
+ self.httpHeader = http.Headers.init(allocator);
+ }
+
+ return self.httpHeader;
+ }
+
+ pub fn setStatus(self: *Self, statusCode: u16) void {
+ self.status = statusCode;
+ }
+
+ pub fn write(self: *Self, data: []const u8) !u32 {
+ if (std.unicode.utf8ValidateSlice(data)) {
+ self.data = data;
+ } else {
+ self.base64 = true;
+ self.data = base64Encode(data);
+ }
+
+ if (self.status == 0) {
+ self.setStatus(200);
+ }
+
+ for (self.httpHeader.list.items) |item| {
+ try self.headers.put(item.name, item.value);
+ }
+
+ // prepare writer for json
+ var out_buf: [1024]u8 = undefined;
+ var slice_stream = std.io.fixedBufferStream(&out_buf);
+ const out = slice_stream.writer();
+ var w = std.json.writeStream(out, .{ .whitespace = .minified });
+
+ slice_stream.reset();
+ try w.beginObject();
+
+ try w.objectField("data");
+ try w.write(self.data);
+
+ try w.objectField("status");
+ try w.write(self.status);
+
+ try w.objectField("base64");
+ try w.write(self.base64);
+
+ try w.objectField("headers");
+ try w.write(try getHeadersJsonObject(self.headers));
+
+ try w.objectField("kv");
+ try w.write(try getCacheJsonObject(cache));
+
+ try w.endObject();
+ const result = slice_stream.getWritten();
+
+ // std.debug.print("\noutput json: {s}\n\n", .{ result });
+
+ const stdout = std.io.getStdOut().writer();
+ try stdout.print("{s}", .{ result });
+
+ return self.data.len;
+ }
+};
+
+fn base64Encode(data: []const u8) []const u8 {
+ // This initializing Base64Encoder throws weird error if not wrapped in function (maybe Zig bug?)
+ var enc = std.base64.Base64Encoder.init(std.base64.standard_alphabet_chars, '=');
+ var data_len = enc.calcSize(data.len);
+ var buf: [128]u8 = undefined;
+ return enc.encode(buf[0..data_len], data);
+}
+
+fn getHeadersJsonObject(s: std.StringArrayHashMap([]const u8)) !std.json.Value {
+ var value = std.json.Value{ .object = std.json.ObjectMap.init(allocator) };
+
+ var i = s.iterator();
+ while (i.next()) |kv| {
+ try value.object.put(kv.key_ptr.*, std.json.Value{ .string = kv.value_ptr.*});
+ }
+
+ return value;
+}
+
+fn getCacheJsonObject(s: std.StringHashMap([]const u8)) !std.json.Value {
+ var value = std.json.Value{ .object = std.json.ObjectMap.init(allocator) };
+
+ var i = s.iterator();
+ while (i.next()) |entry| {
+ try value.object.put(entry.key_ptr.*, std.json.Value{ .string = entry.value_ptr.*});
+ }
+
+ return value;
+}
+
+pub fn readInput() !Input {
+ const in = std.io.getStdIn();
+ var buf = std.io.bufferedReader(in.reader());
+ var r = buf.reader();
+
+ var msg = try r.readAllAlloc(allocator, std.math.maxInt(u32));
+ return getInput(msg);
+}
+
+fn getInput(s: []const u8) !Input {
+ var parsed = try std.json.parseFromSlice(std.json.Value, allocator, s, .{});
+ defer parsed.deinit();
+
+ var input = Input{
+ .url = parsed.value.object.get("url").?.string,
+ .method = parsed.value.object.get("method").?.string,
+ .body = parsed.value.object.get("body").?.string,
+ .headers = std.StringArrayHashMap([]const u8).init(allocator),
+ };
+
+ var headers_map = parsed.value.object.get("headers").?.object;
+ var headersIterator = headers_map.iterator();
+ while (headersIterator.next()) |entry| {
+ try input.headers.put(entry.key_ptr.*, entry.value_ptr.*.string);
+ }
+
+ var kv = parsed.value.object.get("kv").?.object;
+ var kvIterator = kv.iterator();
+ while (kvIterator.next()) |entry| {
+ try cache.put(entry.key_ptr.*, entry.value_ptr.*.string);
+ }
+
+ var p = parsed.value.object.get("params").?.object;
+ var paramsIterator = p.iterator();
+ while (paramsIterator.next()) |entry| {
+ try params.put(entry.key_ptr.*, entry.value_ptr.*.string);
+ }
+
+ return input;
+}
+
+pub fn createRequest(in: *Input) !Request {
+ var req = Request{
+ .url = try std.Uri.parseWithoutScheme(in.url),
+ .method = in.method,
+ .headers = http.Headers.init(allocator),
+ .body = in.body,
+ .context = Context.init(),
+ };
+
+ var i = in.headers.iterator();
+ while (i.next()) |kv| {
+ try req.headers.append(kv.key_ptr.*, kv.value_ptr.*);
+ }
+
+ return req;
+}
+
+pub fn getWriterRequest() !RequestAndOutput {
+ var in = readInput() catch |err| {
+ std.debug.print("error reading input: {!}\n", .{err});
+ return std.os.exit(1);
+ };
+
+ var req = createRequest(&in) catch |err| {
+ std.debug.print("error creating request : {!}\n", .{err});
+ return std.os.exit(1);
+ };
+
+ var output = Output.init();
+
+ return RequestAndOutput{
+ .request = req,
+ .output = output,
+ };
+}
+
+pub const Context = struct {
+ cache: *std.StringHashMap([]const u8),
+ params: *std.StringHashMap([]const u8),
+
+ pub fn init() Context {
+ return .{
+ .cache = &cache,
+ .params = ¶ms,
+ };
+ }
+};
+
+pub fn ServeFunc(requestFn: *const fn (*Response, *Request) void) void {
+ var r = try getWriterRequest();
+ var request = r.request;
+ var output = r.output;
+
+ var response = Response{ .body = "", .headers = http.Headers.init(allocator), .request = request, };
+
+ requestFn(&response, &request);
+
+ output.httpHeader = response.headers;
+
+ _ = output.write(response.body) catch |err| {
+ std.debug.print("error writing data: {!} \n", .{ err });
+ };
+}