ziex 0.1.0-dev.1367 → 0.1.0-dev.1381
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/aws-lambda/index.js +20 -29
- package/build.zig.zon +10 -3
- package/cloudflare/index.js +1635 -1854
- package/index.js +155 -216
- package/{pkg/ziex/src/react → jsx}/dom.d.ts +5 -9
- package/{pkg/ziex/src/react → jsx}/index.d.ts +1 -1
- package/{react → jsx}/index.js +19 -25
- package/{pkg/ziex/src/react → jsx}/types.d.ts +14 -9
- package/package.json +6 -14
- package/vercel/index.js +0 -15
- package/wasm/index.js +253 -261
- package/wasm/init.dev.js +242 -189
- package/wasm/init.js +3 -3
- package/pkg/ziex/src/zx.d.ts +0 -1
- package/vendor/jsz/js/src/index.d.ts +0 -1
- package/vendor/jsz/js/src/zigjs.d.ts +0 -107
- /package/{pkg/ziex/src/app.d.ts → app.d.ts} +0 -0
- /package/{pkg/ziex/src/aws-lambda → aws-lambda}/index.d.ts +0 -0
- /package/{pkg/ziex/src/browser → browser}/kv.d.ts +0 -0
- /package/{pkg/ziex/src/cloudflare → cloudflare}/app.d.ts +0 -0
- /package/{pkg/ziex/src/cloudflare → cloudflare}/db.d.ts +0 -0
- /package/{pkg/ziex/src/cloudflare → cloudflare}/do.d.ts +0 -0
- /package/{pkg/ziex/src/cloudflare → cloudflare}/index.d.ts +0 -0
- /package/{pkg/ziex/src/cloudflare → cloudflare}/kv.d.ts +0 -0
- /package/{pkg/ziex/src/cloudflare → cloudflare}/worker.d.ts +0 -0
- /package/{pkg/ziex/src/db.d.ts → db.d.ts} +0 -0
- /package/{pkg/ziex/src/fetch.d.ts → fetch.d.ts} +0 -0
- /package/{pkg/ziex/src/index.d.ts → index.d.ts} +0 -0
- /package/{pkg/ziex/src/kv.d.ts → kv.d.ts} +0 -0
- /package/{pkg/ziex/src/runtime.d.ts → runtime.d.ts} +0 -0
- /package/{pkg/ziex/src/vercel → vercel}/index.d.ts +0 -0
- /package/{pkg/ziex/src/wasi.d.ts → wasi.d.ts} +0 -0
- /package/{pkg/ziex/src/wasm → wasm}/core.d.ts +0 -0
- /package/{pkg/ziex/src/wasm → wasm}/dom.d.ts +0 -0
- /package/{pkg/ziex/src/wasm → wasm}/index.d.ts +0 -0
- /package/{pkg/ziex/src/wasm → wasm}/init.d.ts +0 -0
- /package/{pkg/ziex/src/wasm → wasm}/types.d.ts +0 -0
- /package/{pkg/ziex/src/wasm → wasm}/wasi.d.ts +0 -0
package/wasm/index.js
CHANGED
|
@@ -1,37 +1,36 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __returnValue = (v) => v;
|
|
3
|
-
function __exportSetter(name, newValue) {
|
|
4
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
-
}
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, {
|
|
9
|
-
get: all[name],
|
|
10
|
-
enumerable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
set: __exportSetter.bind(all, name)
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
|
|
16
1
|
// ../../vendor/jsz/js/src/zigjs.ts
|
|
17
2
|
var NAN_PREFIX = 2146959360;
|
|
18
3
|
var predefined = {
|
|
19
|
-
nan: 0,
|
|
20
|
-
null: 1,
|
|
21
|
-
true: 2,
|
|
22
|
-
false: 3,
|
|
23
|
-
undefined: 4,
|
|
24
|
-
globalThis: 5,
|
|
25
|
-
runtime: 6
|
|
4
|
+
"nan": 0,
|
|
5
|
+
"null": 1,
|
|
6
|
+
"true": 2,
|
|
7
|
+
"false": 3,
|
|
8
|
+
"undefined": 4,
|
|
9
|
+
"globalThis": 5,
|
|
10
|
+
"runtime": 6
|
|
26
11
|
};
|
|
27
12
|
var PREDEFINED_ID_MAX = 6;
|
|
28
|
-
var encoder = new TextEncoder;
|
|
13
|
+
var encoder = new TextEncoder();
|
|
29
14
|
var decoder = new TextDecoder("utf-8");
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
15
|
+
var ZigJS = class {
|
|
16
|
+
constructor() {
|
|
17
|
+
/**
|
|
18
|
+
* The values, indexed by ID (number). Duplicate values can be in this
|
|
19
|
+
* if they are loaded multiple times. That just acts as duplicate references.
|
|
20
|
+
* */
|
|
21
|
+
this.values = [NaN, null, true, false, void 0, globalThis, this];
|
|
22
|
+
/**
|
|
23
|
+
* When a value is removed from the values array, its ID is put
|
|
24
|
+
* in the pool so that we can use it next. This avoids fragmentation in
|
|
25
|
+
* our array keys.
|
|
26
|
+
* */
|
|
27
|
+
this.idPool = [];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Returns the import object that should be merged with your import
|
|
31
|
+
* object when instantiating your wasm instance. This injects the required
|
|
32
|
+
* functions into the wasm environment.
|
|
33
|
+
* */
|
|
35
34
|
importObject() {
|
|
36
35
|
return {
|
|
37
36
|
"zig-js": {
|
|
@@ -47,92 +46,121 @@ class ZigJS {
|
|
|
47
46
|
}
|
|
48
47
|
};
|
|
49
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Get a value from the JS environment.
|
|
51
|
+
* */
|
|
50
52
|
valueGet(out, id, ptr, len) {
|
|
51
53
|
const val = this.loadValue(id);
|
|
52
54
|
const str = this.loadString(ptr, len);
|
|
53
55
|
const result = Reflect.get(val, str);
|
|
54
56
|
this.storeValue(out, result);
|
|
55
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Set a value on an object.
|
|
60
|
+
* */
|
|
56
61
|
valueSet(id, ptr, len, refAddr) {
|
|
57
62
|
const obj = this.loadValue(id);
|
|
58
63
|
const str = this.loadString(ptr, len);
|
|
59
64
|
const val = this.loadRef(refAddr);
|
|
60
65
|
Reflect.set(obj, str, val);
|
|
61
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Dereference a value, allowing the JS environment to potentially GC it.
|
|
69
|
+
* */
|
|
62
70
|
valueDeinit(id) {
|
|
63
71
|
if (id > PREDEFINED_ID_MAX) {
|
|
64
72
|
this.values[id] = null;
|
|
65
73
|
this.idPool.push(id);
|
|
66
74
|
}
|
|
67
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Create an empty object.
|
|
78
|
+
* */
|
|
68
79
|
valueObjectCreate(out) {
|
|
69
|
-
this.storeValue(out, new Object);
|
|
80
|
+
this.storeValue(out, new Object());
|
|
70
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Creates a string on the JS side from a UTF-8 encoded string in wasm memory.
|
|
84
|
+
* */
|
|
71
85
|
valueStringCreate(out, ptr, len) {
|
|
72
86
|
const str = this.loadString(ptr, len);
|
|
73
87
|
this.storeValue(out, str);
|
|
74
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns the length of the string given by id.
|
|
91
|
+
* */
|
|
75
92
|
valueStringLen(id) {
|
|
76
93
|
const val = this.loadValue(id);
|
|
77
94
|
const buf = encoder.encode(val);
|
|
78
95
|
return buf.byteLength;
|
|
79
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Copy the string at id "id" into the shared memory at ptr.
|
|
99
|
+
* */
|
|
80
100
|
valueStringCopy(id, ptr, max) {
|
|
81
|
-
if (this.memory == null)
|
|
82
|
-
return;
|
|
101
|
+
if (this.memory == null) return;
|
|
83
102
|
const val = this.loadValue(id);
|
|
84
103
|
const bytes = encoder.encode(val);
|
|
85
|
-
if (bytes.byteLength > max)
|
|
86
|
-
|
|
87
|
-
if (bytes.length === 0)
|
|
88
|
-
return;
|
|
104
|
+
if (bytes.byteLength > max) return;
|
|
105
|
+
if (bytes.length === 0) return;
|
|
89
106
|
new Uint8Array(this.memory.buffer, ptr, bytes.length).set(bytes);
|
|
90
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Call a constructor given by id.
|
|
110
|
+
* */
|
|
91
111
|
valueNew(out, id, argsAddr, argsLen) {
|
|
92
112
|
const fn = this.loadValue(id);
|
|
93
113
|
const args = [];
|
|
94
|
-
for (let i = 0;i < argsLen; i++) {
|
|
114
|
+
for (let i = 0; i < argsLen; i++) {
|
|
95
115
|
args.push(this.loadRef(argsAddr + i * 8));
|
|
96
116
|
}
|
|
97
117
|
const result = Reflect.construct(fn, args);
|
|
98
118
|
this.storeValue(out, result);
|
|
99
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Call a function given by id.
|
|
122
|
+
* */
|
|
100
123
|
funcApply(out, id, thisRefAddr, argsAddr, argsLen) {
|
|
101
124
|
const fn = this.loadValue(id);
|
|
102
125
|
const thisVal = this.loadRef(thisRefAddr);
|
|
103
126
|
const args = [];
|
|
104
|
-
for (let i = 0;i < argsLen; i++) {
|
|
127
|
+
for (let i = 0; i < argsLen; i++) {
|
|
105
128
|
args.push(this.loadRef(argsAddr + i * 8));
|
|
106
129
|
}
|
|
107
130
|
const result = Reflect.apply(fn, thisVal, args);
|
|
108
131
|
this.storeValue(out, result);
|
|
109
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* This can be used to load a value given by an ID. A WASM function
|
|
135
|
+
* might return a value as an ID. This can be used to retrieve it.
|
|
136
|
+
* */
|
|
110
137
|
loadValue(id) {
|
|
111
138
|
return this.values[id];
|
|
112
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* This removes the value from the values list and returns it. This
|
|
142
|
+
* will not remove predefined values but can still be used to retrieve
|
|
143
|
+
* them.
|
|
144
|
+
* */
|
|
113
145
|
deleteValue(id) {
|
|
114
146
|
const val = this.values[id];
|
|
115
147
|
this.valueDeinit(id);
|
|
116
148
|
return val;
|
|
117
149
|
}
|
|
118
150
|
loadRef(refAddr) {
|
|
119
|
-
if (this.memory == null)
|
|
120
|
-
return;
|
|
151
|
+
if (this.memory == null) return;
|
|
121
152
|
const view = new DataView(this.memory.buffer);
|
|
122
153
|
const floatVal = view.getFloat64(refAddr, true);
|
|
123
|
-
if (!isNaN(floatVal))
|
|
124
|
-
return floatVal;
|
|
154
|
+
if (!isNaN(floatVal)) return floatVal;
|
|
125
155
|
const id = this.loadRefId(refAddr);
|
|
126
156
|
return this.values[id];
|
|
127
157
|
}
|
|
128
158
|
loadRefId(refAddr) {
|
|
129
|
-
if (this.memory == null)
|
|
130
|
-
return 0;
|
|
159
|
+
if (this.memory == null) return 0;
|
|
131
160
|
return new DataView(this.memory.buffer).getUint32(refAddr, true);
|
|
132
161
|
}
|
|
133
162
|
storeValue(out, val) {
|
|
134
|
-
if (this.memory == null)
|
|
135
|
-
return;
|
|
163
|
+
if (this.memory == null) return;
|
|
136
164
|
const view = new DataView(this.memory.buffer);
|
|
137
165
|
if (typeof val === "number") {
|
|
138
166
|
if (isNaN(val)) {
|
|
@@ -148,7 +176,7 @@ class ZigJS {
|
|
|
148
176
|
view.setUint32(out + 4, NAN_PREFIX, true);
|
|
149
177
|
return;
|
|
150
178
|
}
|
|
151
|
-
if (val ===
|
|
179
|
+
if (val === void 0) {
|
|
152
180
|
view.setUint32(out, predefined.undefined, true);
|
|
153
181
|
view.setUint32(out + 4, NAN_PREFIX, true);
|
|
154
182
|
return;
|
|
@@ -163,7 +191,7 @@ class ZigJS {
|
|
|
163
191
|
return;
|
|
164
192
|
}
|
|
165
193
|
let id = this.idPool.pop();
|
|
166
|
-
if (id ===
|
|
194
|
+
if (id === void 0) {
|
|
167
195
|
id = this.values.length;
|
|
168
196
|
}
|
|
169
197
|
this.values[id] = val;
|
|
@@ -186,23 +214,22 @@ class ZigJS {
|
|
|
186
214
|
view.setUint32(out + 4, NAN_PREFIX | typeId, true);
|
|
187
215
|
}
|
|
188
216
|
loadString(ptr, len) {
|
|
189
|
-
if (this.memory == null)
|
|
190
|
-
return "";
|
|
217
|
+
if (this.memory == null) return "";
|
|
191
218
|
const arr = new Uint8ClampedArray(this.memory.buffer, ptr, Number(len));
|
|
192
219
|
const data = arr.slice();
|
|
193
220
|
return decoder.decode(data);
|
|
194
221
|
}
|
|
195
|
-
}
|
|
222
|
+
};
|
|
223
|
+
|
|
196
224
|
// src/fetch.ts
|
|
197
225
|
function createFetchImports(getMemory) {
|
|
198
|
-
const encoder2 = new TextEncoder;
|
|
199
|
-
const decoder2 = new TextDecoder;
|
|
226
|
+
const encoder2 = new TextEncoder();
|
|
227
|
+
const decoder2 = new TextDecoder();
|
|
200
228
|
function readStr(ptr, len) {
|
|
201
229
|
return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
|
|
202
230
|
}
|
|
203
|
-
function
|
|
204
|
-
if (data.length > buf_max)
|
|
205
|
-
return -2;
|
|
231
|
+
function writeBytes2(buf_ptr, buf_max, data) {
|
|
232
|
+
if (data.length > buf_max) return -2;
|
|
206
233
|
new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
|
|
207
234
|
return data.length;
|
|
208
235
|
}
|
|
@@ -214,8 +241,7 @@ function createFetchImports(getMemory) {
|
|
|
214
241
|
try {
|
|
215
242
|
headers = JSON.parse(headersJson);
|
|
216
243
|
} catch {
|
|
217
|
-
for (const line of headersJson.split(
|
|
218
|
-
`)) {
|
|
244
|
+
for (const line of headersJson.split("\n")) {
|
|
219
245
|
const colonIdx = line.indexOf(":");
|
|
220
246
|
if (colonIdx > 0) {
|
|
221
247
|
headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
|
|
@@ -228,25 +254,23 @@ function createFetchImports(getMemory) {
|
|
|
228
254
|
const url = readStr(url_ptr, url_len);
|
|
229
255
|
const method = method_len > 0 ? readStr(method_ptr, method_len) : "GET";
|
|
230
256
|
const headersJson = headers_len > 0 ? readStr(headers_ptr, headers_len) : "{}";
|
|
231
|
-
const body = body_len > 0 ? readBytes(body_ptr, body_len) :
|
|
257
|
+
const body = body_len > 0 ? readBytes(body_ptr, body_len) : void 0;
|
|
232
258
|
const headers = parseHeaders(headersJson);
|
|
233
|
-
const controller = new AbortController;
|
|
259
|
+
const controller = new AbortController();
|
|
234
260
|
const timeout = timeout_ms > 0 ? setTimeout(() => controller.abort(), timeout_ms) : null;
|
|
235
261
|
try {
|
|
236
262
|
const response = await fetch(url, {
|
|
237
263
|
method,
|
|
238
|
-
headers: Object.keys(headers).length > 0 ? headers :
|
|
239
|
-
body: method !== "GET" && method !== "HEAD" ? body :
|
|
264
|
+
headers: Object.keys(headers).length > 0 ? headers : void 0,
|
|
265
|
+
body: method !== "GET" && method !== "HEAD" ? body : void 0,
|
|
240
266
|
signal: controller.signal
|
|
241
267
|
});
|
|
242
|
-
if (timeout)
|
|
243
|
-
clearTimeout(timeout);
|
|
268
|
+
if (timeout) clearTimeout(timeout);
|
|
244
269
|
new DataView(getMemory().buffer).setUint16(status_out, response.status, true);
|
|
245
270
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
246
|
-
return
|
|
271
|
+
return writeBytes2(buf_ptr, buf_max, bytes);
|
|
247
272
|
} catch (err) {
|
|
248
|
-
if (timeout)
|
|
249
|
-
clearTimeout(timeout);
|
|
273
|
+
if (timeout) clearTimeout(timeout);
|
|
250
274
|
const msg = err instanceof Error ? err.message : String(err);
|
|
251
275
|
console.error(`wasm fetch failed: ${url} (${msg})`);
|
|
252
276
|
return -1;
|
|
@@ -275,7 +299,7 @@ var CallbackType = {
|
|
|
275
299
|
WebSocketError: 7,
|
|
276
300
|
WebSocketClose: 8
|
|
277
301
|
};
|
|
278
|
-
var jsz = new ZigJS;
|
|
302
|
+
var jsz = new ZigJS();
|
|
279
303
|
var tempRefBuffer = new ArrayBuffer(8);
|
|
280
304
|
var tempRefView = new DataView(tempRefBuffer);
|
|
281
305
|
function storeValueGetRef(val) {
|
|
@@ -285,8 +309,8 @@ function storeValueGetRef(val) {
|
|
|
285
309
|
jsz.memory = originalMemory;
|
|
286
310
|
return tempRefView.getBigUint64(0, true);
|
|
287
311
|
}
|
|
288
|
-
var textDecoder = new TextDecoder;
|
|
289
|
-
var textEncoder = new TextEncoder;
|
|
312
|
+
var textDecoder = new TextDecoder();
|
|
313
|
+
var textEncoder = new TextEncoder();
|
|
290
314
|
var memoryView = null;
|
|
291
315
|
var memoryBuffer = null;
|
|
292
316
|
function getMemoryView() {
|
|
@@ -297,15 +321,14 @@ function getMemoryView() {
|
|
|
297
321
|
}
|
|
298
322
|
return memoryView;
|
|
299
323
|
}
|
|
300
|
-
var stringCache = new Map;
|
|
324
|
+
var stringCache = /* @__PURE__ */ new Map();
|
|
301
325
|
function stringCacheKey(ptr, len) {
|
|
302
326
|
return ptr * 65536 + len;
|
|
303
327
|
}
|
|
304
328
|
function readString(ptr, len) {
|
|
305
329
|
const key = stringCacheKey(ptr, len);
|
|
306
330
|
const cached = stringCache.get(key);
|
|
307
|
-
if (cached !==
|
|
308
|
-
return cached;
|
|
331
|
+
if (cached !== void 0) return cached;
|
|
309
332
|
const str = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
|
|
310
333
|
stringCache.set(key, str);
|
|
311
334
|
return str;
|
|
@@ -314,27 +337,22 @@ function writeBytes(ptr, data) {
|
|
|
314
337
|
getMemoryView().set(data, ptr);
|
|
315
338
|
}
|
|
316
339
|
function wrapPromisingExport(fn) {
|
|
317
|
-
if (!fn)
|
|
318
|
-
return;
|
|
340
|
+
if (!fn) return void 0;
|
|
319
341
|
const promising = WebAssembly.promising;
|
|
320
|
-
if (typeof promising !== "function")
|
|
321
|
-
return fn;
|
|
342
|
+
if (typeof promising !== "function") return fn;
|
|
322
343
|
return promising(fn);
|
|
323
344
|
}
|
|
324
345
|
function invokeWasmExport(fn, ...args) {
|
|
325
|
-
if (!fn)
|
|
326
|
-
return;
|
|
346
|
+
if (!fn) return;
|
|
327
347
|
const result = fn(...args);
|
|
328
348
|
if (result && typeof result.then === "function") {
|
|
329
|
-
result.then(
|
|
349
|
+
void result.then(void 0, (error) => {
|
|
330
350
|
console.error(error);
|
|
331
351
|
});
|
|
332
352
|
}
|
|
333
353
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
#intervals = new Map;
|
|
337
|
-
_alloc;
|
|
354
|
+
var ZxBridgeCore = class _ZxBridgeCore {
|
|
355
|
+
#intervals = /* @__PURE__ */ new Map();
|
|
338
356
|
#handler;
|
|
339
357
|
#fetchCompleteHandler;
|
|
340
358
|
constructor(exports) {
|
|
@@ -345,9 +363,9 @@ class ZxBridgeCore {
|
|
|
345
363
|
throw new Error("__zx_fetch_complete not exported from WASM");
|
|
346
364
|
}
|
|
347
365
|
this.#fetchCompleteHandler = fetchCompleteHandler;
|
|
348
|
-
if (exports.memory)
|
|
349
|
-
jsz.memory = exports.memory;
|
|
366
|
+
if (exports.memory) jsz.memory = exports.memory;
|
|
350
367
|
}
|
|
368
|
+
/** Invoke the unified callback handler */
|
|
351
369
|
#invoke(type, id, data) {
|
|
352
370
|
const handler = this.#handler;
|
|
353
371
|
if (!handler) {
|
|
@@ -357,44 +375,46 @@ class ZxBridgeCore {
|
|
|
357
375
|
const dataRef = storeValueGetRef(data);
|
|
358
376
|
invokeWasmExport(handler, type, id, dataRef);
|
|
359
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Async fetch with full options support.
|
|
380
|
+
* Calls __zx_fetch_complete when done.
|
|
381
|
+
*/
|
|
360
382
|
fetchAsync(urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) {
|
|
361
383
|
const url = readString(urlPtr, urlLen);
|
|
362
384
|
const method = methodLen > 0 ? readString(methodPtr, methodLen) : "GET";
|
|
363
385
|
const headersJson = headersLen > 0 ? readString(headersPtr, headersLen) : "{}";
|
|
364
|
-
const body = bodyLen > 0 ? getMemoryView().subarray(bodyPtr, bodyPtr + bodyLen) :
|
|
386
|
+
const body = bodyLen > 0 ? getMemoryView().subarray(bodyPtr, bodyPtr + bodyLen) : void 0;
|
|
365
387
|
let headers = {};
|
|
366
388
|
try {
|
|
367
389
|
headers = JSON.parse(headersJson);
|
|
368
390
|
} catch {
|
|
369
|
-
for (const line of headersJson.split(
|
|
370
|
-
`)) {
|
|
391
|
+
for (const line of headersJson.split("\n")) {
|
|
371
392
|
const colonIdx = line.indexOf(":");
|
|
372
393
|
if (colonIdx > 0) {
|
|
373
394
|
headers[line.slice(0, colonIdx)] = line.slice(colonIdx + 1);
|
|
374
395
|
}
|
|
375
396
|
}
|
|
376
397
|
}
|
|
377
|
-
const controller = new AbortController;
|
|
398
|
+
const controller = new AbortController();
|
|
378
399
|
const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : null;
|
|
379
400
|
const fetchOptions = {
|
|
380
401
|
method,
|
|
381
|
-
headers: Object.keys(headers).length > 0 ? headers :
|
|
382
|
-
body: method !== "GET" && method !== "HEAD" ? body :
|
|
402
|
+
headers: Object.keys(headers).length > 0 ? headers : void 0,
|
|
403
|
+
body: method !== "GET" && method !== "HEAD" ? body : void 0,
|
|
383
404
|
signal: controller.signal
|
|
384
405
|
};
|
|
385
406
|
fetch(url, fetchOptions).then(async (response) => {
|
|
386
|
-
if (timeout)
|
|
387
|
-
clearTimeout(timeout);
|
|
407
|
+
if (timeout) clearTimeout(timeout);
|
|
388
408
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
389
409
|
this._notifyFetchComplete(fetchId, response.status, bytes, false);
|
|
390
410
|
}).catch((error) => {
|
|
391
|
-
if (timeout)
|
|
392
|
-
clearTimeout(timeout);
|
|
411
|
+
if (timeout) clearTimeout(timeout);
|
|
393
412
|
const isAbort = error.name === "AbortError";
|
|
394
413
|
const errorMsg = isAbort ? "Request timeout" : error.message ?? "Fetch failed";
|
|
395
414
|
this._notifyFetchComplete(fetchId, 0, errorMsg, true);
|
|
396
415
|
});
|
|
397
416
|
}
|
|
417
|
+
/** Notify WASM that a fetch completed. `body` is raw bytes on success, text on error. */
|
|
398
418
|
_notifyFetchComplete(fetchId, statusCode, body, isError) {
|
|
399
419
|
const handler = this.#fetchCompleteHandler;
|
|
400
420
|
const encoded = typeof body === "string" ? textEncoder.encode(body) : body;
|
|
@@ -402,20 +422,23 @@ class ZxBridgeCore {
|
|
|
402
422
|
writeBytes(ptr, encoded);
|
|
403
423
|
invokeWasmExport(handler, fetchId, statusCode, ptr, encoded.length, isError ? 1 : 0);
|
|
404
424
|
}
|
|
425
|
+
/** Set a timeout and callback when it fires */
|
|
405
426
|
setTimeout(callbackId, delayMs) {
|
|
406
427
|
setTimeout(() => {
|
|
407
428
|
this.#invoke(CallbackType.Timeout, callbackId, null);
|
|
408
429
|
}, delayMs);
|
|
409
430
|
}
|
|
431
|
+
/** Set an interval and callback each time it fires */
|
|
410
432
|
setInterval(callbackId, intervalMs) {
|
|
411
433
|
const handle = setInterval(() => {
|
|
412
434
|
this.#invoke(CallbackType.Interval, callbackId, null);
|
|
413
435
|
}, intervalMs);
|
|
414
436
|
this.#intervals.set(callbackId, handle);
|
|
415
437
|
}
|
|
438
|
+
/** Clear an interval */
|
|
416
439
|
clearInterval(callbackId) {
|
|
417
440
|
const handle = this.#intervals.get(callbackId);
|
|
418
|
-
if (handle !==
|
|
441
|
+
if (handle !== void 0) {
|
|
419
442
|
clearInterval(handle);
|
|
420
443
|
this.#intervals.delete(callbackId);
|
|
421
444
|
}
|
|
@@ -426,6 +449,7 @@ class ZxBridgeCore {
|
|
|
426
449
|
}
|
|
427
450
|
this.#intervals.clear();
|
|
428
451
|
}
|
|
452
|
+
/** Write a string to WASM memory, returning pointer and length */
|
|
429
453
|
_writeStringToWasm(str) {
|
|
430
454
|
return this._writeBytesToWasm(textEncoder.encode(str));
|
|
431
455
|
}
|
|
@@ -434,6 +458,7 @@ class ZxBridgeCore {
|
|
|
434
458
|
writeBytes(ptr, data);
|
|
435
459
|
return { ptr, len: data.length };
|
|
436
460
|
}
|
|
461
|
+
/** Log a message from WASM at the given level (0=error, 1=warn, 2=info, 3=debug) */
|
|
437
462
|
static log(level, ptr, len) {
|
|
438
463
|
const msg = textDecoder.decode(getMemoryView().subarray(ptr, ptr + len));
|
|
439
464
|
switch (level) {
|
|
@@ -451,18 +476,34 @@ class ZxBridgeCore {
|
|
|
451
476
|
break;
|
|
452
477
|
}
|
|
453
478
|
}
|
|
479
|
+
/**
|
|
480
|
+
* Create the core import object for WASM instantiation.
|
|
481
|
+
* Includes only environment-agnostic bindings: log, fetch, and timers.
|
|
482
|
+
* Use ZxBridge.createImportObject (from wasm/index.ts) in browser contexts
|
|
483
|
+
* to additionally include DOM and WebSocket bindings.
|
|
484
|
+
*/
|
|
454
485
|
static createImportObject(bridgeRef) {
|
|
455
486
|
return {
|
|
456
487
|
...jsz.importObject(),
|
|
457
488
|
__zx_net: createFetchImports(() => {
|
|
458
|
-
if (!jsz.memory)
|
|
459
|
-
throw new Error("WASM memory is not ready");
|
|
489
|
+
if (!jsz.memory) throw new Error("WASM memory is not ready");
|
|
460
490
|
return jsz.memory;
|
|
461
491
|
}),
|
|
462
492
|
__zx: {
|
|
463
|
-
_log: (level, ptr, len) =>
|
|
493
|
+
_log: (level, ptr, len) => _ZxBridgeCore.log(level, ptr, len),
|
|
464
494
|
_fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
|
|
465
|
-
bridgeRef.current?.fetchAsync(
|
|
495
|
+
bridgeRef.current?.fetchAsync(
|
|
496
|
+
urlPtr,
|
|
497
|
+
urlLen,
|
|
498
|
+
methodPtr,
|
|
499
|
+
methodLen,
|
|
500
|
+
headersPtr,
|
|
501
|
+
headersLen,
|
|
502
|
+
bodyPtr,
|
|
503
|
+
bodyLen,
|
|
504
|
+
timeoutMs,
|
|
505
|
+
fetchId
|
|
506
|
+
);
|
|
466
507
|
},
|
|
467
508
|
_setTimeout: (callbackId, delayMs) => {
|
|
468
509
|
bridgeRef.current?.setTimeout(callbackId, delayMs);
|
|
@@ -476,72 +517,25 @@ class ZxBridgeCore {
|
|
|
476
517
|
}
|
|
477
518
|
};
|
|
478
519
|
}
|
|
479
|
-
}
|
|
520
|
+
};
|
|
521
|
+
|
|
480
522
|
// src/kv.ts
|
|
481
|
-
var exports_kv = {};
|
|
482
|
-
__export(exports_kv, {
|
|
483
|
-
createMemoryKV: () => createMemoryKV,
|
|
484
|
-
createKVImports: () => createKVImports
|
|
485
|
-
});
|
|
486
523
|
function putOptions(ttlSeconds) {
|
|
487
|
-
if (ttlSeconds < 60)
|
|
488
|
-
return;
|
|
524
|
+
if (ttlSeconds < 60) return void 0;
|
|
489
525
|
return { expirationTtl: ttlSeconds };
|
|
490
526
|
}
|
|
491
|
-
function createMemoryKV() {
|
|
492
|
-
const store = new Map;
|
|
493
|
-
function read(key) {
|
|
494
|
-
const entry = store.get(key);
|
|
495
|
-
if (!entry)
|
|
496
|
-
return null;
|
|
497
|
-
if (entry.expiresAt !== undefined && Date.now() >= entry.expiresAt) {
|
|
498
|
-
store.delete(key);
|
|
499
|
-
return null;
|
|
500
|
-
}
|
|
501
|
-
return entry.value;
|
|
502
|
-
}
|
|
503
|
-
function write(key, value, options) {
|
|
504
|
-
let expiresAt;
|
|
505
|
-
if (options?.expiration !== undefined) {
|
|
506
|
-
expiresAt = options.expiration * 1000;
|
|
507
|
-
} else if (options?.expirationTtl !== undefined) {
|
|
508
|
-
expiresAt = Date.now() + options.expirationTtl * 1000;
|
|
509
|
-
}
|
|
510
|
-
store.set(key, { value, expiresAt });
|
|
511
|
-
}
|
|
512
|
-
return {
|
|
513
|
-
async get(key) {
|
|
514
|
-
return read(key);
|
|
515
|
-
},
|
|
516
|
-
async put(key, value, options) {
|
|
517
|
-
write(key, value, options);
|
|
518
|
-
},
|
|
519
|
-
async delete(key) {
|
|
520
|
-
store.delete(key);
|
|
521
|
-
},
|
|
522
|
-
async list(options) {
|
|
523
|
-
const keys = [...store.keys()].filter((k) => {
|
|
524
|
-
if (options?.prefix && !k.startsWith(options.prefix))
|
|
525
|
-
return false;
|
|
526
|
-
return read(k) !== null;
|
|
527
|
-
}).map((name) => ({ name }));
|
|
528
|
-
return { keys };
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
527
|
function isSyncKVNamespace(binding) {
|
|
533
528
|
const candidate = binding;
|
|
534
529
|
return typeof candidate.getSync === "function" && typeof candidate.putSync === "function" && typeof candidate.deleteSync === "function" && typeof candidate.listSync === "function";
|
|
535
530
|
}
|
|
536
531
|
function createKVImports(bindings, getMemory) {
|
|
537
|
-
const encoder2 = new TextEncoder;
|
|
538
|
-
const decoder2 = new TextDecoder;
|
|
532
|
+
const encoder2 = new TextEncoder();
|
|
533
|
+
const decoder2 = new TextDecoder();
|
|
539
534
|
function readStr(ptr, len) {
|
|
540
535
|
return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
|
|
541
536
|
}
|
|
542
537
|
function writeBytes2(buf_ptr, buf_max, data) {
|
|
543
|
-
if (data.length > buf_max)
|
|
544
|
-
return -2;
|
|
538
|
+
if (data.length > buf_max) return -2;
|
|
545
539
|
new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
|
|
546
540
|
return data.length;
|
|
547
541
|
}
|
|
@@ -550,40 +544,36 @@ function createKVImports(bindings, getMemory) {
|
|
|
550
544
|
}
|
|
551
545
|
const Suspending = WebAssembly.Suspending;
|
|
552
546
|
if (typeof Suspending !== "function") {
|
|
553
|
-
let
|
|
547
|
+
let syncBinding2 = function(ns) {
|
|
554
548
|
const candidate = binding(ns);
|
|
555
549
|
return candidate && isSyncKVNamespace(candidate) ? candidate : null;
|
|
556
550
|
};
|
|
551
|
+
var syncBinding = syncBinding2;
|
|
557
552
|
return {
|
|
558
553
|
kv_get: (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
|
|
559
|
-
const b =
|
|
560
|
-
if (!b)
|
|
561
|
-
return -1;
|
|
554
|
+
const b = syncBinding2(readStr(ns_ptr, ns_len));
|
|
555
|
+
if (!b) return -1;
|
|
562
556
|
const value = b.getSync(readStr(key_ptr, key_len));
|
|
563
|
-
if (value === null)
|
|
564
|
-
return -1;
|
|
557
|
+
if (value === null) return -1;
|
|
565
558
|
return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
|
|
566
559
|
},
|
|
567
560
|
kv_put: (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
|
|
568
|
-
const b =
|
|
569
|
-
if (!b)
|
|
570
|
-
return 0;
|
|
561
|
+
const b = syncBinding2(readStr(ns_ptr, ns_len));
|
|
562
|
+
if (!b) return 0;
|
|
571
563
|
b.putSync(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
|
|
572
564
|
return 0;
|
|
573
565
|
},
|
|
574
566
|
kv_delete: (ns_ptr, ns_len, key_ptr, key_len) => {
|
|
575
|
-
const b =
|
|
576
|
-
if (!b)
|
|
577
|
-
return 0;
|
|
567
|
+
const b = syncBinding2(readStr(ns_ptr, ns_len));
|
|
568
|
+
if (!b) return 0;
|
|
578
569
|
b.deleteSync(readStr(key_ptr, key_len));
|
|
579
570
|
return 0;
|
|
580
571
|
},
|
|
581
572
|
kv_list: (ns_ptr, ns_len, pfx_ptr, pfx_len, buf_ptr, buf_max) => {
|
|
582
|
-
const b =
|
|
583
|
-
if (!b)
|
|
584
|
-
return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
|
|
573
|
+
const b = syncBinding2(readStr(ns_ptr, ns_len));
|
|
574
|
+
if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
|
|
585
575
|
const prefix = readStr(pfx_ptr, pfx_len);
|
|
586
|
-
const result = b.listSync(prefix.length > 0 ? { prefix } :
|
|
576
|
+
const result = b.listSync(prefix.length > 0 ? { prefix } : void 0);
|
|
587
577
|
return writeBytes2(buf_ptr, buf_max, encoder2.encode(JSON.stringify(result.keys.map((k) => k.name))));
|
|
588
578
|
}
|
|
589
579
|
};
|
|
@@ -591,33 +581,28 @@ function createKVImports(bindings, getMemory) {
|
|
|
591
581
|
return {
|
|
592
582
|
kv_get: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, buf_ptr, buf_max) => {
|
|
593
583
|
const b = binding(readStr(ns_ptr, ns_len));
|
|
594
|
-
if (!b)
|
|
595
|
-
return -1;
|
|
584
|
+
if (!b) return -1;
|
|
596
585
|
const value = await b.get(readStr(key_ptr, key_len));
|
|
597
|
-
if (value === null)
|
|
598
|
-
return -1;
|
|
586
|
+
if (value === null) return -1;
|
|
599
587
|
return writeBytes2(buf_ptr, buf_max, encoder2.encode(value));
|
|
600
588
|
}),
|
|
601
589
|
kv_put: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len, val_ptr, val_len, ttl_seconds) => {
|
|
602
590
|
const b = binding(readStr(ns_ptr, ns_len));
|
|
603
|
-
if (!b)
|
|
604
|
-
return -1;
|
|
591
|
+
if (!b) return -1;
|
|
605
592
|
await b.put(readStr(key_ptr, key_len), readStr(val_ptr, val_len), putOptions(ttl_seconds));
|
|
606
593
|
return 0;
|
|
607
594
|
}),
|
|
608
595
|
kv_delete: new Suspending(async (ns_ptr, ns_len, key_ptr, key_len) => {
|
|
609
596
|
const b = binding(readStr(ns_ptr, ns_len));
|
|
610
|
-
if (!b)
|
|
611
|
-
return -1;
|
|
597
|
+
if (!b) return -1;
|
|
612
598
|
await b.delete(readStr(key_ptr, key_len));
|
|
613
599
|
return 0;
|
|
614
600
|
}),
|
|
615
601
|
kv_list: new Suspending(async (ns_ptr, ns_len, prefix_ptr, prefix_len, buf_ptr, buf_max) => {
|
|
616
602
|
const b = binding(readStr(ns_ptr, ns_len));
|
|
617
|
-
if (!b)
|
|
618
|
-
return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
|
|
603
|
+
if (!b) return writeBytes2(buf_ptr, buf_max, encoder2.encode("[]"));
|
|
619
604
|
const prefix = readStr(prefix_ptr, prefix_len);
|
|
620
|
-
const result = await b.list(prefix.length > 0 ? { prefix } :
|
|
605
|
+
const result = await b.list(prefix.length > 0 ? { prefix } : void 0);
|
|
621
606
|
return writeBytes2(buf_ptr, buf_max, encoder2.encode(JSON.stringify(result.keys.map((k) => k.name))));
|
|
622
607
|
})
|
|
623
608
|
};
|
|
@@ -729,10 +714,9 @@ function createLocalStorageKV(options = {}) {
|
|
|
729
714
|
listSync(options2) {
|
|
730
715
|
const prefix = namespacePrefix + (options2?.prefix ?? "");
|
|
731
716
|
const keys = [];
|
|
732
|
-
for (let i = 0;i < storage.length; i += 1) {
|
|
717
|
+
for (let i = 0; i < storage.length; i += 1) {
|
|
733
718
|
const key = storage.key(i);
|
|
734
|
-
if (!key || !key.startsWith(prefix))
|
|
735
|
-
continue;
|
|
719
|
+
if (!key || !key.startsWith(prefix)) continue;
|
|
736
720
|
keys.push({ name: key.slice(namespacePrefix.length) });
|
|
737
721
|
}
|
|
738
722
|
return { keys };
|
|
@@ -753,8 +737,8 @@ function createBrowserKVBindings(options = {}) {
|
|
|
753
737
|
}
|
|
754
738
|
|
|
755
739
|
// src/wasm/index.ts
|
|
756
|
-
|
|
757
|
-
#websockets = new Map;
|
|
740
|
+
var ZxBridge = class extends ZxBridgeCore {
|
|
741
|
+
#websockets = /* @__PURE__ */ new Map();
|
|
758
742
|
#wsOnOpenHandler;
|
|
759
743
|
#wsOnMessageHandler;
|
|
760
744
|
#wsOnErrorHandler;
|
|
@@ -768,7 +752,9 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
768
752
|
this.#wsOnErrorHandler = wrapPromisingExport(exports.__zx_ws_onerror);
|
|
769
753
|
this.#wsOnCloseHandler = wrapPromisingExport(exports.__zx_ws_onclose);
|
|
770
754
|
this.#eventbridge = exports.__zx_eventbridge;
|
|
771
|
-
this.#eventbridgeAsync = wrapPromisingExport(
|
|
755
|
+
this.#eventbridgeAsync = wrapPromisingExport(
|
|
756
|
+
exports.__zx_eventbridge_async ?? exports.__zx_eventbridge
|
|
757
|
+
);
|
|
772
758
|
}
|
|
773
759
|
eventMaySuspend(velementId, eventTypeId) {
|
|
774
760
|
return !!((eventHandlerModes.get(velementId) ?? 0) & 1 << eventTypeId);
|
|
@@ -777,19 +763,19 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
777
763
|
const bit = 1 << eventTypeId;
|
|
778
764
|
const current = eventHandlerModes.get(velementId) ?? 0;
|
|
779
765
|
const next = maySuspend ? current | bit : current & ~bit;
|
|
780
|
-
if (next === 0)
|
|
781
|
-
|
|
782
|
-
else
|
|
783
|
-
eventHandlerModes.set(velementId, next);
|
|
766
|
+
if (next === 0) eventHandlerModes.delete(velementId);
|
|
767
|
+
else eventHandlerModes.set(velementId, next);
|
|
784
768
|
}
|
|
785
769
|
clearEventHandlerModes(velementId) {
|
|
786
770
|
eventHandlerModes.delete(velementId);
|
|
787
771
|
}
|
|
772
|
+
/** Submit a form action with bound-state round-trip. */
|
|
788
773
|
submitFormActionAsync(form, actionId, statesJson, fetchId) {
|
|
789
774
|
const formData = new FormData(form);
|
|
790
775
|
formData.append("__$states", statesJson);
|
|
791
776
|
fetch(window.location.href, {
|
|
792
777
|
method: "POST",
|
|
778
|
+
// `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
|
|
793
779
|
headers: { "x-action": String(actionId >>> 0) },
|
|
794
780
|
body: formData
|
|
795
781
|
}).then(async (response) => {
|
|
@@ -800,25 +786,27 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
800
786
|
this._notifyFetchComplete(fetchId, 0, msg, true);
|
|
801
787
|
});
|
|
802
788
|
}
|
|
789
|
+
/**
|
|
790
|
+
* Create and connect a WebSocket.
|
|
791
|
+
* Calls __zx_ws_onopen, __zx_ws_onmessage, __zx_ws_onerror, __zx_ws_onclose.
|
|
792
|
+
*/
|
|
803
793
|
wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) {
|
|
804
794
|
const url = readString(urlPtr, urlLen);
|
|
805
795
|
const protocolsStr = protocolsLen > 0 ? readString(protocolsPtr, protocolsLen) : "";
|
|
806
|
-
const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) :
|
|
796
|
+
const protocols = protocolsStr ? protocolsStr.split(",").map((p) => p.trim()).filter(Boolean) : void 0;
|
|
807
797
|
try {
|
|
808
798
|
const ws = protocols && protocols.length > 0 ? new WebSocket(url, protocols) : new WebSocket(url);
|
|
809
799
|
ws.binaryType = "arraybuffer";
|
|
810
800
|
ws.onopen = () => {
|
|
811
801
|
const handler = this.#wsOnOpenHandler;
|
|
812
|
-
if (!handler)
|
|
813
|
-
return;
|
|
802
|
+
if (!handler) return;
|
|
814
803
|
const protocol = ws.protocol || "";
|
|
815
804
|
const { ptr, len } = this._writeStringToWasm(protocol);
|
|
816
805
|
invokeWasmExport(handler, wsId, ptr, len);
|
|
817
806
|
};
|
|
818
807
|
ws.onmessage = (event) => {
|
|
819
808
|
const handler = this.#wsOnMessageHandler;
|
|
820
|
-
if (!handler)
|
|
821
|
-
return;
|
|
809
|
+
if (!handler) return;
|
|
822
810
|
const isBinary = event.data instanceof ArrayBuffer;
|
|
823
811
|
const data = isBinary ? new Uint8Array(event.data) : textEncoder.encode(event.data);
|
|
824
812
|
const { ptr, len } = this._writeBytesToWasm(data);
|
|
@@ -826,15 +814,13 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
826
814
|
};
|
|
827
815
|
ws.onerror = (_event) => {
|
|
828
816
|
const handler = this.#wsOnErrorHandler;
|
|
829
|
-
if (!handler)
|
|
830
|
-
return;
|
|
817
|
+
if (!handler) return;
|
|
831
818
|
const { ptr, len } = this._writeStringToWasm("WebSocket error");
|
|
832
819
|
invokeWasmExport(handler, wsId, ptr, len);
|
|
833
820
|
};
|
|
834
821
|
ws.onclose = (event) => {
|
|
835
822
|
const handler = this.#wsOnCloseHandler;
|
|
836
|
-
if (!handler)
|
|
837
|
-
return;
|
|
823
|
+
if (!handler) return;
|
|
838
824
|
const reason = event.reason || "";
|
|
839
825
|
const { ptr, len } = this._writeStringToWasm(reason);
|
|
840
826
|
invokeWasmExport(handler, wsId, event.code, ptr, len, event.wasClean ? 1 : 0);
|
|
@@ -850,10 +836,10 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
850
836
|
}
|
|
851
837
|
}
|
|
852
838
|
}
|
|
839
|
+
/** Send data over WebSocket */
|
|
853
840
|
wsSend(wsId, dataPtr, dataLen, isBinary) {
|
|
854
841
|
const ws = this.#websockets.get(wsId);
|
|
855
|
-
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
856
|
-
return;
|
|
842
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) return;
|
|
857
843
|
const memory = getMemoryView();
|
|
858
844
|
if (isBinary) {
|
|
859
845
|
ws.send(memory.slice(dataPtr, dataPtr + dataLen));
|
|
@@ -861,16 +847,14 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
861
847
|
ws.send(textDecoder.decode(memory.subarray(dataPtr, dataPtr + dataLen)));
|
|
862
848
|
}
|
|
863
849
|
}
|
|
850
|
+
/** Close WebSocket connection */
|
|
864
851
|
wsClose(wsId, code, reasonPtr, reasonLen) {
|
|
865
852
|
const ws = this.#websockets.get(wsId);
|
|
866
|
-
if (!ws)
|
|
867
|
-
|
|
868
|
-
const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : undefined;
|
|
853
|
+
if (!ws) return;
|
|
854
|
+
const reason = reasonLen > 0 ? readString(reasonPtr, reasonLen) : void 0;
|
|
869
855
|
try {
|
|
870
|
-
if (reason)
|
|
871
|
-
|
|
872
|
-
else
|
|
873
|
-
ws.close(code);
|
|
856
|
+
if (reason) ws.close(code, reason);
|
|
857
|
+
else ws.close(code);
|
|
874
858
|
} catch {
|
|
875
859
|
ws.close();
|
|
876
860
|
}
|
|
@@ -881,10 +865,12 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
881
865
|
for (const ws of this.#websockets.values()) {
|
|
882
866
|
try {
|
|
883
867
|
ws.close();
|
|
884
|
-
} catch {
|
|
868
|
+
} catch {
|
|
869
|
+
}
|
|
885
870
|
}
|
|
886
871
|
this.#websockets.clear();
|
|
887
872
|
}
|
|
873
|
+
/** Handle a DOM event (called by event delegation) */
|
|
888
874
|
eventbridge(velementId, eventTypeId, event) {
|
|
889
875
|
const eventRef = storeValueGetRef(event);
|
|
890
876
|
if (this.eventMaySuspend(velementId, eventTypeId)) {
|
|
@@ -893,12 +879,12 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
893
879
|
}
|
|
894
880
|
invokeWasmExport(this.#eventbridge, velementId, eventTypeId, eventRef);
|
|
895
881
|
}
|
|
882
|
+
/** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
|
|
896
883
|
static createImportObject(bridgeRef) {
|
|
897
884
|
return {
|
|
898
885
|
...jsz.importObject(),
|
|
899
886
|
__zx_net: createFetchImports(() => {
|
|
900
|
-
if (!jsz.memory)
|
|
901
|
-
throw new Error("WASM memory is not ready");
|
|
887
|
+
if (!jsz.memory) throw new Error("WASM memory is not ready");
|
|
902
888
|
return jsz.memory;
|
|
903
889
|
}),
|
|
904
890
|
__zx: {
|
|
@@ -910,7 +896,18 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
910
896
|
bridgeRef.current?.clearEventHandlerModes(vnodeId);
|
|
911
897
|
},
|
|
912
898
|
_fetchAsync: (urlPtr, urlLen, methodPtr, methodLen, headersPtr, headersLen, bodyPtr, bodyLen, timeoutMs, fetchId) => {
|
|
913
|
-
bridgeRef.current?.fetchAsync(
|
|
899
|
+
bridgeRef.current?.fetchAsync(
|
|
900
|
+
urlPtr,
|
|
901
|
+
urlLen,
|
|
902
|
+
methodPtr,
|
|
903
|
+
methodLen,
|
|
904
|
+
headersPtr,
|
|
905
|
+
headersLen,
|
|
906
|
+
bodyPtr,
|
|
907
|
+
bodyLen,
|
|
908
|
+
timeoutMs,
|
|
909
|
+
fetchId
|
|
910
|
+
);
|
|
914
911
|
},
|
|
915
912
|
_setTimeout: (callbackId, delayMs) => {
|
|
916
913
|
bridgeRef.current?.setTimeout(callbackId, delayMs);
|
|
@@ -921,6 +918,7 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
921
918
|
_clearInterval: (callbackId) => {
|
|
922
919
|
bridgeRef.current?.clearInterval(callbackId);
|
|
923
920
|
},
|
|
921
|
+
// WebSocket API
|
|
924
922
|
_wsConnect: (wsId, urlPtr, urlLen, protocolsPtr, protocolsLen) => {
|
|
925
923
|
bridgeRef.current?.wsConnect(wsId, urlPtr, urlLen, protocolsPtr, protocolsLen);
|
|
926
924
|
},
|
|
@@ -964,26 +962,22 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
964
962
|
},
|
|
965
963
|
_snv: (vnodeId, ptr, len) => {
|
|
966
964
|
const node = domNodes.get(vnodeId);
|
|
967
|
-
if (node)
|
|
968
|
-
node.nodeValue = readString(ptr, len);
|
|
965
|
+
if (node) node.nodeValue = readString(ptr, len);
|
|
969
966
|
},
|
|
970
967
|
_srh: (vnodeId, ptr, len) => {
|
|
971
968
|
const el = domNodes.get(vnodeId);
|
|
972
|
-
if (el)
|
|
973
|
-
el.innerHTML = readString(ptr, len);
|
|
969
|
+
if (el) el.innerHTML = readString(ptr, len);
|
|
974
970
|
},
|
|
975
971
|
_ac: (parentId, childId) => {
|
|
976
972
|
const parent = domNodes.get(parentId);
|
|
977
973
|
const child = domNodes.get(childId);
|
|
978
|
-
if (parent && child)
|
|
979
|
-
parent.appendChild(child);
|
|
974
|
+
if (parent && child) parent.appendChild(child);
|
|
980
975
|
},
|
|
981
976
|
_ib: (parentId, childId, refId) => {
|
|
982
977
|
const parent = domNodes.get(parentId);
|
|
983
978
|
const child = domNodes.get(childId);
|
|
984
979
|
const ref = domNodes.get(refId) ?? null;
|
|
985
|
-
if (parent && child)
|
|
986
|
-
parent.insertBefore(child, ref);
|
|
980
|
+
if (parent && child) parent.insertBefore(child, ref);
|
|
987
981
|
},
|
|
988
982
|
_rc: (parentId, childId) => {
|
|
989
983
|
const parent = domNodes.get(parentId);
|
|
@@ -1010,8 +1004,7 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
1010
1004
|
},
|
|
1011
1005
|
_getFormData: (vnodeId, bufPtr, bufLen) => {
|
|
1012
1006
|
const form = domNodes.get(vnodeId);
|
|
1013
|
-
if (!form || !(form instanceof HTMLFormElement))
|
|
1014
|
-
return 0;
|
|
1007
|
+
if (!form || !(form instanceof HTMLFormElement)) return 0;
|
|
1015
1008
|
const formData = new FormData(form);
|
|
1016
1009
|
const urlEncoded = new URLSearchParams(formData).toString();
|
|
1017
1010
|
const bytes = textEncoder.encode(urlEncoded);
|
|
@@ -1021,34 +1014,32 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
1021
1014
|
},
|
|
1022
1015
|
_submitFormAction: (vnodeId, actionId) => {
|
|
1023
1016
|
const form = domNodes.get(vnodeId);
|
|
1024
|
-
if (!form || !(form instanceof HTMLFormElement))
|
|
1025
|
-
return;
|
|
1017
|
+
if (!form || !(form instanceof HTMLFormElement)) return;
|
|
1026
1018
|
const formData = new FormData(form);
|
|
1027
1019
|
fetch(window.location.href, {
|
|
1028
1020
|
method: "POST",
|
|
1021
|
+
// `>>> 0` reinterprets the i32 from wasm as u32 (ids can exceed 2^31).
|
|
1029
1022
|
headers: { "x-action": String(actionId >>> 0) },
|
|
1030
1023
|
body: formData
|
|
1031
|
-
}).catch(() => {
|
|
1024
|
+
}).catch(() => {
|
|
1025
|
+
});
|
|
1032
1026
|
},
|
|
1033
1027
|
_submitFormActionAsync: (vnodeId, actionId, statesPtr, statesLen, fetchId) => {
|
|
1034
1028
|
const form = domNodes.get(vnodeId);
|
|
1035
|
-
if (!form || !(form instanceof HTMLFormElement))
|
|
1036
|
-
return;
|
|
1029
|
+
if (!form || !(form instanceof HTMLFormElement)) return;
|
|
1037
1030
|
const statesJson = statesLen > 0 ? readString(statesPtr, statesLen) : "[]";
|
|
1038
1031
|
bridgeRef.current?.submitFormActionAsync(form, actionId, statesJson, fetchId);
|
|
1039
1032
|
}
|
|
1040
1033
|
}
|
|
1041
1034
|
};
|
|
1042
1035
|
}
|
|
1043
|
-
}
|
|
1044
|
-
var domNodes = new Map;
|
|
1036
|
+
};
|
|
1037
|
+
var domNodes = /* @__PURE__ */ new Map();
|
|
1045
1038
|
function cleanupDomNodes(node) {
|
|
1046
1039
|
const ref = node.__zx_ref;
|
|
1047
|
-
if (ref !==
|
|
1048
|
-
domNodes.delete(BigInt(ref));
|
|
1040
|
+
if (ref !== void 0) domNodes.delete(BigInt(ref));
|
|
1049
1041
|
const children = node.childNodes;
|
|
1050
|
-
for (let i = 0;i < children.length; i++)
|
|
1051
|
-
cleanupDomNodes(children[i]);
|
|
1042
|
+
for (let i = 0; i < children.length; i++) cleanupDomNodes(children[i]);
|
|
1052
1043
|
}
|
|
1053
1044
|
var SVG_TAG_START_INDEX = 140;
|
|
1054
1045
|
var TAG_NAMES = [
|
|
@@ -1192,6 +1183,7 @@ var TAG_NAMES = [
|
|
|
1192
1183
|
"strike",
|
|
1193
1184
|
"tt",
|
|
1194
1185
|
"xmp",
|
|
1186
|
+
// SVG Tags
|
|
1195
1187
|
"animate",
|
|
1196
1188
|
"animateMotion",
|
|
1197
1189
|
"animateTransform",
|
|
@@ -1258,6 +1250,7 @@ var DELEGATED_EVENTS = [
|
|
|
1258
1250
|
{ domType: "input", eventTypeId: 2 },
|
|
1259
1251
|
{ domType: "change", eventTypeId: 3 },
|
|
1260
1252
|
{ domType: "submit", eventTypeId: 4 },
|
|
1253
|
+
// focus/blur do not bubble, so delegated handlers must listen to focusin/focusout.
|
|
1261
1254
|
{ domType: "focusin", eventTypeId: 5 },
|
|
1262
1255
|
{ domType: "focusout", eventTypeId: 6 },
|
|
1263
1256
|
{ domType: "keydown", eventTypeId: 7 },
|
|
@@ -1273,21 +1266,20 @@ var DELEGATED_EVENTS = [
|
|
|
1273
1266
|
{ domType: "touchmove", eventTypeId: 17 },
|
|
1274
1267
|
{ domType: "scroll", eventTypeId: 18 }
|
|
1275
1268
|
];
|
|
1276
|
-
var eventHandlerModes = new Map;
|
|
1269
|
+
var eventHandlerModes = /* @__PURE__ */ new Map();
|
|
1277
1270
|
function initEventDelegation(bridge, rootSelector = "body") {
|
|
1278
1271
|
const root = document.querySelector(rootSelector);
|
|
1279
|
-
if (!root)
|
|
1280
|
-
|
|
1272
|
+
if (!root) return () => {
|
|
1273
|
+
};
|
|
1281
1274
|
const removers = [];
|
|
1282
1275
|
for (const delegatedEvent of DELEGATED_EVENTS) {
|
|
1283
1276
|
const listener = (event) => {
|
|
1284
1277
|
let target = event.target;
|
|
1285
1278
|
while (target && target !== document.body) {
|
|
1286
1279
|
const zxRef = target.__zx_ref;
|
|
1287
|
-
if (zxRef !==
|
|
1280
|
+
if (zxRef !== void 0) {
|
|
1288
1281
|
bridge.eventbridge(BigInt(zxRef), delegatedEvent.eventTypeId, event);
|
|
1289
|
-
if (event.cancelBubble)
|
|
1290
|
-
break;
|
|
1282
|
+
if (event.cancelBubble) break;
|
|
1291
1283
|
}
|
|
1292
1284
|
target = target.parentElement;
|
|
1293
1285
|
}
|
|
@@ -1297,8 +1289,7 @@ function initEventDelegation(bridge, rootSelector = "body") {
|
|
|
1297
1289
|
removers.push(() => root.removeEventListener(delegatedEvent.domType, listener, options));
|
|
1298
1290
|
}
|
|
1299
1291
|
return () => {
|
|
1300
|
-
for (const remove of removers)
|
|
1301
|
-
remove();
|
|
1292
|
+
for (const remove of removers) remove();
|
|
1302
1293
|
};
|
|
1303
1294
|
}
|
|
1304
1295
|
var DEFAULT_URL = "/assets/_/main.wasm";
|
|
@@ -1320,8 +1311,7 @@ function normalizeOptions(options = {}) {
|
|
|
1320
1311
|
};
|
|
1321
1312
|
}
|
|
1322
1313
|
function registerDevReinit(options) {
|
|
1323
|
-
if (typeof window === "undefined")
|
|
1324
|
-
return;
|
|
1314
|
+
if (typeof window === "undefined") return;
|
|
1325
1315
|
const reinit = () => init(options);
|
|
1326
1316
|
window.__zx_dev_reinit = reinit;
|
|
1327
1317
|
window.__ZIEX_DEVTOOLS_GLOBAL_HOOK__ = {
|
|
@@ -1341,14 +1331,17 @@ async function init(options = {}) {
|
|
|
1341
1331
|
const kvBindings = options.kv ?? createBrowserKVBindings();
|
|
1342
1332
|
const kvImportObject = {
|
|
1343
1333
|
__zx_kv: createKVImports(kvBindings, () => {
|
|
1344
|
-
if (wasmMemory)
|
|
1345
|
-
|
|
1346
|
-
if (jsz.memory)
|
|
1347
|
-
return jsz.memory;
|
|
1334
|
+
if (wasmMemory) return wasmMemory;
|
|
1335
|
+
if (jsz.memory) return jsz.memory;
|
|
1348
1336
|
throw new Error("WASM memory is not ready");
|
|
1349
1337
|
})
|
|
1350
1338
|
};
|
|
1351
|
-
const importObject = Object.assign(
|
|
1339
|
+
const importObject = Object.assign(
|
|
1340
|
+
{},
|
|
1341
|
+
ZxBridge.createImportObject(bridgeRef),
|
|
1342
|
+
kvImportObject,
|
|
1343
|
+
options.importObject
|
|
1344
|
+
);
|
|
1352
1345
|
const source = await WebAssembly.instantiateStreaming(fetch(url), importObject);
|
|
1353
1346
|
const { instance } = source;
|
|
1354
1347
|
wasmMemory = instance.exports.memory;
|
|
@@ -1367,21 +1360,20 @@ async function init(options = {}) {
|
|
|
1367
1360
|
domNodes.clear();
|
|
1368
1361
|
}
|
|
1369
1362
|
};
|
|
1370
|
-
if (true)
|
|
1371
|
-
registerDevReinit(normalizedOptions);
|
|
1363
|
+
if (true) registerDevReinit(normalizedOptions);
|
|
1372
1364
|
return { source, bridge };
|
|
1373
1365
|
}
|
|
1374
1366
|
export {
|
|
1375
|
-
|
|
1376
|
-
textEncoder,
|
|
1377
|
-
textDecoder,
|
|
1378
|
-
storeValueGetRef,
|
|
1379
|
-
readString,
|
|
1380
|
-
jsz,
|
|
1381
|
-
initEventDelegation,
|
|
1382
|
-
init,
|
|
1383
|
-
getMemoryView,
|
|
1384
|
-
ZxBridgeCore,
|
|
1367
|
+
CallbackType,
|
|
1385
1368
|
ZxBridge,
|
|
1386
|
-
|
|
1369
|
+
ZxBridgeCore,
|
|
1370
|
+
getMemoryView,
|
|
1371
|
+
init,
|
|
1372
|
+
initEventDelegation,
|
|
1373
|
+
jsz,
|
|
1374
|
+
readString,
|
|
1375
|
+
storeValueGetRef,
|
|
1376
|
+
textDecoder,
|
|
1377
|
+
textEncoder,
|
|
1378
|
+
writeBytes
|
|
1387
1379
|
};
|