@livestore/sqlite-wasm 0.0.0-snapshot-9507e455a5c1ff8ca4b9414bde007fe51bb2bcd0 → 0.0.0-snapshot-d3260202d4a0ef658630c9a759c396d7ea3b055d
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/.tsbuildinfo +1 -1
- package/dist/browser/mod.d.ts.map +1 -1
- package/dist/browser/mod.js +4 -3
- package/dist/browser/mod.js.map +1 -1
- package/dist/browser/opfs/AccessHandlePoolVFS.d.ts +6 -15
- package/dist/browser/opfs/AccessHandlePoolVFS.d.ts.map +1 -1
- package/dist/browser/opfs/AccessHandlePoolVFS.js +133 -134
- package/dist/browser/opfs/AccessHandlePoolVFS.js.map +1 -1
- package/dist/make-sqlite-db.d.ts.map +1 -1
- package/dist/make-sqlite-db.js +0 -3
- package/dist/make-sqlite-db.js.map +1 -1
- package/package.json +5 -5
- package/src/browser/mod.ts +5 -3
- package/src/browser/opfs/AccessHandlePoolVFS.ts +308 -246
- package/src/make-sqlite-db.ts +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/browser/mod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAChF,OAAO,EAAgB,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/browser/mod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAChF,OAAO,EAAgB,KAAK,IAAI,EAAW,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gDAAgD,CAAA;AAI/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAGxE,cAAc,yBAAyB,CAAA;AAEvC,KAAK,cAAc,GAAG;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,eAAe,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,WAAW,CAAA;IACjB,GAAG,EAAE,SAAS,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,eAAe,CAAA;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,WAAW,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,IAAI,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,mBAAmB,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,eAAe,CAAC;QAC/B,aAAa,EAAE,MAAM,CAAA;QACrB,mCAAmC;QACnC,YAAY,EAAE,MAAM,CAAA;KACrB,CAAC,CAAA;IACF,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,WAAW,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,IAAI,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,2BAA2B,GAAG,uBAAuB,CAAA;AAEvF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,WAAW,CAAA;IACjB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,IAAI,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,IAAI,CAAA;CACrC,CAAA;AAED,KAAK,uBAAuB,GAAG,YAAY,CAAC,cAAc,EAAE,wBAAwB,EAAE,2BAA2B,CAAC,CAAA;AAElH,KAAK,mBAAmB,GAAG,YAAY,CACrC,cAAc,EACd,oBAAoB,EACpB,uBAAuB,EACvB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CACxB,CAAA;AAED,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE;YAC1C,wBAAwB,GAAG,UAAU,CAAC,uBAAuB,CAAC;YAC9D,oBAAoB,GAAG,UAAU,CAAC,mBAAmB,CAAC;EAoE9E;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA"}
|
package/dist/browser/mod.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Hash } from '@livestore/utils/effect';
|
|
1
|
+
import { Effect, Hash, Runtime } from '@livestore/utils/effect';
|
|
2
2
|
import { makeInMemoryDb } from "../in-memory-vfs.js";
|
|
3
3
|
import { makeSqliteDb } from "../make-sqlite-db.js";
|
|
4
4
|
import { makeOpfsDb } from "./opfs/index.js";
|
|
@@ -34,18 +34,19 @@ export function sqliteDbFactory({ sqlite3 }) {
|
|
|
34
34
|
directory: input.opfsDirectory,
|
|
35
35
|
fileName: dbFilename,
|
|
36
36
|
});
|
|
37
|
+
const runtime = yield* Effect.runtime();
|
|
37
38
|
return makeSqliteDb({
|
|
38
39
|
sqlite3,
|
|
39
40
|
metadata: {
|
|
40
41
|
_tag: 'opfs',
|
|
41
42
|
vfs,
|
|
42
43
|
dbPointer,
|
|
43
|
-
deleteDb: () => vfs.resetAccessHandle(input.fileName),
|
|
44
|
+
deleteDb: () => vfs.resetAccessHandle(input.fileName).pipe(Runtime.runSync(runtime)),
|
|
44
45
|
configureDb: input.configureDb ?? (() => { }),
|
|
45
46
|
persistenceInfo: {
|
|
46
47
|
fileName: dbFilename,
|
|
47
48
|
opfsDirectory: input.opfsDirectory,
|
|
48
|
-
opfsFileName: vfs.getOpfsFileName(dbFilename),
|
|
49
|
+
opfsFileName: yield* vfs.getOpfsFileName(dbFilename),
|
|
49
50
|
},
|
|
50
51
|
},
|
|
51
52
|
});
|
package/dist/browser/mod.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../../src/browser/mod.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../../src/browser/mod.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAa,OAAO,EAAc,MAAM,yBAAyB,CAAA;AAItF,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,cAAc,yBAAyB,CAAA;AAqDvC,MAAM,UAAU,eAAe,CAAC,EAAE,OAAO,EAA0B;IAGjE,SAAS,MAAM,CACb,KAAsD;QAStD,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACzB,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC/B,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;gBAClD,OAAO,YAAY,CAA8B;oBAC/C,OAAO;oBACP,QAAQ,EAAE;wBACR,IAAI,EAAE,WAAW;wBACjB,GAAG;wBACH,SAAS;wBACT,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;wBAClB,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;wBAC5C,eAAe,EAAE;4BACf,QAAQ,EAAE,UAAU;yBACrB;qBACF;iBACF,CAAC,CAAA;YACJ,CAAC;YAED,wCAAwC;YACxC,MAAM,sBAAsB,GAAG,EAAE,CAAA;YAEjC,IAAI,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAA;YAE/B,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,sBAAsB,EAAE,CAAC;gBACnD,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CACtB,yBAAyB,KAAK,CAAC,QAAQ,UAAU,sBAAsB,eAAe,KAAK,CAAC,QAAQ,CAAC,MAAM,cAAc,CAC1H,CAAA;gBACD,UAAU,GAAG,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAA;YACvD,CAAC;YAED,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;gBAC3C,OAAO;gBACP,SAAS,EAAE,KAAK,CAAC,aAAa;gBAC9B,QAAQ,EAAE,UAAU;aACrB,CAAC,CAAA;YAEF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAAa,CAAA;YAElD,OAAO,YAAY,CAA0B;gBAC3C,OAAO;gBACP,QAAQ,EAAE;oBACR,IAAI,EAAE,MAAM;oBACZ,GAAG;oBACH,SAAS;oBACT,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBACpF,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;oBAC5C,eAAe,EAAE;wBACf,QAAQ,EAAE,UAAU;wBACpB,aAAa,EAAE,KAAK,CAAC,aAAa;wBAClC,YAAY,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,UAAU,CAAC;qBACrD;iBACF;aACF,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Opfs, Runtime,
|
|
1
|
+
import { Effect, Opfs, Runtime, type Scope, type WebError } from '@livestore/utils/effect';
|
|
2
2
|
import { FacadeVFS } from '../../FacadeVFS.ts';
|
|
3
3
|
/**
|
|
4
4
|
* This VFS uses the updated Access Handle API with all synchronous methods
|
|
@@ -25,7 +25,7 @@ export declare class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
25
25
|
* It's not the same as the SQLite file name. It's a randomly-generated
|
|
26
26
|
* string that is not meaningful to the application.
|
|
27
27
|
*/
|
|
28
|
-
getOpfsFileName(zName: string)
|
|
28
|
+
getOpfsFileName: (zName: string) => Effect.Effect.AsEffect<Effect.Effect<string, never, never>>;
|
|
29
29
|
/**
|
|
30
30
|
* Reads the SQLite payload (without the OPFS header) for the given file.
|
|
31
31
|
*
|
|
@@ -35,8 +35,8 @@ export declare class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
35
35
|
* acquires an exclusive lock — we don't need to handle short reads as
|
|
36
36
|
* the file cannot be modified by other threads.
|
|
37
37
|
*/
|
|
38
|
-
readFilePayload(zName: string)
|
|
39
|
-
resetAccessHandle(zName: string)
|
|
38
|
+
readFilePayload: (zName: string) => Effect.Effect.AsEffect<Effect.Effect<ArrayBuffer, WebError.WebError, Opfs.Opfs>>;
|
|
39
|
+
resetAccessHandle: (zName: string) => Effect.Effect.AsEffect<Effect.Effect<void, WebError.WebError, Opfs.Opfs>>;
|
|
40
40
|
jOpen(zName: string, fileId: number, flags: number, pOutFlags: DataView): number;
|
|
41
41
|
jClose(fileId: number): number;
|
|
42
42
|
jRead(fileId: number, pData: Uint8Array<ArrayBuffer>, iOffset: number): number;
|
|
@@ -68,21 +68,12 @@ export declare class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
68
68
|
/**
|
|
69
69
|
* Increase the capacity of the file system by n.
|
|
70
70
|
*/
|
|
71
|
-
addCapacity(n: number)
|
|
71
|
+
addCapacity: (n: number) => Effect.Effect<void, WebError.WebError, Opfs.Opfs | Scope.Scope>;
|
|
72
72
|
/**
|
|
73
73
|
* Decrease the capacity of the file system by n. The capacity cannot be
|
|
74
74
|
* decreased to fewer than the current number of SQLite files in the
|
|
75
75
|
* file system.
|
|
76
76
|
*/
|
|
77
|
-
removeCapacity(n: number)
|
|
77
|
+
removeCapacity: (n: number) => Effect.Effect.AsEffect<Effect.Effect<number, WebError.TypeError | WebError.NotFoundError | WebError.NotAllowedError | WebError.UnknownError | WebError.NoModificationAllowedError | WebError.InvalidModificationError, Opfs.Opfs>>;
|
|
78
78
|
}
|
|
79
|
-
declare const OpfsError_base: Schema.TaggedErrorClass<OpfsError, "OpfsError", {
|
|
80
|
-
readonly _tag: Schema.tag<"OpfsError">;
|
|
81
|
-
} & {
|
|
82
|
-
cause: typeof Schema.Defect;
|
|
83
|
-
path: typeof Schema.String;
|
|
84
|
-
}>;
|
|
85
|
-
export declare class OpfsError extends OpfsError_base {
|
|
86
|
-
}
|
|
87
|
-
export {};
|
|
88
79
|
//# sourceMappingURL=AccessHandlePoolVFS.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessHandlePoolVFS.d.ts","sourceRoot":"","sources":["../../../src/browser/opfs/AccessHandlePoolVFS.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAY,
|
|
1
|
+
{"version":3,"file":"AccessHandlePoolVFS.d.ts","sourceRoot":"","sources":["../../../src/browser/opfs/AccessHandlePoolVFS.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAY,KAAK,KAAK,EAAU,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAE5G,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AA+C9C;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;;IAChD,GAAG,OAAO;IAuBV,MAAM,CAAC,MAAM,2HAKX;gBAEU,EACV,IAAI,EACJ,aAAa,EACb,MAAM,EACN,OAAO,GACR,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;KAAE;IAM1G;;;;;;;;OAQG;IACH,eAAe,iFAMd;IAED;;;;;;;;OAQG;IACH,eAAe,sGAyBd;IAED,iBAAiB,+FAQhB;IAED,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,GAAG,MAAM;IAiChF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAkB9B,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAkB9E,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAiB/E,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAYhD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAY7C,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,MAAM;IAcpD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIpC,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAI/C,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,MAAM;IAYjE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAYhD,KAAK;IAIC,OAAO;IAeb;;OAEG;IACH,OAAO,IAAI,MAAM;IAIjB;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;;;;OAKG;IACH,mBAAmB,IAAI,MAAM,EAAE;IAI/B;;OAEG;IACH,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAc1F;IAED;;;;OAIG;IACH,cAAc,oPAoBb;CA6KF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Based on https://github.com/rhashimoto/wa-sqlite/blob/master/src/examples/AccessHandlePoolVFS.js
|
|
2
|
-
import { Effect, Opfs, Runtime, Schedule,
|
|
2
|
+
import { Effect, Opfs, Runtime, Schedule, Stream } from '@livestore/utils/effect';
|
|
3
3
|
import * as VFS from '@livestore/wa-sqlite/src/VFS.js';
|
|
4
4
|
import { FacadeVFS } from "../../FacadeVFS.js";
|
|
5
5
|
const SECTOR_SIZE = 4096;
|
|
@@ -86,11 +86,11 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
86
86
|
* It's not the same as the SQLite file name. It's a randomly-generated
|
|
87
87
|
* string that is not meaningful to the application.
|
|
88
88
|
*/
|
|
89
|
-
getOpfsFileName(zName) {
|
|
89
|
+
getOpfsFileName = Effect.fn((zName) => Effect.gen(this, function* () {
|
|
90
90
|
const path = this.#getPath(zName);
|
|
91
91
|
const accessHandle = this.#mapPathToAccessHandle.get(path);
|
|
92
92
|
return this.#mapAccessHandleToName.get(accessHandle);
|
|
93
|
-
}
|
|
93
|
+
}));
|
|
94
94
|
/**
|
|
95
95
|
* Reads the SQLite payload (without the OPFS header) for the given file.
|
|
96
96
|
*
|
|
@@ -100,42 +100,33 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
100
100
|
* acquires an exclusive lock — we don't need to handle short reads as
|
|
101
101
|
* the file cannot be modified by other threads.
|
|
102
102
|
*/
|
|
103
|
-
readFilePayload(zName) {
|
|
103
|
+
readFilePayload = Effect.fn((zName) => Effect.gen(this, function* () {
|
|
104
104
|
const path = this.#getPath(zName);
|
|
105
105
|
const accessHandle = this.#mapPathToAccessHandle.get(path);
|
|
106
106
|
if (accessHandle === undefined) {
|
|
107
|
-
|
|
108
|
-
path,
|
|
109
|
-
cause: new Error('Cannot read payload for untracked OPFS path'),
|
|
110
|
-
});
|
|
107
|
+
return yield* Effect.dieMessage('Cannot read payload for untracked OPFS path');
|
|
111
108
|
}
|
|
112
|
-
const fileSize = Opfs.Opfs.syncGetSize(accessHandle)
|
|
109
|
+
const fileSize = yield* Opfs.Opfs.syncGetSize(accessHandle);
|
|
113
110
|
if (fileSize <= HEADER_OFFSET_DATA) {
|
|
114
|
-
|
|
115
|
-
path,
|
|
116
|
-
cause: new Error(`OPFS file too small to contain header and payload: size ${fileSize} < HEADER_OFFSET_DATA ${HEADER_OFFSET_DATA}`),
|
|
117
|
-
});
|
|
111
|
+
return yield* Effect.dieMessage(`OPFS file too small to contain header and payload: size ${fileSize} < HEADER_OFFSET_DATA ${HEADER_OFFSET_DATA}`);
|
|
118
112
|
}
|
|
119
113
|
const payloadSize = fileSize - HEADER_OFFSET_DATA;
|
|
120
114
|
const payload = new Uint8Array(payloadSize);
|
|
121
|
-
const bytesRead = Opfs.Opfs.syncRead(accessHandle, payload, { at: HEADER_OFFSET_DATA })
|
|
115
|
+
const bytesRead = yield* Opfs.Opfs.syncRead(accessHandle, payload, { at: HEADER_OFFSET_DATA });
|
|
122
116
|
if (bytesRead !== payloadSize) {
|
|
123
|
-
|
|
124
|
-
path,
|
|
125
|
-
cause: new Error(`Failed to read full payload from OPFS file: read ${bytesRead}/${payloadSize}`),
|
|
126
|
-
});
|
|
117
|
+
return yield* Effect.dieMessage(`Failed to read full payload from OPFS file: read ${bytesRead}/${payloadSize}`);
|
|
127
118
|
}
|
|
128
119
|
return payload.buffer;
|
|
129
|
-
}
|
|
130
|
-
resetAccessHandle(zName) {
|
|
120
|
+
}));
|
|
121
|
+
resetAccessHandle = Effect.fn((zName) => Effect.gen(this, function* () {
|
|
131
122
|
const path = this.#getPath(zName);
|
|
132
123
|
const accessHandle = this.#mapPathToAccessHandle.get(path);
|
|
133
|
-
Opfs.Opfs.syncTruncate(accessHandle, HEADER_OFFSET_DATA)
|
|
124
|
+
yield* Opfs.Opfs.syncTruncate(accessHandle, HEADER_OFFSET_DATA);
|
|
134
125
|
// accessHandle.write(new Uint8Array(), { at: HEADER_OFFSET_DATA })
|
|
135
126
|
// accessHandle.flush()
|
|
136
|
-
}
|
|
127
|
+
}));
|
|
137
128
|
jOpen(zName, fileId, flags, pOutFlags) {
|
|
138
|
-
|
|
129
|
+
return Effect.gen(this, function* () {
|
|
139
130
|
// First try to open a path that already exists in the file system.
|
|
140
131
|
const path = zName ? this.#getPath(zName) : Math.random().toString(36);
|
|
141
132
|
let accessHandle = this.#mapPathToAccessHandle.get(path);
|
|
@@ -145,73 +136,84 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
145
136
|
// Choose an unassociated OPFS file from the pool.
|
|
146
137
|
;
|
|
147
138
|
[accessHandle] = this.#availableAccessHandles.keys();
|
|
148
|
-
this.#setAssociatedPath(accessHandle, path, flags);
|
|
139
|
+
yield* this.#setAssociatedPath(accessHandle, path, flags);
|
|
149
140
|
}
|
|
150
141
|
else {
|
|
151
142
|
// Out of unassociated files. This can be fixed by calling
|
|
152
143
|
// addCapacity() from the application.
|
|
153
|
-
|
|
144
|
+
return yield* Effect.dieMessage('cannot create file');
|
|
154
145
|
}
|
|
155
146
|
}
|
|
156
|
-
if (!accessHandle)
|
|
157
|
-
|
|
158
|
-
}
|
|
147
|
+
if (!accessHandle)
|
|
148
|
+
return yield* Effect.dieMessage('file not found');
|
|
159
149
|
// Subsequent methods are only passed the fileId, so make sure we have
|
|
160
150
|
// a way to get the file resources.
|
|
161
151
|
const file = { path, flags, accessHandle };
|
|
162
152
|
this.#mapIdToFile.set(fileId, file);
|
|
163
153
|
pOutFlags.setInt32(0, flags, true);
|
|
164
154
|
return VFS.SQLITE_OK;
|
|
165
|
-
}
|
|
166
|
-
catch (e) {
|
|
167
|
-
console.error(e.message);
|
|
168
|
-
return VFS.SQLITE_CANTOPEN;
|
|
169
|
-
}
|
|
155
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_CANTOPEN)), Runtime.runSync(this.#runtime));
|
|
170
156
|
}
|
|
171
157
|
jClose(fileId) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
158
|
+
return Effect.gen(this, function* () {
|
|
159
|
+
const file = this.#mapIdToFile.get(fileId);
|
|
160
|
+
if (file) {
|
|
161
|
+
yield* Opfs.Opfs.syncFlush(file.accessHandle);
|
|
162
|
+
this.#mapIdToFile.delete(fileId);
|
|
163
|
+
if (file.flags & VFS.SQLITE_OPEN_DELETEONCLOSE) {
|
|
164
|
+
yield* this.#deletePath(file.path);
|
|
165
|
+
}
|
|
178
166
|
}
|
|
179
|
-
|
|
180
|
-
|
|
167
|
+
return VFS.SQLITE_OK;
|
|
168
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_CLOSE)), Runtime.runSync(this.#runtime));
|
|
181
169
|
}
|
|
182
170
|
jRead(fileId, pData, iOffset) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
171
|
+
return Effect.gen(this, function* () {
|
|
172
|
+
const file = this.#mapIdToFile.get(fileId);
|
|
173
|
+
const nBytes = yield* Opfs.Opfs.syncRead(file.accessHandle, pData.subarray(), {
|
|
174
|
+
at: HEADER_OFFSET_DATA + iOffset,
|
|
175
|
+
});
|
|
176
|
+
if (nBytes < pData.byteLength) {
|
|
177
|
+
pData.fill(0, nBytes, pData.byteLength);
|
|
178
|
+
return VFS.SQLITE_IOERR_SHORT_READ;
|
|
179
|
+
}
|
|
180
|
+
return VFS.SQLITE_OK;
|
|
181
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_READ)), Runtime.runSync(this.#runtime));
|
|
192
182
|
}
|
|
193
183
|
jWrite(fileId, pData, iOffset) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
184
|
+
return Effect.gen(this, function* () {
|
|
185
|
+
const file = this.#mapIdToFile.get(fileId);
|
|
186
|
+
const nBytes = yield* Opfs.Opfs.syncWrite(file.accessHandle, pData.subarray(), {
|
|
187
|
+
at: HEADER_OFFSET_DATA + iOffset,
|
|
188
|
+
});
|
|
189
|
+
if (nBytes !== pData.byteLength) {
|
|
190
|
+
return yield* Effect.dieMessage(`Wrote ${nBytes} bytes, expected ${pData.byteLength}`);
|
|
191
|
+
}
|
|
192
|
+
return VFS.SQLITE_OK;
|
|
193
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_WRITE)), Runtime.runSync(this.#runtime));
|
|
199
194
|
}
|
|
200
195
|
jTruncate(fileId, iSize) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
196
|
+
return Effect.gen(this, function* () {
|
|
197
|
+
const file = this.#mapIdToFile.get(fileId);
|
|
198
|
+
yield* Opfs.Opfs.syncTruncate(file.accessHandle, HEADER_OFFSET_DATA + iSize);
|
|
199
|
+
return VFS.SQLITE_OK;
|
|
200
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_TRUNCATE)), Runtime.runSync(this.#runtime));
|
|
204
201
|
}
|
|
205
202
|
jSync(fileId, _flags) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
return Effect.gen(this, function* () {
|
|
204
|
+
const file = this.#mapIdToFile.get(fileId);
|
|
205
|
+
yield* Opfs.Opfs.syncFlush(file.accessHandle);
|
|
206
|
+
return VFS.SQLITE_OK;
|
|
207
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_FSYNC)), Runtime.runSync(this.#runtime));
|
|
209
208
|
}
|
|
210
209
|
jFileSize(fileId, pSize64) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
210
|
+
return Effect.gen(this, function* () {
|
|
211
|
+
const file = this.#mapIdToFile.get(fileId);
|
|
212
|
+
const opfsFileSize = yield* Opfs.Opfs.syncGetSize(file.accessHandle);
|
|
213
|
+
const size = opfsFileSize - HEADER_OFFSET_DATA;
|
|
214
|
+
pSize64.setBigInt64(0, BigInt(size), true);
|
|
215
|
+
return VFS.SQLITE_OK;
|
|
216
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_FSTAT)), Runtime.runSync(this.#runtime));
|
|
215
217
|
}
|
|
216
218
|
jSectorSize(_fileId) {
|
|
217
219
|
return SECTOR_SIZE;
|
|
@@ -220,28 +222,34 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
220
222
|
return VFS.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
|
|
221
223
|
}
|
|
222
224
|
jAccess(zName, _flags, pResOut) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
return Effect.gen(this, function* () {
|
|
226
|
+
const path = this.#getPath(zName);
|
|
227
|
+
pResOut.setInt32(0, this.#mapPathToAccessHandle.has(path) ? 1 : 0, true);
|
|
228
|
+
return VFS.SQLITE_OK;
|
|
229
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_ACCESS)), Runtime.runSync(this.#runtime));
|
|
226
230
|
}
|
|
227
231
|
jDelete(zName, _syncDir) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
232
|
+
return Effect.gen(this, function* () {
|
|
233
|
+
const path = this.#getPath(zName);
|
|
234
|
+
yield* this.#deletePath(path);
|
|
235
|
+
return VFS.SQLITE_OK;
|
|
236
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(() => Effect.succeed(VFS.SQLITE_IOERR_DELETE)), Runtime.runSync(this.#runtime));
|
|
231
237
|
}
|
|
232
238
|
close() {
|
|
233
|
-
this.#releaseAccessHandles();
|
|
239
|
+
this.#releaseAccessHandles().pipe(Runtime.runPromise(this.#runtime));
|
|
234
240
|
}
|
|
235
241
|
async isReady() {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
+
return Effect.gen(this, function* () {
|
|
243
|
+
if (!this.#directoryHandle) {
|
|
244
|
+
// All files are stored in a single directory.
|
|
245
|
+
this.#directoryHandle = yield* Opfs.getDirectoryHandleByPath(this.#directoryPath, { create: true });
|
|
246
|
+
yield* this.#acquireAccessHandles();
|
|
247
|
+
if (this.getCapacity() === 0) {
|
|
248
|
+
yield* this.addCapacity(DEFAULT_CAPACITY);
|
|
249
|
+
}
|
|
242
250
|
}
|
|
243
|
-
|
|
244
|
-
|
|
251
|
+
return true;
|
|
252
|
+
}).pipe(Runtime.runPromise(this.#runtime));
|
|
245
253
|
}
|
|
246
254
|
/**
|
|
247
255
|
* Returns the number of SQLite files in the file system.
|
|
@@ -267,78 +275,74 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
267
275
|
/**
|
|
268
276
|
* Increase the capacity of the file system by n.
|
|
269
277
|
*/
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
return n;
|
|
278
|
-
}
|
|
278
|
+
addCapacity = Effect.fn((n) => Effect.repeatN(Effect.gen(this, function* () {
|
|
279
|
+
const name = Math.random().toString(36).replace('0.', '');
|
|
280
|
+
const accessHandle = yield* Opfs.Opfs.getFileHandle(this.#directoryHandle, name, { create: true }).pipe(Effect.andThen((handle) => Opfs.Opfs.createSyncAccessHandle(handle)), Effect.retry(Schedule.exponentialBackoff10Sec));
|
|
281
|
+
this.#mapAccessHandleToName.set(accessHandle, name);
|
|
282
|
+
yield* this.#setAssociatedPath(accessHandle, '', 0);
|
|
283
|
+
}), n));
|
|
279
284
|
/**
|
|
280
285
|
* Decrease the capacity of the file system by n. The capacity cannot be
|
|
281
286
|
* decreased to fewer than the current number of SQLite files in the
|
|
282
287
|
* file system.
|
|
283
288
|
*/
|
|
284
|
-
|
|
289
|
+
removeCapacity = Effect.fn((n) => Effect.gen(this, function* () {
|
|
285
290
|
let nRemoved = 0;
|
|
286
|
-
|
|
291
|
+
yield* Effect.forEach(this.#availableAccessHandles, (accessHandle) => Effect.gen(this, function* () {
|
|
287
292
|
if (nRemoved === n || this.getSize() === this.getCapacity())
|
|
288
293
|
return nRemoved;
|
|
289
294
|
const name = this.#mapAccessHandleToName.get(accessHandle);
|
|
290
295
|
accessHandle.close();
|
|
291
|
-
Opfs.Opfs.removeEntry(this.#directoryHandle, name)
|
|
296
|
+
yield* Opfs.Opfs.removeEntry(this.#directoryHandle, name);
|
|
292
297
|
this.#mapAccessHandleToName.delete(accessHandle);
|
|
293
298
|
this.#availableAccessHandles.delete(accessHandle);
|
|
294
299
|
++nRemoved;
|
|
295
|
-
}
|
|
300
|
+
}), { concurrency: 'unbounded', discard: true });
|
|
296
301
|
return nRemoved;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const handlesStream = Opfs.Opfs.values(this.#directoryHandle)
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
302
|
+
}));
|
|
303
|
+
#acquireAccessHandles = Effect.fn(() => Effect.gen(this, function* () {
|
|
304
|
+
const handlesStream = yield* Opfs.Opfs.values(this.#directoryHandle);
|
|
305
|
+
yield* handlesStream.pipe(Stream.filter((handle) => handle.kind === 'file'), Stream.mapEffect((fileHandle) => Effect.gen(function* () {
|
|
306
|
+
return {
|
|
307
|
+
opfsFileName: fileHandle.name,
|
|
308
|
+
accessHandle: yield* Opfs.Opfs.createSyncAccessHandle(fileHandle),
|
|
309
|
+
};
|
|
310
|
+
}), { concurrency: 'unbounded' }), Stream.runForEach(({ opfsFileName, accessHandle }) => Effect.gen(this, function* () {
|
|
311
|
+
this.#mapAccessHandleToName.set(accessHandle, opfsFileName);
|
|
312
|
+
const path = yield* this.#getAssociatedPath(accessHandle);
|
|
307
313
|
if (path) {
|
|
308
314
|
this.#mapPathToAccessHandle.set(path, accessHandle);
|
|
309
315
|
}
|
|
310
316
|
else {
|
|
311
317
|
this.#availableAccessHandles.add(accessHandle);
|
|
312
318
|
}
|
|
313
|
-
}));
|
|
314
|
-
}
|
|
315
|
-
#releaseAccessHandles() {
|
|
316
|
-
|
|
317
|
-
accessHandle.close();
|
|
318
|
-
}
|
|
319
|
+
})));
|
|
320
|
+
}));
|
|
321
|
+
#releaseAccessHandles = Effect.fn(() => Effect.gen(this, function* () {
|
|
322
|
+
yield* Effect.forEach(this.#mapAccessHandleToName.keys(), (accessHandle) => Effect.sync(() => accessHandle.close()), { concurrency: 'unbounded', discard: true });
|
|
319
323
|
this.#mapAccessHandleToName.clear();
|
|
320
324
|
this.#mapPathToAccessHandle.clear();
|
|
321
325
|
this.#availableAccessHandles.clear();
|
|
322
|
-
}
|
|
326
|
+
}));
|
|
323
327
|
/**
|
|
324
328
|
* Read and return the associated path from an OPFS file header.
|
|
325
329
|
* Empty string is returned for an unassociated OPFS file.
|
|
326
330
|
* @returns {string} path or empty string
|
|
327
331
|
*/
|
|
328
|
-
#getAssociatedPath(accessHandle) {
|
|
332
|
+
#getAssociatedPath = Effect.fn((accessHandle) => Effect.gen(this, function* () {
|
|
329
333
|
// Read the path and digest of the path from the file.
|
|
330
334
|
const corpus = new Uint8Array(HEADER_CORPUS_SIZE);
|
|
331
|
-
Opfs.Opfs.syncRead(accessHandle, corpus, { at: 0 })
|
|
335
|
+
yield* Opfs.Opfs.syncRead(accessHandle, corpus, { at: 0 });
|
|
332
336
|
// Delete files not expected to be present.
|
|
333
337
|
const dataView = new DataView(corpus.buffer, corpus.byteOffset);
|
|
334
338
|
const flags = dataView.getUint32(HEADER_OFFSET_FLAGS);
|
|
335
339
|
if (corpus[0] && (flags & VFS.SQLITE_OPEN_DELETEONCLOSE || (flags & PERSISTENT_FILE_TYPES) === 0)) {
|
|
336
|
-
|
|
337
|
-
this.#setAssociatedPath(accessHandle, '', 0);
|
|
340
|
+
yield* Effect.logWarning(`Remove file with unexpected flags ${flags.toString(16)}`);
|
|
341
|
+
yield* this.#setAssociatedPath(accessHandle, '', 0);
|
|
338
342
|
return '';
|
|
339
343
|
}
|
|
340
344
|
const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4);
|
|
341
|
-
Opfs.Opfs.syncRead(accessHandle, fileDigest, { at: HEADER_OFFSET_DIGEST })
|
|
345
|
+
yield* Opfs.Opfs.syncRead(accessHandle, fileDigest, { at: HEADER_OFFSET_DIGEST });
|
|
342
346
|
// Verify the digest.
|
|
343
347
|
const computedDigest = this.#computeDigest(corpus);
|
|
344
348
|
if (fileDigest.every((value, i) => value === computedDigest[i])) {
|
|
@@ -349,35 +353,35 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
349
353
|
// truncated in #setAssociatedPath after the header is written. If
|
|
350
354
|
// an interruption occurs right before the truncation then garbage
|
|
351
355
|
// may remain in the file.
|
|
352
|
-
Opfs.Opfs.syncTruncate(accessHandle, HEADER_OFFSET_DATA)
|
|
356
|
+
yield* Opfs.Opfs.syncTruncate(accessHandle, HEADER_OFFSET_DATA);
|
|
353
357
|
}
|
|
354
358
|
return new TextDecoder().decode(corpus.subarray(0, pathBytes));
|
|
355
359
|
}
|
|
356
360
|
else {
|
|
357
361
|
// Bad digest. Repair this header.
|
|
358
|
-
|
|
359
|
-
this.#setAssociatedPath(accessHandle, '', 0);
|
|
362
|
+
yield* Effect.logWarning('Disassociating file with bad digest.');
|
|
363
|
+
yield* this.#setAssociatedPath(accessHandle, '', 0);
|
|
360
364
|
return '';
|
|
361
365
|
}
|
|
362
|
-
}
|
|
366
|
+
}));
|
|
363
367
|
/**
|
|
364
368
|
* Set the path on an OPFS file header.
|
|
365
369
|
*/
|
|
366
|
-
#setAssociatedPath(accessHandle, path, flags) {
|
|
370
|
+
#setAssociatedPath = Effect.fn((accessHandle, path, flags) => Effect.gen(this, function* () {
|
|
367
371
|
// Convert the path string to UTF-8.
|
|
368
372
|
const corpus = new Uint8Array(HEADER_CORPUS_SIZE);
|
|
369
373
|
const encodedResult = new TextEncoder().encodeInto(path, corpus);
|
|
370
374
|
if (encodedResult.written >= HEADER_MAX_PATH_SIZE) {
|
|
371
|
-
|
|
375
|
+
return yield* Effect.dieMessage('path too long');
|
|
372
376
|
}
|
|
373
377
|
// Add the creation flags.
|
|
374
378
|
const dataView = new DataView(corpus.buffer, corpus.byteOffset);
|
|
375
379
|
dataView.setUint32(HEADER_OFFSET_FLAGS, flags);
|
|
376
380
|
// Write the OPFS file header, including the digest.
|
|
377
381
|
const digest = this.#computeDigest(corpus);
|
|
378
|
-
Opfs.Opfs.syncWrite(accessHandle, corpus, { at: 0 })
|
|
379
|
-
Opfs.Opfs.syncWrite(accessHandle, digest, { at: HEADER_OFFSET_DIGEST })
|
|
380
|
-
Opfs.Opfs.syncFlush(accessHandle)
|
|
382
|
+
yield* Opfs.Opfs.syncWrite(accessHandle, corpus, { at: 0 });
|
|
383
|
+
yield* Opfs.Opfs.syncWrite(accessHandle, digest, { at: HEADER_OFFSET_DIGEST });
|
|
384
|
+
yield* Opfs.Opfs.syncFlush(accessHandle);
|
|
381
385
|
if (path) {
|
|
382
386
|
this.#mapPathToAccessHandle.set(path, accessHandle);
|
|
383
387
|
this.#availableAccessHandles.delete(accessHandle);
|
|
@@ -385,10 +389,10 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
385
389
|
else {
|
|
386
390
|
// This OPFS file doesn't represent any SQLite file so it doesn't
|
|
387
391
|
// need to keep any data.
|
|
388
|
-
Opfs.Opfs.syncTruncate(accessHandle, HEADER_OFFSET_DATA)
|
|
392
|
+
yield* Opfs.Opfs.syncTruncate(accessHandle, HEADER_OFFSET_DATA);
|
|
389
393
|
this.#availableAccessHandles.add(accessHandle);
|
|
390
394
|
}
|
|
391
|
-
}
|
|
395
|
+
}));
|
|
392
396
|
/**
|
|
393
397
|
* We need a synchronous digest function so can't use WebCrypto.
|
|
394
398
|
* Adapted from https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
|
|
@@ -420,18 +424,13 @@ export class AccessHandlePoolVFS extends FacadeVFS {
|
|
|
420
424
|
* Remove the association between a path and an OPFS file.
|
|
421
425
|
* @param {string} path
|
|
422
426
|
*/
|
|
423
|
-
#deletePath(path) {
|
|
427
|
+
#deletePath = Effect.fn((path) => Effect.gen(this, function* () {
|
|
424
428
|
const accessHandle = this.#mapPathToAccessHandle.get(path);
|
|
425
429
|
if (accessHandle) {
|
|
426
430
|
// Un-associate the SQLite path from the OPFS file.
|
|
427
431
|
this.#mapPathToAccessHandle.delete(path);
|
|
428
|
-
this.#setAssociatedPath(accessHandle, '', 0);
|
|
432
|
+
yield* this.#setAssociatedPath(accessHandle, '', 0);
|
|
429
433
|
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
export class OpfsError extends Schema.TaggedError()('OpfsError', {
|
|
433
|
-
cause: Schema.Defect,
|
|
434
|
-
path: Schema.String,
|
|
435
|
-
}) {
|
|
434
|
+
}));
|
|
436
435
|
}
|
|
437
436
|
//# sourceMappingURL=AccessHandlePoolVFS.js.map
|