hyperdb-wasm 0.0.27106-dev.wasm.ga8c1b33c → 0.0.27136-dev.wasm.g5f4b267e
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 +2 -0
- package/dist/browser.js +19 -2
- package/dist/browser_external_directory.d.ts +4 -2
- package/dist/browser_worker.js +64 -15
- package/dist/client.d.ts +1 -0
- package/dist/hyperdb-wasm.cjs +1 -1
- package/dist/hyperdb-wasm.js +1 -1
- package/dist/hyperdb-wasm.wasm.br +0 -0
- package/dist/node.js +19 -2
- package/dist/node_external_directory.d.ts +5 -2
- package/dist/node_worker.js +84 -19
- package/dist/protocol.d.ts +4 -0
- package/dist/raw.browser.js +24 -0
- package/dist/raw.node.js +24 -0
- package/dist/wasm_bindings.d.ts +6 -2
- package/dist/worker_setup.d.ts +3 -2
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface HyperDBClient {
|
|
|
12
12
|
startQuery(connection: number, sql: string): Promise<WasmResult>;
|
|
13
13
|
mount(source: MountSource, path: string, mode: MountAccessMode): Promise<WasmResult>;
|
|
14
14
|
unmount(path: string): Promise<WasmResult>;
|
|
15
|
+
refreshMount(path: string): Promise<WasmResult>;
|
|
15
16
|
pollQuery(query: number): Promise<WasmResult>;
|
|
16
17
|
cancelQuery(query: number): Promise<WasmResult>;
|
|
17
18
|
finishQuery(query: number): Promise<WasmResult>;
|
|
@@ -28,6 +29,7 @@ export interface MountOptions {
|
|
|
28
29
|
}
|
|
29
30
|
export interface MountedResource {
|
|
30
31
|
readonly path: string;
|
|
32
|
+
refresh(): Promise<void>;
|
|
31
33
|
close(): Promise<void>;
|
|
32
34
|
}
|
|
33
35
|
export declare function validateMountPath(path: unknown): asserts path is string;
|
package/dist/browser.js
CHANGED
|
@@ -118,6 +118,9 @@ var init_client = __esm({
|
|
|
118
118
|
unmount(path) {
|
|
119
119
|
return this.request({ id: this.nextId++, type: "unmount", path });
|
|
120
120
|
}
|
|
121
|
+
refreshMount(path) {
|
|
122
|
+
return this.request({ id: this.nextId++, type: "refreshMount", path });
|
|
123
|
+
}
|
|
121
124
|
pollQuery(query) {
|
|
122
125
|
return this.request({ id: this.nextId++, type: "pollQuery", query });
|
|
123
126
|
}
|
|
@@ -498,17 +501,24 @@ var EngineQueryOperation = class {
|
|
|
498
501
|
}
|
|
499
502
|
};
|
|
500
503
|
var MountedResourceImpl = class {
|
|
501
|
-
constructor(path, unmount, cleanup) {
|
|
504
|
+
constructor(path, unmount, refreshMount, cleanup) {
|
|
502
505
|
this.path = path;
|
|
503
506
|
this.unmount = unmount;
|
|
507
|
+
this.refreshMount = refreshMount;
|
|
504
508
|
this.cleanup = cleanup;
|
|
505
509
|
}
|
|
506
510
|
path;
|
|
507
511
|
unmount;
|
|
512
|
+
refreshMount;
|
|
508
513
|
cleanup;
|
|
509
514
|
closed = false;
|
|
510
515
|
closing;
|
|
511
516
|
cleaned = false;
|
|
517
|
+
async refresh() {
|
|
518
|
+
if (this.closed) throw new Error("mounted resource is closed");
|
|
519
|
+
if (this.closing) throw new Error("mounted resource is closing");
|
|
520
|
+
await this.refreshMount(this.path);
|
|
521
|
+
}
|
|
512
522
|
async close() {
|
|
513
523
|
if (this.closed) return;
|
|
514
524
|
if (!this.closing) {
|
|
@@ -577,7 +587,14 @@ var HyperDB = class _HyperDB {
|
|
|
577
587
|
expectOk(result, "mount");
|
|
578
588
|
const mountedPath = new TextDecoder("utf-8", { fatal: true }).decode(result.payload);
|
|
579
589
|
if (mountedPath !== path) throw new Error("mount returned an invalid path");
|
|
580
|
-
const resource = new MountedResourceImpl(
|
|
590
|
+
const resource = new MountedResourceImpl(
|
|
591
|
+
mountedPath,
|
|
592
|
+
(mounted) => this.unmount(mounted),
|
|
593
|
+
(path2) => this.runDatabaseOperation(async () => {
|
|
594
|
+
expectOk(await this.client.refreshMount(path2), "refresh mount");
|
|
595
|
+
}),
|
|
596
|
+
cleanup
|
|
597
|
+
);
|
|
581
598
|
this.mountedResources.add(resource);
|
|
582
599
|
return resource;
|
|
583
600
|
});
|
|
@@ -13,17 +13,19 @@ export declare class BrowserExternalDirectoryBackend implements ExternalDirector
|
|
|
13
13
|
readonly locator: string;
|
|
14
14
|
};
|
|
15
15
|
registered(path: string, locator: string): void;
|
|
16
|
+
refresh(path: string): void;
|
|
17
|
+
releaseGeneration(locator: string, generation: string): void;
|
|
16
18
|
removed(pathOrLocator: string): void;
|
|
17
19
|
list(locator: string): Promise<readonly string[]>;
|
|
18
20
|
listEntries(locator: string, path: string): Promise<readonly BrowserDirectoryEntry[]>;
|
|
19
|
-
lookup(locator: string, path: string): Promise<{
|
|
21
|
+
lookup(locator: string, path: string, generation: string): Promise<{
|
|
20
22
|
readonly kind: 'directory';
|
|
21
23
|
} | {
|
|
22
24
|
readonly kind: 'file';
|
|
23
25
|
readonly locator: string;
|
|
24
26
|
readonly size: number;
|
|
25
27
|
} | undefined>;
|
|
26
|
-
open(locator: string, path: string): Promise<{
|
|
28
|
+
open(locator: string, path: string, generation: string): Promise<{
|
|
27
29
|
readonly locator: string;
|
|
28
30
|
readonly size: number;
|
|
29
31
|
}>;
|
package/dist/browser_worker.js
CHANGED
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
registerExternalFile;
|
|
62
62
|
registerExternalDirectory;
|
|
63
63
|
removeExternalRegistration;
|
|
64
|
+
refreshExternalDirectory;
|
|
64
65
|
projectExternalFile;
|
|
65
66
|
projectExternalDirectory;
|
|
66
67
|
startQuery;
|
|
@@ -71,6 +72,7 @@
|
|
|
71
72
|
resultPayloadLength;
|
|
72
73
|
free;
|
|
73
74
|
mountedPaths = /* @__PURE__ */ new Set();
|
|
75
|
+
mountedDirectoryPaths = /* @__PURE__ */ new Set();
|
|
74
76
|
constructor(module) {
|
|
75
77
|
this.module = module;
|
|
76
78
|
this.initialize = module.cwrap("hyperdb_wasm_initialize", "pointer", ["string", "string", "number"]);
|
|
@@ -80,6 +82,7 @@
|
|
|
80
82
|
this.registerExternalFile = module.cwrap("hyperdb_wasm_register_external_file", "pointer", ["string", "string", "number", "number"]);
|
|
81
83
|
this.registerExternalDirectory = module.cwrap("hyperdb_wasm_register_external_directory", "pointer", ["string", "string", "number", "number"]);
|
|
82
84
|
this.removeExternalRegistration = module.cwrap("hyperdb_wasm_remove_external_registration", "pointer", ["string", "number"]);
|
|
85
|
+
this.refreshExternalDirectory = module.cwrap("hyperdb_wasm_refresh_external_directory", "pointer", ["string", "number"]);
|
|
83
86
|
this.projectExternalFile = module.cwrap("hyperdb_wasm_project_external_file", "pointer", ["string", "string", "number", "number"]);
|
|
84
87
|
this.projectExternalDirectory = module.cwrap("hyperdb_wasm_project_external_directory", "pointer", ["string", "string", "number"]);
|
|
85
88
|
this.startQuery = module.cwrap("hyperdb_wasm_query_start", "pointer", ["number", "string", "number", "number"]);
|
|
@@ -108,11 +111,22 @@
|
|
|
108
111
|
if (request.type === "mount" && request.source.kind === "browser-file") {
|
|
109
112
|
return this.mountFile(request, request.source.url, safeInteger(request.source.size, "external file size"));
|
|
110
113
|
}
|
|
114
|
+
if (request.type === "refreshMount") {
|
|
115
|
+
validateCString(request.path, "external registration path");
|
|
116
|
+
const backend = this.module.externalDirectoryBackend;
|
|
117
|
+
if (!backend) return { response: { id: request.id, type: "response", result: { state: "error", error: "External directories are not supported by this client" } }, transfer: [] };
|
|
118
|
+
if (!this.mountedDirectoryPaths.has(request.path)) {
|
|
119
|
+
const error = this.mountedPaths.has(request.path) ? "Only directory mounts can be refreshed" : "External directory registration was not found";
|
|
120
|
+
return { response: { id: request.id, type: "response", result: { state: "error", error } }, transfer: [] };
|
|
121
|
+
}
|
|
122
|
+
backend.refresh(request.path);
|
|
123
|
+
}
|
|
111
124
|
if (request.type === "unmount" && (this.module.externalFileBackend || this.module.externalDirectoryBackend)) {
|
|
112
125
|
validateCString(request.path, "external registration path");
|
|
113
126
|
const pointer2 = safeInteger(this.removeExternalRegistration(request.path, request.id), "result pointer");
|
|
114
127
|
const result2 = this.decodeResult(pointer2);
|
|
115
128
|
if (result2.state === "ok" || result2.state === "error" && result2.error === "External registration was not found" && this.mountedPaths.has(request.path)) {
|
|
129
|
+
this.mountedDirectoryPaths.delete(request.path);
|
|
116
130
|
const cleanup = async () => {
|
|
117
131
|
await Promise.all([
|
|
118
132
|
this.module.externalFileBackend?.removed(request.path),
|
|
@@ -130,6 +144,8 @@
|
|
|
130
144
|
const pointer = safeInteger(this.invoke(request), "result pointer");
|
|
131
145
|
const result = this.decodeResult(pointer);
|
|
132
146
|
if (request.type === "shutdown" && result.state === "ok") {
|
|
147
|
+
this.mountedPaths.clear();
|
|
148
|
+
this.mountedDirectoryPaths.clear();
|
|
133
149
|
const completion = completionFor([
|
|
134
150
|
this.module.externalFileBackend?.shutdown(),
|
|
135
151
|
this.module.externalDirectoryBackend?.shutdown()
|
|
@@ -141,6 +157,7 @@
|
|
|
141
157
|
};
|
|
142
158
|
}
|
|
143
159
|
const response = { id: request.id, type: "response", result };
|
|
160
|
+
if (request.type === "unmount" && result.state === "ok") this.mountedPaths.delete(request.path);
|
|
144
161
|
return { response, transfer: result.state === "chunk" ? [result.payload.buffer] : [] };
|
|
145
162
|
}
|
|
146
163
|
invoke(request) {
|
|
@@ -164,6 +181,8 @@
|
|
|
164
181
|
case "unmount":
|
|
165
182
|
validateCString(request.path, "external registration path");
|
|
166
183
|
return this.removeExternalRegistration(request.path, request.id);
|
|
184
|
+
case "refreshMount":
|
|
185
|
+
return this.refreshExternalDirectory(request.path, request.id);
|
|
167
186
|
case "startQuery":
|
|
168
187
|
validateCStringContents(request.sql, "SQL");
|
|
169
188
|
return this.startQuery(request.connection, request.sql, Number(request.sqlTestMode ?? false), request.id);
|
|
@@ -234,12 +253,14 @@
|
|
|
234
253
|
if (projection.state !== "ok") throw new Error(resultError(projection));
|
|
235
254
|
backend.registered(path, registration.locator);
|
|
236
255
|
this.mountedPaths.add(path);
|
|
256
|
+
this.mountedDirectoryPaths.add(path);
|
|
237
257
|
} catch (error) {
|
|
238
258
|
const cleanupPointer = safeInteger(this.removeExternalRegistration(path, request.id), "result pointer");
|
|
239
259
|
const cleanup = this.decodeResult(cleanupPointer);
|
|
240
260
|
if (cleanup.state !== "ok") {
|
|
241
261
|
backend.registered(path, registration.locator);
|
|
242
262
|
this.mountedPaths.add(path);
|
|
263
|
+
this.mountedDirectoryPaths.add(path);
|
|
243
264
|
preserveBackend = true;
|
|
244
265
|
throw new Error(`mount failed and rollback also failed: ${resultError(cleanup)}`, { cause: error });
|
|
245
266
|
}
|
|
@@ -343,6 +364,7 @@
|
|
|
343
364
|
}
|
|
344
365
|
}
|
|
345
366
|
case "unmount":
|
|
367
|
+
case "refreshMount":
|
|
346
368
|
return hasKeys(value, ["id", "type", "path"]) && typeof value.path === "string" && !!value.path && !value.path.includes("\0");
|
|
347
369
|
case "pollQuery":
|
|
348
370
|
case "cancelQuery":
|
|
@@ -440,9 +462,14 @@
|
|
|
440
462
|
};
|
|
441
463
|
module.hyperdbWasmFetchCancel = (id) => fetches.get(id)?.abort();
|
|
442
464
|
}
|
|
443
|
-
function installExternalDirectoryRuntime(module) {
|
|
465
|
+
function installExternalDirectoryRuntime(module, transport) {
|
|
444
466
|
const backend = module.externalDirectoryBackend;
|
|
445
467
|
if (!backend) return;
|
|
468
|
+
module.hyperdbWasmExternalDirectoryReleaseGeneration = (locator, generation) => {
|
|
469
|
+
void Promise.resolve().then(() => backend.releaseGeneration(locator, generation)).catch(() => {
|
|
470
|
+
transport.postMessage({ type: "log", text: "External directory generation cleanup failed; mount removal will retry" });
|
|
471
|
+
});
|
|
472
|
+
};
|
|
446
473
|
const listComplete = module._hyperdb_wasm_external_directory_list_complete;
|
|
447
474
|
const openComplete = module._hyperdb_wasm_external_directory_open_complete;
|
|
448
475
|
if (listComplete) {
|
|
@@ -455,8 +482,8 @@
|
|
|
455
482
|
};
|
|
456
483
|
}
|
|
457
484
|
if (openComplete) {
|
|
458
|
-
module.hyperdbWasmExternalDirectoryOpenStart = (id, locator, path) => {
|
|
459
|
-
void backend.open(locator, path).then((file) => {
|
|
485
|
+
module.hyperdbWasmExternalDirectoryOpenStart = (id, locator, path, generation) => {
|
|
486
|
+
void backend.open(locator, path, generation).then((file) => {
|
|
460
487
|
openComplete(id, safePointer(module.stringToNewUTF8(file.locator), "external file locator pointer"), file.size);
|
|
461
488
|
}).catch((error) => openComplete(id, 0, isNotFoundError(error) ? -2 : -1));
|
|
462
489
|
};
|
|
@@ -545,8 +572,8 @@
|
|
|
545
572
|
complete(id, safePointer(module.stringToNewUTF8(JSON.stringify(encoded)), "filesystem listing pointer"), 0);
|
|
546
573
|
}).catch(() => complete(id, 0, -1));
|
|
547
574
|
};
|
|
548
|
-
module.hyperdbWasmFilesystemLookupStart = (id, locator, path) => {
|
|
549
|
-
const lookup = module.externalDirectoryBackend?.lookup?.(locator, path);
|
|
575
|
+
module.hyperdbWasmFilesystemLookupStart = (id, locator, path, generation) => {
|
|
576
|
+
const lookup = module.externalDirectoryBackend?.lookup?.(locator, path, generation);
|
|
550
577
|
if (!lookup) {
|
|
551
578
|
complete(id, 0, -1);
|
|
552
579
|
return;
|
|
@@ -611,7 +638,7 @@
|
|
|
611
638
|
configureFilesystem(module);
|
|
612
639
|
installHttpRuntime(module, transport);
|
|
613
640
|
installHostFileRuntime(module);
|
|
614
|
-
installExternalDirectoryRuntime(module);
|
|
641
|
+
installExternalDirectoryRuntime(module, transport);
|
|
615
642
|
installFilesystemProjectionRuntime(module);
|
|
616
643
|
bindings = new HyperDBBindings(module);
|
|
617
644
|
transport.postMessage({ type: "ready" });
|
|
@@ -664,13 +691,29 @@
|
|
|
664
691
|
const directoryHandle = asDirectoryHandle(handle);
|
|
665
692
|
validateSegment(directoryHandle.name);
|
|
666
693
|
const locator = `${directoryLocatorPrefix}${opaqueId()}`;
|
|
667
|
-
this.directories.set(locator, { handle: directoryHandle, mode,
|
|
694
|
+
this.directories.set(locator, { handle: directoryHandle, mode, generations: /* @__PURE__ */ new Map(), locators: /* @__PURE__ */ new Set() });
|
|
668
695
|
return { name: directoryHandle.name, locator };
|
|
669
696
|
}
|
|
670
697
|
registered(path, locator) {
|
|
671
698
|
if (!this.directories.has(locator)) throw new Error("External directory registration is unavailable");
|
|
672
699
|
this.paths.set(path, locator);
|
|
673
700
|
}
|
|
701
|
+
/// Clears future path lookups, retaining File locators until generation release
|
|
702
|
+
refresh(path) {
|
|
703
|
+
const locator = this.paths.get(path);
|
|
704
|
+
if (locator === void 0) throw new Error("External directory registration does not exist");
|
|
705
|
+
for (const generation of this.getDirectory(locator).generations.values()) generation.files.clear();
|
|
706
|
+
}
|
|
707
|
+
releaseGeneration(locator, generation) {
|
|
708
|
+
const directory = this.directories.get(locator);
|
|
709
|
+
const state = directory?.generations.get(generation);
|
|
710
|
+
if (!directory || !state) return;
|
|
711
|
+
directory.generations.delete(generation);
|
|
712
|
+
for (const fileLocator of state.locators) {
|
|
713
|
+
this.files.delete(fileLocator);
|
|
714
|
+
directory.locators.delete(fileLocator);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
674
717
|
removed(pathOrLocator) {
|
|
675
718
|
const locator = this.paths.get(pathOrLocator) ?? pathOrLocator;
|
|
676
719
|
const directory = this.directories.get(locator);
|
|
@@ -709,7 +752,7 @@
|
|
|
709
752
|
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
710
753
|
return entries;
|
|
711
754
|
}
|
|
712
|
-
async lookup(locator, path) {
|
|
755
|
+
async lookup(locator, path, generation) {
|
|
713
756
|
const directory = this.getDirectory(locator);
|
|
714
757
|
const segments = relativeSegments(path);
|
|
715
758
|
const parent = await this.openDirectory(directory, segments.slice(0, -1));
|
|
@@ -719,14 +762,19 @@
|
|
|
719
762
|
validateSegment(child.name);
|
|
720
763
|
if (child.name !== name) continue;
|
|
721
764
|
if (child.kind === "directory") return { kind: "directory" };
|
|
722
|
-
if (child.kind === "file") return { kind: "file", ...await this.open(locator, path) };
|
|
765
|
+
if (child.kind === "file") return { kind: "file", ...await this.open(locator, path, generation) };
|
|
723
766
|
throw new Error("External directory contains an unsupported entry");
|
|
724
767
|
}
|
|
725
768
|
return void 0;
|
|
726
769
|
}
|
|
727
|
-
async open(locator, path) {
|
|
770
|
+
async open(locator, path, generation) {
|
|
728
771
|
const directory = this.getDirectory(locator);
|
|
729
|
-
|
|
772
|
+
let state = directory.generations.get(generation);
|
|
773
|
+
if (!state) {
|
|
774
|
+
state = { files: /* @__PURE__ */ new Map(), locators: /* @__PURE__ */ new Set() };
|
|
775
|
+
directory.generations.set(generation, state);
|
|
776
|
+
}
|
|
777
|
+
const cached = state.files.get(path);
|
|
730
778
|
if (cached) {
|
|
731
779
|
const file = await cached;
|
|
732
780
|
return { locator: file.locator, size: file.file.size };
|
|
@@ -748,14 +796,15 @@
|
|
|
748
796
|
const fileLocator = `${fileLocatorPrefix}${opaqueId()}`;
|
|
749
797
|
this.files.set(fileLocator, file);
|
|
750
798
|
directory.locators.add(fileLocator);
|
|
799
|
+
state.locators.add(fileLocator);
|
|
751
800
|
return { locator: fileLocator, file };
|
|
752
801
|
})();
|
|
753
|
-
|
|
802
|
+
state.files.set(path, snapshot);
|
|
754
803
|
try {
|
|
755
804
|
const file = await snapshot;
|
|
756
805
|
return { locator: file.locator, size: file.file.size };
|
|
757
806
|
} catch (error) {
|
|
758
|
-
|
|
807
|
+
if (state.files.get(path) === snapshot) state.files.delete(path);
|
|
759
808
|
throw error;
|
|
760
809
|
}
|
|
761
810
|
}
|
|
@@ -847,7 +896,7 @@
|
|
|
847
896
|
await this.cleanupWriter(state).catch(() => void 0);
|
|
848
897
|
throw failure;
|
|
849
898
|
}
|
|
850
|
-
this.getDirectory(state.locator).files.delete(state.path);
|
|
899
|
+
for (const generation of this.getDirectory(state.locator).generations.values()) generation.files.delete(state.path);
|
|
851
900
|
}, true);
|
|
852
901
|
return operation.finally(() => this.writers.delete(writer));
|
|
853
902
|
}
|
|
@@ -889,7 +938,7 @@
|
|
|
889
938
|
return state;
|
|
890
939
|
}
|
|
891
940
|
async cleanupWriter(state) {
|
|
892
|
-
this.directories.get(state.locator)?.files.delete(state.path);
|
|
941
|
+
for (const generation of this.directories.get(state.locator)?.generations.values() ?? []) generation.files.delete(state.path);
|
|
893
942
|
try {
|
|
894
943
|
await state.stream?.abort();
|
|
895
944
|
} finally {
|
package/dist/client.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare class HyperDBEngineClient {
|
|
|
19
19
|
startQuery(connection: number, sql: string, sqlTestMode?: boolean): Promise<WasmResult>;
|
|
20
20
|
mount(source: MountSource, path: string, mode: MountAccessMode): Promise<WasmResult>;
|
|
21
21
|
unmount(path: string): Promise<WasmResult>;
|
|
22
|
+
refreshMount(path: string): Promise<WasmResult>;
|
|
22
23
|
pollQuery(query: number): Promise<WasmResult>;
|
|
23
24
|
cancelQuery(query: number): Promise<WasmResult>;
|
|
24
25
|
finishQuery(query: number): Promise<WasmResult>;
|