ziex 0.1.0-dev.628 → 0.1.0-dev.765
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.
- package/README.md +141 -149
- package/cloudflare/index.d.ts +2 -0
- package/cloudflare/index.js +383 -0
- package/cloudflare/kv.d.ts +19 -0
- package/cloudflare/worker.d.ts +39 -0
- package/index.js +21 -4
- package/package.json +5 -4
- package/react/index.js +11 -0
- package/wasm/index.js +16 -20
- package/wasm/init.js +5 -20
package/README.md
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Ziex
|
|
2
2
|
|
|
3
3
|
A full-stack web framework for Zig. Write declarative UI components using familiar JSX patterns, transpiled to efficient Zig code.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Ziex combines the power and performance of Zig with the expressiveness of JSX, enabling you to build fast, type-safe web applications.
|
|
6
6
|
|
|
7
7
|
**[Documentation →](https://ziex.dev/learn)**
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
|
|
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. 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.
|
|
12
|
+
|
|
13
|
+
|
|
9
14
|
## Installation
|
|
10
15
|
|
|
11
16
|
##### Linux/macOS
|
|
@@ -25,51 +30,45 @@ winget install -e --id zig.zig # Windows
|
|
|
25
30
|
```
|
|
26
31
|
[_See for other platforms →_](https://ziglang.org/learn/getting-started/)
|
|
27
32
|
|
|
28
|
-
## Quick Example
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
## At a Glance
|
|
35
|
+
|
|
36
|
+
```tsx site/pages/examples/playground.zx
|
|
37
|
+
pub fn Playground(allocator: zx.Allocator) zx.Component {
|
|
32
38
|
const is_loading = true;
|
|
33
|
-
const chars = "Hello, ZX Dev!";
|
|
34
39
|
var i: usize = 0;
|
|
40
|
+
|
|
35
41
|
return (
|
|
36
42
|
<main @allocator={allocator}>
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
</
|
|
44
|
-
|
|
45
|
-
<
|
|
46
|
-
{for (users) |user| (
|
|
47
|
-
<Profile name={user.name} age={user.age} role={user.role} />
|
|
48
|
-
)}
|
|
49
|
-
</section>
|
|
50
|
-
|
|
51
|
-
<section>
|
|
52
|
-
{while (i < 10) : (i += 1) (<p>{i}</p>)}
|
|
53
|
-
</section>
|
|
43
|
+
<h1>Hello, Ziex!</h1>
|
|
44
|
+
|
|
45
|
+
{for (users) |user| (
|
|
46
|
+
<Profile name={user.name} age={user.age} role={user.role} />
|
|
47
|
+
)}
|
|
48
|
+
|
|
49
|
+
{if (is_loading) (<p>Loading...</p>) else (<p>Loaded</p>)}
|
|
50
|
+
|
|
51
|
+
{while (i < 5) : (i += 1) (<i>{i}</i>)}
|
|
54
52
|
</main>
|
|
55
53
|
);
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
fn Profile(
|
|
56
|
+
fn Profile(ctx: *zx.ComponentCtx(User)) zx.Component {
|
|
59
57
|
return (
|
|
60
|
-
<div @allocator={allocator}>
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
<div @allocator={ctx.allocator}>
|
|
59
|
+
<h3>{ctx.props.name}</h3>
|
|
60
|
+
<div>{ctx.props.age}</div>
|
|
61
|
+
<strong>
|
|
62
|
+
{switch (ctx.props.role) {
|
|
63
|
+
.admin => "Admin",
|
|
64
|
+
.member => "Member",
|
|
65
|
+
}}
|
|
66
|
+
</strong>
|
|
67
67
|
</div>
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
const
|
|
72
|
-
const User = struct { name: []const u8, age: u32, role: UserRole };
|
|
71
|
+
const User = struct { name: []const u8, age: u32, role: enum { admin, member } };
|
|
73
72
|
|
|
74
73
|
const users = [_]User{
|
|
75
74
|
.{ .name = "John", .age = 20, .role = .admin },
|
|
@@ -78,123 +77,116 @@ const users = [_]User{
|
|
|
78
77
|
|
|
79
78
|
const zx = @import("zx");
|
|
80
79
|
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
|
|
163
|
-
##
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
* [
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
* [
|
|
187
|
-
* [
|
|
188
|
-
* [
|
|
189
|
-
* [zigomponent](https://zigomp.prjct.dev/) - HTML compoenents in pure zig
|
|
190
|
-
|
|
191
|
-
## Related Projects
|
|
192
|
-
|
|
193
|
-
* [Codeberg Mirror](https://codeberg.org/nurulhudaapon/zx) - ZX repository mirror on Codeberg
|
|
194
|
-
* [ziex.dev](https://github.com/nurulhudaapon/zx/tree/main/site) - Official documentation site of ZX made using ZX.
|
|
195
|
-
* [zx-example-portfolio](https://github.com/nurulhudaapon/zx-example-portfolio) - Demo portfolio web application built with ZX
|
|
196
|
-
* [thegates.dev](https://github.com/nurulhudaapon/thegates.dev) - Example clone demonstrating ZX capabilities
|
|
80
|
+
|
|
81
|
+
Try this in [Playground →](https://ziex.dev/playground#data=eF59U01vnDAQ_StTTtAiyGZVqSKAEuVSVa2USy8NUUTAu2sJbGQgoUv83ztjlo-y2_rCfLx5zMyze-uhSH_vlWxF7h07K7Cq9gV2AuawnRaFzNJGqgCOnXc3eg5597KspGCigT4RgCeTom6A18-FTHMu9hBBo1p2M2RfUwU8gLbmR4aZKwwPCcWaVgmwB49OWKZcwO3086ifTB3PMAM9bOKvDLMu_OKs-xD6GBiZx9PvpAK7rZmqHXin7_vydxPXg5I7XjAQacminnAemRrS_eijpUHJYvTJ1OCvunL0WQt8B_a8GgfssIq_D47neaFfxQ6womZTguUmeM70dqAebQ4hfHYgIOtTBBui5HHPdehzUzYWhD6t89Shg2s3lKTzMK6dNV0AH5eK3jed_RPHcy4LfUGxnL_-JRhyev8RbRsbRKVkVQ87RuG2axiSLnG0-9Cn4ApXN0qK_SpKp6_feJMdwJ5JSDBnHGR9vDQv8eZFMSTWHZmJ5f4DWbLyhakB-sPYF7Far3r1z5pdjjTJM7wl0gDfCpa0GW7fXMwAHp-GbPvFpZuJb2p77ZpLGQATbYlAM4cLpyY16JuZ1LwDZH18fiL-0yq8HowQmEisb_JAowOtHAPXV2gSP9qnFWn3Ulkq2LJssygbW8G6ZTPHDpO3HC-YauzEOnaJRTuw9B927V4U)
|
|
82
|
+
|
|
83
|
+
<details>
|
|
84
|
+
<summary>Explanation of this</summary>
|
|
85
|
+
|
|
86
|
+
```tsx site/pages/examples/playground.zx
|
|
87
|
+
// A Zig function that returns a `zx.Component`.
|
|
88
|
+
pub fn Playground(allocator: zx.Allocator) zx.Component {
|
|
89
|
+
const is_loading = true;
|
|
90
|
+
var i: usize = 0;
|
|
91
|
+
|
|
92
|
+
// HTML Block is always surrounded by parentheses and can contain HTML elements and control flow statements.
|
|
93
|
+
return (
|
|
94
|
+
// @allocator or any other attribute starting with `@` is called builtin attribute
|
|
95
|
+
// `@allocator` is used to specify the allocator for the component and its children for mem allocation.
|
|
96
|
+
<main @allocator={allocator}>
|
|
97
|
+
<h1>Hello, Ziex!</h1>
|
|
98
|
+
|
|
99
|
+
// `for` loop to iterate over `users` array and render a `Profile` component for each user.
|
|
100
|
+
// Since this is an expression the HTMLs are inside parenteses not curly braces.
|
|
101
|
+
{for (users) |user| (
|
|
102
|
+
// `Profile` component is called with props: name, age, and role.
|
|
103
|
+
// Optional props can be omitted, and the component will receive default values for them.
|
|
104
|
+
<Profile name={user.name} age={user.age} role={user.role} />
|
|
105
|
+
)}
|
|
106
|
+
|
|
107
|
+
// `if` statement works just like other control flow statements.
|
|
108
|
+
{if (is_loading) (<p>Loading...</p>) else (<p>Loaded</p>)}
|
|
109
|
+
|
|
110
|
+
// `while` loop with an optional increment statement.
|
|
111
|
+
{while (i < 5) : (i += 1) (<i>{i}</i>)}
|
|
112
|
+
</main>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// A Ziex Component is a Zig function that returns a `zx.Component`.
|
|
117
|
+
// It can have signatures like:
|
|
118
|
+
// - `pub fn ComponentName(allocator: zx.Allocator) zx.Component`
|
|
119
|
+
// - `pub fn ComponentName(ctx: *zx.ComponentCtx<PropsType>) zx.Component`
|
|
120
|
+
// - `pub fn ComponentName(allocator: zx.Allocator, props: PropsType) zx.Component`
|
|
121
|
+
fn Profile(ctx: *zx.ComponentCtx(User)) zx.Component {
|
|
122
|
+
return (
|
|
123
|
+
<div @allocator={ctx.allocator}>
|
|
124
|
+
// Exrepssion starts with `{` and ends with `}`. You can use it to access props, call functions, any valid Zig expression
|
|
125
|
+
<h3>{ctx.props.name}</h3>
|
|
126
|
+
<div>{ctx.props.age}</div>
|
|
127
|
+
<strong>
|
|
128
|
+
{switch (ctx.props.role) {
|
|
129
|
+
.admin => "Admin",
|
|
130
|
+
.member => "Member",
|
|
131
|
+
}}
|
|
132
|
+
</strong>
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const User = struct { name: []const u8, age: u32, role: enum { admin, member } };
|
|
138
|
+
|
|
139
|
+
const users = [_]User{
|
|
140
|
+
.{ .name = "John", .age = 20, .role = .admin },
|
|
141
|
+
.{ .name = "Jane", .age = 21, .role = .member },
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const zx = @import("zx");
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
</details>
|
|
148
|
+
|
|
149
|
+
## Features
|
|
150
|
+
- **JSX-like Syntax**: Write declarative UI components using familiar JSX patterns, transpiled to efficient Zig code.
|
|
151
|
+
- **Full-Stack Capabilities**: Build both frontend and backend of your web application using
|
|
152
|
+
- **It's Fast**: Significantly faster at SSR than many other frameworks.
|
|
153
|
+
- **Compile-time Safety**: Zig's type system catches bugs at compile time. No runtime surprises, no GC.
|
|
154
|
+
- **Familiar Syntax**: Familiar JSX-like syntax, or plain HTML-style markup, with full access to Zig's control flow.
|
|
155
|
+
- **Server-side Rendering**: Render per request on the server for dynamic data, auth, and personalized pages for best performance and SEO.
|
|
156
|
+
- **Static Site Generation**: Pre-render pages at build/export time into static HTML for fast CDN delivery.
|
|
157
|
+
- **File System Routing**: Folder structure defines routes. No configs, no magic strings, just files in folders.
|
|
158
|
+
- **Client-side Rendering**: Optional client-side rendering for interactive experiences when you need it.
|
|
159
|
+
- **Control Flow in Zig's Syntax**: if/else, for/while, and switch all work as expected. It's just Zig.
|
|
160
|
+
- **Developer Tooling**: CLI, hot reload, and editor extensions for the best DX.
|
|
161
|
+
|
|
162
|
+
## Roadmap
|
|
163
|
+
|
|
164
|
+
We track our feature roadmap and bugs using GitHub Issues.
|
|
165
|
+
You can view our current progress and planned features here:
|
|
166
|
+
|
|
167
|
+
**[Check out the Ziex Issue Tracker →](https://github.com/ziex-dev/ziex/issues)**
|
|
168
|
+
|
|
169
|
+
## Editor Support
|
|
170
|
+
|
|
171
|
+
* [VSCode](https://marketplace.visualstudio.com/items?itemName=ziex.ziex)/[VSCode Forks](https://open-vsx.org/extension/ziex/ziex) Extension
|
|
172
|
+
* [Neovim](/ide/neovim/)
|
|
173
|
+
* [Helix](/ide/helix/)
|
|
174
|
+
* [Zed](/ide/zed/)
|
|
175
|
+
|
|
176
|
+
## Community
|
|
177
|
+
|
|
178
|
+
- [Discord](https://ziex.dev/r/discord)
|
|
179
|
+
- [Topic on Ziggit](https://ziex.dev/r/ziggit)
|
|
180
|
+
- [Project on Zig Discord Community](https://ziex.dev/r/zig-discord) (Join Zig Discord first: https://discord.gg/zig)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
## Links
|
|
184
|
+
|
|
185
|
+
* [Codeberg Mirror](https://codeberg.org/ziex-dev/ziex) - ZX repository mirror on Codeberg
|
|
186
|
+
* [ziex.dev](https://github.com/ziex-dev/ziex/tree/main/site) - Official documentation site of ZX made using ZX.
|
|
187
|
+
* [example-blog](https://github.com/ziex-dev/example-blog) - Demo blog web application built with ZX
|
|
197
188
|
* [zx-numbers-game](https://github.com/Andrew-Velox/zx-numbers-game) - ZX numbers game
|
|
189
|
+
* [Comparision with other frameworks](https://ziex.dev/vs)
|
|
198
190
|
|
|
199
191
|
## Contributing
|
|
200
192
|
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/cloudflare/worker.ts
|
|
13
|
+
var exports_worker = {};
|
|
14
|
+
__export(exports_worker, {
|
|
15
|
+
run: () => run,
|
|
16
|
+
respond: () => respond,
|
|
17
|
+
prepare: () => prepare
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// src/cloudflare/kv.ts
|
|
21
|
+
var exports_kv = {};
|
|
22
|
+
__export(exports_kv, {
|
|
23
|
+
createKVImports: () => createKVImports
|
|
24
|
+
});
|
|
25
|
+
function createKVImports(bindings, getMemory) {
|
|
26
|
+
const encoder = new TextEncoder;
|
|
27
|
+
const decoder = new TextDecoder;
|
|
28
|
+
function readStr(ptr, len) {
|
|
29
|
+
return decoder.decode(new Uint8Array(getMemory().buffer, ptr, len));
|
|
30
|
+
}
|
|
31
|
+
function writeBytes(buf_ptr, buf_max, data) {
|
|
32
|
+
if (data.length > buf_max)
|
|
33
|
+
return -2;
|
|
34
|
+
new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
|
|
35
|
+
return data.length;
|
|
36
|
+
}
|
|
37
|
+
function binding(ns) {
|
|
38
|
+
return bindings[ns] ?? bindings["default"] ?? null;
|
|
39
|
+
}
|
|
40
|
+
const Suspending = WebAssembly.Suspending;
|
|
41
|
+
return {
|
|
42
|
+
kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
|
|
43
|
+
const b = binding(readStr(ns_ptr, ns_len));
|
|
44
|
+
if (!b)
|
|
45
|
+
return -1;
|
|
46
|
+
const value = await b.get(readStr(key_ptr, key_len));
|
|
47
|
+
if (value === null)
|
|
48
|
+
return -1;
|
|
49
|
+
return writeBytes(buf_ptr, buf_max, encoder.encode(value));
|
|
50
|
+
}),
|
|
51
|
+
kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len) => {
|
|
52
|
+
const b = binding(readStr(ns_ptr, ns_len));
|
|
53
|
+
if (!b)
|
|
54
|
+
return -1;
|
|
55
|
+
await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len));
|
|
56
|
+
return 0;
|
|
57
|
+
}),
|
|
58
|
+
kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
|
|
59
|
+
const b = binding(readStr(ns_ptr, ns_len));
|
|
60
|
+
if (!b)
|
|
61
|
+
return -1;
|
|
62
|
+
await b.delete(readStr(key_ptr, key_len));
|
|
63
|
+
return 0;
|
|
64
|
+
}),
|
|
65
|
+
kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
|
|
66
|
+
const b = binding(readStr(ns_ptr, ns_len));
|
|
67
|
+
if (!b)
|
|
68
|
+
return writeBytes(buf_ptr, buf_max, encoder.encode("[]"));
|
|
69
|
+
const prefix = readStr(prefix_ptr, prefix_len);
|
|
70
|
+
const result = await b.list(prefix.length > 0 ? { prefix } : undefined);
|
|
71
|
+
return writeBytes(buf_ptr, buf_max, encoder.encode(JSON.stringify(result.keys.map((k) => k.name))));
|
|
72
|
+
})
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/cloudflare/worker.ts
|
|
77
|
+
class ProcExit extends Error {
|
|
78
|
+
code;
|
|
79
|
+
constructor(code) {
|
|
80
|
+
super(`proc_exit(${code})`);
|
|
81
|
+
this.code = code;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function createWasiImports({
|
|
85
|
+
request,
|
|
86
|
+
stdinData
|
|
87
|
+
}) {
|
|
88
|
+
const encoder = new TextEncoder;
|
|
89
|
+
const decoder = new TextDecoder;
|
|
90
|
+
const url = new URL(request.url);
|
|
91
|
+
const argStrings = [
|
|
92
|
+
"wasm",
|
|
93
|
+
"--pathname",
|
|
94
|
+
url.pathname,
|
|
95
|
+
"--method",
|
|
96
|
+
request.method,
|
|
97
|
+
"--search",
|
|
98
|
+
url.search
|
|
99
|
+
];
|
|
100
|
+
for (const name of FORWARDED_HEADERS) {
|
|
101
|
+
const value = request.headers.get(name);
|
|
102
|
+
if (value)
|
|
103
|
+
argStrings.push("--header", `${name}:${value}`);
|
|
104
|
+
}
|
|
105
|
+
const encodedArgs = argStrings.map((a) => encoder.encode(a + "\x00"));
|
|
106
|
+
const argBufSize = encodedArgs.reduce((s, a) => s + a.length, 0);
|
|
107
|
+
let wasmMemory = null;
|
|
108
|
+
const setMemory = (m2) => {
|
|
109
|
+
wasmMemory = m2;
|
|
110
|
+
};
|
|
111
|
+
const stdoutChunks = [];
|
|
112
|
+
const stderrChunks = [];
|
|
113
|
+
let stdinOffset = 0;
|
|
114
|
+
function v() {
|
|
115
|
+
return new DataView(wasmMemory.buffer);
|
|
116
|
+
}
|
|
117
|
+
function m() {
|
|
118
|
+
return new Uint8Array(wasmMemory.buffer);
|
|
119
|
+
}
|
|
120
|
+
const wasiImport = {
|
|
121
|
+
args_sizes_get(argc_ptr, argv_buf_size_ptr) {
|
|
122
|
+
v().setUint32(argc_ptr, encodedArgs.length, true);
|
|
123
|
+
v().setUint32(argv_buf_size_ptr, argBufSize, true);
|
|
124
|
+
return 0;
|
|
125
|
+
},
|
|
126
|
+
args_get(argv_ptr, argv_buf_ptr) {
|
|
127
|
+
const dv = v();
|
|
128
|
+
const mem = m();
|
|
129
|
+
let offset = argv_buf_ptr;
|
|
130
|
+
for (const arg of encodedArgs) {
|
|
131
|
+
dv.setUint32(argv_ptr, offset, true);
|
|
132
|
+
mem.set(arg, offset);
|
|
133
|
+
argv_ptr += 4;
|
|
134
|
+
offset += arg.length;
|
|
135
|
+
}
|
|
136
|
+
return 0;
|
|
137
|
+
},
|
|
138
|
+
environ_sizes_get(count_ptr, buf_size_ptr) {
|
|
139
|
+
v().setUint32(count_ptr, 0, true);
|
|
140
|
+
v().setUint32(buf_size_ptr, 0, true);
|
|
141
|
+
return 0;
|
|
142
|
+
},
|
|
143
|
+
environ_get(_environ_ptr, _environ_buf_ptr) {
|
|
144
|
+
return 0;
|
|
145
|
+
},
|
|
146
|
+
fd_write(fd, iovs_ptr, iovs_len, nwritten_ptr) {
|
|
147
|
+
const dv = v();
|
|
148
|
+
const mem = m();
|
|
149
|
+
let written = 0;
|
|
150
|
+
for (let i = 0;i < iovs_len; i++) {
|
|
151
|
+
const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
|
|
152
|
+
const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
|
|
153
|
+
const chunk = mem.slice(buf_ptr, buf_ptr + buf_len);
|
|
154
|
+
if (fd === 1)
|
|
155
|
+
stdoutChunks.push(chunk);
|
|
156
|
+
else if (fd === 2)
|
|
157
|
+
stderrChunks.push(chunk);
|
|
158
|
+
written += buf_len;
|
|
159
|
+
}
|
|
160
|
+
dv.setUint32(nwritten_ptr, written, true);
|
|
161
|
+
return 0;
|
|
162
|
+
},
|
|
163
|
+
fd_read(fd, iovs_ptr, iovs_len, nread_ptr) {
|
|
164
|
+
const dv = v();
|
|
165
|
+
const mem = m();
|
|
166
|
+
const stdin = stdinData ?? new Uint8Array(0);
|
|
167
|
+
let totalRead = 0;
|
|
168
|
+
for (let i = 0;i < iovs_len; i++) {
|
|
169
|
+
const buf_ptr = dv.getUint32(iovs_ptr + i * 8, true);
|
|
170
|
+
const buf_len = dv.getUint32(iovs_ptr + i * 8 + 4, true);
|
|
171
|
+
if (fd === 0 && stdinOffset < stdin.length) {
|
|
172
|
+
const toRead = Math.min(buf_len, stdin.length - stdinOffset);
|
|
173
|
+
mem.set(stdin.subarray(stdinOffset, stdinOffset + toRead), buf_ptr);
|
|
174
|
+
stdinOffset += toRead;
|
|
175
|
+
totalRead += toRead;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
dv.setUint32(nread_ptr, totalRead, true);
|
|
179
|
+
return 0;
|
|
180
|
+
},
|
|
181
|
+
fd_fdstat_get(_fd, fdstat_ptr) {
|
|
182
|
+
const dv = v();
|
|
183
|
+
dv.setUint8(fdstat_ptr, 2);
|
|
184
|
+
dv.setUint8(fdstat_ptr + 1, 0);
|
|
185
|
+
dv.setUint16(fdstat_ptr + 2, 0, true);
|
|
186
|
+
dv.setUint32(fdstat_ptr + 4, 0, true);
|
|
187
|
+
dv.setBigUint64(fdstat_ptr + 8, 0n, true);
|
|
188
|
+
dv.setBigUint64(fdstat_ptr + 16, 0n, true);
|
|
189
|
+
return 0;
|
|
190
|
+
},
|
|
191
|
+
fd_prestat_get(_fd, _bufptr) {
|
|
192
|
+
return 8;
|
|
193
|
+
},
|
|
194
|
+
fd_prestat_dir_name(_fd, _path, _path_len) {
|
|
195
|
+
return 8;
|
|
196
|
+
},
|
|
197
|
+
fd_close(_fd) {
|
|
198
|
+
return 0;
|
|
199
|
+
},
|
|
200
|
+
fd_pread(_fd, _iovs, _iovs_len, _offset, nread_ptr) {
|
|
201
|
+
v().setUint32(nread_ptr, 0, true);
|
|
202
|
+
return 0;
|
|
203
|
+
},
|
|
204
|
+
fd_pwrite(_fd, _iovs, _iovs_len, _offset, nwritten_ptr) {
|
|
205
|
+
v().setUint32(nwritten_ptr, 0, true);
|
|
206
|
+
return 0;
|
|
207
|
+
},
|
|
208
|
+
fd_filestat_get(_fd, filestat_ptr) {
|
|
209
|
+
const dv = v();
|
|
210
|
+
dv.setBigUint64(filestat_ptr, 0n, true);
|
|
211
|
+
dv.setBigUint64(filestat_ptr + 8, 0n, true);
|
|
212
|
+
dv.setUint8(filestat_ptr + 16, 2);
|
|
213
|
+
dv.setBigUint64(filestat_ptr + 24, 1n, true);
|
|
214
|
+
dv.setBigUint64(filestat_ptr + 32, 0n, true);
|
|
215
|
+
dv.setBigUint64(filestat_ptr + 40, 0n, true);
|
|
216
|
+
dv.setBigUint64(filestat_ptr + 48, 0n, true);
|
|
217
|
+
dv.setBigUint64(filestat_ptr + 56, 0n, true);
|
|
218
|
+
return 0;
|
|
219
|
+
},
|
|
220
|
+
fd_seek(_fd, _offset, _whence, newoffset_ptr) {
|
|
221
|
+
v().setBigInt64(newoffset_ptr, 0n, true);
|
|
222
|
+
return 0;
|
|
223
|
+
},
|
|
224
|
+
proc_exit(code) {
|
|
225
|
+
throw new ProcExit(code);
|
|
226
|
+
},
|
|
227
|
+
sched_yield() {
|
|
228
|
+
return 0;
|
|
229
|
+
},
|
|
230
|
+
clock_time_get(_id, _precision, time_ptr) {
|
|
231
|
+
v().setBigUint64(time_ptr, BigInt(Date.now()) * 1000000n, true);
|
|
232
|
+
return 0;
|
|
233
|
+
},
|
|
234
|
+
random_get(buf_ptr, buf_len) {
|
|
235
|
+
crypto.getRandomValues(new Uint8Array(wasmMemory.buffer, buf_ptr, buf_len));
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
function collectOutput() {
|
|
240
|
+
return {
|
|
241
|
+
stdout: mergeUint8Arrays(stdoutChunks),
|
|
242
|
+
stderrText: decoder.decode(mergeUint8Arrays(stderrChunks))
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
return { wasiImport, setMemory, collectOutput };
|
|
246
|
+
}
|
|
247
|
+
function buildResponse({
|
|
248
|
+
stdout,
|
|
249
|
+
stderrText
|
|
250
|
+
}) {
|
|
251
|
+
const meta = parseEdgeMeta(stderrText);
|
|
252
|
+
return new Response(stdout.buffer, {
|
|
253
|
+
status: meta.status,
|
|
254
|
+
headers: meta.headers
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
async function run({
|
|
258
|
+
request,
|
|
259
|
+
env,
|
|
260
|
+
ctx,
|
|
261
|
+
module,
|
|
262
|
+
kv: kvBindings,
|
|
263
|
+
imports
|
|
264
|
+
}) {
|
|
265
|
+
const stdinData = request.body ? new Uint8Array(await request.arrayBuffer()) : undefined;
|
|
266
|
+
const { wasiImport, setMemory, collectOutput } = createWasiImports({ request, stdinData });
|
|
267
|
+
let wasmMemory = null;
|
|
268
|
+
const mem = () => wasmMemory;
|
|
269
|
+
const instance = new WebAssembly.Instance(module, {
|
|
270
|
+
wasi_snapshot_preview1: wasiImport,
|
|
271
|
+
...kvBindings ? { __zx_kv: createKVImports(kvBindings, mem) } : {},
|
|
272
|
+
...imports ? imports(mem) : {}
|
|
273
|
+
});
|
|
274
|
+
wasmMemory = instance.exports.memory;
|
|
275
|
+
setMemory(wasmMemory);
|
|
276
|
+
const start = WebAssembly.promising(instance.exports._start);
|
|
277
|
+
try {
|
|
278
|
+
await start();
|
|
279
|
+
} catch (e) {
|
|
280
|
+
if (!(e instanceof Error) || !e.message.startsWith("proc_exit"))
|
|
281
|
+
throw e;
|
|
282
|
+
}
|
|
283
|
+
return buildResponse(collectOutput());
|
|
284
|
+
}
|
|
285
|
+
var FORWARDED_HEADERS = [
|
|
286
|
+
"content-type",
|
|
287
|
+
"accept",
|
|
288
|
+
"authorization",
|
|
289
|
+
"cookie",
|
|
290
|
+
"user-agent",
|
|
291
|
+
"referer",
|
|
292
|
+
"x-forwarded-for",
|
|
293
|
+
"x-forwarded-proto",
|
|
294
|
+
"x-real-ip"
|
|
295
|
+
];
|
|
296
|
+
function parseEdgeMeta(stderrText) {
|
|
297
|
+
const meta = { status: 200, headers: new Headers };
|
|
298
|
+
const metaPrefix = "__EDGE_META__:";
|
|
299
|
+
const metaLine = stderrText.split(`
|
|
300
|
+
`).find((line) => line.startsWith(metaPrefix));
|
|
301
|
+
if (metaLine) {
|
|
302
|
+
try {
|
|
303
|
+
const parsed = JSON.parse(metaLine.slice(metaPrefix.length));
|
|
304
|
+
if (parsed.status)
|
|
305
|
+
meta.status = parsed.status;
|
|
306
|
+
if (Array.isArray(parsed.headers)) {
|
|
307
|
+
for (const [name, value] of parsed.headers) {
|
|
308
|
+
meta.headers.append(name, value);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} catch {}
|
|
312
|
+
}
|
|
313
|
+
return meta;
|
|
314
|
+
}
|
|
315
|
+
function mergeUint8Arrays(arrays) {
|
|
316
|
+
const totalLen = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
|
317
|
+
const result = new Uint8Array(totalLen);
|
|
318
|
+
let offset = 0;
|
|
319
|
+
for (const arr of arrays) {
|
|
320
|
+
result.set(arr, offset);
|
|
321
|
+
offset += arr.length;
|
|
322
|
+
}
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
async function collectStream(readable, chunks) {
|
|
326
|
+
const reader = readable.getReader();
|
|
327
|
+
while (true) {
|
|
328
|
+
const { done, value } = await reader.read();
|
|
329
|
+
if (done)
|
|
330
|
+
break;
|
|
331
|
+
if (value)
|
|
332
|
+
chunks.push(value);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function prepare({
|
|
336
|
+
request,
|
|
337
|
+
env,
|
|
338
|
+
ctx
|
|
339
|
+
}) {
|
|
340
|
+
const stdout = new TransformStream;
|
|
341
|
+
const stderr = new TransformStream;
|
|
342
|
+
const url = new URL(request.url);
|
|
343
|
+
const args = [
|
|
344
|
+
"--pathname",
|
|
345
|
+
url.pathname,
|
|
346
|
+
"--method",
|
|
347
|
+
request.method,
|
|
348
|
+
"--search",
|
|
349
|
+
url.search
|
|
350
|
+
];
|
|
351
|
+
for (const name of FORWARDED_HEADERS) {
|
|
352
|
+
const value = request.headers.get(name);
|
|
353
|
+
if (value) {
|
|
354
|
+
args.push("--header", `${name}:${value}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const stdin = request.body ?? undefined;
|
|
358
|
+
return { args, stdout, stderr, stdin };
|
|
359
|
+
}
|
|
360
|
+
async function respond({
|
|
361
|
+
exec,
|
|
362
|
+
stdout,
|
|
363
|
+
stderr
|
|
364
|
+
}) {
|
|
365
|
+
const stdoutChunks = [];
|
|
366
|
+
const stderrChunks = [];
|
|
367
|
+
const stderrReadable = stderr instanceof ReadableStream ? stderr : stderr.readable;
|
|
368
|
+
await Promise.all([
|
|
369
|
+
exec,
|
|
370
|
+
collectStream(stdout.readable, stdoutChunks),
|
|
371
|
+
collectStream(stderrReadable, stderrChunks)
|
|
372
|
+
]);
|
|
373
|
+
const stderrText = new TextDecoder().decode(mergeUint8Arrays(stderrChunks));
|
|
374
|
+
const meta = parseEdgeMeta(stderrText);
|
|
375
|
+
return new Response(mergeUint8Arrays(stdoutChunks).buffer, {
|
|
376
|
+
status: meta.status,
|
|
377
|
+
headers: meta.headers
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
export {
|
|
381
|
+
exports_worker as worker,
|
|
382
|
+
exports_kv as kv
|
|
383
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface KVNamespace {
|
|
2
|
+
get(key: string): Promise<string | null>;
|
|
3
|
+
put(key: string, value: string, options?: {
|
|
4
|
+
expiration?: number;
|
|
5
|
+
expirationTtl?: number;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
delete(key: string): Promise<void>;
|
|
8
|
+
list(options?: {
|
|
9
|
+
prefix?: string;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
keys: {
|
|
12
|
+
name: string;
|
|
13
|
+
}[];
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a `__zx_kv` import object for use with `worker.run({ kv: ... })`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createKVImports(bindings: Record<string, KVNamespace>, getMemory: () => WebAssembly.Memory): Record<string, unknown>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a WASM module for a single request using JSPI.
|
|
3
|
+
*
|
|
4
|
+
* Pass `kv` as a map of binding names → KV namespaces. The Zig side selects
|
|
5
|
+
* a binding via `zx.kv.scope("name")`; the top-level `zx.kv.*` functions use
|
|
6
|
+
* `"default"`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* return worker.run({
|
|
11
|
+
* request, env, ctx, wasmModule,
|
|
12
|
+
* kv: { default: env.KV, users: env.USERS_KV },
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function run({ request, env, ctx, module, kv: kvBindings, imports, }: {
|
|
17
|
+
request: Request;
|
|
18
|
+
env?: unknown;
|
|
19
|
+
ctx?: unknown;
|
|
20
|
+
module: WebAssembly.Module;
|
|
21
|
+
/** KV namespace bindings — `{ default: env.KV, otherName: env.OTHER_KV }` */
|
|
22
|
+
kv?: Record<string, import("./kv").KVNamespace>;
|
|
23
|
+
imports?: (mem: () => WebAssembly.Memory) => Record<string, Record<string, unknown>>;
|
|
24
|
+
}): Promise<Response>;
|
|
25
|
+
export declare function prepare({ request, env, ctx, }: {
|
|
26
|
+
request: Request;
|
|
27
|
+
env: unknown;
|
|
28
|
+
ctx: unknown;
|
|
29
|
+
}): {
|
|
30
|
+
args: string[];
|
|
31
|
+
stdout: TransformStream<any, any>;
|
|
32
|
+
stderr: TransformStream<any, any>;
|
|
33
|
+
stdin: ReadableStream<Uint8Array<ArrayBufferLike>> | undefined;
|
|
34
|
+
};
|
|
35
|
+
export declare function respond({ exec, stdout, stderr, }: {
|
|
36
|
+
exec: Promise<number | undefined>;
|
|
37
|
+
stdout: TransformStream;
|
|
38
|
+
stderr: TransformStream | ReadableStream<Uint8Array>;
|
|
39
|
+
}): Promise<Response>;
|
package/index.js
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
1
12
|
// src/index.ts
|
|
2
13
|
var zx = {
|
|
3
14
|
name: "zx",
|
|
4
|
-
version: "0.1.0-dev.
|
|
15
|
+
version: "0.1.0-dev.765",
|
|
16
|
+
jsglue_version: "0.1.0-dev.727",
|
|
5
17
|
description: "ZX is a framework for building web applications with Zig.",
|
|
6
|
-
repository: "https://github.com/
|
|
18
|
+
repository: "https://github.com/ziex-dev/ziex",
|
|
19
|
+
homepage: "https://ziex.dev",
|
|
7
20
|
fingerprint: 14616285862371232000,
|
|
8
21
|
minimum_zig_version: "0.15.2",
|
|
9
22
|
dependencies: {
|
|
@@ -21,7 +34,10 @@ var zx = {
|
|
|
21
34
|
path: "vendor/zig-tree-sitter"
|
|
22
35
|
},
|
|
23
36
|
tree_sitter_zx: {
|
|
24
|
-
path: "
|
|
37
|
+
path: "pkg/tree-sitter-zx"
|
|
38
|
+
},
|
|
39
|
+
tree_sitter_mdzx: {
|
|
40
|
+
path: "pkg/tree-sitter-mdzx"
|
|
25
41
|
},
|
|
26
42
|
cachez: {
|
|
27
43
|
path: "vendor/cachez"
|
|
@@ -31,7 +47,8 @@ var zx = {
|
|
|
31
47
|
"build.zig",
|
|
32
48
|
"build.zig.zon",
|
|
33
49
|
"src",
|
|
34
|
-
"
|
|
50
|
+
"pkg/tree-sitter-zx",
|
|
51
|
+
"pkg/tree-sitter-mdzx",
|
|
35
52
|
"vendor/cachez",
|
|
36
53
|
"vendor/cliz",
|
|
37
54
|
"vendor/jsz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ziex",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.765",
|
|
4
4
|
"description": "ZX is a framework for building web applications with Zig.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
".": "./index.js",
|
|
9
9
|
"./react": "./react/index.js",
|
|
10
10
|
"./wasm": "./wasm/index.js",
|
|
11
|
-
"./wasm/init": "./wasm/init.js"
|
|
11
|
+
"./wasm/init": "./wasm/init.js",
|
|
12
|
+
"./cloudflare": "./cloudflare/index.js"
|
|
12
13
|
},
|
|
13
|
-
"homepage": "https://
|
|
14
|
+
"homepage": "https://ziex.dev",
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/
|
|
17
|
+
"url": "git+https://github.com/ziex-dev/ziex.git"
|
|
17
18
|
},
|
|
18
19
|
"keywords": [
|
|
19
20
|
"zx",
|
package/react/index.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
1
12
|
// src/react/dom.ts
|
|
2
13
|
function findCommentMarker(id) {
|
|
3
14
|
const startPrefix = `$${id} `;
|
package/wasm/index.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
1
12
|
// ../../vendor/jsz/js/src/zigjs.ts
|
|
2
13
|
var NAN_PREFIX = 2146959360;
|
|
3
14
|
var predefined = {
|
|
@@ -205,6 +216,9 @@ class ZxBridge {
|
|
|
205
216
|
constructor(exports) {
|
|
206
217
|
this.#exports = exports;
|
|
207
218
|
}
|
|
219
|
+
get #alloc() {
|
|
220
|
+
return this.#exports.__zx_alloc;
|
|
221
|
+
}
|
|
208
222
|
get #handler() {
|
|
209
223
|
return this.#exports.__zx_cb;
|
|
210
224
|
}
|
|
@@ -272,19 +286,8 @@ class ZxBridge {
|
|
|
272
286
|
}
|
|
273
287
|
#notifyFetchComplete(fetchId, statusCode, body, isError) {
|
|
274
288
|
const handler = this.#fetchCompleteHandler;
|
|
275
|
-
if (!handler) {
|
|
276
|
-
console.warn("__zx_fetch_complete not exported from WASM");
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
289
|
const encoded = new TextEncoder().encode(body);
|
|
280
|
-
const
|
|
281
|
-
let ptr = 0;
|
|
282
|
-
if (allocFn) {
|
|
283
|
-
ptr = allocFn(encoded.length);
|
|
284
|
-
} else {
|
|
285
|
-
const heapBase = this.#exports.__heap_base?.value ?? 65536;
|
|
286
|
-
ptr = heapBase + Number(fetchId % BigInt(256)) * 65536;
|
|
287
|
-
}
|
|
290
|
+
const ptr = this.#alloc(encoded.length);
|
|
288
291
|
writeBytes(ptr, encoded);
|
|
289
292
|
handler(fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
|
|
290
293
|
}
|
|
@@ -394,14 +397,7 @@ class ZxBridge {
|
|
|
394
397
|
return this.#writeBytesToWasm(encoded);
|
|
395
398
|
}
|
|
396
399
|
#writeBytesToWasm(data) {
|
|
397
|
-
const
|
|
398
|
-
let ptr = 0;
|
|
399
|
-
if (allocFn) {
|
|
400
|
-
ptr = allocFn(data.length);
|
|
401
|
-
} else {
|
|
402
|
-
const heapBase = this.#exports.__heap_base?.value ?? 65536;
|
|
403
|
-
ptr = heapBase + Date.now() % 256 * 4096;
|
|
404
|
-
}
|
|
400
|
+
const ptr = this.#alloc(data.length);
|
|
405
401
|
writeBytes(ptr, data);
|
|
406
402
|
return { ptr, len: data.length };
|
|
407
403
|
}
|
package/wasm/init.js
CHANGED
|
@@ -205,6 +205,9 @@ class ZxBridge {
|
|
|
205
205
|
constructor(exports) {
|
|
206
206
|
this.#exports = exports;
|
|
207
207
|
}
|
|
208
|
+
get #alloc() {
|
|
209
|
+
return this.#exports.__zx_alloc;
|
|
210
|
+
}
|
|
208
211
|
get #handler() {
|
|
209
212
|
return this.#exports.__zx_cb;
|
|
210
213
|
}
|
|
@@ -272,19 +275,8 @@ class ZxBridge {
|
|
|
272
275
|
}
|
|
273
276
|
#notifyFetchComplete(fetchId, statusCode, body, isError) {
|
|
274
277
|
const handler = this.#fetchCompleteHandler;
|
|
275
|
-
if (!handler) {
|
|
276
|
-
console.warn("__zx_fetch_complete not exported from WASM");
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
278
|
const encoded = new TextEncoder().encode(body);
|
|
280
|
-
const
|
|
281
|
-
let ptr = 0;
|
|
282
|
-
if (allocFn) {
|
|
283
|
-
ptr = allocFn(encoded.length);
|
|
284
|
-
} else {
|
|
285
|
-
const heapBase = this.#exports.__heap_base?.value ?? 65536;
|
|
286
|
-
ptr = heapBase + Number(fetchId % BigInt(256)) * 65536;
|
|
287
|
-
}
|
|
279
|
+
const ptr = this.#alloc(encoded.length);
|
|
288
280
|
writeBytes(ptr, encoded);
|
|
289
281
|
handler(fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
|
|
290
282
|
}
|
|
@@ -394,14 +386,7 @@ class ZxBridge {
|
|
|
394
386
|
return this.#writeBytesToWasm(encoded);
|
|
395
387
|
}
|
|
396
388
|
#writeBytesToWasm(data) {
|
|
397
|
-
const
|
|
398
|
-
let ptr = 0;
|
|
399
|
-
if (allocFn) {
|
|
400
|
-
ptr = allocFn(data.length);
|
|
401
|
-
} else {
|
|
402
|
-
const heapBase = this.#exports.__heap_base?.value ?? 65536;
|
|
403
|
-
ptr = heapBase + Date.now() % 256 * 4096;
|
|
404
|
-
}
|
|
389
|
+
const ptr = this.#alloc(data.length);
|
|
405
390
|
writeBytes(ptr, data);
|
|
406
391
|
return { ptr, len: data.length };
|
|
407
392
|
}
|