@velarscript/node 0.10.1
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/LICENSE +201 -0
- package/README.md +148 -0
- package/dist/compiler.d.ts +12 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +954 -0
- package/dist/compiler.js.map +1 -0
- package/dist/environment-runtime.d.ts +2 -0
- package/dist/environment-runtime.d.ts.map +1 -0
- package/dist/environment-runtime.js +53 -0
- package/dist/environment-runtime.js.map +1 -0
- package/dist/filesystem-runtime.d.ts +2 -0
- package/dist/filesystem-runtime.d.ts.map +1 -0
- package/dist/filesystem-runtime.js +329 -0
- package/dist/filesystem-runtime.js.map +1 -0
- package/dist/host-runtime.d.ts +2 -0
- package/dist/host-runtime.d.ts.map +1 -0
- package/dist/host-runtime.js +149 -0
- package/dist/host-runtime.js.map +1 -0
- package/dist/http-runtime.d.ts +2 -0
- package/dist/http-runtime.d.ts.map +1 -0
- package/dist/http-runtime.js +612 -0
- package/dist/http-runtime.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/node-host-runtime.d.ts +2 -0
- package/dist/node-host-runtime.d.ts.map +1 -0
- package/dist/node-host-runtime.js +314 -0
- package/dist/node-host-runtime.js.map +1 -0
- package/dist/node-host-worker-runtime.d.ts +2 -0
- package/dist/node-host-worker-runtime.d.ts.map +1 -0
- package/dist/node-host-worker-runtime.js +1144 -0
- package/dist/node-host-worker-runtime.js.map +1 -0
- package/dist/process-runtime.d.ts +2 -0
- package/dist/process-runtime.d.ts.map +1 -0
- package/dist/process-runtime.js +167 -0
- package/dist/process-runtime.js.map +1 -0
- package/dist/process-worker-runtime.d.ts +2 -0
- package/dist/process-worker-runtime.d.ts.map +1 -0
- package/dist/process-worker-runtime.js +473 -0
- package/dist/process-worker-runtime.js.map +1 -0
- package/dist/serve-runtime.d.ts +2 -0
- package/dist/serve-runtime.d.ts.map +1 -0
- package/dist/serve-runtime.js +463 -0
- package/dist/serve-runtime.js.map +1 -0
- package/dist/sqlite-runtime.d.ts +3 -0
- package/dist/sqlite-runtime.d.ts.map +1 -0
- package/dist/sqlite-runtime.js +92 -0
- package/dist/sqlite-runtime.js.map +1 -0
- package/dist/terminal-runtime.d.ts +2 -0
- package/dist/terminal-runtime.d.ts.map +1 -0
- package/dist/terminal-runtime.js +290 -0
- package/dist/terminal-runtime.js.map +1 -0
- package/dist/terminal-worker-runtime.d.ts +2 -0
- package/dist/terminal-worker-runtime.d.ts.map +1 -0
- package/dist/terminal-worker-runtime.js +311 -0
- package/dist/terminal-worker-runtime.js.map +1 -0
- package/dist/websocket-runtime.d.ts +2 -0
- package/dist/websocket-runtime.d.ts.map +1 -0
- package/dist/websocket-runtime.js +46 -0
- package/dist/websocket-runtime.js.map +1 -0
- package/dist/worker-runtime.d.ts +2 -0
- package/dist/worker-runtime.d.ts.map +1 -0
- package/dist/worker-runtime.js +160 -0
- package/dist/worker-runtime.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
// Application-facing velar/serve contract. HTTP sockets, request streams,
|
|
2
|
+
// backpressure and static-file effects live in the shared isolated Node host;
|
|
3
|
+
// this Realm owns only Velar values, handlers and strict JSON/type boundaries.
|
|
4
|
+
export const VELAR_NODE_SERVE_RUNTIME = String.raw `
|
|
5
|
+
import { __velarNodeHostInvoke, __velarNodeHostOn } from "velar/node-host-v1";
|
|
6
|
+
|
|
7
|
+
const __velarServeArray = globalThis.Array;
|
|
8
|
+
const __velarServeError = globalThis.Error;
|
|
9
|
+
const __velarServeMap = globalThis.Map;
|
|
10
|
+
const __velarServeNumber = globalThis.Number;
|
|
11
|
+
const __velarServeObject = globalThis.Object;
|
|
12
|
+
const __velarServeRangeError = globalThis.RangeError;
|
|
13
|
+
const __velarServeRegExp = globalThis.RegExp;
|
|
14
|
+
const __velarServeReflect = globalThis.Reflect;
|
|
15
|
+
const __velarServeString = globalThis.String;
|
|
16
|
+
const __velarServeTypeError = globalThis.TypeError;
|
|
17
|
+
const __velarServeOwnDescriptor = __velarServeObject.getOwnPropertyDescriptor;
|
|
18
|
+
const __velarServeApply = __velarServeReflect.apply;
|
|
19
|
+
function __velarServeDataOperation(target, name) {
|
|
20
|
+
const descriptor = __velarServeOwnDescriptor(target, name);
|
|
21
|
+
if (!descriptor || !("value" in descriptor) || typeof descriptor.value !== "function") {
|
|
22
|
+
throw new __velarServeError("VelarScript serve operation '" + name + "' is unavailable");
|
|
23
|
+
}
|
|
24
|
+
return descriptor.value;
|
|
25
|
+
}
|
|
26
|
+
const __velarServeArrayIsArray = __velarServeDataOperation(__velarServeArray, "isArray");
|
|
27
|
+
const __velarServeNumberIsFinite = __velarServeDataOperation(__velarServeNumber, "isFinite");
|
|
28
|
+
const __velarServeNumberIsSafeInteger = __velarServeDataOperation(__velarServeNumber, "isSafeInteger");
|
|
29
|
+
const __velarServeObjectCreate = __velarServeDataOperation(__velarServeObject, "create");
|
|
30
|
+
const __velarServeObjectDefineProperty = __velarServeDataOperation(__velarServeObject, "defineProperty");
|
|
31
|
+
const __velarServeObjectFreeze = __velarServeDataOperation(__velarServeObject, "freeze");
|
|
32
|
+
const __velarServeObjectGetPrototypeOf = __velarServeDataOperation(__velarServeObject, "getPrototypeOf");
|
|
33
|
+
const __velarServeOwnKeys = __velarServeDataOperation(__velarServeReflect, "ownKeys");
|
|
34
|
+
const __velarServeMapEntries = __velarServeDataOperation(__velarServeMap.prototype, "entries");
|
|
35
|
+
const __velarServeMapGet = __velarServeDataOperation(__velarServeMap.prototype, "get");
|
|
36
|
+
const __velarServeMapHas = __velarServeDataOperation(__velarServeMap.prototype, "has");
|
|
37
|
+
const __velarServeMapSet = __velarServeDataOperation(__velarServeMap.prototype, "set");
|
|
38
|
+
const __velarServeMapDelete = __velarServeDataOperation(__velarServeMap.prototype, "delete");
|
|
39
|
+
const __velarServeMapSize = __velarServeOwnDescriptor(__velarServeMap.prototype, "size")?.get;
|
|
40
|
+
const __velarServeMapIterator = __velarServeApply(__velarServeMapEntries, new __velarServeMap(), []);
|
|
41
|
+
const __velarServeMapIteratorNext = __velarServeDataOperation(__velarServeApply(__velarServeObjectGetPrototypeOf, __velarServeObject, [__velarServeMapIterator]), "next");
|
|
42
|
+
const __velarServeStringIncludes = __velarServeDataOperation(__velarServeString.prototype, "includes");
|
|
43
|
+
const __velarServeStringStartsWith = __velarServeDataOperation(__velarServeString.prototype, "startsWith");
|
|
44
|
+
const __velarServeStringToLowerCase = __velarServeDataOperation(__velarServeString.prototype, "toLowerCase");
|
|
45
|
+
const __velarServeRegExpTest = __velarServeDataOperation(__velarServeRegExp.prototype, "test");
|
|
46
|
+
const __velarServeHeaderNamePattern = /^[!#$%&'*+.^_|~0-9A-Za-z-]+$/u;
|
|
47
|
+
const __velarServeHeaderValuePattern = /[\0\r\n]/u;
|
|
48
|
+
const __velarServeMethodPattern = /^[!#$%&'*+.^_\x60|~0-9A-Z-]+$/u;
|
|
49
|
+
const __velarServeMaxBodyBytes = 16 * 1024 * 1024;
|
|
50
|
+
const __velarServeMaxPathCodeUnits = 4096;
|
|
51
|
+
const __velarServeFileMarker = Symbol("velar.serve.file-response");
|
|
52
|
+
const __velarServeHandlers = new __velarServeMap();
|
|
53
|
+
const __velarServeResponseFields = __velarServeFieldMap(["status", "json", "text", "contentType", "stream", "headers"]);
|
|
54
|
+
const __velarServeBodyFields = __velarServeFieldMap(["text", "bytes", "tooLarge"]);
|
|
55
|
+
const __velarServeRequestFields = __velarServeFieldMap(["token", "request", "method", "path", "query", "headers"]);
|
|
56
|
+
const __velarServeStartFields = __velarServeFieldMap(["handle", "port"]);
|
|
57
|
+
let __velarServeNextToken = 1;
|
|
58
|
+
|
|
59
|
+
function __velarServeCall(operation, receiver, args) {
|
|
60
|
+
return __velarServeApply(operation, receiver, args);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function __velarServeFieldMap(names) {
|
|
64
|
+
const output = new __velarServeMap();
|
|
65
|
+
for (let index = 0; index < names.length; index += 1) __velarServeCall(__velarServeMapSet, output, [names[index], true]);
|
|
66
|
+
return output;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function __velarServeIsArray(value) {
|
|
70
|
+
return __velarServeCall(__velarServeArrayIsArray, __velarServeArray, [value]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function __velarServeIsSafeInteger(value) {
|
|
74
|
+
return __velarServeCall(__velarServeNumberIsSafeInteger, __velarServeNumber, [value]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function __velarServePlainRecord(value, name) {
|
|
78
|
+
if (!value || typeof value !== "object" || __velarServeIsArray(value)) throw new __velarServeTypeError(name + " must be a plain record");
|
|
79
|
+
const prototype = __velarServeCall(__velarServeObjectGetPrototypeOf, __velarServeObject, [value]);
|
|
80
|
+
if (prototype !== __velarServeObject.prototype && prototype !== null) throw new __velarServeTypeError(name + " must be a plain record");
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function __velarServeRecord(value, allowed, name) {
|
|
85
|
+
value = __velarServePlainRecord(value, name);
|
|
86
|
+
const output = __velarServeCall(__velarServeObjectCreate, __velarServeObject, [null]);
|
|
87
|
+
const keys = __velarServeCall(__velarServeOwnKeys, __velarServeReflect, [value]);
|
|
88
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
89
|
+
const key = keys[index];
|
|
90
|
+
if (typeof key !== "string" || !__velarServeCall(__velarServeMapHas, allowed, [key])) {
|
|
91
|
+
throw new __velarServeTypeError(name + " has an unknown field");
|
|
92
|
+
}
|
|
93
|
+
const descriptor = __velarServeOwnDescriptor(value, key);
|
|
94
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) throw new __velarServeTypeError(name + " fields must be enumerable data values");
|
|
95
|
+
output[key] = descriptor.value;
|
|
96
|
+
}
|
|
97
|
+
return output;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function __velarServeDataField(value, key, name) {
|
|
101
|
+
const descriptor = __velarServeOwnDescriptor(value, key);
|
|
102
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) throw new __velarServeTypeError(name + "." + key + " must be an enumerable data value");
|
|
103
|
+
return descriptor.value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function __velarServeMapSnapshot(value, name, maximum = 1000) {
|
|
107
|
+
let size;
|
|
108
|
+
let iterator;
|
|
109
|
+
try {
|
|
110
|
+
size = __velarServeCall(__velarServeMapSize, value, []);
|
|
111
|
+
iterator = __velarServeCall(__velarServeMapEntries, value, []);
|
|
112
|
+
} catch { throw new __velarServeTypeError(name + " must be a Map<string, string>"); }
|
|
113
|
+
if (!__velarServeIsSafeInteger(size) || size < 0 || size > maximum) throw new __velarServeRangeError(name + " cannot contain more than " + maximum + " fields");
|
|
114
|
+
const output = [];
|
|
115
|
+
let units = 0;
|
|
116
|
+
while (true) {
|
|
117
|
+
let step;
|
|
118
|
+
try { step = __velarServeCall(__velarServeMapIteratorNext, iterator, []); }
|
|
119
|
+
catch { throw new __velarServeTypeError(name + " must be a Map<string, string>"); }
|
|
120
|
+
const done = __velarServeOwnDescriptor(step, "done");
|
|
121
|
+
if (!done || !("value" in done) || typeof done.value !== "boolean") throw new __velarServeTypeError(name + " must be a Map<string, string>");
|
|
122
|
+
if (done.value) break;
|
|
123
|
+
const item = __velarServeOwnDescriptor(step, "value");
|
|
124
|
+
if (!item || !("value" in item) || !__velarServeIsArray(item.value) || item.value.length !== 2) throw new __velarServeTypeError(name + " must be a Map<string, string>");
|
|
125
|
+
const key = __velarServeOwnDescriptor(item.value, "0");
|
|
126
|
+
const valueDescriptor = __velarServeOwnDescriptor(item.value, "1");
|
|
127
|
+
if (!key || !("value" in key) || !valueDescriptor || !("value" in valueDescriptor)
|
|
128
|
+
|| typeof key.value !== "string" || typeof valueDescriptor.value !== "string") {
|
|
129
|
+
throw new __velarServeTypeError(name + " must be a Map<string, string>");
|
|
130
|
+
}
|
|
131
|
+
units += key.value.length + valueDescriptor.value.length;
|
|
132
|
+
if (units > 1024 * 1024) throw new __velarServeRangeError(name + " cannot exceed 1 MiB of text");
|
|
133
|
+
output[output.length] = [key.value, valueDescriptor.value];
|
|
134
|
+
}
|
|
135
|
+
if (output.length !== size) throw new __velarServeTypeError(name + " changed while it was being read");
|
|
136
|
+
return output;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function __velarServePairsMap(value, name) {
|
|
140
|
+
if (!__velarServeIsArray(value) || value.length > 1000) throw new __velarServeTypeError(name + " host result is invalid");
|
|
141
|
+
const output = new __velarServeMap();
|
|
142
|
+
let units = 0;
|
|
143
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
144
|
+
const descriptor = __velarServeOwnDescriptor(value, __velarServeString(index));
|
|
145
|
+
if (!descriptor?.enumerable || !("value" in descriptor) || !__velarServeIsArray(descriptor.value) || descriptor.value.length !== 2) {
|
|
146
|
+
throw new __velarServeTypeError(name + " host result is invalid");
|
|
147
|
+
}
|
|
148
|
+
const key = __velarServeOwnDescriptor(descriptor.value, "0");
|
|
149
|
+
const item = __velarServeOwnDescriptor(descriptor.value, "1");
|
|
150
|
+
if (!key || !("value" in key) || !item || !("value" in item) || typeof key.value !== "string" || typeof item.value !== "string") {
|
|
151
|
+
throw new __velarServeTypeError(name + " host result is invalid");
|
|
152
|
+
}
|
|
153
|
+
units += key.value.length + item.value.length;
|
|
154
|
+
if (units > 1024 * 1024) throw new __velarServeRangeError(name + " host result exceeds 1 MiB");
|
|
155
|
+
if (!__velarServeCall(__velarServeMapHas, output, [key.value])) __velarServeCall(__velarServeMapSet, output, [key.value, item.value]);
|
|
156
|
+
}
|
|
157
|
+
return output;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function __velarServeTypeObject(check, message, internal = null) {
|
|
161
|
+
const value = {
|
|
162
|
+
is(candidate) { try { return check(candidate); } catch { return false; } },
|
|
163
|
+
parse(candidate) { if (!check(candidate)) throw new __velarServeTypeError(message); return candidate; },
|
|
164
|
+
};
|
|
165
|
+
if (internal !== null) __velarServeCall(__velarServeObjectDefineProperty, __velarServeObject, [value, "__velarHandleNative", {value: internal, enumerable: false, configurable: false, writable: false}]);
|
|
166
|
+
return __velarRegisterRuntimeType(__velarServeCall(__velarServeObjectFreeze, __velarServeObject, [value]));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export class RequestBodyTooLargeError extends __velarServeRangeError {
|
|
170
|
+
constructor(maxBytes) {
|
|
171
|
+
super("Request body exceeds maxBytes (" + maxBytes + ")");
|
|
172
|
+
__velarServeCall(__velarServeObjectDefineProperty, __velarServeObject, [this, "name", {value: "RequestBodyTooLargeError", enumerable: false, configurable: true, writable: true}]);
|
|
173
|
+
__velarServeCall(__velarServeObjectDefineProperty, __velarServeObject, [this, "maxBytes", {value: maxBytes, enumerable: true, configurable: false, writable: false}]);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function __velarServeIsFileResponse(value) {
|
|
178
|
+
if (!value || typeof value !== "object") return false;
|
|
179
|
+
const descriptor = __velarServeOwnDescriptor(value, __velarServeFileMarker);
|
|
180
|
+
return descriptor?.enumerable === true && "value" in descriptor && descriptor.value === true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function __velarServeResponse(value) {
|
|
184
|
+
if (__velarServeIsFileResponse(value)) return value;
|
|
185
|
+
const fields = __velarServeRecord(value, __velarServeResponseFields, "ServeResponse");
|
|
186
|
+
if (!__velarServeIsSafeInteger(fields.status) || fields.status < 100 || fields.status > 599) {
|
|
187
|
+
throw new __velarServeRangeError("ServeResponse.status must be an HTTP status integer from 100 through 599");
|
|
188
|
+
}
|
|
189
|
+
let bodies = 0;
|
|
190
|
+
const bodyNames = ["json", "text", "stream"];
|
|
191
|
+
for (let index = 0; index < bodyNames.length; index += 1) if (__velarServeOwnDescriptor(fields, bodyNames[index])) bodies += 1;
|
|
192
|
+
if (bodies !== 1) throw new __velarServeTypeError("ServeResponse requires exactly one of json, text, or stream");
|
|
193
|
+
if (__velarServeOwnDescriptor(fields, "json") && __velarUtf8ByteLength(__velarJsonStringify(fields.json)) > __velarServeMaxBodyBytes) {
|
|
194
|
+
throw new __velarServeRangeError("ServeResponse.json cannot exceed 16 MiB");
|
|
195
|
+
}
|
|
196
|
+
if (__velarServeOwnDescriptor(fields, "text") && typeof fields.text !== "string") throw new __velarServeTypeError("ServeResponse.text must be a string");
|
|
197
|
+
if (__velarServeOwnDescriptor(fields, "text") && __velarUtf8ByteLength(fields.text) > __velarServeMaxBodyBytes) throw new __velarServeRangeError("ServeResponse.text cannot exceed 16 MiB");
|
|
198
|
+
if (__velarServeOwnDescriptor(fields, "stream") && typeof fields.stream !== "function") throw new __velarServeTypeError("ServeResponse.stream must be an async producer");
|
|
199
|
+
if (fields.contentType != null && (typeof fields.contentType !== "string" || fields.contentType.length === 0 || fields.contentType.length > 1024
|
|
200
|
+
|| __velarServeCall(__velarServeStringIncludes, fields.contentType, ["\0"]) || __velarServeCall(__velarServeStringIncludes, fields.contentType, ["\r"])
|
|
201
|
+
|| __velarServeCall(__velarServeStringIncludes, fields.contentType, ["\n"]))) {
|
|
202
|
+
throw new __velarServeTypeError("ServeResponse.contentType must be bounded single-line text");
|
|
203
|
+
}
|
|
204
|
+
__velarServeResponseHeaders(fields.headers);
|
|
205
|
+
return fields;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function __velarServeResponseHeaders(value) {
|
|
209
|
+
const pairs = value == null ? [] : __velarServeMapSnapshot(value, "ServeResponse.headers");
|
|
210
|
+
for (let index = 0; index < pairs.length; index += 1) {
|
|
211
|
+
const name = pairs[index][0];
|
|
212
|
+
const item = pairs[index][1];
|
|
213
|
+
if (!__velarServeCall(__velarServeRegExpTest, __velarServeHeaderNamePattern, [name])
|
|
214
|
+
|| __velarServeCall(__velarServeRegExpTest, __velarServeHeaderValuePattern, [item])) {
|
|
215
|
+
throw new __velarServeTypeError("ServeResponse headers must use valid HTTP names and single-line values");
|
|
216
|
+
}
|
|
217
|
+
const lower = __velarServeCall(__velarServeStringToLowerCase, name, []);
|
|
218
|
+
if (lower === "content-length" || lower === "transfer-encoding" || lower === "connection") {
|
|
219
|
+
throw new __velarServeTypeError("ServeResponse cannot set transport-owned header '" + name + "'");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return pairs;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function __velarServeIsRequest(value) {
|
|
226
|
+
try {
|
|
227
|
+
value = __velarServePlainRecord(value, "ServeRequest");
|
|
228
|
+
const method = __velarServeDataField(value, "method", "ServeRequest");
|
|
229
|
+
const path = __velarServeDataField(value, "path", "ServeRequest");
|
|
230
|
+
const valid = typeof method === "string" && method.length > 0 && method.length <= 32
|
|
231
|
+
&& __velarServeCall(__velarServeRegExpTest, __velarServeMethodPattern, [method])
|
|
232
|
+
&& typeof path === "string" && __velarServeCall(__velarServeStringStartsWith, path, ["/"]) && path.length <= __velarServeMaxPathCodeUnits
|
|
233
|
+
&& !__velarServeCall(__velarServeStringIncludes, path, ["\0"])
|
|
234
|
+
&& typeof __velarServeDataField(value, "text", "ServeRequest") === "function"
|
|
235
|
+
&& typeof __velarServeDataField(value, "json", "ServeRequest") === "function"
|
|
236
|
+
&& typeof __velarServeDataField(value, "parse", "ServeRequest") === "function";
|
|
237
|
+
if (!valid) return false;
|
|
238
|
+
__velarServeMapSnapshot(__velarServeDataField(value, "query", "ServeRequest"), "ServeRequest.query");
|
|
239
|
+
__velarServeMapSnapshot(__velarServeDataField(value, "headers", "ServeRequest"), "ServeRequest.headers");
|
|
240
|
+
return true;
|
|
241
|
+
} catch { return false; }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export const ServeRequest = __velarServeTypeObject(__velarServeIsRequest, "ServeRequest requires the request fields provided by velar/serve", __velarServeHandleNative);
|
|
245
|
+
export const ServeResponse = __velarServeTypeObject(value => { __velarServeResponse(value); return true; }, "ServeResponse requires exactly one checked body");
|
|
246
|
+
export const Server = __velarServeTypeObject(value => {
|
|
247
|
+
try {
|
|
248
|
+
value = __velarServePlainRecord(value, "Server");
|
|
249
|
+
const port = __velarServeDataField(value, "port", "Server");
|
|
250
|
+
return __velarServeIsSafeInteger(port) && port >= 0 && port <= 65535 && typeof __velarServeDataField(value, "stop", "Server") === "function";
|
|
251
|
+
} catch { return false; }
|
|
252
|
+
}, "Server requires port and stop fields");
|
|
253
|
+
|
|
254
|
+
function __velarServeRequestPath(value) {
|
|
255
|
+
if (typeof value !== "string" || value.length === 0 || value.length > __velarServeMaxPathCodeUnits
|
|
256
|
+
|| __velarServeCall(__velarServeStringIncludes, value, ["\0"]) || __velarServeCall(__velarServeStringIncludes, value, ["\\"])) {
|
|
257
|
+
throw new __velarServeTypeError("fileResponse path must be bounded URL path text");
|
|
258
|
+
}
|
|
259
|
+
return value;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function fileResponse(root, path, fallback = null) {
|
|
263
|
+
if (typeof root !== "string" || root.length === 0 || root.length > __velarServeMaxPathCodeUnits || __velarServeCall(__velarServeStringIncludes, root, ["\0"])) {
|
|
264
|
+
throw new __velarServeTypeError("fileResponse root must be a bounded path string");
|
|
265
|
+
}
|
|
266
|
+
path = __velarServeRequestPath(path);
|
|
267
|
+
if (fallback !== null) fallback = __velarServeRequestPath(fallback);
|
|
268
|
+
return __velarServeCall(__velarServeObjectFreeze, __velarServeObject, [{[__velarServeFileMarker]: true, root, path, fallback}]);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function __velarServeBodyResult(value, maximum) {
|
|
272
|
+
value = __velarServeRecord(value, __velarServeBodyFields, "ServeRequest body result");
|
|
273
|
+
if (!__velarServeIsSafeInteger(value.bytes) || value.bytes < 0 || value.bytes > __velarServeMaxBodyBytes || typeof value.tooLarge !== "boolean"
|
|
274
|
+
|| value.tooLarge && value.text !== null || !value.tooLarge && typeof value.text !== "string") {
|
|
275
|
+
throw new __velarServeTypeError("Node host returned an invalid request body");
|
|
276
|
+
}
|
|
277
|
+
if (value.tooLarge || value.bytes > maximum) throw new RequestBodyTooLargeError(maximum);
|
|
278
|
+
return value.text;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function __velarServeRequest(value) {
|
|
282
|
+
value = __velarServeRecord(value, __velarServeRequestFields, "Node serve request event");
|
|
283
|
+
if (!__velarServeIsSafeInteger(value.token) || value.token < 1 || !__velarServeIsSafeInteger(value.request) || value.request < 1
|
|
284
|
+
|| typeof value.method !== "string" || value.method.length === 0 || value.method.length > 32
|
|
285
|
+
|| !__velarServeCall(__velarServeRegExpTest, __velarServeMethodPattern, [value.method])
|
|
286
|
+
|| typeof value.path !== "string" || !__velarServeCall(__velarServeStringStartsWith, value.path, ["/"]) || value.path.length > __velarServeMaxPathCodeUnits) {
|
|
287
|
+
throw new __velarServeTypeError("Node host returned an invalid serve request");
|
|
288
|
+
}
|
|
289
|
+
const handle = value.request;
|
|
290
|
+
const body = async (maxBytes = __velarServeMaxBodyBytes) => {
|
|
291
|
+
if (!__velarServeIsSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > __velarServeMaxBodyBytes) {
|
|
292
|
+
throw new __velarServeRangeError("Request body maxBytes must be an integer from 1 through 16777216");
|
|
293
|
+
}
|
|
294
|
+
return __velarServeBodyResult(await __velarNodeHostInvoke("serve.body", [handle, maxBytes]), maxBytes);
|
|
295
|
+
};
|
|
296
|
+
const json = async (maxBytes = __velarServeMaxBodyBytes) => __velarJsonParse(await body(maxBytes), "ServeRequest JSON text");
|
|
297
|
+
return {token: value.token, handle, request: __velarServeCall(__velarServeObjectFreeze, __velarServeObject, [{
|
|
298
|
+
method: value.method,
|
|
299
|
+
path: value.path,
|
|
300
|
+
query: __velarServePairsMap(value.query, "ServeRequest.query"),
|
|
301
|
+
headers: __velarServePairsMap(value.headers, "ServeRequest.headers"),
|
|
302
|
+
text: body,
|
|
303
|
+
json,
|
|
304
|
+
parse: async (Type, maxBytes = __velarServeMaxBodyBytes) => {
|
|
305
|
+
Type = __velarRequireRuntimeType(Type, "ServeRequest.parse");
|
|
306
|
+
return Type.parse(await json(maxBytes));
|
|
307
|
+
},
|
|
308
|
+
}])};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async function __velarServeWriteResponse(handle, value) {
|
|
312
|
+
if (__velarServeIsFileResponse(value)) {
|
|
313
|
+
await __velarNodeHostInvoke("serve.respondFile", [handle, value.root, value.path, value.fallback]);
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
const response = __velarServeResponse(value);
|
|
317
|
+
const headers = __velarServeResponseHeaders(response.headers);
|
|
318
|
+
if (__velarServeOwnDescriptor(response, "json")) {
|
|
319
|
+
const body = __velarJsonStringify(response.json);
|
|
320
|
+
if (__velarUtf8ByteLength(body) > __velarServeMaxBodyBytes) throw new __velarServeRangeError("ServeResponse.json cannot exceed 16 MiB");
|
|
321
|
+
await __velarNodeHostInvoke("serve.respond", [handle, response.status, headers, "json", body, null]);
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
if (__velarServeOwnDescriptor(response, "text")) {
|
|
325
|
+
await __velarNodeHostInvoke("serve.respond", [handle, response.status, headers, "text", response.text, response.contentType ?? null]);
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
await __velarNodeHostInvoke("serve.streamStart", [handle, response.status, headers]);
|
|
329
|
+
const write = async chunk => {
|
|
330
|
+
if (typeof chunk !== "string") throw new __velarServeTypeError("ServeResponse.stream chunks must be strings");
|
|
331
|
+
if (__velarUtf8ByteLength(chunk) > 1024 * 1024) throw new __velarServeRangeError("ServeResponse.stream chunks cannot exceed 1 MiB");
|
|
332
|
+
await __velarNodeHostInvoke("serve.streamWrite", [handle, chunk]);
|
|
333
|
+
return null;
|
|
334
|
+
};
|
|
335
|
+
const result = await response.stream(write);
|
|
336
|
+
if (result !== null) throw new __velarServeTypeError("ServeResponse.stream producer must resolve to null");
|
|
337
|
+
await __velarNodeHostInvoke("serve.streamEnd", [handle]);
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function __velarServeNativeHeaders(request) {
|
|
342
|
+
const output = new __velarServeMap();
|
|
343
|
+
let units = 0;
|
|
344
|
+
for (const [name, value] of __velarServeObject.entries(request.headers)) {
|
|
345
|
+
if (value === undefined) continue;
|
|
346
|
+
const text = __velarServeIsArray(value) ? value.join(", ") : __velarServeString(value);
|
|
347
|
+
units += name.length + text.length;
|
|
348
|
+
if (units > 1024 * 1024) throw new __velarServeRangeError("ServeRequest headers cannot exceed 1 MiB");
|
|
349
|
+
output.set(name, text);
|
|
350
|
+
}
|
|
351
|
+
return output;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function __velarServeNativeRequest(request) {
|
|
355
|
+
const method = request.method ?? "GET";
|
|
356
|
+
if (typeof method !== "string" || !__velarServeCall(__velarServeRegExpTest, __velarServeMethodPattern, [method])) throw new __velarServeTypeError("Native HTTP method is invalid");
|
|
357
|
+
const url = new URL(request.url ?? "/", "http://velar.local");
|
|
358
|
+
if (url.pathname.length > __velarServeMaxPathCodeUnits) throw new __velarServeRangeError("ServeRequest path is too long");
|
|
359
|
+
const query = new __velarServeMap();
|
|
360
|
+
for (const [name, value] of url.searchParams) query.set(name, value);
|
|
361
|
+
let bodyPromise = null;
|
|
362
|
+
const body = async (maxBytes = __velarServeMaxBodyBytes) => {
|
|
363
|
+
if (!__velarServeIsSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > __velarServeMaxBodyBytes) throw new __velarServeRangeError("Request body maxBytes must be an integer from 1 through 16777216");
|
|
364
|
+
if (bodyPromise === null) bodyPromise = (async () => {
|
|
365
|
+
const chunks = []; let total = 0;
|
|
366
|
+
for await (const chunk of request) { const bytes = chunk instanceof Uint8Array ? chunk : Buffer.from(chunk); total += bytes.byteLength; if (total > __velarServeMaxBodyBytes) { request.resume(); throw new RequestBodyTooLargeError(__velarServeMaxBodyBytes); } chunks.push(bytes); }
|
|
367
|
+
return Buffer.concat(chunks, total).toString("utf8");
|
|
368
|
+
})();
|
|
369
|
+
const text = await bodyPromise;
|
|
370
|
+
if (__velarUtf8ByteLength(text) > maxBytes) throw new RequestBodyTooLargeError(maxBytes);
|
|
371
|
+
return text;
|
|
372
|
+
};
|
|
373
|
+
const json = async (maxBytes = __velarServeMaxBodyBytes) => __velarJsonParse(await body(maxBytes), "ServeRequest JSON text");
|
|
374
|
+
return __velarServeCall(__velarServeObjectFreeze, __velarServeObject, [{method, path: url.pathname, query, headers: __velarServeNativeHeaders(request), text: body, json, parse: async (Type, maxBytes = __velarServeMaxBodyBytes) => { Type = __velarRequireRuntimeType(Type, "ServeRequest.parse"); return Type.parse(await json(maxBytes)); }}]);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function __velarServeNativeSetHeaders(response, headers) { for (const [name, value] of headers) response.setHeader(name, value); }
|
|
378
|
+
async function __velarServeNativeFile(value, operations) {
|
|
379
|
+
const root = await operations.realpath(operations.resolve(value.root));
|
|
380
|
+
const load = async path => {
|
|
381
|
+
const target = await operations.realpath(operations.resolve(root, path.startsWith("/") ? "." + path : path));
|
|
382
|
+
const relative = operations.relative(root, target);
|
|
383
|
+
if (relative.startsWith("..") || operations.isAbsolute(relative)) throw new __velarServeTypeError("fileResponse path escapes its root");
|
|
384
|
+
const info = await operations.stat(target);
|
|
385
|
+
if (!info.isFile() || info.size > 64 * 1024 * 1024) throw new __velarServeRangeError("fileResponse file exceeds 64 MiB");
|
|
386
|
+
return operations.readFile(target);
|
|
387
|
+
};
|
|
388
|
+
try { return await load(value.path); } catch (error) { if (value.fallback === null) throw error; return load(value.fallback); }
|
|
389
|
+
}
|
|
390
|
+
async function __velarServeNativeEnd(response, value) { await new Promise((resolve, reject) => { response.once("error", reject); response.end(value, () => { response.off("error", reject); resolve(null); }); }); }
|
|
391
|
+
async function __velarServeNativeWrite(response, value) { if (response.write(value)) return; await new Promise((resolve, reject) => { const failed = error => { response.off("drain", ready); reject(error); }; const ready = () => { response.off("error", failed); resolve(null); }; response.once("error", failed); response.once("drain", ready); }); }
|
|
392
|
+
async function __velarServeHandleNative(handler, request, response, operations) {
|
|
393
|
+
try {
|
|
394
|
+
const value = await handler(__velarServeNativeRequest(request));
|
|
395
|
+
if (__velarServeIsFileResponse(value)) { response.statusCode = 200; await __velarServeNativeEnd(response, await __velarServeNativeFile(value, operations)); return null; }
|
|
396
|
+
const checked = __velarServeResponse(value); response.statusCode = checked.status; __velarServeNativeSetHeaders(response, __velarServeResponseHeaders(checked.headers));
|
|
397
|
+
if (__velarServeOwnDescriptor(checked, "json")) { response.setHeader("content-type", "application/json; charset=utf-8"); await __velarServeNativeEnd(response, __velarJsonStringify(checked.json)); return null; }
|
|
398
|
+
if (__velarServeOwnDescriptor(checked, "text")) { response.setHeader("content-type", checked.contentType ?? "text/plain; charset=utf-8"); await __velarServeNativeEnd(response, checked.text); return null; }
|
|
399
|
+
const write = async chunk => { if (typeof chunk !== "string" || __velarUtf8ByteLength(chunk) > 1024 * 1024) throw new __velarServeTypeError("ServeResponse.stream chunks must be text of at most 1 MiB"); await __velarServeNativeWrite(response, chunk); return null; };
|
|
400
|
+
const result = await checked.stream(write); if (result !== null) throw new __velarServeTypeError("ServeResponse.stream producer must resolve to null"); await __velarServeNativeEnd(response); return null;
|
|
401
|
+
} catch { if (!response.headersSent) { response.statusCode = 500; response.setHeader("content-type", "text/plain; charset=utf-8"); response.end("Internal server error"); } else response.destroy(); return null; }
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
async function __velarServeDispatch(event) {
|
|
405
|
+
let value;
|
|
406
|
+
try { value = __velarServeRequest(event); }
|
|
407
|
+
catch {
|
|
408
|
+
const request = event && typeof event === "object" ? __velarServeOwnDescriptor(event, "request") : null;
|
|
409
|
+
if (request && "value" in request && __velarServeIsSafeInteger(request.value) && request.value > 0) {
|
|
410
|
+
try { await __velarNodeHostInvoke("serve.fail", [request.value]); }
|
|
411
|
+
catch {}
|
|
412
|
+
}
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const handler = __velarServeCall(__velarServeMapGet, __velarServeHandlers, [value.token]);
|
|
416
|
+
if (typeof handler !== "function") { await __velarNodeHostInvoke("serve.fail", [value.handle]); return; }
|
|
417
|
+
try { await __velarServeWriteResponse(value.handle, await handler(value.request)); }
|
|
418
|
+
catch {
|
|
419
|
+
try { await __velarNodeHostInvoke("serve.fail", [value.handle]); }
|
|
420
|
+
catch {}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
__velarNodeHostOn("serve.request", event => { __velarServeDispatch(event); });
|
|
425
|
+
|
|
426
|
+
export async function serve(handler, port, host = "127.0.0.1") {
|
|
427
|
+
if (typeof handler !== "function") throw new __velarServeTypeError("serve requires an async request handler");
|
|
428
|
+
if (!__velarServeIsSafeInteger(port) || port < 0 || port > 65535) throw new __velarServeRangeError("serve port must be an integer from 0 through 65535");
|
|
429
|
+
if (typeof host !== "string" || host.length === 0 || host.length > 255 || __velarServeCall(__velarServeStringIncludes, host, ["\0"])) {
|
|
430
|
+
throw new __velarServeTypeError("serve host must be bounded text");
|
|
431
|
+
}
|
|
432
|
+
if (!__velarServeIsSafeInteger(__velarServeNextToken)) __velarServeNextToken = 1;
|
|
433
|
+
let attempts = 0;
|
|
434
|
+
while (__velarServeCall(__velarServeMapHas, __velarServeHandlers, [__velarServeNextToken])) {
|
|
435
|
+
__velarServeNextToken += 1;
|
|
436
|
+
if (!__velarServeIsSafeInteger(__velarServeNextToken)) __velarServeNextToken = 1;
|
|
437
|
+
attempts += 1;
|
|
438
|
+
if (attempts > 128) throw new __velarServeRangeError("serve cannot own more than 128 servers");
|
|
439
|
+
}
|
|
440
|
+
const token = __velarServeNextToken++;
|
|
441
|
+
__velarServeCall(__velarServeMapSet, __velarServeHandlers, [token, handler]);
|
|
442
|
+
let started;
|
|
443
|
+
try { started = __velarServeRecord(await __velarNodeHostInvoke("serve.start", [token, port, host]), __velarServeStartFields, "Node serve start result"); }
|
|
444
|
+
catch (error) { __velarServeCall(__velarServeMapDelete, __velarServeHandlers, [token]); throw error; }
|
|
445
|
+
if (!__velarServeIsSafeInteger(started.handle) || started.handle < 1 || !__velarServeIsSafeInteger(started.port) || started.port < 0 || started.port > 65535) {
|
|
446
|
+
__velarServeCall(__velarServeMapDelete, __velarServeHandlers, [token]);
|
|
447
|
+
throw new __velarServeTypeError("Node host returned an invalid server");
|
|
448
|
+
}
|
|
449
|
+
let stopped = null;
|
|
450
|
+
const stop = async () => {
|
|
451
|
+
if (stopped !== null) return stopped;
|
|
452
|
+
stopped = (async () => {
|
|
453
|
+
const result = await __velarNodeHostInvoke("serve.stop", [started.handle]);
|
|
454
|
+
if (result !== null) throw new __velarServeTypeError("Node host returned an invalid server stop completion");
|
|
455
|
+
__velarServeCall(__velarServeMapDelete, __velarServeHandlers, [token]);
|
|
456
|
+
return null;
|
|
457
|
+
})();
|
|
458
|
+
return stopped;
|
|
459
|
+
};
|
|
460
|
+
return __velarServeCall(__velarServeObjectFreeze, __velarServeObject, [{port: started.port, stop}]);
|
|
461
|
+
}
|
|
462
|
+
`.trimStart();
|
|
463
|
+
//# sourceMappingURL=serve-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-runtime.js","sourceRoot":"","sources":["../src/serve-runtime.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8EAA8E;AAC9E,+EAA+E;AAC/E,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0cjD,CAAC,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-runtime.d.ts","sourceRoot":"","sources":["../src/sqlite-runtime.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,+BAA+B,QA8C3C,CAAC;AAEF,eAAO,MAAM,yBAAyB,QA2CzB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export const VELAR_NODE_SQLITE_WORKER_SOURCE = String.raw `
|
|
2
|
+
const { parentPort, workerData } = require("node:worker_threads");
|
|
3
|
+
const { DatabaseSync } = require("node:sqlite");
|
|
4
|
+
const database = new DatabaseSync(workerData.path, { timeout: workerData.busyTimeout });
|
|
5
|
+
const statements = new Map();
|
|
6
|
+
let nextStatement = 1;
|
|
7
|
+
let transaction = 0;
|
|
8
|
+
function params(value) { if (!Array.isArray(value) || value.length > 10000) throw new TypeError("SQLite parameters must be a bounded List"); return value; }
|
|
9
|
+
function sql(value) { if (typeof value !== "string" || value.length === 0 || value.length > 1024 * 1024) throw new TypeError("SQLite SQL must be non-empty text no longer than 1 MiB"); return value; }
|
|
10
|
+
function statement(id) { const value = statements.get(id); if (!value) throw new Error("SQLite statement is closed"); return value; }
|
|
11
|
+
function normalize(value, transfers, seen = new WeakSet()) {
|
|
12
|
+
if (value === null || typeof value !== "object") return value;
|
|
13
|
+
if (value instanceof Uint8Array) { const bytes = new Uint8Array(value.byteLength); bytes.set(value); transfers.push(bytes.buffer); return bytes; }
|
|
14
|
+
if (seen.has(value)) throw new TypeError("SQLite returned cyclic data"); seen.add(value);
|
|
15
|
+
if (Array.isArray(value)) return value.map(item => normalize(item, transfers, seen));
|
|
16
|
+
const output = Object.create(null); for (const key of Object.keys(value)) output[key] = normalize(value[key], transfers, seen); return output;
|
|
17
|
+
}
|
|
18
|
+
function resultSize(value, seen = new WeakSet()) { if (value === null) return 4; if (typeof value === "string") return Buffer.byteLength(value, "utf8"); if (typeof value === "number") return 8; if (value instanceof Uint8Array) return value.byteLength; if (typeof value !== "object" || seen.has(value)) return 0; seen.add(value); if (Array.isArray(value)) return value.reduce((sum, item) => sum + resultSize(item, seen), 0); return Object.entries(value).reduce((sum, [key, item]) => sum + Buffer.byteLength(key, "utf8") + resultSize(item, seen), 0); }
|
|
19
|
+
function bounded(value) { if (Array.isArray(value) && value.length > workerData.maxRows) throw new RangeError("SQLite result exceeds maxRows"); if (resultSize(value) > workerData.maxResultBytes) throw new RangeError("SQLite result exceeds maxResultBytes"); return value; }
|
|
20
|
+
function execute(target, values) { const result = target.run(...params(values)); return Number(result.changes); }
|
|
21
|
+
function one(target, values) { return target.get(...params(values)) ?? null; }
|
|
22
|
+
function all(target, values) { return target.all(...params(values)); }
|
|
23
|
+
function transactionId(value) { if (value === 0) { if (transaction !== 0) throw new Error("Use the active Transaction handle while a transaction is open"); return; } if (value !== transaction) throw new Error("SQLite transaction is no longer active"); }
|
|
24
|
+
parentPort.on("message", message => {
|
|
25
|
+
const transfers = [];
|
|
26
|
+
try {
|
|
27
|
+
const tx = Number.isSafeInteger(message.transaction) ? message.transaction : 0;
|
|
28
|
+
if (message.operation !== "close") transactionId(tx);
|
|
29
|
+
let value = null;
|
|
30
|
+
if (message.operation === "execute") value = execute(database.prepare(sql(message.sql)), message.params ?? []);
|
|
31
|
+
else if (message.operation === "one") value = bounded(one(database.prepare(sql(message.sql)), message.params ?? []));
|
|
32
|
+
else if (message.operation === "all") value = bounded(all(database.prepare(sql(message.sql)), message.params ?? []));
|
|
33
|
+
else if (message.operation === "prepare") { const id = nextStatement++; statements.set(id, database.prepare(sql(message.sql))); value = id; }
|
|
34
|
+
else if (message.operation === "statement.execute") value = execute(statement(message.statement), message.params ?? []);
|
|
35
|
+
else if (message.operation === "statement.one") value = bounded(one(statement(message.statement), message.params ?? []));
|
|
36
|
+
else if (message.operation === "statement.all") value = bounded(all(statement(message.statement), message.params ?? []));
|
|
37
|
+
else if (message.operation === "statement.close") { statements.delete(message.statement); value = null; }
|
|
38
|
+
else if (message.operation === "transaction") { if (transaction !== 0) throw new Error("SQLite transaction is already active"); database.exec("BEGIN IMMEDIATE"); transaction = message.transactionId; value = transaction; }
|
|
39
|
+
else if (message.operation === "commit") { database.exec("COMMIT"); transaction = 0; value = null; }
|
|
40
|
+
else if (message.operation === "rollback") { database.exec("ROLLBACK"); transaction = 0; value = null; }
|
|
41
|
+
else if (message.operation === "close") { if (transaction !== 0) { database.exec("ROLLBACK"); transaction = 0; } statements.clear(); database.close(); value = null; }
|
|
42
|
+
else throw new Error("Unknown SQLite operation");
|
|
43
|
+
const normalized = normalize(value, transfers); parentPort.postMessage({ id: message.id, ok: true, value: normalized }, transfers);
|
|
44
|
+
} catch (error) { parentPort.postMessage({ id: message.id, ok: false, error: { name: error?.name ?? "Error", message: error?.message ?? String(error), code: error?.code ?? null } }); }
|
|
45
|
+
});
|
|
46
|
+
parentPort.postMessage({ ready: true });
|
|
47
|
+
`;
|
|
48
|
+
export const VELAR_NODE_SQLITE_RUNTIME = String.raw `
|
|
49
|
+
import { Worker as __VelarSqliteWorker } from "node:worker_threads";
|
|
50
|
+
const __velarSqliteDatabases = new WeakMap();
|
|
51
|
+
const __velarSqliteStatements = new WeakMap();
|
|
52
|
+
const __velarSqliteTransactions = new WeakMap();
|
|
53
|
+
export class SqliteError extends Error { constructor(message = "SQLite operation failed", code = null) { super(message); this.name = "SqliteError"; this.code = code; } }
|
|
54
|
+
export class SqliteBackpressureError extends Error { constructor(message = "SQLite queue is full") { super(message); this.name = "SqliteBackpressureError"; } }
|
|
55
|
+
function __velarSqliteInteger(value, fallback, minimum, maximum, name) { if (value === undefined || value === null) return fallback; if (!Number.isSafeInteger(value) || value < minimum || value > maximum) throw new RangeError(name + " must be an integer from " + minimum + " through " + maximum); return value; }
|
|
56
|
+
function __velarSqliteOptions(options = {}) { if (options === null || typeof options !== "object" || Array.isArray(options)) throw new TypeError("SQLite options must be a record"); return { busyTimeout: __velarSqliteInteger(options.busyTimeout, 5000, 0, 2147483647, "busyTimeout"), queueCapacity: __velarSqliteInteger(options.queueCapacity, 256, 1, 10000, "queueCapacity"), maxRows: __velarSqliteInteger(options.maxRows, 10000, 1, 1000000, "maxRows"), maxResultBytes: __velarSqliteInteger(options.maxResultBytes, 16 * 1024 * 1024, 1, 64 * 1024 * 1024, "maxResultBytes") }; }
|
|
57
|
+
function __velarSqliteDatabase(value) { const state = __velarSqliteDatabases.get(value); if (!state) throw new TypeError("SQLite method requires a Database receiver"); return state; }
|
|
58
|
+
function __velarSqliteStatement(value) { const state = __velarSqliteStatements.get(value); if (!state) throw new TypeError("SQLite method requires a Statement receiver"); return state; }
|
|
59
|
+
function __velarSqliteTransaction(value) { const state = __velarSqliteTransactions.get(value); if (!state) throw new TypeError("SQLite method requires a Transaction receiver"); return state; }
|
|
60
|
+
function __velarSqliteParams(value = []) { if (!Array.isArray(value) || value.length > 10000) throw new TypeError("SQLite parameters must be a bounded List"); return value; }
|
|
61
|
+
function __velarSqliteRequest(state, message) { if (state.closed) return Promise.reject(new SqliteError("SQLite database is closed")); if (state.pending.size >= state.options.queueCapacity) return Promise.reject(new SqliteBackpressureError("SQLite queue capacity " + state.options.queueCapacity + " is full")); const id = state.nextId++; return new Promise((resolve, reject) => { state.pending.set(id, { resolve, reject }); state.worker.postMessage({ ...message, id }); }); }
|
|
62
|
+
function __velarSqliteRead(state, operation, sql, params, Type, transaction = 0, statement = 0) { if ((typeof Type !== "object" && typeof Type !== "function") || Type === null || typeof Type.parse !== "function") return Promise.reject(new TypeError("SQLite row validation requires a runtime Type")); return __velarSqliteRequest(state, { operation, sql, params: __velarSqliteParams(params), transaction, statement }).then(value => operation.endsWith("one") ? value === null ? null : Type.parse(value) : value.map(row => Type.parse(row))); }
|
|
63
|
+
const __velarSqliteDatabasePrototype = Object.freeze({
|
|
64
|
+
execute(sql, params = []) { return __velarSqliteRequest(__velarSqliteDatabase(this), { operation: "execute", sql, params: __velarSqliteParams(params), transaction: 0 }); },
|
|
65
|
+
one(sql, params, Type) { const state = __velarSqliteDatabase(this); return __velarSqliteRead(state, "one", sql, params, Type); }, all(sql, params, Type) { const state = __velarSqliteDatabase(this); return __velarSqliteRead(state, "all", sql, params, Type); },
|
|
66
|
+
async prepare(sql) { const state = __velarSqliteDatabase(this); const id = await __velarSqliteRequest(state, { operation: "prepare", sql, transaction: 0 }); return __velarSqliteMakeStatement(state, id, 0); },
|
|
67
|
+
async transaction() { const state = __velarSqliteDatabase(this); const transaction = state.nextTransaction++; await __velarSqliteRequest(state, { operation: "transaction", transaction: 0, transactionId: transaction }); return __velarSqliteMakeTransaction(state, transaction); },
|
|
68
|
+
async close() { const state = __velarSqliteDatabase(this); if (state.closed) return null; await __velarSqliteRequest(state, { operation: "close", transaction: 0 }); state.closed = true; await state.worker.terminate(); return null; },
|
|
69
|
+
});
|
|
70
|
+
const __velarSqliteStatementPrototype = Object.freeze({
|
|
71
|
+
execute(params = []) { const item = __velarSqliteStatement(this); return __velarSqliteRequest(item.database, { operation: "statement.execute", statement: item.id, params: __velarSqliteParams(params), transaction: item.transaction }); },
|
|
72
|
+
one(params, Type) { const item = __velarSqliteStatement(this); return __velarSqliteRead(item.database, "statement.one", null, params, Type, item.transaction, item.id); }, all(params, Type) { const item = __velarSqliteStatement(this); return __velarSqliteRead(item.database, "statement.all", null, params, Type, item.transaction, item.id); },
|
|
73
|
+
async close() { const item = __velarSqliteStatement(this); if (item.closed) return null; await __velarSqliteRequest(item.database, { operation: "statement.close", statement: item.id, transaction: item.transaction }); item.closed = true; if (item.owner) item.owner.statements.delete(item); return null; },
|
|
74
|
+
});
|
|
75
|
+
async function __velarSqliteCloseTransactionStatements(item) { for (const statement of [...item.statements]) { if (statement.closed) continue; await __velarSqliteRequest(item.database, { operation: "statement.close", statement: statement.id, transaction: item.id }); statement.closed = true; } item.statements.clear(); }
|
|
76
|
+
const __velarSqliteTransactionPrototype = Object.freeze({
|
|
77
|
+
execute(sql, params = []) { const item = __velarSqliteTransaction(this); return __velarSqliteRequest(item.database, { operation: "execute", sql, params: __velarSqliteParams(params), transaction: item.id }); },
|
|
78
|
+
one(sql, params, Type) { const item = __velarSqliteTransaction(this); return __velarSqliteRead(item.database, "one", sql, params, Type, item.id); }, all(sql, params, Type) { const item = __velarSqliteTransaction(this); return __velarSqliteRead(item.database, "all", sql, params, Type, item.id); },
|
|
79
|
+
async prepare(sql) { const item = __velarSqliteTransaction(this); if (!item.active) throw new SqliteError("SQLite transaction is no longer active"); const id = await __velarSqliteRequest(item.database, { operation: "prepare", sql, transaction: item.id }); return __velarSqliteMakeStatement(item.database, id, item.id, item); },
|
|
80
|
+
async commit() { const item = __velarSqliteTransaction(this); if (!item.active) throw new SqliteError("SQLite transaction is no longer active"); await __velarSqliteCloseTransactionStatements(item); await __velarSqliteRequest(item.database, { operation: "commit", transaction: item.id }); item.active = false; return null; },
|
|
81
|
+
async rollback() { const item = __velarSqliteTransaction(this); if (!item.active) return null; await __velarSqliteCloseTransactionStatements(item); await __velarSqliteRequest(item.database, { operation: "rollback", transaction: item.id }); item.active = false; return null; },
|
|
82
|
+
async close() { return this.rollback(); },
|
|
83
|
+
});
|
|
84
|
+
function __velarSqliteMakeStatement(database, id, transaction, owner = null) { const value = Object.create(__velarSqliteStatementPrototype); const state = { database, id, transaction, owner, closed: false }; __velarSqliteStatements.set(value, state); if (owner) owner.statements.add(state); return Object.freeze(value); }
|
|
85
|
+
function __velarSqliteMakeTransaction(database, id) { const value = Object.create(__velarSqliteTransactionPrototype); __velarSqliteTransactions.set(value, { database, id, active: true, statements: new Set() }); return Object.freeze(value); }
|
|
86
|
+
const __velarSqliteDatabaseType = Object.freeze({ is(value) { return __velarSqliteDatabases.has(value); }, parse(value) { if (!this.is(value)) throw new TypeError("Value does not match Database"); return value; } });
|
|
87
|
+
const __velarSqliteStatementType = Object.freeze({ is(value) { return __velarSqliteStatements.has(value); }, parse(value) { if (!this.is(value)) throw new TypeError("Value does not match Statement"); return value; } });
|
|
88
|
+
const __velarSqliteTransactionType = Object.freeze({ is(value) { return __velarSqliteTransactions.has(value); }, parse(value) { if (!this.is(value)) throw new TypeError("Value does not match Transaction"); return value; } });
|
|
89
|
+
export const Database = __velarSqliteDatabaseType; export const Statement = __velarSqliteStatementType; export const Transaction = __velarSqliteTransactionType;
|
|
90
|
+
export function open(path, options = {}) { if (typeof path !== "string" || path.length === 0 || path.includes("\0")) return Promise.reject(new TypeError("SQLite path must be non-empty text without NUL")); const checked = __velarSqliteOptions(options); return new Promise((resolve, reject) => { const worker = new __VelarSqliteWorker(WORKER_SOURCE, { eval: true, workerData: { path, ...checked } }); const value = Object.create(__velarSqliteDatabasePrototype); const state = { worker, options: checked, pending: new Map(), nextId: 1, nextTransaction: 1, closed: false }; __velarSqliteDatabases.set(value, state); worker.on("message", message => { if (message?.ready) { resolve(Object.freeze(value)); return; } const pending = state.pending.get(message?.id); if (!pending) return; state.pending.delete(message.id); if (message.ok) pending.resolve(message.value); else pending.reject(new SqliteError(message.error?.message ?? "SQLite operation failed", message.error?.code ?? null)); }); worker.on("error", error => { state.closed = true; for (const pending of state.pending.values()) pending.reject(new SqliteError(error.message)); state.pending.clear(); reject(error); }); worker.on("exit", code => { if (!state.closed && code !== 0) { state.closed = true; for (const pending of state.pending.values()) pending.reject(new SqliteError("SQLite worker exited with code " + code)); state.pending.clear(); } }); }); }
|
|
91
|
+
`.trimStart();
|
|
92
|
+
//# sourceMappingURL=sqlite-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-runtime.js","sourceRoot":"","sources":["../src/sqlite-runtime.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,+BAA+B,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CxD,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ClD,CAAC,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-runtime.d.ts","sourceRoot":"","sources":["../src/terminal-runtime.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,2BAA2B,QA6R3B,CAAC"}
|