ziex 0.1.0-dev.866 → 0.1.0-dev.928
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/app.d.ts +12 -0
- package/aws-lambda/index.js +5 -1
- package/bin/ziex +19 -55
- package/cloudflare/db.d.ts +2 -0
- package/cloudflare/do.d.ts +2 -0
- package/cloudflare/index.js +221 -5
- package/db.d.ts +22 -0
- package/index.js +164 -1
- package/package.json +5 -13
- package/react/index.js +5 -1
- package/runtime.d.ts +4 -1
- package/vercel/index.js +5 -1
- package/wasm/core.d.ts +1 -0
- package/wasm/index.d.ts +8 -1
- package/wasm/index.js +61 -6
- package/wasm/init.js +56 -5
- package/install.cjs +0 -218
package/app.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DurableObjectNamespace } from "./runtime";
|
|
2
2
|
import type { KVNamespace } from "./kv";
|
|
3
|
+
import type { D1Database } from "./db";
|
|
3
4
|
import type { WASI } from "./wasi";
|
|
4
5
|
/**
|
|
5
6
|
* Anything that can be resolved to a `WebAssembly.Module`:
|
|
@@ -23,6 +24,9 @@ type KVKey<Env> = {
|
|
|
23
24
|
type DOKey<Env> = {
|
|
24
25
|
[K in keyof Env]: Env[K] extends DurableObjectNamespace ? K : never;
|
|
25
26
|
}[keyof Env];
|
|
27
|
+
type DBKey<Env> = {
|
|
28
|
+
[K in keyof Env]: Env[K] extends D1Database ? K : never;
|
|
29
|
+
}[keyof Env];
|
|
26
30
|
type ZiexOptions<Env> = {
|
|
27
31
|
/** WASM module — accepts any {@link WasmInput}. Resolved and cached on first request. */
|
|
28
32
|
module: WasmInput;
|
|
@@ -46,6 +50,13 @@ type ZiexOptions<Env> = {
|
|
|
46
50
|
* ```
|
|
47
51
|
*/
|
|
48
52
|
kv?: KVKey<Env> | Record<string, KVKey<Env>>;
|
|
53
|
+
/**
|
|
54
|
+
* D1 database bindings. Same shape as `kv`:
|
|
55
|
+
*
|
|
56
|
+
* - `"DB"` maps `env.DB` to the `"default"` database binding.
|
|
57
|
+
* - `{ default: "DB", analytics: "ANALYTICS_DB" }` maps multiple bindings.
|
|
58
|
+
*/
|
|
59
|
+
db?: DBKey<Env> | Record<string, DBKey<Env>>;
|
|
49
60
|
/**
|
|
50
61
|
* Env key whose value is a `DurableObjectNamespace` for WebSocket pub/sub.
|
|
51
62
|
* Requires `createWebSocketDO` export on the worker.
|
|
@@ -99,6 +110,7 @@ export declare class Ziex<Env = Record<string, unknown>> {
|
|
|
99
110
|
constructor(options: ZiexOptions<Env>);
|
|
100
111
|
private getModule;
|
|
101
112
|
private resolveKV;
|
|
113
|
+
private resolveDB;
|
|
102
114
|
/**
|
|
103
115
|
* Fetch handler called by the runtime on every request.
|
|
104
116
|
*
|
package/aws-lambda/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __returnValue = (v) => v;
|
|
3
|
+
function __exportSetter(name, newValue) {
|
|
4
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
+
}
|
|
2
6
|
var __export = (target, all) => {
|
|
3
7
|
for (var name in all)
|
|
4
8
|
__defProp(target, name, {
|
|
5
9
|
get: all[name],
|
|
6
10
|
enumerable: true,
|
|
7
11
|
configurable: true,
|
|
8
|
-
set: (
|
|
12
|
+
set: __exportSetter.bind(all, name)
|
|
9
13
|
});
|
|
10
14
|
};
|
|
11
15
|
|
package/bin/ziex
CHANGED
|
@@ -1,61 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
2
4
|
|
|
3
|
-
// Stub that delegates to the native zx binary.
|
|
4
|
-
// The postinstall script copies it to bin/zx, but if that hasn't run
|
|
5
|
-
// (e.g. bunx), we resolve the platform package's binary directly.
|
|
6
|
-
|
|
7
|
-
import { execFileSync } from "child_process";
|
|
8
|
-
import { existsSync } from "fs";
|
|
9
|
-
import { createRequire } from "module";
|
|
10
|
-
import { dirname, join } from "path";
|
|
11
|
-
import { fileURLToPath } from "url";
|
|
12
|
-
|
|
13
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
5
|
const require = createRequire(import.meta.url);
|
|
15
|
-
const
|
|
16
|
-
const ext = isWindows ? ".exe" : "";
|
|
17
|
-
|
|
18
|
-
function findBinary() {
|
|
19
|
-
// 1. Check if postinstall already placed the binary
|
|
20
|
-
const localBin = join(__dirname, `zx${ext}`);
|
|
21
|
-
if (existsSync(localBin)) return localBin;
|
|
22
|
-
|
|
23
|
-
// 2. Resolve from the platform-specific optional dependency
|
|
24
|
-
const platformPkgs = {
|
|
25
|
-
"darwin-arm64": "@ziex/cli-darwin-arm64",
|
|
26
|
-
"darwin-x64": "@ziex/cli-darwin-x64",
|
|
27
|
-
"linux-x64": "@ziex/cli-linux-x64",
|
|
28
|
-
"linux-arm64": "@ziex/cli-linux-arm64",
|
|
29
|
-
"win32-x64": "@ziex/cli-win32-x64",
|
|
30
|
-
"win32-arm64": "@ziex/cli-win32-arm64",
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const pkg = platformPkgs[`${process.platform}-${process.arch}`];
|
|
34
|
-
if (pkg) {
|
|
35
|
-
try {
|
|
36
|
-
const pkgDir = dirname(require.resolve(`${pkg}/package.json`));
|
|
37
|
-
const bin = join(pkgDir, "bin", `zx${ext}`);
|
|
38
|
-
if (existsSync(bin)) return bin;
|
|
39
|
-
} catch {}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const bin = findBinary();
|
|
46
|
-
if (!bin) {
|
|
47
|
-
console.error(
|
|
48
|
-
"Error: ziex native binary not found. The postinstall script may not have run.",
|
|
49
|
-
);
|
|
50
|
-
console.error("Try reinstalling: npm install -g ziex");
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
6
|
+
const pkgName = `@ziex/cli-${process.platform}-${process.arch}`;
|
|
53
7
|
|
|
54
8
|
try {
|
|
55
|
-
|
|
9
|
+
const binaryPath = require.resolve(`${pkgName}/bin/zx`);
|
|
10
|
+
|
|
11
|
+
const child = spawn(binaryPath, process.argv.slice(2), {
|
|
12
|
+
stdio: 'inherit',
|
|
13
|
+
shell: process.platform === 'win32'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
17
|
+
child.on('error', (err) => {
|
|
18
|
+
console.error('Failed to start child process:', err);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
56
21
|
} catch (e) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
22
|
+
console.error(`Error: Could not find binary for ${process.platform}-${process.arch}`);
|
|
23
|
+
console.error(`Ensure the optional dependency "${pkgName}" is installed.`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
package/cloudflare/do.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { WsState } from "../runtime";
|
|
2
2
|
import type { KVNamespace } from "../kv";
|
|
3
|
+
import type { D1Database } from "../db";
|
|
3
4
|
type ConnState = WsState & {
|
|
4
5
|
topics: Set<string>;
|
|
5
6
|
};
|
|
@@ -35,6 +36,7 @@ export declare function createWebSocketDO(module: WebAssembly.Module, options?:
|
|
|
35
36
|
* ```
|
|
36
37
|
*/
|
|
37
38
|
kv?: (env: any) => Record<string, KVNamespace>;
|
|
39
|
+
db?: (env: any) => Record<string, D1Database>;
|
|
38
40
|
imports?: (mem: () => WebAssembly.Memory) => Record<string, Record<string, unknown>>;
|
|
39
41
|
}): {
|
|
40
42
|
new (state: any, env: any): {
|
package/cloudflare/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __returnValue = (v) => v;
|
|
3
|
+
function __exportSetter(name, newValue) {
|
|
4
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
+
}
|
|
2
6
|
var __export = (target, all) => {
|
|
3
7
|
for (var name in all)
|
|
4
8
|
__defProp(target, name, {
|
|
5
9
|
get: all[name],
|
|
6
10
|
enumerable: true,
|
|
7
11
|
configurable: true,
|
|
8
|
-
set: (
|
|
12
|
+
set: __exportSetter.bind(all, name)
|
|
9
13
|
});
|
|
10
14
|
};
|
|
11
15
|
|
|
@@ -313,6 +317,12 @@ class ZxBridgeCore {
|
|
|
313
317
|
this.#intervals.delete(callbackId);
|
|
314
318
|
}
|
|
315
319
|
}
|
|
320
|
+
dispose() {
|
|
321
|
+
for (const handle of this.#intervals.values()) {
|
|
322
|
+
clearInterval(handle);
|
|
323
|
+
}
|
|
324
|
+
this.#intervals.clear();
|
|
325
|
+
}
|
|
316
326
|
_writeStringToWasm(str) {
|
|
317
327
|
return this._writeBytesToWasm(textEncoder.encode(str));
|
|
318
328
|
}
|
|
@@ -465,6 +475,15 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
465
475
|
ws.close();
|
|
466
476
|
}
|
|
467
477
|
}
|
|
478
|
+
dispose() {
|
|
479
|
+
super.dispose();
|
|
480
|
+
for (const ws of this.#websockets.values()) {
|
|
481
|
+
try {
|
|
482
|
+
ws.close();
|
|
483
|
+
} catch {}
|
|
484
|
+
}
|
|
485
|
+
this.#websockets.clear();
|
|
486
|
+
}
|
|
468
487
|
eventbridge(velementId, eventTypeId, event) {
|
|
469
488
|
if (!this.#eventbridge)
|
|
470
489
|
return;
|
|
@@ -847,9 +866,10 @@ var EVENT_TYPE_MAP = {
|
|
|
847
866
|
function initEventDelegation(bridge, rootSelector = "body") {
|
|
848
867
|
const root = document.querySelector(rootSelector);
|
|
849
868
|
if (!root)
|
|
850
|
-
return;
|
|
869
|
+
return () => {};
|
|
870
|
+
const removers = [];
|
|
851
871
|
for (const eventType of DELEGATED_EVENTS) {
|
|
852
|
-
|
|
872
|
+
const listener = (event) => {
|
|
853
873
|
let target = event.target;
|
|
854
874
|
while (target && target !== document.body) {
|
|
855
875
|
const zxRef = target.__zx_ref;
|
|
@@ -860,11 +880,36 @@ function initEventDelegation(bridge, rootSelector = "body") {
|
|
|
860
880
|
}
|
|
861
881
|
target = target.parentElement;
|
|
862
882
|
}
|
|
863
|
-
}
|
|
883
|
+
};
|
|
884
|
+
const options = { passive: eventType.startsWith("touch") || eventType === "scroll" };
|
|
885
|
+
root.addEventListener(eventType, listener, options);
|
|
886
|
+
removers.push(() => root.removeEventListener(eventType, listener, options));
|
|
864
887
|
}
|
|
888
|
+
return () => {
|
|
889
|
+
for (const remove of removers)
|
|
890
|
+
remove();
|
|
891
|
+
};
|
|
865
892
|
}
|
|
866
893
|
var DEFAULT_URL = "/assets/_/main.wasm";
|
|
894
|
+
var activeRuntime = null;
|
|
895
|
+
function normalizeOptions(options = {}) {
|
|
896
|
+
return {
|
|
897
|
+
url: options.url,
|
|
898
|
+
eventDelegationRoot: options.eventDelegationRoot,
|
|
899
|
+
importObject: options.importObject
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
function registerDevReinit(options) {
|
|
903
|
+
if (typeof window === "undefined")
|
|
904
|
+
return;
|
|
905
|
+
window.__zx_dev_reinit = () => init(options);
|
|
906
|
+
}
|
|
867
907
|
async function init(options = {}) {
|
|
908
|
+
const normalizedOptions = normalizeOptions(options);
|
|
909
|
+
if (activeRuntime) {
|
|
910
|
+
activeRuntime.dispose();
|
|
911
|
+
activeRuntime = null;
|
|
912
|
+
}
|
|
868
913
|
const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
|
|
869
914
|
const bridgeRef = { current: null };
|
|
870
915
|
const importObject = Object.assign({}, ZxBridge.createImportObject(bridgeRef), options.importObject);
|
|
@@ -873,10 +918,20 @@ async function init(options = {}) {
|
|
|
873
918
|
jsz.memory = instance.exports.memory;
|
|
874
919
|
const bridge = new ZxBridge(instance.exports);
|
|
875
920
|
bridgeRef.current = bridge;
|
|
876
|
-
|
|
921
|
+
domNodes.clear();
|
|
922
|
+
const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
|
|
877
923
|
const main = instance.exports.mainClient;
|
|
878
924
|
if (typeof main === "function")
|
|
879
925
|
main();
|
|
926
|
+
activeRuntime = {
|
|
927
|
+
options: normalizedOptions,
|
|
928
|
+
dispose: () => {
|
|
929
|
+
disposeDelegation();
|
|
930
|
+
bridge.dispose();
|
|
931
|
+
domNodes.clear();
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
registerDevReinit(normalizedOptions);
|
|
880
935
|
return { source, bridge };
|
|
881
936
|
}
|
|
882
937
|
|
|
@@ -1097,6 +1152,149 @@ function createKVImports(bindings, getMemory) {
|
|
|
1097
1152
|
};
|
|
1098
1153
|
}
|
|
1099
1154
|
|
|
1155
|
+
// src/db.ts
|
|
1156
|
+
function decodeBlob(base64) {
|
|
1157
|
+
const binary = atob(base64);
|
|
1158
|
+
const bytes = new Uint8Array(binary.length);
|
|
1159
|
+
for (let i = 0;i < binary.length; i++)
|
|
1160
|
+
bytes[i] = binary.charCodeAt(i);
|
|
1161
|
+
return bytes;
|
|
1162
|
+
}
|
|
1163
|
+
function toD1Value(value) {
|
|
1164
|
+
switch (value.kind) {
|
|
1165
|
+
case "null":
|
|
1166
|
+
return null;
|
|
1167
|
+
case "integer":
|
|
1168
|
+
return value.integer;
|
|
1169
|
+
case "float":
|
|
1170
|
+
return value.float;
|
|
1171
|
+
case "text":
|
|
1172
|
+
return value.text;
|
|
1173
|
+
case "blob":
|
|
1174
|
+
return decodeBlob(value.blob);
|
|
1175
|
+
case "boolean":
|
|
1176
|
+
return value.boolean;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
function toPositionalBindings(json) {
|
|
1180
|
+
switch (json.kind) {
|
|
1181
|
+
case "none":
|
|
1182
|
+
return [];
|
|
1183
|
+
case "positional":
|
|
1184
|
+
return json.values.map(toD1Value);
|
|
1185
|
+
case "named":
|
|
1186
|
+
throw new Error("Cloudflare D1 adapter does not support named bindings yet");
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
function toWireValue(value) {
|
|
1190
|
+
if (value === null || value === undefined)
|
|
1191
|
+
return { kind: "null" };
|
|
1192
|
+
if (typeof value === "string")
|
|
1193
|
+
return { kind: "text", text: value };
|
|
1194
|
+
if (typeof value === "boolean")
|
|
1195
|
+
return { kind: "boolean", boolean: value };
|
|
1196
|
+
if (typeof value === "number") {
|
|
1197
|
+
return Number.isInteger(value) ? { kind: "integer", integer: value } : { kind: "float", float: value };
|
|
1198
|
+
}
|
|
1199
|
+
if (value instanceof ArrayBuffer) {
|
|
1200
|
+
const bytes = new Uint8Array(value);
|
|
1201
|
+
let binary = "";
|
|
1202
|
+
for (const byte of bytes)
|
|
1203
|
+
binary += String.fromCharCode(byte);
|
|
1204
|
+
return { kind: "blob", blob: btoa(binary) };
|
|
1205
|
+
}
|
|
1206
|
+
if (ArrayBuffer.isView(value)) {
|
|
1207
|
+
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
1208
|
+
let binary = "";
|
|
1209
|
+
for (const byte of bytes)
|
|
1210
|
+
binary += String.fromCharCode(byte);
|
|
1211
|
+
return { kind: "blob", blob: btoa(binary) };
|
|
1212
|
+
}
|
|
1213
|
+
return { kind: "text", text: String(value) };
|
|
1214
|
+
}
|
|
1215
|
+
function objectToWireRow(record) {
|
|
1216
|
+
return {
|
|
1217
|
+
fields: Object.entries(record).map(([name, value]) => ({
|
|
1218
|
+
name,
|
|
1219
|
+
value: toWireValue(value)
|
|
1220
|
+
}))
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
function valuesToWireRows(rows) {
|
|
1224
|
+
return rows.map((row) => row.map((value) => toWireValue(value)));
|
|
1225
|
+
}
|
|
1226
|
+
function createD1Imports(bindings, getMemory) {
|
|
1227
|
+
const encoder3 = new TextEncoder;
|
|
1228
|
+
const decoder3 = new TextDecoder;
|
|
1229
|
+
function readStr(ptr, len) {
|
|
1230
|
+
return decoder3.decode(new Uint8Array(getMemory().buffer, ptr, len));
|
|
1231
|
+
}
|
|
1232
|
+
function writeJson(buf_ptr, buf_max, value) {
|
|
1233
|
+
const data = encoder3.encode(JSON.stringify(value));
|
|
1234
|
+
if (data.length > buf_max)
|
|
1235
|
+
return -2;
|
|
1236
|
+
new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
|
|
1237
|
+
return data.length;
|
|
1238
|
+
}
|
|
1239
|
+
function binding(ns) {
|
|
1240
|
+
return bindings[ns] ?? bindings["default"] ?? null;
|
|
1241
|
+
}
|
|
1242
|
+
async function statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len) {
|
|
1243
|
+
const database = binding(readStr(ns_ptr, ns_len));
|
|
1244
|
+
if (!database)
|
|
1245
|
+
return null;
|
|
1246
|
+
const sql = readStr(sql_ptr, sql_len);
|
|
1247
|
+
const bindingsJson = JSON.parse(readStr(bindings_ptr, bindings_len));
|
|
1248
|
+
return database.prepare(sql).bind(...toPositionalBindings(bindingsJson));
|
|
1249
|
+
}
|
|
1250
|
+
const Suspending = WebAssembly.Suspending;
|
|
1251
|
+
if (typeof Suspending !== "function") {
|
|
1252
|
+
return {
|
|
1253
|
+
db_open: (_ns, _ns_len) => -1,
|
|
1254
|
+
db_run: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
|
|
1255
|
+
db_get: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
|
|
1256
|
+
db_all: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
|
|
1257
|
+
db_values: (_a, _b, _c, _d, _e, _f, _g, _h) => -1
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
return {
|
|
1261
|
+
db_open: (ns_ptr, ns_len) => binding(readStr(ns_ptr, ns_len)) ? 0 : -1,
|
|
1262
|
+
db_run: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
1263
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
1264
|
+
if (!stmt)
|
|
1265
|
+
return -1;
|
|
1266
|
+
const result = await stmt.run();
|
|
1267
|
+
return writeJson(buf_ptr, buf_max, {
|
|
1268
|
+
last_insert_rowid: result.meta?.last_row_id ?? 0,
|
|
1269
|
+
changes: result.meta?.changes ?? 0
|
|
1270
|
+
});
|
|
1271
|
+
}),
|
|
1272
|
+
db_get: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
1273
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
1274
|
+
if (!stmt)
|
|
1275
|
+
return -1;
|
|
1276
|
+
const row = await stmt.first();
|
|
1277
|
+
if (!row)
|
|
1278
|
+
return 0;
|
|
1279
|
+
return writeJson(buf_ptr, buf_max, [objectToWireRow(row)]);
|
|
1280
|
+
}),
|
|
1281
|
+
db_all: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
1282
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
1283
|
+
if (!stmt)
|
|
1284
|
+
return -1;
|
|
1285
|
+
const result = await stmt.all();
|
|
1286
|
+
return writeJson(buf_ptr, buf_max, (result.results ?? []).map(objectToWireRow));
|
|
1287
|
+
}),
|
|
1288
|
+
db_values: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
1289
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
1290
|
+
if (!stmt)
|
|
1291
|
+
return -1;
|
|
1292
|
+
const rows = await stmt.raw();
|
|
1293
|
+
return writeJson(buf_ptr, buf_max, valuesToWireRows(rows));
|
|
1294
|
+
})
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1100
1298
|
// src/wasi.ts
|
|
1101
1299
|
class ProcExit extends Error {
|
|
1102
1300
|
code;
|
|
@@ -1473,6 +1671,7 @@ async function run({
|
|
|
1473
1671
|
ctx,
|
|
1474
1672
|
module,
|
|
1475
1673
|
kv: kvBindings,
|
|
1674
|
+
db: dbBindings,
|
|
1476
1675
|
imports,
|
|
1477
1676
|
wasi,
|
|
1478
1677
|
websocket: doNamespace
|
|
@@ -1511,6 +1710,7 @@ async function run({
|
|
|
1511
1710
|
__zx_sys: buildSysImports(jspi, Suspending),
|
|
1512
1711
|
__zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder, wsState),
|
|
1513
1712
|
__zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
|
|
1713
|
+
__zx_db: createD1Imports(dbBindings ?? {}, mem),
|
|
1514
1714
|
...imports ? imports(mem) : {},
|
|
1515
1715
|
...ZxWasiBridge.createImportObject(bridgeRef)
|
|
1516
1716
|
});
|
|
@@ -1589,6 +1789,19 @@ class Ziex {
|
|
|
1589
1789
|
}
|
|
1590
1790
|
return { default: env[kv] };
|
|
1591
1791
|
}
|
|
1792
|
+
resolveDB(env) {
|
|
1793
|
+
const { db } = this.options;
|
|
1794
|
+
if (db === undefined)
|
|
1795
|
+
return;
|
|
1796
|
+
if (typeof db === "object" && db !== null) {
|
|
1797
|
+
const result = {};
|
|
1798
|
+
for (const [name, key] of Object.entries(db)) {
|
|
1799
|
+
result[name] = env[key];
|
|
1800
|
+
}
|
|
1801
|
+
return result;
|
|
1802
|
+
}
|
|
1803
|
+
return { default: env[db] };
|
|
1804
|
+
}
|
|
1592
1805
|
fetch = async (request, env, ctx) => {
|
|
1593
1806
|
const module = await this.getModule();
|
|
1594
1807
|
const { wasi, imports, websocket } = this.options;
|
|
@@ -1600,6 +1813,7 @@ class Ziex {
|
|
|
1600
1813
|
wasi,
|
|
1601
1814
|
imports,
|
|
1602
1815
|
kv: this.resolveKV(env),
|
|
1816
|
+
db: this.resolveDB(env),
|
|
1603
1817
|
websocket: websocket !== undefined ? env[websocket] : undefined
|
|
1604
1818
|
});
|
|
1605
1819
|
};
|
|
@@ -1662,11 +1876,13 @@ function createWebSocketDO(module, options) {
|
|
|
1662
1876
|
};
|
|
1663
1877
|
const wsImports = buildWsImports(jspi ? Suspending : null, mem, decoder3, connState);
|
|
1664
1878
|
const kvBindings = options?.kv?.(this.env);
|
|
1879
|
+
const dbBindings = options?.db?.(this.env);
|
|
1665
1880
|
const instance = new WebAssembly.Instance(module, {
|
|
1666
1881
|
wasi_snapshot_preview1: wasiImport,
|
|
1667
1882
|
__zx_sys: sysImports,
|
|
1668
1883
|
__zx_ws: wsImports,
|
|
1669
1884
|
__zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
|
|
1885
|
+
__zx_db: createD1Imports(dbBindings ?? {}, mem),
|
|
1670
1886
|
...options?.imports ? options.imports(mem) : {},
|
|
1671
1887
|
...bridgeImports
|
|
1672
1888
|
});
|
package/db.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type D1Value = null | string | number | boolean | ArrayBuffer | ArrayBufferView;
|
|
2
|
+
export interface D1ExecResult {
|
|
3
|
+
meta?: {
|
|
4
|
+
changes?: number;
|
|
5
|
+
last_row_id?: number;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export interface D1PreparedStatement {
|
|
9
|
+
bind(...values: D1Value[]): D1PreparedStatement;
|
|
10
|
+
first<T = Record<string, unknown>>(): Promise<T | null>;
|
|
11
|
+
all<T = Record<string, unknown>>(): Promise<{
|
|
12
|
+
results?: T[];
|
|
13
|
+
}>;
|
|
14
|
+
raw(options?: {
|
|
15
|
+
columnNames?: boolean;
|
|
16
|
+
}): Promise<unknown[][]>;
|
|
17
|
+
run(): Promise<D1ExecResult>;
|
|
18
|
+
}
|
|
19
|
+
export interface D1Database {
|
|
20
|
+
prepare(query: string): D1PreparedStatement;
|
|
21
|
+
}
|
|
22
|
+
export declare function createD1Imports(bindings: Record<string, D1Database>, getMemory: () => WebAssembly.Memory): Record<string, unknown>;
|
package/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __returnValue = (v) => v;
|
|
3
|
+
function __exportSetter(name, newValue) {
|
|
4
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
+
}
|
|
2
6
|
var __export = (target, all) => {
|
|
3
7
|
for (var name in all)
|
|
4
8
|
__defProp(target, name, {
|
|
5
9
|
get: all[name],
|
|
6
10
|
enumerable: true,
|
|
7
11
|
configurable: true,
|
|
8
|
-
set: (
|
|
12
|
+
set: __exportSetter.bind(all, name)
|
|
9
13
|
});
|
|
10
14
|
};
|
|
11
15
|
|
|
@@ -226,6 +230,149 @@ function createKVImports(bindings, getMemory) {
|
|
|
226
230
|
};
|
|
227
231
|
}
|
|
228
232
|
|
|
233
|
+
// src/db.ts
|
|
234
|
+
function decodeBlob(base64) {
|
|
235
|
+
const binary = atob(base64);
|
|
236
|
+
const bytes = new Uint8Array(binary.length);
|
|
237
|
+
for (let i = 0;i < binary.length; i++)
|
|
238
|
+
bytes[i] = binary.charCodeAt(i);
|
|
239
|
+
return bytes;
|
|
240
|
+
}
|
|
241
|
+
function toD1Value(value) {
|
|
242
|
+
switch (value.kind) {
|
|
243
|
+
case "null":
|
|
244
|
+
return null;
|
|
245
|
+
case "integer":
|
|
246
|
+
return value.integer;
|
|
247
|
+
case "float":
|
|
248
|
+
return value.float;
|
|
249
|
+
case "text":
|
|
250
|
+
return value.text;
|
|
251
|
+
case "blob":
|
|
252
|
+
return decodeBlob(value.blob);
|
|
253
|
+
case "boolean":
|
|
254
|
+
return value.boolean;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function toPositionalBindings(json) {
|
|
258
|
+
switch (json.kind) {
|
|
259
|
+
case "none":
|
|
260
|
+
return [];
|
|
261
|
+
case "positional":
|
|
262
|
+
return json.values.map(toD1Value);
|
|
263
|
+
case "named":
|
|
264
|
+
throw new Error("Cloudflare D1 adapter does not support named bindings yet");
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function toWireValue(value) {
|
|
268
|
+
if (value === null || value === undefined)
|
|
269
|
+
return { kind: "null" };
|
|
270
|
+
if (typeof value === "string")
|
|
271
|
+
return { kind: "text", text: value };
|
|
272
|
+
if (typeof value === "boolean")
|
|
273
|
+
return { kind: "boolean", boolean: value };
|
|
274
|
+
if (typeof value === "number") {
|
|
275
|
+
return Number.isInteger(value) ? { kind: "integer", integer: value } : { kind: "float", float: value };
|
|
276
|
+
}
|
|
277
|
+
if (value instanceof ArrayBuffer) {
|
|
278
|
+
const bytes = new Uint8Array(value);
|
|
279
|
+
let binary = "";
|
|
280
|
+
for (const byte of bytes)
|
|
281
|
+
binary += String.fromCharCode(byte);
|
|
282
|
+
return { kind: "blob", blob: btoa(binary) };
|
|
283
|
+
}
|
|
284
|
+
if (ArrayBuffer.isView(value)) {
|
|
285
|
+
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
286
|
+
let binary = "";
|
|
287
|
+
for (const byte of bytes)
|
|
288
|
+
binary += String.fromCharCode(byte);
|
|
289
|
+
return { kind: "blob", blob: btoa(binary) };
|
|
290
|
+
}
|
|
291
|
+
return { kind: "text", text: String(value) };
|
|
292
|
+
}
|
|
293
|
+
function objectToWireRow(record) {
|
|
294
|
+
return {
|
|
295
|
+
fields: Object.entries(record).map(([name, value]) => ({
|
|
296
|
+
name,
|
|
297
|
+
value: toWireValue(value)
|
|
298
|
+
}))
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function valuesToWireRows(rows) {
|
|
302
|
+
return rows.map((row) => row.map((value) => toWireValue(value)));
|
|
303
|
+
}
|
|
304
|
+
function createD1Imports(bindings, getMemory) {
|
|
305
|
+
const encoder2 = new TextEncoder;
|
|
306
|
+
const decoder2 = new TextDecoder;
|
|
307
|
+
function readStr(ptr, len) {
|
|
308
|
+
return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
|
|
309
|
+
}
|
|
310
|
+
function writeJson(buf_ptr, buf_max, value) {
|
|
311
|
+
const data = encoder2.encode(JSON.stringify(value));
|
|
312
|
+
if (data.length > buf_max)
|
|
313
|
+
return -2;
|
|
314
|
+
new Uint8Array(getMemory().buffer, buf_ptr, data.length).set(data);
|
|
315
|
+
return data.length;
|
|
316
|
+
}
|
|
317
|
+
function binding(ns) {
|
|
318
|
+
return bindings[ns] ?? bindings["default"] ?? null;
|
|
319
|
+
}
|
|
320
|
+
async function statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len) {
|
|
321
|
+
const database = binding(readStr(ns_ptr, ns_len));
|
|
322
|
+
if (!database)
|
|
323
|
+
return null;
|
|
324
|
+
const sql = readStr(sql_ptr, sql_len);
|
|
325
|
+
const bindingsJson = JSON.parse(readStr(bindings_ptr, bindings_len));
|
|
326
|
+
return database.prepare(sql).bind(...toPositionalBindings(bindingsJson));
|
|
327
|
+
}
|
|
328
|
+
const Suspending = WebAssembly.Suspending;
|
|
329
|
+
if (typeof Suspending !== "function") {
|
|
330
|
+
return {
|
|
331
|
+
db_open: (_ns, _ns_len) => -1,
|
|
332
|
+
db_run: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
|
|
333
|
+
db_get: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
|
|
334
|
+
db_all: (_a, _b, _c, _d, _e, _f, _g, _h) => -1,
|
|
335
|
+
db_values: (_a, _b, _c, _d, _e, _f, _g, _h) => -1
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
db_open: (ns_ptr, ns_len) => binding(readStr(ns_ptr, ns_len)) ? 0 : -1,
|
|
340
|
+
db_run: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
341
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
342
|
+
if (!stmt)
|
|
343
|
+
return -1;
|
|
344
|
+
const result = await stmt.run();
|
|
345
|
+
return writeJson(buf_ptr, buf_max, {
|
|
346
|
+
last_insert_rowid: result.meta?.last_row_id ?? 0,
|
|
347
|
+
changes: result.meta?.changes ?? 0
|
|
348
|
+
});
|
|
349
|
+
}),
|
|
350
|
+
db_get: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
351
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
352
|
+
if (!stmt)
|
|
353
|
+
return -1;
|
|
354
|
+
const row = await stmt.first();
|
|
355
|
+
if (!row)
|
|
356
|
+
return 0;
|
|
357
|
+
return writeJson(buf_ptr, buf_max, [objectToWireRow(row)]);
|
|
358
|
+
}),
|
|
359
|
+
db_all: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
360
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
361
|
+
if (!stmt)
|
|
362
|
+
return -1;
|
|
363
|
+
const result = await stmt.all();
|
|
364
|
+
return writeJson(buf_ptr, buf_max, (result.results ?? []).map(objectToWireRow));
|
|
365
|
+
}),
|
|
366
|
+
db_values: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, buf_ptr, buf_max) => {
|
|
367
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
368
|
+
if (!stmt)
|
|
369
|
+
return -1;
|
|
370
|
+
const rows = await stmt.raw();
|
|
371
|
+
return writeJson(buf_ptr, buf_max, valuesToWireRows(rows));
|
|
372
|
+
})
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
229
376
|
// src/wasi.ts
|
|
230
377
|
class ProcExit extends Error {
|
|
231
378
|
code;
|
|
@@ -602,6 +749,7 @@ async function run({
|
|
|
602
749
|
ctx,
|
|
603
750
|
module,
|
|
604
751
|
kv: kvBindings,
|
|
752
|
+
db: dbBindings,
|
|
605
753
|
imports,
|
|
606
754
|
wasi,
|
|
607
755
|
websocket: doNamespace
|
|
@@ -640,6 +788,7 @@ async function run({
|
|
|
640
788
|
__zx_sys: buildSysImports(jspi, Suspending),
|
|
641
789
|
__zx_ws: buildWsImports(jspi ? Suspending : null, mem, new TextDecoder, wsState),
|
|
642
790
|
__zx_kv: createKVImports(kvBindings ?? { default: createMemoryKV() }, mem),
|
|
791
|
+
__zx_db: createD1Imports(dbBindings ?? {}, mem),
|
|
643
792
|
...imports ? imports(mem) : {},
|
|
644
793
|
...ZxWasiBridge.createImportObject(bridgeRef)
|
|
645
794
|
});
|
|
@@ -719,6 +868,19 @@ class Ziex {
|
|
|
719
868
|
}
|
|
720
869
|
return { default: env[kv] };
|
|
721
870
|
}
|
|
871
|
+
resolveDB(env) {
|
|
872
|
+
const { db } = this.options;
|
|
873
|
+
if (db === undefined)
|
|
874
|
+
return;
|
|
875
|
+
if (typeof db === "object" && db !== null) {
|
|
876
|
+
const result = {};
|
|
877
|
+
for (const [name, key] of Object.entries(db)) {
|
|
878
|
+
result[name] = env[key];
|
|
879
|
+
}
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
882
|
+
return { default: env[db] };
|
|
883
|
+
}
|
|
722
884
|
fetch = async (request, env, ctx) => {
|
|
723
885
|
const module = await this.getModule();
|
|
724
886
|
const { wasi, imports, websocket } = this.options;
|
|
@@ -730,6 +892,7 @@ class Ziex {
|
|
|
730
892
|
wasi,
|
|
731
893
|
imports,
|
|
732
894
|
kv: this.resolveKV(env),
|
|
895
|
+
db: this.resolveDB(env),
|
|
733
896
|
websocket: websocket !== undefined ? env[websocket] : undefined
|
|
734
897
|
});
|
|
735
898
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ziex",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.928",
|
|
4
4
|
"description": "ZX is a framework for building web applications with Zig.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"ziex": "bin/ziex"
|
|
9
|
-
"zx": "bin/ziex"
|
|
8
|
+
"ziex": "bin/ziex"
|
|
10
9
|
},
|
|
11
10
|
"exports": {
|
|
12
11
|
".": "./index.js",
|
|
@@ -36,8 +35,9 @@
|
|
|
36
35
|
],
|
|
37
36
|
"author": "Nurul Huda (Apon) <me@nurulhudaapon.com>",
|
|
38
37
|
"license": "MIT",
|
|
39
|
-
"scripts": {
|
|
40
|
-
|
|
38
|
+
"scripts": {},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@ziex/cli": "0.1.0-dev.928"
|
|
41
41
|
},
|
|
42
42
|
"peerDependenciesMeta": {
|
|
43
43
|
"react": {
|
|
@@ -47,14 +47,6 @@
|
|
|
47
47
|
"optional": true
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
|
-
"optionalDependencies": {
|
|
51
|
-
"@ziex/cli-darwin-arm64": "0.1.0-dev.805",
|
|
52
|
-
"@ziex/cli-darwin-x64": "0.1.0-dev.805",
|
|
53
|
-
"@ziex/cli-linux-x64": "0.1.0-dev.805",
|
|
54
|
-
"@ziex/cli-linux-arm64": "0.1.0-dev.805",
|
|
55
|
-
"@ziex/cli-win32-x64": "0.1.0-dev.805",
|
|
56
|
-
"@ziex/cli-win32-arm64": "0.1.0-dev.805"
|
|
57
|
-
},
|
|
58
50
|
"module": "index.js",
|
|
59
51
|
"types": "index.d.ts"
|
|
60
52
|
}
|
package/react/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __returnValue = (v) => v;
|
|
3
|
+
function __exportSetter(name, newValue) {
|
|
4
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
+
}
|
|
2
6
|
var __export = (target, all) => {
|
|
3
7
|
for (var name in all)
|
|
4
8
|
__defProp(target, name, {
|
|
5
9
|
get: all[name],
|
|
6
10
|
enumerable: true,
|
|
7
11
|
configurable: true,
|
|
8
|
-
set: (
|
|
12
|
+
set: __exportSetter.bind(all, name)
|
|
9
13
|
});
|
|
10
14
|
};
|
|
11
15
|
|
package/runtime.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { WASI } from "./wasi";
|
|
2
2
|
import type { KVNamespace } from "./kv";
|
|
3
|
+
import type { D1Database } from "./db";
|
|
3
4
|
/** Minimal Durable Object namespace shape needed for WebSocket routing. */
|
|
4
5
|
export type DurableObjectNamespace = {
|
|
5
6
|
idFromName(name: string): unknown;
|
|
@@ -50,7 +51,7 @@ export declare function attachWebSocket(ws: WsState): {
|
|
|
50
51
|
* });
|
|
51
52
|
* ```
|
|
52
53
|
*/
|
|
53
|
-
export declare function run({ request, env, ctx, module, kv: kvBindings, imports, wasi, websocket: doNamespace, }: {
|
|
54
|
+
export declare function run({ request, env, ctx, module, kv: kvBindings, db: dbBindings, imports, wasi, websocket: doNamespace, }: {
|
|
54
55
|
request: Request;
|
|
55
56
|
env?: unknown;
|
|
56
57
|
ctx?: {
|
|
@@ -59,6 +60,8 @@ export declare function run({ request, env, ctx, module, kv: kvBindings, imports
|
|
|
59
60
|
module: WebAssembly.Module;
|
|
60
61
|
/** KV namespace bindings — `{ default: env.KV, otherName: env.OTHER_KV }` */
|
|
61
62
|
kv?: Record<string, KVNamespace>;
|
|
63
|
+
/** D1 bindings — `{ default: env.DB, analytics: env.ANALYTICS_DB }` */
|
|
64
|
+
db?: Record<string, D1Database>;
|
|
62
65
|
imports?: (mem: () => WebAssembly.Memory) => Record<string, Record<string, unknown>>;
|
|
63
66
|
wasi?: WASI;
|
|
64
67
|
/**
|
package/vercel/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __returnValue = (v) => v;
|
|
3
|
+
function __exportSetter(name, newValue) {
|
|
4
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
+
}
|
|
2
6
|
var __export = (target, all) => {
|
|
3
7
|
for (var name in all)
|
|
4
8
|
__defProp(target, name, {
|
|
5
9
|
get: all[name],
|
|
6
10
|
enumerable: true,
|
|
7
11
|
configurable: true,
|
|
8
|
-
set: (
|
|
12
|
+
set: __exportSetter.bind(all, name)
|
|
9
13
|
});
|
|
10
14
|
};
|
|
11
15
|
|
package/wasm/core.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export declare class ZxBridgeCore {
|
|
|
55
55
|
setInterval(callbackId: bigint, intervalMs: number): void;
|
|
56
56
|
/** Clear an interval */
|
|
57
57
|
clearInterval(callbackId: bigint): void;
|
|
58
|
+
dispose(): void;
|
|
58
59
|
/** Write a string to WASM memory, returning pointer and length */
|
|
59
60
|
protected _writeStringToWasm(str: string): {
|
|
60
61
|
ptr: number;
|
package/wasm/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare class ZxBridge extends ZxBridgeCore {
|
|
|
20
20
|
wsSend(wsId: bigint, dataPtr: number, dataLen: number, isBinary: number): void;
|
|
21
21
|
/** Close WebSocket connection */
|
|
22
22
|
wsClose(wsId: bigint, code: number, reasonPtr: number, reasonLen: number): void;
|
|
23
|
+
dispose(): void;
|
|
23
24
|
/** Handle a DOM event (called by event delegation) */
|
|
24
25
|
eventbridge(velementId: bigint, eventTypeId: number, event: Event): void;
|
|
25
26
|
/** Create the full browser import object for WASM instantiation (includes DOM + WebSocket). */
|
|
@@ -28,7 +29,7 @@ export declare class ZxBridge extends ZxBridgeCore {
|
|
|
28
29
|
}): WebAssembly.Imports;
|
|
29
30
|
}
|
|
30
31
|
/** Initialize event delegation */
|
|
31
|
-
export declare function initEventDelegation(bridge: ZxBridge, rootSelector?: string): void;
|
|
32
|
+
export declare function initEventDelegation(bridge: ZxBridge, rootSelector?: string): () => void;
|
|
32
33
|
export type InitOptions = {
|
|
33
34
|
url?: string;
|
|
34
35
|
eventDelegationRoot?: string;
|
|
@@ -43,4 +44,10 @@ declare global {
|
|
|
43
44
|
interface HTMLElement {
|
|
44
45
|
__zx_ref?: number;
|
|
45
46
|
}
|
|
47
|
+
interface Window {
|
|
48
|
+
__zx_dev_reinit?: () => Promise<{
|
|
49
|
+
source: WebAssembly.WebAssemblyInstantiatedSource;
|
|
50
|
+
bridge: ZxBridge;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
46
53
|
}
|
package/wasm/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __returnValue = (v) => v;
|
|
3
|
+
function __exportSetter(name, newValue) {
|
|
4
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
+
}
|
|
2
6
|
var __export = (target, all) => {
|
|
3
7
|
for (var name in all)
|
|
4
8
|
__defProp(target, name, {
|
|
5
9
|
get: all[name],
|
|
6
10
|
enumerable: true,
|
|
7
11
|
configurable: true,
|
|
8
|
-
set: (
|
|
12
|
+
set: __exportSetter.bind(all, name)
|
|
9
13
|
});
|
|
10
14
|
};
|
|
11
15
|
|
|
@@ -313,6 +317,12 @@ class ZxBridgeCore {
|
|
|
313
317
|
this.#intervals.delete(callbackId);
|
|
314
318
|
}
|
|
315
319
|
}
|
|
320
|
+
dispose() {
|
|
321
|
+
for (const handle of this.#intervals.values()) {
|
|
322
|
+
clearInterval(handle);
|
|
323
|
+
}
|
|
324
|
+
this.#intervals.clear();
|
|
325
|
+
}
|
|
316
326
|
_writeStringToWasm(str) {
|
|
317
327
|
return this._writeBytesToWasm(textEncoder.encode(str));
|
|
318
328
|
}
|
|
@@ -465,6 +475,15 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
465
475
|
ws.close();
|
|
466
476
|
}
|
|
467
477
|
}
|
|
478
|
+
dispose() {
|
|
479
|
+
super.dispose();
|
|
480
|
+
for (const ws of this.#websockets.values()) {
|
|
481
|
+
try {
|
|
482
|
+
ws.close();
|
|
483
|
+
} catch {}
|
|
484
|
+
}
|
|
485
|
+
this.#websockets.clear();
|
|
486
|
+
}
|
|
468
487
|
eventbridge(velementId, eventTypeId, event) {
|
|
469
488
|
if (!this.#eventbridge)
|
|
470
489
|
return;
|
|
@@ -847,9 +866,10 @@ var EVENT_TYPE_MAP = {
|
|
|
847
866
|
function initEventDelegation(bridge, rootSelector = "body") {
|
|
848
867
|
const root = document.querySelector(rootSelector);
|
|
849
868
|
if (!root)
|
|
850
|
-
return;
|
|
869
|
+
return () => {};
|
|
870
|
+
const removers = [];
|
|
851
871
|
for (const eventType of DELEGATED_EVENTS) {
|
|
852
|
-
|
|
872
|
+
const listener = (event) => {
|
|
853
873
|
let target = event.target;
|
|
854
874
|
while (target && target !== document.body) {
|
|
855
875
|
const zxRef = target.__zx_ref;
|
|
@@ -860,11 +880,36 @@ function initEventDelegation(bridge, rootSelector = "body") {
|
|
|
860
880
|
}
|
|
861
881
|
target = target.parentElement;
|
|
862
882
|
}
|
|
863
|
-
}
|
|
864
|
-
|
|
883
|
+
};
|
|
884
|
+
const options = { passive: eventType.startsWith("touch") || eventType === "scroll" };
|
|
885
|
+
root.addEventListener(eventType, listener, options);
|
|
886
|
+
removers.push(() => root.removeEventListener(eventType, listener, options));
|
|
887
|
+
}
|
|
888
|
+
return () => {
|
|
889
|
+
for (const remove of removers)
|
|
890
|
+
remove();
|
|
891
|
+
};
|
|
865
892
|
}
|
|
866
893
|
var DEFAULT_URL = "/assets/_/main.wasm";
|
|
894
|
+
var activeRuntime = null;
|
|
895
|
+
function normalizeOptions(options = {}) {
|
|
896
|
+
return {
|
|
897
|
+
url: options.url,
|
|
898
|
+
eventDelegationRoot: options.eventDelegationRoot,
|
|
899
|
+
importObject: options.importObject
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
function registerDevReinit(options) {
|
|
903
|
+
if (typeof window === "undefined")
|
|
904
|
+
return;
|
|
905
|
+
window.__zx_dev_reinit = () => init(options);
|
|
906
|
+
}
|
|
867
907
|
async function init(options = {}) {
|
|
908
|
+
const normalizedOptions = normalizeOptions(options);
|
|
909
|
+
if (activeRuntime) {
|
|
910
|
+
activeRuntime.dispose();
|
|
911
|
+
activeRuntime = null;
|
|
912
|
+
}
|
|
868
913
|
const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
|
|
869
914
|
const bridgeRef = { current: null };
|
|
870
915
|
const importObject = Object.assign({}, ZxBridge.createImportObject(bridgeRef), options.importObject);
|
|
@@ -873,10 +918,20 @@ async function init(options = {}) {
|
|
|
873
918
|
jsz.memory = instance.exports.memory;
|
|
874
919
|
const bridge = new ZxBridge(instance.exports);
|
|
875
920
|
bridgeRef.current = bridge;
|
|
876
|
-
|
|
921
|
+
domNodes.clear();
|
|
922
|
+
const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
|
|
877
923
|
const main = instance.exports.mainClient;
|
|
878
924
|
if (typeof main === "function")
|
|
879
925
|
main();
|
|
926
|
+
activeRuntime = {
|
|
927
|
+
options: normalizedOptions,
|
|
928
|
+
dispose: () => {
|
|
929
|
+
disposeDelegation();
|
|
930
|
+
bridge.dispose();
|
|
931
|
+
domNodes.clear();
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
registerDevReinit(normalizedOptions);
|
|
880
935
|
return { source, bridge };
|
|
881
936
|
}
|
|
882
937
|
export {
|
package/wasm/init.js
CHANGED
|
@@ -302,6 +302,12 @@ class ZxBridgeCore {
|
|
|
302
302
|
this.#intervals.delete(callbackId);
|
|
303
303
|
}
|
|
304
304
|
}
|
|
305
|
+
dispose() {
|
|
306
|
+
for (const handle of this.#intervals.values()) {
|
|
307
|
+
clearInterval(handle);
|
|
308
|
+
}
|
|
309
|
+
this.#intervals.clear();
|
|
310
|
+
}
|
|
305
311
|
_writeStringToWasm(str) {
|
|
306
312
|
return this._writeBytesToWasm(textEncoder.encode(str));
|
|
307
313
|
}
|
|
@@ -454,6 +460,15 @@ class ZxBridge extends ZxBridgeCore {
|
|
|
454
460
|
ws.close();
|
|
455
461
|
}
|
|
456
462
|
}
|
|
463
|
+
dispose() {
|
|
464
|
+
super.dispose();
|
|
465
|
+
for (const ws of this.#websockets.values()) {
|
|
466
|
+
try {
|
|
467
|
+
ws.close();
|
|
468
|
+
} catch {}
|
|
469
|
+
}
|
|
470
|
+
this.#websockets.clear();
|
|
471
|
+
}
|
|
457
472
|
eventbridge(velementId, eventTypeId, event) {
|
|
458
473
|
if (!this.#eventbridge)
|
|
459
474
|
return;
|
|
@@ -836,9 +851,10 @@ var EVENT_TYPE_MAP = {
|
|
|
836
851
|
function initEventDelegation(bridge, rootSelector = "body") {
|
|
837
852
|
const root = document.querySelector(rootSelector);
|
|
838
853
|
if (!root)
|
|
839
|
-
return;
|
|
854
|
+
return () => {};
|
|
855
|
+
const removers = [];
|
|
840
856
|
for (const eventType of DELEGATED_EVENTS) {
|
|
841
|
-
|
|
857
|
+
const listener = (event) => {
|
|
842
858
|
let target = event.target;
|
|
843
859
|
while (target && target !== document.body) {
|
|
844
860
|
const zxRef = target.__zx_ref;
|
|
@@ -849,11 +865,36 @@ function initEventDelegation(bridge, rootSelector = "body") {
|
|
|
849
865
|
}
|
|
850
866
|
target = target.parentElement;
|
|
851
867
|
}
|
|
852
|
-
}
|
|
853
|
-
|
|
868
|
+
};
|
|
869
|
+
const options = { passive: eventType.startsWith("touch") || eventType === "scroll" };
|
|
870
|
+
root.addEventListener(eventType, listener, options);
|
|
871
|
+
removers.push(() => root.removeEventListener(eventType, listener, options));
|
|
872
|
+
}
|
|
873
|
+
return () => {
|
|
874
|
+
for (const remove of removers)
|
|
875
|
+
remove();
|
|
876
|
+
};
|
|
854
877
|
}
|
|
855
878
|
var DEFAULT_URL = "/assets/_/main.wasm";
|
|
879
|
+
var activeRuntime = null;
|
|
880
|
+
function normalizeOptions(options = {}) {
|
|
881
|
+
return {
|
|
882
|
+
url: options.url,
|
|
883
|
+
eventDelegationRoot: options.eventDelegationRoot,
|
|
884
|
+
importObject: options.importObject
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
function registerDevReinit(options) {
|
|
888
|
+
if (typeof window === "undefined")
|
|
889
|
+
return;
|
|
890
|
+
window.__zx_dev_reinit = () => init(options);
|
|
891
|
+
}
|
|
856
892
|
async function init(options = {}) {
|
|
893
|
+
const normalizedOptions = normalizeOptions(options);
|
|
894
|
+
if (activeRuntime) {
|
|
895
|
+
activeRuntime.dispose();
|
|
896
|
+
activeRuntime = null;
|
|
897
|
+
}
|
|
857
898
|
const url = options.url ?? document.getElementById("__$wasmlink")?.href ?? DEFAULT_URL;
|
|
858
899
|
const bridgeRef = { current: null };
|
|
859
900
|
const importObject = Object.assign({}, ZxBridge.createImportObject(bridgeRef), options.importObject);
|
|
@@ -862,10 +903,20 @@ async function init(options = {}) {
|
|
|
862
903
|
jsz.memory = instance.exports.memory;
|
|
863
904
|
const bridge = new ZxBridge(instance.exports);
|
|
864
905
|
bridgeRef.current = bridge;
|
|
865
|
-
|
|
906
|
+
domNodes.clear();
|
|
907
|
+
const disposeDelegation = initEventDelegation(bridge, options.eventDelegationRoot ?? "body");
|
|
866
908
|
const main = instance.exports.mainClient;
|
|
867
909
|
if (typeof main === "function")
|
|
868
910
|
main();
|
|
911
|
+
activeRuntime = {
|
|
912
|
+
options: normalizedOptions,
|
|
913
|
+
dispose: () => {
|
|
914
|
+
disposeDelegation();
|
|
915
|
+
bridge.dispose();
|
|
916
|
+
domNodes.clear();
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
registerDevReinit(normalizedOptions);
|
|
869
920
|
return { source, bridge };
|
|
870
921
|
}
|
|
871
922
|
|
package/install.cjs
DELETED
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
// Postinstall script for ziex npm package
|
|
2
|
-
// Resolves the native binary from platform-specific optionalDependencies
|
|
3
|
-
// or falls back to downloading from GitHub releases.
|
|
4
|
-
|
|
5
|
-
const { existsSync, mkdirSync, copyFileSync, chmodSync, createWriteStream, unlinkSync } = require("fs");
|
|
6
|
-
const { execSync } = require("child_process");
|
|
7
|
-
const path = require("path");
|
|
8
|
-
const https = require("https");
|
|
9
|
-
const { createGunzip } = require("zlib");
|
|
10
|
-
|
|
11
|
-
const PLATFORM_MAP = {
|
|
12
|
-
darwin: {
|
|
13
|
-
arm64: { pkg: "@ziex/cli-darwin-arm64", target: "macos-aarch64" },
|
|
14
|
-
x64: { pkg: "@ziex/cli-darwin-x64", target: "macos-x64" },
|
|
15
|
-
},
|
|
16
|
-
linux: {
|
|
17
|
-
x64: { pkg: "@ziex/cli-linux-x64", target: "linux-x64" },
|
|
18
|
-
arm64: { pkg: "@ziex/cli-linux-arm64", target: "linux-aarch64" },
|
|
19
|
-
},
|
|
20
|
-
win32: {
|
|
21
|
-
x64: { pkg: "@ziex/cli-win32-x64", target: "windows-x64" },
|
|
22
|
-
arm64: { pkg: "@ziex/cli-win32-arm64", target: "windows-aarch64" },
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const GITHUB_REPO = "ziex-dev/ziex";
|
|
27
|
-
|
|
28
|
-
function getPlatformInfo() {
|
|
29
|
-
const os = process.platform;
|
|
30
|
-
const arch = process.arch;
|
|
31
|
-
const info = PLATFORM_MAP[os]?.[arch];
|
|
32
|
-
if (!info) {
|
|
33
|
-
throw new Error(`Unsupported platform: ${os}-${arch}`);
|
|
34
|
-
}
|
|
35
|
-
return info;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function getVersion() {
|
|
39
|
-
const pkg = require("./package.json");
|
|
40
|
-
return pkg.version;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function getBinaryName(target) {
|
|
44
|
-
const isWindows = process.platform === "win32";
|
|
45
|
-
return `zx-${target}${isWindows ? ".exe" : ""}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function getOutputPath() {
|
|
49
|
-
const binDir = path.join(__dirname, "bin");
|
|
50
|
-
const isWindows = process.platform === "win32";
|
|
51
|
-
return path.join(binDir, isWindows ? "zx.exe" : "zx");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Try to resolve binary from optionalDependencies
|
|
55
|
-
function tryResolveFromOptionalDep(pkgName) {
|
|
56
|
-
try {
|
|
57
|
-
const pkgPath = require.resolve(`${pkgName}/package.json`);
|
|
58
|
-
const pkgDir = path.dirname(pkgPath);
|
|
59
|
-
const pkgJson = require(pkgPath);
|
|
60
|
-
const binName = pkgJson.bin?.zx || pkgJson.bin?.ziex;
|
|
61
|
-
if (binName) {
|
|
62
|
-
const binPath = path.join(pkgDir, binName);
|
|
63
|
-
if (existsSync(binPath)) {
|
|
64
|
-
return binPath;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// Fallback: look for the binary directly
|
|
68
|
-
const isWindows = process.platform === "win32";
|
|
69
|
-
const possibleNames = isWindows ? ["zx.exe"] : ["zx"];
|
|
70
|
-
for (const name of possibleNames) {
|
|
71
|
-
const candidate = path.join(pkgDir, "bin", name);
|
|
72
|
-
if (existsSync(candidate)) return candidate;
|
|
73
|
-
}
|
|
74
|
-
} catch {
|
|
75
|
-
// Package not installed
|
|
76
|
-
}
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Download from GitHub releases
|
|
81
|
-
function downloadFromGitHub(target, version) {
|
|
82
|
-
return new Promise((resolve, reject) => {
|
|
83
|
-
const isWindows = process.platform === "win32";
|
|
84
|
-
const ext = isWindows ? "zip" : "tar.gz";
|
|
85
|
-
const tag = version.startsWith("0.") ? `zx-v${version}` : `zx-v${version}`;
|
|
86
|
-
const url = `https://github.com/${GITHUB_REPO}/releases/download/${tag}/zx-${target}.${ext}`;
|
|
87
|
-
const latestUrl = `https://github.com/${GITHUB_REPO}/releases/latest/download/zx-${target}.${ext}`;
|
|
88
|
-
|
|
89
|
-
const binDir = path.join(__dirname, "bin");
|
|
90
|
-
mkdirSync(binDir, { recursive: true });
|
|
91
|
-
const archivePath = path.join(binDir, `zx-${target}.${ext}`);
|
|
92
|
-
|
|
93
|
-
console.log(`Downloading ziex binary for ${target}...`);
|
|
94
|
-
|
|
95
|
-
function download(downloadUrl, isRetry) {
|
|
96
|
-
const followRedirect = (url) => {
|
|
97
|
-
const proto = url.startsWith("https") ? https : require("http");
|
|
98
|
-
proto
|
|
99
|
-
.get(url, { headers: { "User-Agent": "ziex-npm" } }, (res) => {
|
|
100
|
-
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
101
|
-
followRedirect(res.headers.location);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
if (res.statusCode !== 200) {
|
|
105
|
-
if (!isRetry) {
|
|
106
|
-
// Retry with latest
|
|
107
|
-
download(latestUrl, true);
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
reject(new Error(`Download failed with status ${res.statusCode}: ${downloadUrl}`));
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const file = createWriteStream(archivePath);
|
|
115
|
-
res.pipe(file);
|
|
116
|
-
file.on("finish", () => {
|
|
117
|
-
file.close(() => resolve(archivePath));
|
|
118
|
-
});
|
|
119
|
-
})
|
|
120
|
-
.on("error", reject);
|
|
121
|
-
};
|
|
122
|
-
followRedirect(downloadUrl);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
download(url, false);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function extractTarGz(archivePath, targetBinaryName, outputPath) {
|
|
130
|
-
const binDir = path.dirname(outputPath);
|
|
131
|
-
// Use tar command (available on macOS and Linux)
|
|
132
|
-
execSync(`tar -xzf "${archivePath}" -C "${binDir}"`, { stdio: "pipe" });
|
|
133
|
-
const extractedPath = path.join(binDir, targetBinaryName);
|
|
134
|
-
if (existsSync(extractedPath)) {
|
|
135
|
-
copyFileSync(extractedPath, outputPath);
|
|
136
|
-
unlinkSync(extractedPath);
|
|
137
|
-
}
|
|
138
|
-
unlinkSync(archivePath);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function extractZip(archivePath, targetBinaryName, outputPath) {
|
|
142
|
-
const binDir = path.dirname(outputPath);
|
|
143
|
-
execSync(`unzip -o "${archivePath}" -d "${binDir}"`, { stdio: "pipe" });
|
|
144
|
-
const extractedPath = path.join(binDir, targetBinaryName);
|
|
145
|
-
if (existsSync(extractedPath)) {
|
|
146
|
-
copyFileSync(extractedPath, outputPath);
|
|
147
|
-
unlinkSync(extractedPath);
|
|
148
|
-
}
|
|
149
|
-
unlinkSync(archivePath);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async function main() {
|
|
153
|
-
const { pkg: pkgName, target } = getPlatformInfo();
|
|
154
|
-
const outputPath = getOutputPath();
|
|
155
|
-
const binDir = path.dirname(outputPath);
|
|
156
|
-
mkdirSync(binDir, { recursive: true });
|
|
157
|
-
|
|
158
|
-
// Step 1: Try to resolve from optional dependency
|
|
159
|
-
const resolvedPath = tryResolveFromOptionalDep(pkgName);
|
|
160
|
-
if (resolvedPath) {
|
|
161
|
-
console.log(`Found ziex binary from ${pkgName}`);
|
|
162
|
-
copyFileSync(resolvedPath, outputPath);
|
|
163
|
-
chmodSync(outputPath, 0o755);
|
|
164
|
-
|
|
165
|
-
// Create ziex alias (symlink or copy)
|
|
166
|
-
createAliases(outputPath);
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Step 2: Download from GitHub releases
|
|
171
|
-
console.log(`Platform package ${pkgName} not found, downloading from GitHub...`);
|
|
172
|
-
try {
|
|
173
|
-
const version = getVersion();
|
|
174
|
-
const archivePath = await downloadFromGitHub(target, version);
|
|
175
|
-
const binaryName = getBinaryName(target);
|
|
176
|
-
const isWindows = process.platform === "win32";
|
|
177
|
-
|
|
178
|
-
if (isWindows) {
|
|
179
|
-
extractZip(archivePath, binaryName, outputPath);
|
|
180
|
-
} else {
|
|
181
|
-
extractTarGz(archivePath, binaryName, outputPath);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
chmodSync(outputPath, 0o755);
|
|
185
|
-
createAliases(outputPath);
|
|
186
|
-
console.log("ziex binary installed successfully!");
|
|
187
|
-
} catch (err) {
|
|
188
|
-
console.error(`Failed to install ziex binary: ${err.message}`);
|
|
189
|
-
console.error("You can install it manually from: https://ziex.dev/install");
|
|
190
|
-
process.exit(1);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function createAliases(zxPath) {
|
|
195
|
-
const binDir = path.dirname(zxPath);
|
|
196
|
-
const isWindows = process.platform === "win32";
|
|
197
|
-
const ziexPath = path.join(binDir, isWindows ? "ziex.exe" : "ziex");
|
|
198
|
-
|
|
199
|
-
// The main binary is `zx`, create `ziex` as a copy/symlink
|
|
200
|
-
try {
|
|
201
|
-
if (existsSync(ziexPath) && ziexPath !== zxPath) unlinkSync(ziexPath);
|
|
202
|
-
if (ziexPath !== zxPath) {
|
|
203
|
-
try {
|
|
204
|
-
const fs = require("fs");
|
|
205
|
-
fs.symlinkSync(path.basename(zxPath), ziexPath);
|
|
206
|
-
} catch {
|
|
207
|
-
copyFileSync(zxPath, ziexPath);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
} catch {
|
|
211
|
-
// Non-critical
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
main().catch((err) => {
|
|
216
|
-
console.error(err.message);
|
|
217
|
-
process.exit(1);
|
|
218
|
-
});
|