ziex 0.1.0-dev.1389 → 0.1.0-dev.1466
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/app.d.ts +6 -6
- package/build.zig.zon +1 -1
- package/index.js +490 -174
- package/package.json +7 -5
- package/{aws-lambda → platforms/aws-lambda}/index.js +1 -1
- package/platforms/cloudflare/app.d.ts +2 -0
- package/platforms/cloudflare/db.d.ts +6 -0
- package/{cloudflare → platforms/cloudflare}/do.d.ts +5 -5
- package/platforms/cloudflare/index.d.ts +4 -0
- package/{cloudflare → platforms/cloudflare}/index.js +1959 -1532
- package/platforms/cloudflare/kv.d.ts +5 -0
- package/platforms/cloudflare/worker.d.ts +3 -0
- package/{vercel → platforms/vercel}/index.js +1 -1
- package/runtime/db/extern.d.ts +38 -0
- package/runtime/db/sqlite.d.ts +7 -0
- package/runtime/db.d.ts +3 -0
- package/runtime/db.js +419 -0
- package/{fetch.d.ts → runtime/fetch.d.ts} +1 -1
- package/{runtime.d.ts → runtime/index.d.ts} +6 -15
- package/runtime/kv/extern.d.ts +11 -0
- package/runtime/kv/indexdb.d.ts +7 -0
- package/runtime/kv/localstorage.d.ts +6 -0
- package/runtime/kv/memory.d.ts +6 -0
- package/runtime/kv.d.ts +45 -0
- package/runtime/kv.js +543 -0
- package/wasm/constants.d.ts +33 -0
- package/wasm/core.d.ts +23 -33
- package/wasm/dom_cmd.d.ts +15 -0
- package/wasm/generated/event_bits.d.ts +2 -0
- package/wasm/generated/events.d.ts +1 -0
- package/wasm/generated/tag_indices.d.ts +2 -0
- package/wasm/generated/tags.d.ts +1 -0
- package/wasm/index.d.ts +15 -13
- package/wasm/index.js +911 -676
- package/wasm/init.dev.js +895 -674
- package/wasm/init.js +3 -3
- package/wasm/wasi.d.ts +1 -5
- package/browser/kv.d.ts +0 -13
- package/cloudflare/app.d.ts +0 -2
- package/cloudflare/db.d.ts +0 -2
- package/cloudflare/index.d.ts +0 -4
- package/cloudflare/kv.d.ts +0 -2
- package/cloudflare/worker.d.ts +0 -3
- package/db.d.ts +0 -22
- package/kv.d.ts +0 -42
- /package/{aws-lambda → platforms/aws-lambda}/index.d.ts +0 -0
- /package/{vercel → platforms/vercel}/index.d.ts +0 -0
- /package/{wasi.d.ts → runtime/wasi.d.ts} +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type WasmAllocRef } from "../../wasm/core";
|
|
2
|
+
export type { WasmAllocRef };
|
|
3
|
+
export type DbValue = null | string | number | boolean | ArrayBuffer | ArrayBufferView;
|
|
4
|
+
/** Result of a mutating statement (`INSERT`/`UPDATE`/`DELETE`). */
|
|
5
|
+
export interface ExecResult {
|
|
6
|
+
meta?: {
|
|
7
|
+
changes?: number;
|
|
8
|
+
last_row_id?: number;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** Prepared statement - Cloudflare D1–shaped; Postgres/SQLite adapters implement the same. */
|
|
12
|
+
export interface PreparedStatement {
|
|
13
|
+
bind(...values: DbValue[]): PreparedStatement;
|
|
14
|
+
first<T = Record<string, unknown>>(): Promise<T | null>;
|
|
15
|
+
all<T = Record<string, unknown>>(): Promise<{
|
|
16
|
+
results?: T[];
|
|
17
|
+
}>;
|
|
18
|
+
raw(options?: {
|
|
19
|
+
columnNames?: boolean;
|
|
20
|
+
}): Promise<unknown[][]>;
|
|
21
|
+
run(): Promise<ExecResult>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* SQL database binding for `__zx_db`.
|
|
25
|
+
* Shape matches Cloudflare D1 so Workers bindings work as-is; Postgres and other
|
|
26
|
+
* drivers adapt to this interface.
|
|
27
|
+
*/
|
|
28
|
+
export interface Database {
|
|
29
|
+
prepare(query: string): PreparedStatement;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build the `__zx_db` host functions for SQL database bindings.
|
|
33
|
+
*
|
|
34
|
+
* ```ts
|
|
35
|
+
* if (__FEAT_DB__) importObject.__zx_db = createDbImports(bindings, getMemory, allocRef);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function createDbImports(bindings: Record<string, Database>, getMemory: () => WebAssembly.Memory, allocRef: WasmAllocRef): WebAssembly.ModuleImports;
|
package/runtime/db.d.ts
ADDED
package/runtime/db.js
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
// ../../vendor/jsz/js/src/zigjs.ts
|
|
2
|
+
var NAN_PREFIX = 2146959360;
|
|
3
|
+
var predefined = {
|
|
4
|
+
"nan": 0,
|
|
5
|
+
"null": 1,
|
|
6
|
+
"true": 2,
|
|
7
|
+
"false": 3,
|
|
8
|
+
"undefined": 4,
|
|
9
|
+
"globalThis": 5,
|
|
10
|
+
"runtime": 6
|
|
11
|
+
};
|
|
12
|
+
var PREDEFINED_ID_MAX = 6;
|
|
13
|
+
var encoder = new TextEncoder();
|
|
14
|
+
var decoder = new TextDecoder("utf-8");
|
|
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
|
+
* */
|
|
34
|
+
importObject() {
|
|
35
|
+
return {
|
|
36
|
+
"zig-js": {
|
|
37
|
+
valueGet: this.valueGet.bind(this),
|
|
38
|
+
valueSet: this.valueSet.bind(this),
|
|
39
|
+
valueDeinit: this.valueDeinit.bind(this),
|
|
40
|
+
valueObjectCreate: this.valueObjectCreate.bind(this),
|
|
41
|
+
valueStringCreate: this.valueStringCreate.bind(this),
|
|
42
|
+
valueStringLen: this.valueStringLen.bind(this),
|
|
43
|
+
valueStringCopy: this.valueStringCopy.bind(this),
|
|
44
|
+
valueNew: this.valueNew.bind(this),
|
|
45
|
+
funcApply: this.funcApply.bind(this)
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get a value from the JS environment.
|
|
51
|
+
* */
|
|
52
|
+
valueGet(out, id, ptr, len) {
|
|
53
|
+
const val = this.loadValue(id);
|
|
54
|
+
if (val === null || val === void 0 || typeof val !== "object" && typeof val !== "function") {
|
|
55
|
+
this.storeValue(out, void 0);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const str = this.loadString(ptr, len);
|
|
59
|
+
const result = Reflect.get(val, str);
|
|
60
|
+
this.storeValue(out, result);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Set a value on an object.
|
|
64
|
+
* */
|
|
65
|
+
valueSet(id, ptr, len, refAddr) {
|
|
66
|
+
const obj = this.loadValue(id);
|
|
67
|
+
const str = this.loadString(ptr, len);
|
|
68
|
+
const val = this.loadRef(refAddr);
|
|
69
|
+
Reflect.set(obj, str, val);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Dereference a value, allowing the JS environment to potentially GC it.
|
|
73
|
+
* */
|
|
74
|
+
valueDeinit(id) {
|
|
75
|
+
if (id > PREDEFINED_ID_MAX) {
|
|
76
|
+
this.values[id] = null;
|
|
77
|
+
this.idPool.push(id);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Create an empty object.
|
|
82
|
+
* */
|
|
83
|
+
valueObjectCreate(out) {
|
|
84
|
+
this.storeValue(out, new Object());
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Creates a string on the JS side from a UTF-8 encoded string in wasm memory.
|
|
88
|
+
* */
|
|
89
|
+
valueStringCreate(out, ptr, len) {
|
|
90
|
+
const str = this.loadString(ptr, len);
|
|
91
|
+
this.storeValue(out, str);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Returns the length of the string given by id.
|
|
95
|
+
* */
|
|
96
|
+
valueStringLen(id) {
|
|
97
|
+
const val = this.loadValue(id);
|
|
98
|
+
const buf = encoder.encode(val);
|
|
99
|
+
return buf.byteLength;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Copy the string at id "id" into the shared memory at ptr.
|
|
103
|
+
* */
|
|
104
|
+
valueStringCopy(id, ptr, max) {
|
|
105
|
+
if (this.memory == null) return;
|
|
106
|
+
const dest = ptr >>> 0;
|
|
107
|
+
const cap = max >>> 0;
|
|
108
|
+
const val = this.loadValue(id);
|
|
109
|
+
if (typeof val !== "string") return;
|
|
110
|
+
const bytes = encoder.encode(val);
|
|
111
|
+
if (bytes.byteLength > cap || bytes.length === 0) return;
|
|
112
|
+
const buf = this.memory.buffer;
|
|
113
|
+
if (dest + bytes.length > buf.byteLength) return;
|
|
114
|
+
new Uint8Array(buf, dest, bytes.length).set(bytes);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Call a constructor given by id.
|
|
118
|
+
* */
|
|
119
|
+
valueNew(out, id, argsAddr, argsLen) {
|
|
120
|
+
const fn = this.loadValue(id);
|
|
121
|
+
const args = [];
|
|
122
|
+
const base = argsAddr >>> 0;
|
|
123
|
+
const count = argsLen >>> 0;
|
|
124
|
+
for (let i = 0; i < count; i++) {
|
|
125
|
+
args.push(this.loadRef(base + i * 8));
|
|
126
|
+
}
|
|
127
|
+
const result = Reflect.construct(fn, args);
|
|
128
|
+
this.storeValue(out, result);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Call a function given by id.
|
|
132
|
+
* */
|
|
133
|
+
funcApply(out, id, thisRefAddr, argsAddr, argsLen) {
|
|
134
|
+
const fn = this.loadValue(id);
|
|
135
|
+
const thisVal = this.loadRef(thisRefAddr >>> 0);
|
|
136
|
+
const args = [];
|
|
137
|
+
const base = argsAddr >>> 0;
|
|
138
|
+
const count = argsLen >>> 0;
|
|
139
|
+
for (let i = 0; i < count; i++) {
|
|
140
|
+
args.push(this.loadRef(base + i * 8));
|
|
141
|
+
}
|
|
142
|
+
if (typeof fn !== "function") {
|
|
143
|
+
this.storeValue(out, void 0);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const result = Reflect.apply(fn, thisVal, args);
|
|
148
|
+
this.storeValue(out, result);
|
|
149
|
+
} catch {
|
|
150
|
+
this.storeValue(out, void 0);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* This can be used to load a value given by an ID. A WASM function
|
|
155
|
+
* might return a value as an ID. This can be used to retrieve it.
|
|
156
|
+
* */
|
|
157
|
+
loadValue(id) {
|
|
158
|
+
return this.values[id];
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* This removes the value from the values list and returns it. This
|
|
162
|
+
* will not remove predefined values but can still be used to retrieve
|
|
163
|
+
* them.
|
|
164
|
+
* */
|
|
165
|
+
deleteValue(id) {
|
|
166
|
+
const val = this.values[id];
|
|
167
|
+
this.valueDeinit(id);
|
|
168
|
+
return val;
|
|
169
|
+
}
|
|
170
|
+
loadRef(refAddr) {
|
|
171
|
+
if (this.memory == null) return;
|
|
172
|
+
const addr = refAddr >>> 0;
|
|
173
|
+
const view = new DataView(this.memory.buffer);
|
|
174
|
+
const floatVal = view.getFloat64(addr, true);
|
|
175
|
+
if (!isNaN(floatVal)) return floatVal;
|
|
176
|
+
const id = this.loadRefId(addr);
|
|
177
|
+
return this.values[id];
|
|
178
|
+
}
|
|
179
|
+
loadRefId(refAddr) {
|
|
180
|
+
if (this.memory == null) return 0;
|
|
181
|
+
return new DataView(this.memory.buffer).getUint32(refAddr >>> 0, true);
|
|
182
|
+
}
|
|
183
|
+
storeValue(out, val) {
|
|
184
|
+
if (this.memory == null) return;
|
|
185
|
+
const view = new DataView(this.memory.buffer);
|
|
186
|
+
out = out >>> 0;
|
|
187
|
+
if (typeof val === "number") {
|
|
188
|
+
if (isNaN(val)) {
|
|
189
|
+
view.setUint32(out, predefined.nan, true);
|
|
190
|
+
view.setUint32(out + 4, NAN_PREFIX, true);
|
|
191
|
+
} else {
|
|
192
|
+
view.setFloat64(out, val, true);
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (val === null) {
|
|
197
|
+
view.setUint32(out, predefined.null, true);
|
|
198
|
+
view.setUint32(out + 4, NAN_PREFIX, true);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (val === void 0) {
|
|
202
|
+
view.setUint32(out, predefined.undefined, true);
|
|
203
|
+
view.setUint32(out + 4, NAN_PREFIX, true);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (typeof val === "boolean") {
|
|
207
|
+
view.setUint32(out, val ? predefined.true : predefined.false, true);
|
|
208
|
+
view.setUint32(out + 4, NAN_PREFIX, true);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (typeof val === "bigint") {
|
|
212
|
+
view.setFloat64(out, Number(val), true);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
let id = this.idPool.pop();
|
|
216
|
+
if (id === void 0) {
|
|
217
|
+
id = this.values.length;
|
|
218
|
+
}
|
|
219
|
+
this.values[id] = val;
|
|
220
|
+
let typeId = 0;
|
|
221
|
+
switch (typeof val) {
|
|
222
|
+
case "object":
|
|
223
|
+
typeId = 1;
|
|
224
|
+
break;
|
|
225
|
+
case "string":
|
|
226
|
+
typeId = 2;
|
|
227
|
+
break;
|
|
228
|
+
case "symbol":
|
|
229
|
+
typeId = 3;
|
|
230
|
+
break;
|
|
231
|
+
case "function":
|
|
232
|
+
typeId = 4;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
view.setUint32(out, Number(id), true);
|
|
236
|
+
view.setUint32(out + 4, NAN_PREFIX | typeId, true);
|
|
237
|
+
}
|
|
238
|
+
loadString(ptr, len) {
|
|
239
|
+
if (this.memory == null) return "";
|
|
240
|
+
const start = ptr >>> 0;
|
|
241
|
+
const length = Number(len) >>> 0;
|
|
242
|
+
const buf = this.memory.buffer;
|
|
243
|
+
if (length === 0 || start + length > buf.byteLength) return "";
|
|
244
|
+
const arr = new Uint8ClampedArray(buf, start, length);
|
|
245
|
+
const data = arr.slice();
|
|
246
|
+
return decoder.decode(data);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// src/wasm/core.ts
|
|
251
|
+
var jsz = new ZigJS();
|
|
252
|
+
var tempRefBuffer = new ArrayBuffer(8);
|
|
253
|
+
var tempRefView = new DataView(tempRefBuffer);
|
|
254
|
+
var textDecoder = new TextDecoder();
|
|
255
|
+
var textEncoder = new TextEncoder();
|
|
256
|
+
function writeBytesOut(getMemory, allocRef, outPtrAddr, data) {
|
|
257
|
+
if (data.length === 0) {
|
|
258
|
+
new DataView(getMemory().buffer).setUint32(outPtrAddr, 0, true);
|
|
259
|
+
return 0;
|
|
260
|
+
}
|
|
261
|
+
const alloc = allocRef[0];
|
|
262
|
+
if (!alloc) return -1;
|
|
263
|
+
const ptr = alloc(data.length) >>> 0;
|
|
264
|
+
if (!ptr) return -1;
|
|
265
|
+
const buffer = getMemory().buffer;
|
|
266
|
+
if (ptr + data.length > buffer.byteLength) return -1;
|
|
267
|
+
new Uint8Array(buffer, ptr, data.length).set(data);
|
|
268
|
+
new DataView(buffer).setUint32(outPtrAddr >>> 0, ptr, true);
|
|
269
|
+
return data.length;
|
|
270
|
+
}
|
|
271
|
+
function writeJsonOut(getMemory, allocRef, outPtrAddr, value) {
|
|
272
|
+
return writeBytesOut(getMemory, allocRef, outPtrAddr, textEncoder.encode(JSON.stringify(value)));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/runtime/db/extern.ts
|
|
276
|
+
function decodeBlob(base64) {
|
|
277
|
+
const binary = atob(base64);
|
|
278
|
+
const bytes = new Uint8Array(binary.length);
|
|
279
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
280
|
+
return bytes;
|
|
281
|
+
}
|
|
282
|
+
function toDbValue(value) {
|
|
283
|
+
switch (value.kind) {
|
|
284
|
+
case "null":
|
|
285
|
+
return null;
|
|
286
|
+
case "integer":
|
|
287
|
+
return value.integer;
|
|
288
|
+
case "float":
|
|
289
|
+
return value.float;
|
|
290
|
+
case "text":
|
|
291
|
+
return value.text;
|
|
292
|
+
case "blob":
|
|
293
|
+
return decodeBlob(value.blob);
|
|
294
|
+
case "boolean":
|
|
295
|
+
return value.boolean;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function toPositionalBindings(json) {
|
|
299
|
+
switch (json.kind) {
|
|
300
|
+
case "none":
|
|
301
|
+
return [];
|
|
302
|
+
case "positional":
|
|
303
|
+
return json.values.map(toDbValue);
|
|
304
|
+
case "named":
|
|
305
|
+
throw new Error("named SQL bindings are not supported yet");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function toWireValue(value) {
|
|
309
|
+
if (value === null || value === void 0) return { kind: "null" };
|
|
310
|
+
if (typeof value === "string") return { kind: "text", text: value };
|
|
311
|
+
if (typeof value === "boolean") return { kind: "boolean", boolean: value };
|
|
312
|
+
if (typeof value === "number") {
|
|
313
|
+
return Number.isInteger(value) ? { kind: "integer", integer: value } : { kind: "float", float: value };
|
|
314
|
+
}
|
|
315
|
+
if (value instanceof ArrayBuffer) {
|
|
316
|
+
const bytes = new Uint8Array(value);
|
|
317
|
+
let binary = "";
|
|
318
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
319
|
+
return { kind: "blob", blob: btoa(binary) };
|
|
320
|
+
}
|
|
321
|
+
if (ArrayBuffer.isView(value)) {
|
|
322
|
+
const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
323
|
+
let binary = "";
|
|
324
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
325
|
+
return { kind: "blob", blob: btoa(binary) };
|
|
326
|
+
}
|
|
327
|
+
return { kind: "text", text: String(value) };
|
|
328
|
+
}
|
|
329
|
+
function objectToWireRow(record) {
|
|
330
|
+
return {
|
|
331
|
+
fields: Object.entries(record).map(([name, value]) => ({
|
|
332
|
+
name,
|
|
333
|
+
value: toWireValue(value)
|
|
334
|
+
}))
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function valuesToWireRows(rows) {
|
|
338
|
+
return rows.map((row) => row.map((value) => toWireValue(value)));
|
|
339
|
+
}
|
|
340
|
+
function createDbImports(bindings, getMemory, allocRef) {
|
|
341
|
+
const decoder2 = new TextDecoder();
|
|
342
|
+
function readStr(ptr, len) {
|
|
343
|
+
return decoder2.decode(new Uint8Array(getMemory().buffer, ptr, len));
|
|
344
|
+
}
|
|
345
|
+
function binding(ns) {
|
|
346
|
+
return bindings[ns] ?? bindings["default"] ?? null;
|
|
347
|
+
}
|
|
348
|
+
async function statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len) {
|
|
349
|
+
const database = binding(readStr(ns_ptr, ns_len));
|
|
350
|
+
if (!database) return null;
|
|
351
|
+
const sql = readStr(sql_ptr, sql_len);
|
|
352
|
+
const bindingsJson = JSON.parse(readStr(bindings_ptr, bindings_len));
|
|
353
|
+
return database.prepare(sql).bind(...toPositionalBindings(bindingsJson));
|
|
354
|
+
}
|
|
355
|
+
const Suspending = WebAssembly.Suspending;
|
|
356
|
+
if (typeof Suspending !== "function") {
|
|
357
|
+
return {
|
|
358
|
+
db_open: (_ns, _ns_len) => -1,
|
|
359
|
+
db_run: (_a, _b, _c, _d, _e, _f, _g) => -1,
|
|
360
|
+
db_get: (_a, _b, _c, _d, _e, _f, _g) => -1,
|
|
361
|
+
db_all: (_a, _b, _c, _d, _e, _f, _g) => -1,
|
|
362
|
+
db_values: (_a, _b, _c, _d, _e, _f, _g) => -1
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
db_open: (ns_ptr, ns_len) => binding(readStr(ns_ptr, ns_len)) ? 0 : -1,
|
|
367
|
+
db_run: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
|
|
368
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
369
|
+
if (!stmt) return -1;
|
|
370
|
+
const result = await stmt.run();
|
|
371
|
+
return writeJsonOut(getMemory, allocRef, out_ptr, {
|
|
372
|
+
last_insert_rowid: result.meta?.last_row_id ?? 0,
|
|
373
|
+
changes: result.meta?.changes ?? 0
|
|
374
|
+
});
|
|
375
|
+
}),
|
|
376
|
+
db_get: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
|
|
377
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
378
|
+
if (!stmt) return -1;
|
|
379
|
+
const row = await stmt.first();
|
|
380
|
+
if (!row) {
|
|
381
|
+
new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
|
|
382
|
+
return 0;
|
|
383
|
+
}
|
|
384
|
+
return writeJsonOut(getMemory, allocRef, out_ptr, [objectToWireRow(row)]);
|
|
385
|
+
}),
|
|
386
|
+
db_all: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
|
|
387
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
388
|
+
if (!stmt) return -1;
|
|
389
|
+
const result = await stmt.all();
|
|
390
|
+
const rows = (result.results ?? []).map(objectToWireRow);
|
|
391
|
+
if (rows.length === 0) {
|
|
392
|
+
new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
|
|
393
|
+
return 0;
|
|
394
|
+
}
|
|
395
|
+
return writeJsonOut(getMemory, allocRef, out_ptr, rows);
|
|
396
|
+
}),
|
|
397
|
+
db_values: new Suspending(async (ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len, out_ptr) => {
|
|
398
|
+
const stmt = await statement(ns_ptr, ns_len, sql_ptr, sql_len, bindings_ptr, bindings_len);
|
|
399
|
+
if (!stmt) return -1;
|
|
400
|
+
const rows = await stmt.raw();
|
|
401
|
+
if (rows.length === 0) {
|
|
402
|
+
new DataView(getMemory().buffer).setUint32(out_ptr, 0, true);
|
|
403
|
+
return 0;
|
|
404
|
+
}
|
|
405
|
+
return writeJsonOut(getMemory, allocRef, out_ptr, valuesToWireRows(rows));
|
|
406
|
+
})
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/runtime/db/sqlite.ts
|
|
411
|
+
var Sqlite = {
|
|
412
|
+
open(_path) {
|
|
413
|
+
throw new Error("db/sqlite: not implemented yet");
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
export {
|
|
417
|
+
Sqlite,
|
|
418
|
+
createDbImports
|
|
419
|
+
};
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* Create a `fetch` import object for blocking WASM fetch via JSPI.
|
|
3
3
|
* When JSPI is unavailable the import always returns -1 (network error).
|
|
4
4
|
*/
|
|
5
|
-
export declare function createFetchImports(getMemory: () => WebAssembly.Memory):
|
|
5
|
+
export declare function createFetchImports(getMemory: () => WebAssembly.Memory): WebAssembly.ModuleImports;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { WASI } from "./wasi";
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
2
|
+
import { type KVNamespace } from "./kv";
|
|
3
|
+
import type { Database } from "./db";
|
|
4
4
|
/** Minimal Durable Object namespace shape needed for WebSocket routing. */
|
|
5
5
|
export type DurableObjectNamespace = {
|
|
6
6
|
idFromName(name: string): unknown;
|
|
@@ -22,16 +22,7 @@ export type WsState = {
|
|
|
22
22
|
isSubscribed?: (topic: string) => boolean;
|
|
23
23
|
};
|
|
24
24
|
/** Build the __zx_ws import object for a given connection state. */
|
|
25
|
-
export declare function buildWsImports(Suspending: any, mem: () => WebAssembly.Memory, decoder: TextDecoder, ws: WsState):
|
|
26
|
-
ws_upgrade: () => void;
|
|
27
|
-
ws_write: (ptr: number, len: number) => void;
|
|
28
|
-
ws_close: (code: number, reason_ptr: number, reason_len: number) => void;
|
|
29
|
-
ws_recv: any;
|
|
30
|
-
ws_subscribe: (ptr: number, len: number) => void;
|
|
31
|
-
ws_unsubscribe: (ptr: number, len: number) => void;
|
|
32
|
-
ws_publish: (topic_ptr: number, topic_len: number, data_ptr: number, data_len: number) => number;
|
|
33
|
-
ws_is_subscribed: (ptr: number, len: number) => number;
|
|
34
|
-
};
|
|
25
|
+
export declare function buildWsImports(Suspending: any, mem: () => WebAssembly.Memory, decoder: TextDecoder, ws: WsState): WebAssembly.ModuleImports;
|
|
35
26
|
/** Create WebSocketPair, wire message/close listeners, flush pending writes. */
|
|
36
27
|
export declare function attachWebSocket(ws: WsState): {
|
|
37
28
|
client: WebSocket;
|
|
@@ -60,9 +51,9 @@ export declare function run({ request, env, ctx, module, kv: kvBindings, db: dbB
|
|
|
60
51
|
module: WebAssembly.Module;
|
|
61
52
|
/** KV namespace bindings - `{ default: env.KV, otherName: env.OTHER_KV }` */
|
|
62
53
|
kv?: Record<string, KVNamespace>;
|
|
63
|
-
/**
|
|
64
|
-
db?: Record<string,
|
|
65
|
-
imports?: (mem: () => WebAssembly.Memory) =>
|
|
54
|
+
/** DB bindings - `{ default: env.DB, analytics: env.ANALYTICS_DB }` */
|
|
55
|
+
db?: Record<string, Database>;
|
|
56
|
+
imports?: (mem: () => WebAssembly.Memory) => WebAssembly.Imports;
|
|
66
57
|
wasi?: WASI;
|
|
67
58
|
/**
|
|
68
59
|
* Durable Object namespace to use for WebSocket connections.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type WasmAllocRef } from "../../wasm/core";
|
|
2
|
+
import type { KVNamespace } from "../kv";
|
|
3
|
+
export type { WasmAllocRef };
|
|
4
|
+
/**
|
|
5
|
+
* Build the `__zx_kv` host functions for key/value namespace bindings.
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* if (__FEAT_KV__) importObject.__zx_kv = createKVImports(bindings, getMemory, allocRef);
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare function createKVImports(bindings: Record<string, KVNamespace>, getMemory: () => WebAssembly.Memory, allocRef: WasmAllocRef): WebAssembly.ModuleImports;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { KVNamespace } from "../kv";
|
|
2
|
+
/**
|
|
3
|
+
* In-memory KV. Used as the default shim on platforms that don't provide a
|
|
4
|
+
* real KV binding (e.g. Vercel). Data lives only for the lifetime of the isolate.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createMemoryKV(): KVNamespace;
|
package/runtime/kv.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type { WasmAllocRef } from "../wasm/core";
|
|
2
|
+
/** Key/value namespace binding. Cloudflare KV–shaped so CF bindings work as-is; other backends adapt to the same interface. */
|
|
3
|
+
export interface KVNamespace {
|
|
4
|
+
get(key: string): Promise<string | null>;
|
|
5
|
+
put(key: string, value: string, options?: {
|
|
6
|
+
expiration?: number;
|
|
7
|
+
expirationTtl?: number;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
delete(key: string): Promise<void>;
|
|
10
|
+
list(options?: {
|
|
11
|
+
prefix?: string;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
keys: {
|
|
14
|
+
name: string;
|
|
15
|
+
}[];
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
/** Synchronous KV used when JSPI is unavailable (e.g. localStorage). */
|
|
19
|
+
export interface SyncKVNamespace extends KVNamespace {
|
|
20
|
+
getSync(key: string): string | null;
|
|
21
|
+
putSync(key: string, value: string, options?: {
|
|
22
|
+
expiration?: number;
|
|
23
|
+
expirationTtl?: number;
|
|
24
|
+
}): void;
|
|
25
|
+
deleteSync(key: string): void;
|
|
26
|
+
listSync(options?: {
|
|
27
|
+
prefix?: string;
|
|
28
|
+
}): {
|
|
29
|
+
keys: {
|
|
30
|
+
name: string;
|
|
31
|
+
}[];
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export { createMemoryKV } from "./kv/memory";
|
|
35
|
+
export { createLocalStorageKV, type LocalStorageKVOptions } from "./kv/localstorage";
|
|
36
|
+
export { createIndexedDbKV, type IndexedDbKVOptions } from "./kv/indexdb";
|
|
37
|
+
export { createKVImports } from "./kv/extern";
|
|
38
|
+
import { type IndexedDbKVOptions } from "./kv/indexdb";
|
|
39
|
+
export type BrowserKVOptions = IndexedDbKVOptions & {
|
|
40
|
+
storagePrefix?: string;
|
|
41
|
+
forceLocalStorage?: boolean;
|
|
42
|
+
};
|
|
43
|
+
export declare function hasJSPI(): boolean;
|
|
44
|
+
/** Prefer IndexedDB when JSPI is available, otherwise localStorage. */
|
|
45
|
+
export declare function createBrowserKVBindings(options?: BrowserKVOptions): Record<string, KVNamespace>;
|