hyperdb-wasm 0.0.27367-dev.wasm.g50457039 → 0.0.27368-dev.wasm.ge6142229
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/dist/api.d.ts +8 -0
- package/dist/browser.d.ts +14 -3
- package/dist/browser.js +134 -12
- package/dist/browser_worker.js +483 -12
- package/dist/client.d.ts +2 -0
- package/dist/database_locks.d.ts +2 -0
- package/dist/external_directory_dispatcher.d.ts +38 -0
- package/dist/hyperdb-wasm.wasm.br +0 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.node.d.ts +5 -1
- package/dist/memory_directory.d.ts +16 -0
- package/dist/memory_external_directory.d.ts +50 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +138 -16
- package/dist/node_worker.js +484 -21
- package/dist/protocol.d.ts +20 -1
- package/dist/raw.browser.js +509 -7
- package/dist/raw.d.ts +6 -1
- package/dist/raw.node.js +464 -2
- package/dist/wasm_bindings.d.ts +5 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface HyperDBClient {
|
|
|
14
14
|
mount(source: MountSource, path: string, mode: MountAccessMode): Promise<WasmResult>;
|
|
15
15
|
unmount(path: string): Promise<WasmResult>;
|
|
16
16
|
refreshMount(path: string): Promise<WasmResult>;
|
|
17
|
+
listMount(path: string): Promise<WasmResult>;
|
|
18
|
+
readMountFile(path: string, file: string): Promise<WasmResult>;
|
|
17
19
|
pollQuery(query: number): Promise<WasmResult>;
|
|
18
20
|
cancelQuery(query: number): Promise<WasmResult>;
|
|
19
21
|
finishQuery(query: number): Promise<WasmResult>;
|
|
@@ -31,8 +33,14 @@ export interface MountOptions {
|
|
|
31
33
|
export interface MountedResource {
|
|
32
34
|
readonly path: string;
|
|
33
35
|
refresh(): Promise<void>;
|
|
36
|
+
list(): Promise<readonly MountFileEntry[]>;
|
|
37
|
+
readFile(path: string): Promise<Blob>;
|
|
34
38
|
close(): Promise<void>;
|
|
35
39
|
}
|
|
40
|
+
export interface MountFileEntry {
|
|
41
|
+
readonly path: string;
|
|
42
|
+
readonly size: number;
|
|
43
|
+
}
|
|
36
44
|
export declare function validateMountPath(path: unknown): asserts path is string;
|
|
37
45
|
export type HyperDBSettingValue = string | number | boolean | null | readonly HyperDBSettingValue[] | {
|
|
38
46
|
readonly [key: string]: HyperDBSettingValue;
|
package/dist/browser.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export interface BrowserWorkerLike {
|
|
|
8
8
|
terminate(): void;
|
|
9
9
|
}
|
|
10
10
|
export interface BrowserClientOptions {
|
|
11
|
+
/** Blob workers inline both scripts so pthreads can start without an origin */
|
|
12
|
+
readonly worker?: 'url' | 'blob';
|
|
13
|
+
/** Memory storage is private to this engine and discarded on termination */
|
|
14
|
+
readonly storage?: 'persistent' | 'memory';
|
|
11
15
|
readonly workerUrl?: string | URL;
|
|
12
16
|
readonly engineUrl?: string | URL;
|
|
13
17
|
readonly wasmUrl?: string | URL;
|
|
@@ -30,10 +34,11 @@ type BrowserEnvironment = {
|
|
|
30
34
|
};
|
|
31
35
|
};
|
|
32
36
|
};
|
|
33
|
-
export declare function assertBrowserSupport(environment?: BrowserEnvironment): void;
|
|
37
|
+
export declare function assertBrowserSupport(environment?: BrowserEnvironment, storage?: BrowserClientOptions['storage']): void;
|
|
34
38
|
export declare class BrowserWorker implements WorkerTransport {
|
|
35
39
|
private readonly worker;
|
|
36
|
-
|
|
40
|
+
private blobUrl?;
|
|
41
|
+
constructor(worker: BrowserWorkerLike, blobUrl?: string | undefined);
|
|
37
42
|
postMessage(message: EngineRequest, transfer?: readonly ArrayBuffer[]): void;
|
|
38
43
|
onMessage(listener: (message: unknown) => void): () => void;
|
|
39
44
|
onError(listener: (error: Error) => void): () => void;
|
|
@@ -41,5 +46,11 @@ export declare class BrowserWorker implements WorkerTransport {
|
|
|
41
46
|
terminate(): void;
|
|
42
47
|
}
|
|
43
48
|
export declare function resolveBrowserWorkerUrl(workerUrl: string | URL, engineUrl: string | URL, wasmUrl?: string | URL, storagePath?: string, baseUrl?: string | URL): URL;
|
|
44
|
-
export declare function createBrowserClient(options
|
|
49
|
+
export declare function createBrowserClient(options: BrowserClientOptions & {
|
|
50
|
+
worker: 'blob';
|
|
51
|
+
}): Promise<HyperDBEngineClient>;
|
|
52
|
+
export declare function createBrowserClient(options?: BrowserClientOptions & {
|
|
53
|
+
worker?: 'url';
|
|
54
|
+
}): HyperDBEngineClient;
|
|
55
|
+
export declare function createBrowserClient(options: BrowserClientOptions): HyperDBEngineClient | Promise<HyperDBEngineClient>;
|
|
45
56
|
export {};
|
package/dist/browser.js
CHANGED
|
@@ -28,6 +28,10 @@ function isWasmResult(value) {
|
|
|
28
28
|
case "ok":
|
|
29
29
|
case "chunk":
|
|
30
30
|
return hasKeys(value, ["state", "payload"]) && value.payload instanceof Uint8Array;
|
|
31
|
+
case "mountList":
|
|
32
|
+
return hasKeys(value, ["state", "entries"]) && Array.isArray(value.entries) && value.entries.every((entry) => isRecord(entry) && hasKeys(entry, ["path", "size"]) && typeof entry.path === "string" && !!entry.path && Number.isSafeInteger(entry.size) && entry.size >= 0);
|
|
33
|
+
case "mountFile":
|
|
34
|
+
return hasKeys(value, ["state", "blob"]) && value.blob instanceof Blob;
|
|
31
35
|
case "pending":
|
|
32
36
|
case "done":
|
|
33
37
|
return hasKeys(value, ["state"]);
|
|
@@ -127,6 +131,12 @@ var init_client = __esm({
|
|
|
127
131
|
refreshMount(path) {
|
|
128
132
|
return this.request({ id: this.nextId++, type: "refreshMount", path });
|
|
129
133
|
}
|
|
134
|
+
listMount(path) {
|
|
135
|
+
return this.request({ id: this.nextId++, type: "listMount", path });
|
|
136
|
+
}
|
|
137
|
+
readMountFile(path, file) {
|
|
138
|
+
return this.request({ id: this.nextId++, type: "readMountFile", path, file });
|
|
139
|
+
}
|
|
130
140
|
pollQuery(query) {
|
|
131
141
|
return this.request({ id: this.nextId++, type: "pollQuery", query });
|
|
132
142
|
}
|
|
@@ -210,7 +220,7 @@ __export(browser_exports, {
|
|
|
210
220
|
createBrowserClient: () => createBrowserClient,
|
|
211
221
|
resolveBrowserWorkerUrl: () => resolveBrowserWorkerUrl
|
|
212
222
|
});
|
|
213
|
-
function assertBrowserSupport(environment = globalThis) {
|
|
223
|
+
function assertBrowserSupport(environment = globalThis, storage = "persistent") {
|
|
214
224
|
if (typeof environment.WebAssembly?.validate !== "function") {
|
|
215
225
|
throw new Error("HyperDB cannot initialize because this browser does not support WebAssembly");
|
|
216
226
|
}
|
|
@@ -241,7 +251,7 @@ function assertBrowserSupport(environment = globalThis) {
|
|
|
241
251
|
if (environment.crossOriginIsolated !== true) {
|
|
242
252
|
throw new Error("HyperDB cannot initialize because this page is not cross-origin isolated");
|
|
243
253
|
}
|
|
244
|
-
if (typeof environment.navigator?.storage?.getDirectory !== "function") {
|
|
254
|
+
if (storage !== "memory" && typeof environment.navigator?.storage?.getDirectory !== "function") {
|
|
245
255
|
throw new Error("HyperDB cannot initialize because this browser does not support the origin-private file system");
|
|
246
256
|
}
|
|
247
257
|
}
|
|
@@ -253,15 +263,51 @@ function resolveBrowserWorkerUrl(workerUrl, engineUrl, wasmUrl, storagePath, bas
|
|
|
253
263
|
return resolved;
|
|
254
264
|
}
|
|
255
265
|
function createBrowserClient(options = {}) {
|
|
256
|
-
|
|
266
|
+
if (options.storage === "memory" && options.storagePath !== void 0) throw new Error("storagePath cannot be used with memory storage");
|
|
267
|
+
if (options.storage !== void 0 && options.storage !== "persistent" && options.storage !== "memory") throw new Error("Unsupported storage mode");
|
|
268
|
+
if (options.worker !== void 0 && options.worker !== "url" && options.worker !== "blob") throw new Error("Unsupported worker mode");
|
|
269
|
+
assertBrowserSupport(globalThis, options.storage);
|
|
257
270
|
const workerUrl = options.workerUrl ?? new URL("./browser_worker.js", import.meta.url);
|
|
258
271
|
const engineUrl = options.engineUrl ?? new URL("./hyperdb-wasm.js", import.meta.url);
|
|
272
|
+
if (options.worker === "blob") return createBlobClient(options, workerUrl, engineUrl);
|
|
273
|
+
const resolved = resolveBrowserWorkerUrl(workerUrl, engineUrl, options.wasmUrl, options.storagePath);
|
|
274
|
+
if (options.storage === "memory") resolved.searchParams.set("storage", "memory");
|
|
259
275
|
return new HyperDBEngineClient(
|
|
260
|
-
new BrowserWorker(new Worker(
|
|
276
|
+
new BrowserWorker(new Worker(resolved, { type: "classic" })),
|
|
261
277
|
options.onSetupProgress,
|
|
262
278
|
options.onLog
|
|
263
279
|
);
|
|
264
280
|
}
|
|
281
|
+
async function createBlobClient(options, workerUrl, engineUrl) {
|
|
282
|
+
const baseUrl = globalThis.document?.baseURI ?? globalThis.location?.href ?? import.meta.url;
|
|
283
|
+
const resolvedEngineUrl = new URL(engineUrl, baseUrl);
|
|
284
|
+
const configuration = {
|
|
285
|
+
engineUrl: resolvedEngineUrl.href,
|
|
286
|
+
wasmUrl: options.wasmUrl === void 0 ? new URL("hyperdb-wasm.wasm.br", resolvedEngineUrl).href : new URL(options.wasmUrl, baseUrl).href,
|
|
287
|
+
storage: options.storage ?? "persistent",
|
|
288
|
+
storagePath: options.storagePath ?? "",
|
|
289
|
+
inlineEngine: true
|
|
290
|
+
};
|
|
291
|
+
const fetchScript = async (url) => {
|
|
292
|
+
const response = await fetch(url, { mode: "cors", credentials: "omit" });
|
|
293
|
+
if (!response.ok) throw new Error(`Failed to fetch HyperDB script: ${response.status} ${response.statusText}`);
|
|
294
|
+
return (await response.text()).replace(/^#![^\r\n]*/, "");
|
|
295
|
+
};
|
|
296
|
+
const [workerScript, engineScript] = await Promise.all([fetchScript(new URL(workerUrl, baseUrl)), fetchScript(resolvedEngineUrl)]);
|
|
297
|
+
const blobUrl = URL.createObjectURL(new Blob([
|
|
298
|
+
`self.HYPERDB_WASM_CONFIGURATION = ${JSON.stringify(configuration)};
|
|
299
|
+
`,
|
|
300
|
+
workerScript,
|
|
301
|
+
"\n",
|
|
302
|
+
engineScript
|
|
303
|
+
], { type: "text/javascript" }));
|
|
304
|
+
try {
|
|
305
|
+
return new HyperDBEngineClient(new BrowserWorker(new Worker(blobUrl, { type: "classic" }), blobUrl), options.onSetupProgress, options.onLog);
|
|
306
|
+
} catch (error) {
|
|
307
|
+
URL.revokeObjectURL(blobUrl);
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
265
311
|
var memory64Probe, threadsProbe, exceptionsProbe, tailCallsProbe, BrowserWorker;
|
|
266
312
|
var init_browser = __esm({
|
|
267
313
|
"src/browser.ts"() {
|
|
@@ -272,10 +318,12 @@ var init_browser = __esm({
|
|
|
272
318
|
exceptionsProbe = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 13, 3, 1, 0, 0]);
|
|
273
319
|
tailCallsProbe = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 3, 3, 2, 0, 0, 10, 9, 2, 4, 0, 18, 1, 11, 2, 0, 11]);
|
|
274
320
|
BrowserWorker = class {
|
|
275
|
-
constructor(worker) {
|
|
321
|
+
constructor(worker, blobUrl) {
|
|
276
322
|
this.worker = worker;
|
|
323
|
+
this.blobUrl = blobUrl;
|
|
277
324
|
}
|
|
278
325
|
worker;
|
|
326
|
+
blobUrl;
|
|
279
327
|
postMessage(message, transfer = []) {
|
|
280
328
|
this.worker.postMessage(message, [...transfer]);
|
|
281
329
|
}
|
|
@@ -293,7 +341,12 @@ var init_browser = __esm({
|
|
|
293
341
|
return () => void 0;
|
|
294
342
|
}
|
|
295
343
|
terminate() {
|
|
296
|
-
|
|
344
|
+
try {
|
|
345
|
+
this.worker.terminate();
|
|
346
|
+
} finally {
|
|
347
|
+
if (this.blobUrl !== void 0) URL.revokeObjectURL(this.blobUrl);
|
|
348
|
+
this.blobUrl = void 0;
|
|
349
|
+
}
|
|
297
350
|
}
|
|
298
351
|
};
|
|
299
352
|
}
|
|
@@ -301,6 +354,43 @@ var init_browser = __esm({
|
|
|
301
354
|
|
|
302
355
|
// src/api.ts
|
|
303
356
|
import { RecordBatchReader, Table } from "apache-arrow";
|
|
357
|
+
|
|
358
|
+
// src/memory_directory.ts
|
|
359
|
+
function validateMemoryFilePath(path) {
|
|
360
|
+
if (!path || path.startsWith("/") || path.endsWith("/") || path.includes("\\") || path.includes("\0") || path.split("/").some((segment) => !segment || segment === "." || segment === "..")) {
|
|
361
|
+
throw new Error("Memory directory file path must contain safe relative path segments");
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
var MemoryDirectory = class {
|
|
365
|
+
kind = "memory-directory";
|
|
366
|
+
files;
|
|
367
|
+
maxBytes;
|
|
368
|
+
constructor(options = {}) {
|
|
369
|
+
if (options.maxBytes !== void 0 && (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 0)) {
|
|
370
|
+
throw new Error("Memory directory maxBytes must be a nonnegative safe integer");
|
|
371
|
+
}
|
|
372
|
+
const files = { ...options.files };
|
|
373
|
+
let size = 0;
|
|
374
|
+
for (const [path, blob] of Object.entries(files)) {
|
|
375
|
+
validateMemoryFilePath(path);
|
|
376
|
+
if (!(blob instanceof Blob)) throw new Error("Memory directory files must be Blobs");
|
|
377
|
+
size += blob.size;
|
|
378
|
+
if (!Number.isSafeInteger(size)) throw new Error("Memory directory size must be a safe integer");
|
|
379
|
+
const segments = path.split("/");
|
|
380
|
+
for (let index = 1; index < segments.length; ++index) {
|
|
381
|
+
if (Object.hasOwn(files, segments.slice(0, index).join("/"))) throw new Error("Memory directory file paths overlap");
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (options.maxBytes !== void 0 && size > options.maxBytes) throw new Error("Memory directory quota exceeded (maxBytes)");
|
|
385
|
+
this.files = Object.freeze(files);
|
|
386
|
+
if (options.maxBytes !== void 0) this.maxBytes = options.maxBytes;
|
|
387
|
+
}
|
|
388
|
+
toMountSource() {
|
|
389
|
+
return { kind: "memory-directory", files: this.files, ...this.maxBytes !== void 0 && { maxBytes: this.maxBytes } };
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// src/api.ts
|
|
304
394
|
function validateMountPath(path) {
|
|
305
395
|
if (typeof path !== "string" || !path.startsWith("/mnt/external/")) {
|
|
306
396
|
throw new Error("Mount path must be an absolute path below /mnt/external");
|
|
@@ -526,21 +616,33 @@ var EngineQueryOperation = class {
|
|
|
526
616
|
}
|
|
527
617
|
};
|
|
528
618
|
var MountedResourceImpl = class {
|
|
529
|
-
constructor(path, unmount, refreshMount) {
|
|
619
|
+
constructor(path, unmount, refreshMount, listMount, readMountFile) {
|
|
530
620
|
this.path = path;
|
|
531
621
|
this.unmount = unmount;
|
|
532
622
|
this.refreshMount = refreshMount;
|
|
623
|
+
this.listMount = listMount;
|
|
624
|
+
this.readMountFile = readMountFile;
|
|
533
625
|
}
|
|
534
626
|
path;
|
|
535
627
|
unmount;
|
|
536
628
|
refreshMount;
|
|
629
|
+
listMount;
|
|
630
|
+
readMountFile;
|
|
537
631
|
closed = false;
|
|
538
632
|
closing;
|
|
539
633
|
async refresh() {
|
|
540
|
-
|
|
541
|
-
if (this.closing) throw new Error("mounted resource is closing");
|
|
634
|
+
this.ensureOpen();
|
|
542
635
|
await this.refreshMount(this.path);
|
|
543
636
|
}
|
|
637
|
+
async list() {
|
|
638
|
+
this.ensureOpen();
|
|
639
|
+
return this.listMount(this.path);
|
|
640
|
+
}
|
|
641
|
+
async readFile(path) {
|
|
642
|
+
this.ensureOpen();
|
|
643
|
+
validateMemoryFilePath(path);
|
|
644
|
+
return this.readMountFile(this.path, path);
|
|
645
|
+
}
|
|
544
646
|
async close() {
|
|
545
647
|
if (this.closed) return;
|
|
546
648
|
if (!this.closing) {
|
|
@@ -559,6 +661,10 @@ var MountedResourceImpl = class {
|
|
|
559
661
|
releaseAfterShutdown() {
|
|
560
662
|
this.closed = true;
|
|
561
663
|
}
|
|
664
|
+
ensureOpen() {
|
|
665
|
+
if (this.closed) throw new Error("mounted resource is closed");
|
|
666
|
+
if (this.closing) throw new Error("mounted resource is closing");
|
|
667
|
+
}
|
|
562
668
|
};
|
|
563
669
|
var HyperDB = class _HyperDB {
|
|
564
670
|
constructor(client) {
|
|
@@ -572,7 +678,7 @@ var HyperDB = class _HyperDB {
|
|
|
572
678
|
mountedResources = /* @__PURE__ */ new Set();
|
|
573
679
|
static async create(options = {}) {
|
|
574
680
|
const { createBrowserClient: createBrowserClient2 } = await Promise.resolve().then(() => (init_browser(), browser_exports));
|
|
575
|
-
const client = createBrowserClient2(options);
|
|
681
|
+
const client = await createBrowserClient2(options);
|
|
576
682
|
const database = new _HyperDB(client);
|
|
577
683
|
try {
|
|
578
684
|
await database.ready();
|
|
@@ -608,6 +714,16 @@ var HyperDB = class _HyperDB {
|
|
|
608
714
|
(mounted) => this.unmount(mounted),
|
|
609
715
|
(path2) => this.runDatabaseOperation(async () => {
|
|
610
716
|
expectOk(await this.client.refreshMount(path2), "refresh mount");
|
|
717
|
+
}),
|
|
718
|
+
(path2) => this.runDatabaseOperation(async () => {
|
|
719
|
+
const result2 = await this.client.listMount(path2);
|
|
720
|
+
if (result2.state !== "mountList") throw readErrorFromResult(result2, "list mount");
|
|
721
|
+
return result2.entries;
|
|
722
|
+
}),
|
|
723
|
+
(path2, file) => this.runDatabaseOperation(async () => {
|
|
724
|
+
const result2 = await this.client.readMountFile(path2, file);
|
|
725
|
+
if (result2.state !== "mountFile") throw readErrorFromResult(result2, "read mount file");
|
|
726
|
+
return result2.blob;
|
|
611
727
|
})
|
|
612
728
|
);
|
|
613
729
|
this.mountedResources.add(resource);
|
|
@@ -861,7 +977,7 @@ var HyperDBConnection = class {
|
|
|
861
977
|
init_browser();
|
|
862
978
|
var HyperDB2 = class _HyperDB extends HyperDB {
|
|
863
979
|
static async create(options = {}) {
|
|
864
|
-
const client = createBrowserClient(options);
|
|
980
|
+
const client = await createBrowserClient(options);
|
|
865
981
|
const database = new _HyperDB(client);
|
|
866
982
|
try {
|
|
867
983
|
await database.ready();
|
|
@@ -878,6 +994,11 @@ var HyperDB2 = class _HyperDB extends HyperDB {
|
|
|
878
994
|
async mount(source, options) {
|
|
879
995
|
const path = options?.path;
|
|
880
996
|
validateMountPath(path);
|
|
997
|
+
if (source && "kind" in source && source.kind === "memory-directory") {
|
|
998
|
+
const mode2 = options.mode ?? "read";
|
|
999
|
+
if (mode2 !== "read" && mode2 !== "readwrite") throw new Error(`Unsupported mount mode: ${String(mode2)}`);
|
|
1000
|
+
return this.mountSource(new MemoryDirectory(source).toMountSource(), path, mode2);
|
|
1001
|
+
}
|
|
881
1002
|
if (typeof File !== "undefined" && source instanceof File) {
|
|
882
1003
|
if (options.mode !== void 0 && options.mode !== "read") throw new Error("File mounts are always read-only");
|
|
883
1004
|
if (!source.name) throw new Error("Mounted file name must not be empty");
|
|
@@ -907,5 +1028,6 @@ var HyperDB2 = class _HyperDB extends HyperDB {
|
|
|
907
1028
|
export {
|
|
908
1029
|
HyperDB2 as HyperDB,
|
|
909
1030
|
HyperDBConnection,
|
|
910
|
-
HyperDBError
|
|
1031
|
+
HyperDBError,
|
|
1032
|
+
MemoryDirectory
|
|
911
1033
|
};
|