document-drive 1.19.0 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/src/cache/memory.d.ts +10 -0
- package/dist/src/cache/memory.d.ts.map +1 -0
- package/dist/src/cache/memory.js +26 -0
- package/dist/src/cache/redis.d.ts +14 -0
- package/dist/src/cache/redis.d.ts.map +1 -0
- package/dist/src/cache/redis.js +40 -0
- package/dist/src/cache/types.d.ts +7 -0
- package/dist/src/cache/types.d.ts.map +1 -0
- package/dist/src/cache/types.js +1 -0
- package/dist/src/drive-document-model/constants.d.ts +2 -0
- package/dist/src/drive-document-model/constants.d.ts.map +1 -0
- package/dist/src/drive-document-model/constants.js +1 -0
- package/dist/src/drive-document-model/gen/actions.d.ts +7 -0
- package/dist/src/drive-document-model/gen/actions.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/actions.js +2 -0
- package/dist/src/drive-document-model/gen/constants.d.ts +7 -0
- package/dist/src/drive-document-model/gen/constants.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/constants.js +16 -0
- package/dist/src/drive-document-model/gen/creators.d.ts +3 -0
- package/dist/src/drive-document-model/gen/creators.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/creators.js +2 -0
- package/dist/src/drive-document-model/gen/document-model.d.ts +3 -0
- package/dist/src/drive-document-model/gen/document-model.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/document-model.js +210 -0
- package/dist/src/drive-document-model/gen/drive/actions.d.ts +12 -0
- package/dist/src/drive-document-model/gen/drive/actions.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/drive/actions.js +1 -0
- package/dist/src/drive-document-model/gen/drive/creators.d.ts +11 -0
- package/dist/src/drive-document-model/gen/drive/creators.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/drive/creators.js +10 -0
- package/dist/src/drive-document-model/gen/drive/error.d.ts +2 -0
- package/dist/src/drive-document-model/gen/drive/error.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/drive/error.js +1 -0
- package/dist/src/drive-document-model/gen/drive/object.d.ts +14 -0
- package/dist/src/drive-document-model/gen/drive/object.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/drive/object.js +28 -0
- package/dist/src/drive-document-model/gen/drive/operations.d.ts +14 -0
- package/dist/src/drive-document-model/gen/drive/operations.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/drive/operations.js +1 -0
- package/dist/src/drive-document-model/gen/node/actions.d.ts +11 -0
- package/dist/src/drive-document-model/gen/node/actions.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/node/actions.js +1 -0
- package/dist/src/drive-document-model/gen/node/creators.d.ts +10 -0
- package/dist/src/drive-document-model/gen/node/creators.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/node/creators.js +9 -0
- package/dist/src/drive-document-model/gen/node/error.d.ts +2 -0
- package/dist/src/drive-document-model/gen/node/error.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/node/error.js +1 -0
- package/dist/src/drive-document-model/gen/node/object.d.ts +13 -0
- package/dist/src/drive-document-model/gen/node/object.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/node/object.js +25 -0
- package/dist/src/drive-document-model/gen/node/operations.d.ts +13 -0
- package/dist/src/drive-document-model/gen/node/operations.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/node/operations.js +1 -0
- package/dist/src/drive-document-model/gen/object.d.ts +21 -0
- package/dist/src/drive-document-model/gen/object.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/object.js +28 -0
- package/dist/src/drive-document-model/gen/reducer.d.ts +4 -0
- package/dist/src/drive-document-model/gen/reducer.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/reducer.js +74 -0
- package/dist/src/drive-document-model/gen/schema/types.d.ts +176 -0
- package/dist/src/drive-document-model/gen/schema/types.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/schema/types.js +1 -0
- package/dist/src/drive-document-model/gen/schema/zod.d.ts +87 -0
- package/dist/src/drive-document-model/gen/schema/zod.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/schema/zod.js +203 -0
- package/dist/src/drive-document-model/gen/types.d.ts +9 -0
- package/dist/src/drive-document-model/gen/types.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/types.js +1 -0
- package/dist/src/drive-document-model/gen/utils.d.ts +10 -0
- package/dist/src/drive-document-model/gen/utils.d.ts.map +1 -0
- package/dist/src/drive-document-model/gen/utils.js +27 -0
- package/dist/src/drive-document-model/index.d.ts +2 -0
- package/dist/src/drive-document-model/index.d.ts.map +1 -0
- package/dist/src/drive-document-model/index.js +1 -0
- package/dist/src/drive-document-model/module.d.ts +3 -0
- package/dist/src/drive-document-model/module.d.ts.map +1 -0
- package/dist/src/drive-document-model/module.js +12 -0
- package/dist/src/drive-document-model/src/reducers/drive.d.ts +8 -0
- package/dist/src/drive-document-model/src/reducers/drive.d.ts.map +1 -0
- package/dist/src/drive-document-model/src/reducers/drive.js +37 -0
- package/dist/src/drive-document-model/src/reducers/node.d.ts +8 -0
- package/dist/src/drive-document-model/src/reducers/node.d.ts.map +1 -0
- package/dist/src/drive-document-model/src/reducers/node.js +185 -0
- package/dist/src/drive-document-model/src/utils.d.ts +34 -0
- package/dist/src/drive-document-model/src/utils.d.ts.map +1 -0
- package/dist/src/drive-document-model/src/utils.js +146 -0
- package/dist/src/queue/base.d.ts +43 -0
- package/dist/src/queue/base.d.ts.map +1 -0
- package/dist/src/queue/base.js +241 -0
- package/dist/src/queue/redis.d.ts +28 -0
- package/dist/src/queue/redis.d.ts.map +1 -0
- package/dist/src/queue/redis.js +110 -0
- package/dist/src/queue/types.d.ts +55 -0
- package/dist/src/queue/types.d.ts.map +1 -0
- package/dist/src/queue/types.js +6 -0
- package/dist/src/read-mode/errors.d.ts +12 -0
- package/dist/src/read-mode/errors.d.ts.map +1 -0
- package/dist/src/read-mode/errors.js +17 -0
- package/dist/src/read-mode/server.d.ts +4 -0
- package/dist/src/read-mode/server.d.ts.map +1 -0
- package/dist/src/read-mode/server.js +78 -0
- package/dist/src/read-mode/service.d.ts +18 -0
- package/dist/src/read-mode/service.d.ts.map +1 -0
- package/dist/src/read-mode/service.js +112 -0
- package/dist/src/read-mode/types.d.ts +35 -0
- package/dist/src/read-mode/types.d.ts.map +1 -0
- package/dist/src/read-mode/types.js +1 -0
- package/dist/src/server/base-server.d.ts +112 -0
- package/dist/src/server/base-server.d.ts.map +1 -0
- package/dist/src/server/base-server.js +1280 -0
- package/dist/src/server/builder.d.ts +30 -0
- package/dist/src/server/builder.d.ts.map +1 -0
- package/dist/src/server/builder.js +89 -0
- package/dist/src/server/constants.d.ts +2 -0
- package/dist/src/server/constants.d.ts.map +1 -0
- package/dist/src/server/constants.js +1 -0
- package/dist/src/server/error.d.ts +30 -0
- package/dist/src/server/error.d.ts.map +1 -0
- package/dist/src/server/error.js +47 -0
- package/dist/src/server/event-emitter.d.ts +8 -0
- package/dist/src/server/event-emitter.d.ts.map +1 -0
- package/dist/src/server/event-emitter.js +10 -0
- package/dist/src/server/listener/index.d.ts +2 -0
- package/dist/src/server/listener/index.d.ts.map +1 -0
- package/dist/src/server/listener/index.js +1 -0
- package/dist/src/server/listener/listener-manager.d.ts +27 -0
- package/dist/src/server/listener/listener-manager.d.ts.map +1 -0
- package/dist/src/server/listener/listener-manager.js +401 -0
- package/dist/src/server/listener/transmitter/factory.d.ts +8 -0
- package/dist/src/server/listener/transmitter/factory.d.ts.map +1 -0
- package/dist/src/server/listener/transmitter/factory.js +25 -0
- package/dist/src/server/listener/transmitter/internal.d.ts +34 -0
- package/dist/src/server/listener/transmitter/internal.d.ts.map +1 -0
- package/dist/src/server/listener/transmitter/internal.js +87 -0
- package/dist/src/server/listener/transmitter/pull-responder.d.ts +38 -0
- package/dist/src/server/listener/transmitter/pull-responder.d.ts.map +1 -0
- package/dist/src/server/listener/transmitter/pull-responder.js +256 -0
- package/dist/src/server/listener/transmitter/switchboard-push.d.ts +9 -0
- package/dist/src/server/listener/transmitter/switchboard-push.d.ts.map +1 -0
- package/dist/src/server/listener/transmitter/switchboard-push.js +77 -0
- package/dist/src/server/listener/transmitter/types.d.ts +20 -0
- package/dist/src/server/listener/transmitter/types.d.ts.map +1 -0
- package/dist/src/server/listener/transmitter/types.js +1 -0
- package/dist/src/server/listener/util.d.ts +2 -0
- package/dist/src/server/listener/util.d.ts.map +1 -0
- package/dist/src/server/listener/util.js +22 -0
- package/dist/src/server/sync-manager.d.ts +30 -0
- package/dist/src/server/sync-manager.d.ts.map +1 -0
- package/dist/src/server/sync-manager.js +287 -0
- package/dist/src/server/types.d.ts +308 -0
- package/dist/src/server/types.d.ts.map +1 -0
- package/dist/src/server/types.js +12 -0
- package/dist/src/server/utils.d.ts +8 -0
- package/dist/src/server/utils.d.ts.map +1 -0
- package/dist/src/server/utils.js +47 -0
- package/dist/src/storage/base.d.ts +36 -0
- package/dist/src/storage/base.d.ts.map +1 -0
- package/dist/src/storage/base.js +4 -0
- package/dist/src/storage/browser.d.ts +36 -0
- package/dist/src/storage/browser.d.ts.map +1 -0
- package/dist/src/storage/browser.js +155 -0
- package/dist/src/storage/filesystem.d.ts +33 -0
- package/dist/src/storage/filesystem.d.ts.map +1 -0
- package/dist/src/storage/filesystem.js +197 -0
- package/dist/src/storage/memory.d.ts +33 -0
- package/dist/src/storage/memory.d.ts.map +1 -0
- package/dist/src/storage/memory.js +139 -0
- package/dist/src/storage/prisma.d.ts +67 -0
- package/dist/src/storage/prisma.d.ts.map +1 -0
- package/dist/src/storage/prisma.js +445 -0
- package/dist/src/storage/sequelize.d.ts +32 -0
- package/dist/src/storage/sequelize.d.ts.map +1 -0
- package/dist/src/storage/sequelize.js +373 -0
- package/dist/src/storage/types.d.ts +43 -0
- package/dist/src/storage/types.d.ts.map +1 -0
- package/dist/src/storage/types.js +1 -0
- package/dist/src/utils/default-drives-manager.d.ts +29 -0
- package/dist/src/utils/default-drives-manager.d.ts.map +1 -0
- package/dist/src/utils/default-drives-manager.js +208 -0
- package/dist/src/utils/graphql.d.ts +34 -0
- package/dist/src/utils/graphql.d.ts.map +1 -0
- package/dist/src/utils/graphql.js +183 -0
- package/dist/src/utils/logger.d.ts +27 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +105 -0
- package/dist/src/utils/migrations.d.ts +4 -0
- package/dist/src/utils/migrations.d.ts.map +1 -0
- package/dist/src/utils/migrations.js +41 -0
- package/dist/src/utils/misc.d.ts +11 -0
- package/dist/src/utils/misc.d.ts.map +1 -0
- package/dist/src/utils/misc.js +43 -0
- package/dist/src/utils/run-asap.d.ts +12 -0
- package/dist/src/utils/run-asap.d.ts.map +1 -0
- package/dist/src/utils/run-asap.js +131 -0
- package/dist/test/document-helpers/utils.d.ts +8 -0
- package/dist/test/document-helpers/utils.d.ts.map +1 -0
- package/dist/test/document-helpers/utils.js +21 -0
- package/dist/test/utils.d.ts +48 -0
- package/dist/test/utils.d.ts.map +1 -0
- package/dist/test/utils.js +132 -0
- package/dist/test/vitest-setup.d.ts +2 -0
- package/dist/test/vitest-setup.d.ts.map +1 -0
- package/dist/test/vitest-setup.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +20 -0
- package/package.json +20 -38
- package/src/cache/index.ts +0 -2
- package/src/cache/memory.ts +0 -33
- package/src/cache/redis.ts +0 -56
- package/src/cache/types.ts +0 -9
- package/src/index.ts +0 -4
- package/src/queue/base.ts +0 -320
- package/src/queue/index.ts +0 -2
- package/src/queue/redis.ts +0 -144
- package/src/queue/types.ts +0 -79
- package/src/read-mode/errors.ts +0 -19
- package/src/read-mode/index.ts +0 -125
- package/src/read-mode/service.ts +0 -207
- package/src/read-mode/types.ts +0 -108
- package/src/server/error.ts +0 -70
- package/src/server/index.ts +0 -2444
- package/src/server/listener/index.ts +0 -2
- package/src/server/listener/manager.ts +0 -652
- package/src/server/listener/transmitter/index.ts +0 -4
- package/src/server/listener/transmitter/internal.ts +0 -143
- package/src/server/listener/transmitter/pull-responder.ts +0 -462
- package/src/server/listener/transmitter/switchboard-push.ts +0 -125
- package/src/server/listener/transmitter/types.ts +0 -27
- package/src/server/types.ts +0 -596
- package/src/server/utils.ts +0 -82
- package/src/storage/base.ts +0 -81
- package/src/storage/browser.ts +0 -238
- package/src/storage/filesystem.ts +0 -297
- package/src/storage/index.ts +0 -2
- package/src/storage/memory.ts +0 -211
- package/src/storage/prisma.ts +0 -653
- package/src/storage/sequelize.ts +0 -498
- package/src/storage/types.ts +0 -97
- package/src/utils/default-drives-manager.ts +0 -341
- package/src/utils/document-helpers.ts +0 -21
- package/src/utils/graphql.ts +0 -301
- package/src/utils/index.ts +0 -90
- package/src/utils/logger.ts +0 -38
- package/src/utils/migrations.ts +0 -58
- package/src/utils/run-asap.ts +0 -156
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export function buildRevisionsFilter(strands, driveId, documentId) {
|
|
2
|
+
return strands.reduce((acc, s) => {
|
|
3
|
+
if (!(s.driveId === driveId && s.documentId === documentId)) {
|
|
4
|
+
return acc;
|
|
5
|
+
}
|
|
6
|
+
acc[s.scope] = s.operations[s.operations.length - 1]?.index ?? -1;
|
|
7
|
+
return acc;
|
|
8
|
+
}, {});
|
|
9
|
+
}
|
|
10
|
+
export function buildDocumentRevisionsFilter(document) {
|
|
11
|
+
return Object.entries(document.operations).reduce((acc, [scope, operations]) => {
|
|
12
|
+
acc[scope] = operations.at(-1)?.index ?? -1;
|
|
13
|
+
return acc;
|
|
14
|
+
}, {});
|
|
15
|
+
}
|
|
16
|
+
export function filterOperationsByRevision(operations, revisions) {
|
|
17
|
+
if (!revisions) {
|
|
18
|
+
return operations;
|
|
19
|
+
}
|
|
20
|
+
return Object.keys(operations).reduce((acc, scope) => {
|
|
21
|
+
const revision = revisions[scope];
|
|
22
|
+
if (revision !== undefined) {
|
|
23
|
+
acc[scope] = operations[scope].filter((op) => op.index <= revision);
|
|
24
|
+
}
|
|
25
|
+
return acc;
|
|
26
|
+
}, { global: [], local: [] });
|
|
27
|
+
}
|
|
28
|
+
export function isAtRevision(document, revisions) {
|
|
29
|
+
return (!revisions ||
|
|
30
|
+
Object.entries(revisions).find(([scope, revision]) => {
|
|
31
|
+
const operation = document.operations[scope].at(-1);
|
|
32
|
+
if (revision === -1) {
|
|
33
|
+
return operation !== undefined;
|
|
34
|
+
}
|
|
35
|
+
return operation?.index !== revision;
|
|
36
|
+
}) === undefined);
|
|
37
|
+
}
|
|
38
|
+
export function isAfterRevision(document, revisions) {
|
|
39
|
+
return (!revisions ||
|
|
40
|
+
Object.entries(revisions).every(([scope, revision]) => {
|
|
41
|
+
const operation = document.operations[scope].at(-1);
|
|
42
|
+
if (revision === -1) {
|
|
43
|
+
return operation !== undefined;
|
|
44
|
+
}
|
|
45
|
+
return operation && operation.index > revision;
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DocumentDriveAction, DocumentDriveDocument } from "#drive-document-model/gen/types";
|
|
2
|
+
import { SynchronizationUnitQuery } from "#server/types";
|
|
3
|
+
import type { DocumentHeader, Operation, OperationFromDocument, PHDocument } from "document-model";
|
|
4
|
+
import { IDriveStorage, IStorage, IStorageDelegate } from "./types.js";
|
|
5
|
+
declare abstract class BaseStorage implements IStorage {
|
|
6
|
+
abstract checkDocumentExists(drive: string, id: string): Promise<boolean>;
|
|
7
|
+
abstract getDocuments(drive: string): Promise<string[]>;
|
|
8
|
+
abstract getDocument<TDocument extends PHDocument>(drive: string, id: string): Promise<TDocument>;
|
|
9
|
+
abstract createDocument(drive: string, id: string, document: PHDocument): Promise<void>;
|
|
10
|
+
abstract addDocumentOperations(drive: string, id: string, operations: Operation[], header: DocumentHeader): Promise<void>;
|
|
11
|
+
abstract addDocumentOperationsWithTransaction<TDocument extends PHDocument>(drive: string, id: string, callback: (document: TDocument) => Promise<{
|
|
12
|
+
operations: OperationFromDocument<TDocument>[];
|
|
13
|
+
header: DocumentHeader;
|
|
14
|
+
}>): Promise<void>;
|
|
15
|
+
abstract deleteDocument(drive: string, id: string): Promise<void>;
|
|
16
|
+
abstract getOperationResultingState<TGlobalState, TLocalState>(drive: string, id: string, index: number, scope: string, branch: string): Promise<TGlobalState | TLocalState | undefined>;
|
|
17
|
+
abstract setStorageDelegate?(delegate: IStorageDelegate): void;
|
|
18
|
+
abstract getSynchronizationUnitsRevision(units: SynchronizationUnitQuery[]): Promise<{
|
|
19
|
+
driveId: string;
|
|
20
|
+
documentId: string;
|
|
21
|
+
scope: string;
|
|
22
|
+
branch: string;
|
|
23
|
+
lastUpdated: string;
|
|
24
|
+
revision: number;
|
|
25
|
+
}[]>;
|
|
26
|
+
}
|
|
27
|
+
export declare abstract class BaseDriveStorage extends BaseStorage implements IDriveStorage {
|
|
28
|
+
abstract getDrives(): Promise<string[]>;
|
|
29
|
+
abstract getDrive(id: string): Promise<DocumentDriveDocument>;
|
|
30
|
+
abstract getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
|
|
31
|
+
abstract createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
|
|
32
|
+
abstract deleteDrive(id: string): Promise<void>;
|
|
33
|
+
abstract addDriveOperations(id: string, operations: Operation<DocumentDriveAction>[], header: DocumentHeader): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/storage/base.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,qBAAqB,EACrB,UAAU,EACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE,uBAAe,WAAY,YAAW,QAAQ;IAC5C,QAAQ,CAAC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAEzE,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAEvD,QAAQ,CAAC,WAAW,CAAC,SAAS,SAAS,UAAU,EAC/C,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,SAAS,CAAC;IAErB,QAAQ,CAAC,cAAc,CACrB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,UAAU,GACnB,OAAO,CAAC,IAAI,CAAC;IAEhB,QAAQ,CAAC,qBAAqB,CAC5B,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAEhB,QAAQ,CAAC,oCAAoC,CAAC,SAAS,SAAS,UAAU,EACxE,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,OAAO,CAAC;QACzC,UAAU,EAAE,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/C,MAAM,EAAE,cAAc,CAAC;KACxB,CAAC,GACD,OAAO,CAAC,IAAI,CAAC;IAEhB,QAAQ,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEjE,QAAQ,CAAC,0BAA0B,CAAC,YAAY,EAAE,WAAW,EAC3D,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IAElD,QAAQ,CAAC,kBAAkB,CAAC,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAE9D,QAAQ,CAAC,+BAA+B,CACtC,KAAK,EAAE,wBAAwB,EAAE,GAChC,OAAO,CACR;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CACJ;CACF;AAED,8BAAsB,gBACpB,SAAQ,WACR,YAAW,aAAa;IAExB,QAAQ,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAC7D,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IACrE,QAAQ,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7E,QAAQ,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,CACzB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,CAAC,mBAAmB,CAAC,EAAE,EAC5C,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;CACjB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DocumentDriveAction, DocumentDriveDocument } from "#drive-document-model/gen/types";
|
|
2
|
+
import { SynchronizationUnitQuery } from "#server/types";
|
|
3
|
+
import type { DocumentHeader, Operation, PHDocument } from "document-model";
|
|
4
|
+
import { IDriveStorage } from "./types.js";
|
|
5
|
+
export declare class BrowserStorage implements IDriveStorage {
|
|
6
|
+
private db;
|
|
7
|
+
static DBName: string;
|
|
8
|
+
static SEP: string;
|
|
9
|
+
static DRIVES_KEY: string;
|
|
10
|
+
constructor(namespace?: string);
|
|
11
|
+
buildKey(...args: string[]): string;
|
|
12
|
+
checkDocumentExists(drive: string, id: string): Promise<boolean>;
|
|
13
|
+
getDocuments(drive: string): Promise<string[]>;
|
|
14
|
+
getDocument<TDocument extends PHDocument>(driveId: string, id: string): Promise<TDocument>;
|
|
15
|
+
createDocument(drive: string, id: string, document: PHDocument): Promise<void>;
|
|
16
|
+
deleteDocument(drive: string, id: string): Promise<void>;
|
|
17
|
+
clearStorage(): Promise<void>;
|
|
18
|
+
addDocumentOperations(drive: string, id: string, operations: Operation[], header: DocumentHeader): Promise<void>;
|
|
19
|
+
getDrives(): Promise<string[]>;
|
|
20
|
+
getDrive(id: string): Promise<DocumentDriveDocument>;
|
|
21
|
+
getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
|
|
22
|
+
createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
|
|
23
|
+
deleteDrive(id: string): Promise<void>;
|
|
24
|
+
addDriveOperations(id: string, operations: Operation<DocumentDriveAction>[], header: DocumentHeader): Promise<void>;
|
|
25
|
+
getSynchronizationUnitsRevision(units: SynchronizationUnitQuery[]): Promise<{
|
|
26
|
+
driveId: string;
|
|
27
|
+
documentId: string;
|
|
28
|
+
scope: string;
|
|
29
|
+
branch: string;
|
|
30
|
+
lastUpdated: string;
|
|
31
|
+
revision: number;
|
|
32
|
+
}[]>;
|
|
33
|
+
migrateOperationSignatures(): Promise<void>;
|
|
34
|
+
private migrateDocument;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/storage/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAGzD,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EAET,UAAU,EACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,cAAe,YAAW,aAAa;IAClD,OAAO,CAAC,EAAE,CAAuB;IAEjC,MAAM,CAAC,MAAM,SAAqB;IAClC,MAAM,CAAC,GAAG,SAAO;IACjB,MAAM,CAAC,UAAU,SAAY;gBAEjB,SAAS,CAAC,EAAE,MAAM;IAU9B,QAAQ,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;IAIpB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOhE,YAAY,CAAC,KAAK,EAAE,MAAM;IAS1B,WAAW,CAAC,SAAS,SAAS,UAAU,EAC5C,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,SAAS,CAAC;IAUf,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU;IAI9D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAIxC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAgBV,SAAS;IAUT,QAAQ,CAAC,EAAE,EAAE,MAAM;IAWnB,cAAc,CAAC,IAAI,EAAE,MAAM;IAa3B,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB;IAKpD,WAAW,CAAC,EAAE,EAAE,MAAM;IAQtB,kBAAkB,CACtB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,CAAC,mBAAmB,CAAC,EAAE,EAC5C,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAaV,+BAA+B,CACnC,KAAK,EAAE,wBAAwB,EAAE,GAChC,OAAO,CACR;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CACJ;IA6CK,0BAA0B;YAYlB,eAAe;CAU9B"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { DriveNotFoundError } from "#server/error";
|
|
2
|
+
import { migrateDocumentOperationSignatures } from "#utils/migrations";
|
|
3
|
+
import { mergeOperations } from "#utils/misc";
|
|
4
|
+
import LocalForage from "localforage";
|
|
5
|
+
export class BrowserStorage {
|
|
6
|
+
db;
|
|
7
|
+
static DBName = "DOCUMENT_DRIVES";
|
|
8
|
+
static SEP = ":";
|
|
9
|
+
static DRIVES_KEY = "DRIVES";
|
|
10
|
+
constructor(namespace) {
|
|
11
|
+
this.db = LocalForage.ready().then(() => LocalForage.createInstance({
|
|
12
|
+
name: namespace
|
|
13
|
+
? `${namespace}:${BrowserStorage.DBName}`
|
|
14
|
+
: BrowserStorage.DBName,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
buildKey(...args) {
|
|
18
|
+
return args.join(BrowserStorage.SEP);
|
|
19
|
+
}
|
|
20
|
+
async checkDocumentExists(drive, id) {
|
|
21
|
+
const document = await (await this.db).getItem(this.buildKey(drive, id));
|
|
22
|
+
return !!document;
|
|
23
|
+
}
|
|
24
|
+
async getDocuments(drive) {
|
|
25
|
+
const db = await this.db;
|
|
26
|
+
const keys = await db.keys();
|
|
27
|
+
const driveKey = `${drive}${BrowserStorage.SEP}`;
|
|
28
|
+
return keys
|
|
29
|
+
.filter((key) => key.startsWith(driveKey))
|
|
30
|
+
.map((key) => key.slice(driveKey.length));
|
|
31
|
+
}
|
|
32
|
+
async getDocument(driveId, id) {
|
|
33
|
+
const document = await (await this.db).getItem(this.buildKey(driveId, id));
|
|
34
|
+
if (!document) {
|
|
35
|
+
throw new Error(`Document with id ${id} not found`);
|
|
36
|
+
}
|
|
37
|
+
return document;
|
|
38
|
+
}
|
|
39
|
+
async createDocument(drive, id, document) {
|
|
40
|
+
await (await this.db).setItem(this.buildKey(drive, id), document);
|
|
41
|
+
}
|
|
42
|
+
async deleteDocument(drive, id) {
|
|
43
|
+
await (await this.db).removeItem(this.buildKey(drive, id));
|
|
44
|
+
}
|
|
45
|
+
async clearStorage() {
|
|
46
|
+
return (await this.db).clear();
|
|
47
|
+
}
|
|
48
|
+
async addDocumentOperations(drive, id, operations, header) {
|
|
49
|
+
const document = await this.getDocument(drive, id);
|
|
50
|
+
if (!document) {
|
|
51
|
+
throw new Error(`Document with id ${id} not found`);
|
|
52
|
+
}
|
|
53
|
+
const mergedOperations = mergeOperations(document.operations, operations);
|
|
54
|
+
const db = await this.db;
|
|
55
|
+
await db.setItem(this.buildKey(drive, id), {
|
|
56
|
+
...document,
|
|
57
|
+
...header,
|
|
58
|
+
operations: mergedOperations,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async getDrives() {
|
|
62
|
+
const db = await this.db;
|
|
63
|
+
const keys = await db.keys();
|
|
64
|
+
return keys
|
|
65
|
+
.filter((key) => key.startsWith(BrowserStorage.DRIVES_KEY))
|
|
66
|
+
.map((key) => key.slice(BrowserStorage.DRIVES_KEY.length + BrowserStorage.SEP.length));
|
|
67
|
+
}
|
|
68
|
+
async getDrive(id) {
|
|
69
|
+
const db = await this.db;
|
|
70
|
+
const drive = await db.getItem(this.buildKey(BrowserStorage.DRIVES_KEY, id));
|
|
71
|
+
if (!drive) {
|
|
72
|
+
throw new DriveNotFoundError(id);
|
|
73
|
+
}
|
|
74
|
+
return drive;
|
|
75
|
+
}
|
|
76
|
+
async getDriveBySlug(slug) {
|
|
77
|
+
// get oldes drives first
|
|
78
|
+
const drives = (await this.getDrives()).reverse();
|
|
79
|
+
for (const drive of drives) {
|
|
80
|
+
const driveData = await this.getDrive(drive);
|
|
81
|
+
if (driveData.initialState.state.global.slug === slug) {
|
|
82
|
+
return this.getDrive(drive);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Drive with slug ${slug} not found`);
|
|
86
|
+
}
|
|
87
|
+
async createDrive(id, drive) {
|
|
88
|
+
const db = await this.db;
|
|
89
|
+
await db.setItem(this.buildKey(BrowserStorage.DRIVES_KEY, id), drive);
|
|
90
|
+
}
|
|
91
|
+
async deleteDrive(id) {
|
|
92
|
+
const documents = await this.getDocuments(id);
|
|
93
|
+
await Promise.all(documents.map((doc) => this.deleteDocument(id, doc)));
|
|
94
|
+
return (await this.db).removeItem(this.buildKey(BrowserStorage.DRIVES_KEY, id));
|
|
95
|
+
}
|
|
96
|
+
async addDriveOperations(id, operations, header) {
|
|
97
|
+
const drive = await this.getDrive(id);
|
|
98
|
+
const mergedOperations = mergeOperations(drive.operations, operations);
|
|
99
|
+
const db = await this.db;
|
|
100
|
+
await db.setItem(this.buildKey(BrowserStorage.DRIVES_KEY, id), {
|
|
101
|
+
...drive,
|
|
102
|
+
...header,
|
|
103
|
+
operations: mergedOperations,
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
async getSynchronizationUnitsRevision(units) {
|
|
108
|
+
const results = await Promise.allSettled(units.map(async (unit) => {
|
|
109
|
+
try {
|
|
110
|
+
const document = await (unit.documentId
|
|
111
|
+
? this.getDocument(unit.driveId, unit.documentId)
|
|
112
|
+
: this.getDrive(unit.driveId));
|
|
113
|
+
if (!document) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const operation = document.operations[unit.scope].at(-1);
|
|
117
|
+
if (operation) {
|
|
118
|
+
return {
|
|
119
|
+
driveId: unit.driveId,
|
|
120
|
+
documentId: unit.documentId,
|
|
121
|
+
scope: unit.scope,
|
|
122
|
+
branch: unit.branch,
|
|
123
|
+
lastUpdated: operation.timestamp,
|
|
124
|
+
revision: operation.index,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}));
|
|
132
|
+
return results.reduce((acc, curr) => {
|
|
133
|
+
if (curr.status === "fulfilled" && curr.value !== undefined) {
|
|
134
|
+
acc.push(curr.value);
|
|
135
|
+
}
|
|
136
|
+
return acc;
|
|
137
|
+
}, []);
|
|
138
|
+
}
|
|
139
|
+
// migrates all stored operations from legacy signature to signatures array
|
|
140
|
+
async migrateOperationSignatures() {
|
|
141
|
+
const drives = await this.getDrives();
|
|
142
|
+
for (const drive of drives) {
|
|
143
|
+
await this.migrateDocument(BrowserStorage.DRIVES_KEY, drive);
|
|
144
|
+
const documents = await this.getDocuments(drive);
|
|
145
|
+
await Promise.all(documents.map(async (docId) => this.migrateDocument(drive, docId)));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async migrateDocument(drive, id) {
|
|
149
|
+
const document = await this.getDocument(drive, id);
|
|
150
|
+
const migratedDocument = migrateDocumentOperationSignatures(document);
|
|
151
|
+
if (migratedDocument !== document) {
|
|
152
|
+
return (await this.db).setItem(this.buildKey(drive, id), migratedDocument);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DocumentDriveAction, DocumentDriveDocument } from "#drive-document-model/gen/types";
|
|
2
|
+
import { SynchronizationUnitQuery } from "#server/types";
|
|
3
|
+
import { DocumentHeader, Operation, PHDocument } from "document-model";
|
|
4
|
+
import { IDriveStorage } from "./types.js";
|
|
5
|
+
export declare class FilesystemStorage implements IDriveStorage {
|
|
6
|
+
private basePath;
|
|
7
|
+
private drivesPath;
|
|
8
|
+
private static DRIVES_DIR;
|
|
9
|
+
constructor(basePath: string);
|
|
10
|
+
private _buildDocumentPath;
|
|
11
|
+
getDocuments(drive: string): Promise<string[]>;
|
|
12
|
+
checkDocumentExists(drive: string, id: string): Promise<boolean>;
|
|
13
|
+
getDocument<TDocument extends PHDocument>(drive: string, id: string): Promise<TDocument>;
|
|
14
|
+
createDocument(drive: string, id: string, document: PHDocument): Promise<void>;
|
|
15
|
+
clearStorage(): Promise<void>;
|
|
16
|
+
deleteDocument(drive: string, id: string): Promise<void>;
|
|
17
|
+
addDocumentOperations(drive: string, id: string, operations: Operation[], header: DocumentHeader): Promise<void>;
|
|
18
|
+
getDrives(): Promise<string[]>;
|
|
19
|
+
getDrive(id: string): Promise<DocumentDriveDocument>;
|
|
20
|
+
getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
|
|
21
|
+
createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
|
|
22
|
+
deleteDrive(id: string): Promise<void>;
|
|
23
|
+
addDriveOperations(id: string, operations: Operation<DocumentDriveAction>[], header: DocumentHeader): Promise<void>;
|
|
24
|
+
getSynchronizationUnitsRevision(units: SynchronizationUnitQuery[]): Promise<{
|
|
25
|
+
driveId: string;
|
|
26
|
+
documentId: string;
|
|
27
|
+
scope: string;
|
|
28
|
+
branch: string;
|
|
29
|
+
lastUpdated: string;
|
|
30
|
+
revision: number;
|
|
31
|
+
}[]>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=filesystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../../src/storage/filesystem.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,EACL,cAAc,EACd,SAAS,EAET,UAAU,EACX,MAAM,gBAAgB,CAAC;AAaxB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAe3C,qBAAa,iBAAkB,YAAW,aAAa;IACrD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAY;gBAEzB,QAAQ,EAAE,MAAM;IAO5B,OAAO,CAAC,kBAAkB;IAOpB,YAAY,CAAC,KAAK,EAAE,MAAM;IA2BhC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1D,WAAW,CAAC,SAAS,SAAS,UAAU,EAC5C,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,SAAS,CAAC;IAWf,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU;IAS9D,YAAY;IAmCZ,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAIxC,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE,cAAc;IAgBlB,SAAS;IAmBT,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAQpD,cAAc,CAAC,IAAI,EAAE,MAAM;IAkBjC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB;IAI9C,WAAW,CAAC,EAAE,EAAE,MAAM;IAQtB,kBAAkB,CACtB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,CAAC,mBAAmB,CAAC,EAAE,EAC5C,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAcV,+BAA+B,CACnC,KAAK,EAAE,wBAAwB,EAAE,GAChC,OAAO,CACR;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CACJ;CA2CF"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { DriveNotFoundError } from "#server/error";
|
|
2
|
+
import { mergeOperations } from "#utils/misc";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, } from "fs";
|
|
4
|
+
import fs from "fs/promises";
|
|
5
|
+
import stringify from "json-stringify-deterministic";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import sanitize from "sanitize-filename";
|
|
8
|
+
function ensureDir(dir) {
|
|
9
|
+
if (!existsSync(dir)) {
|
|
10
|
+
mkdirSync(dir, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class FilesystemStorage {
|
|
14
|
+
basePath;
|
|
15
|
+
drivesPath;
|
|
16
|
+
static DRIVES_DIR = "drives";
|
|
17
|
+
constructor(basePath) {
|
|
18
|
+
this.basePath = basePath;
|
|
19
|
+
ensureDir(this.basePath);
|
|
20
|
+
this.drivesPath = path.join(this.basePath, FilesystemStorage.DRIVES_DIR);
|
|
21
|
+
ensureDir(this.drivesPath);
|
|
22
|
+
}
|
|
23
|
+
_buildDocumentPath(...args) {
|
|
24
|
+
return `${path.join(this.basePath, ...args.map((arg) => sanitize(arg)))}.json`;
|
|
25
|
+
}
|
|
26
|
+
async getDocuments(drive) {
|
|
27
|
+
let files = [];
|
|
28
|
+
try {
|
|
29
|
+
files = readdirSync(path.join(this.basePath, drive), {
|
|
30
|
+
withFileTypes: true,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
// if folder is not found then drive has no documents
|
|
35
|
+
if (error.code !== "ENOENT") {
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const documents = [];
|
|
40
|
+
for (const file of files.filter((file) => file.isFile())) {
|
|
41
|
+
try {
|
|
42
|
+
const documentId = path.parse(file.name).name;
|
|
43
|
+
// checks if file is document
|
|
44
|
+
await this.getDocument(drive, documentId);
|
|
45
|
+
documents.push(documentId);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
/* Ignore invalid document*/
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return documents;
|
|
52
|
+
}
|
|
53
|
+
checkDocumentExists(drive, id) {
|
|
54
|
+
const documentExists = existsSync(this._buildDocumentPath(drive, id));
|
|
55
|
+
return Promise.resolve(documentExists);
|
|
56
|
+
}
|
|
57
|
+
async getDocument(drive, id) {
|
|
58
|
+
try {
|
|
59
|
+
const content = readFileSync(this._buildDocumentPath(drive, id), {
|
|
60
|
+
encoding: "utf-8",
|
|
61
|
+
});
|
|
62
|
+
return JSON.parse(content);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw new Error(`Document with id ${id} not found`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async createDocument(drive, id, document) {
|
|
69
|
+
const documentPath = this._buildDocumentPath(drive, id);
|
|
70
|
+
ensureDir(path.dirname(documentPath));
|
|
71
|
+
writeFileSync(documentPath, stringify(document), {
|
|
72
|
+
encoding: "utf-8",
|
|
73
|
+
});
|
|
74
|
+
return Promise.resolve();
|
|
75
|
+
}
|
|
76
|
+
async clearStorage() {
|
|
77
|
+
const drivesPath = path.join(this.basePath, FilesystemStorage.DRIVES_DIR);
|
|
78
|
+
// delete content of drives directory
|
|
79
|
+
const drives = (await fs.readdir(drivesPath, {
|
|
80
|
+
withFileTypes: true,
|
|
81
|
+
recursive: true,
|
|
82
|
+
})).filter((dirent) => !!dirent.name);
|
|
83
|
+
await Promise.all(drives.map(async (dirent) => {
|
|
84
|
+
await fs.rm(path.join(drivesPath, dirent.name), {
|
|
85
|
+
recursive: true,
|
|
86
|
+
});
|
|
87
|
+
}));
|
|
88
|
+
// delete files in basePath
|
|
89
|
+
const files = (await fs.readdir(this.basePath, { withFileTypes: true })).filter((file) => file.name !== FilesystemStorage.DRIVES_DIR && !!file.name);
|
|
90
|
+
await Promise.all(files.map(async (dirent) => {
|
|
91
|
+
await fs.rm(path.join(this.basePath, dirent.name), {
|
|
92
|
+
recursive: true,
|
|
93
|
+
});
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
async deleteDocument(drive, id) {
|
|
97
|
+
return fs.rm(this._buildDocumentPath(drive, id));
|
|
98
|
+
}
|
|
99
|
+
async addDocumentOperations(drive, id, operations, header) {
|
|
100
|
+
const document = await this.getDocument(drive, id);
|
|
101
|
+
if (!document) {
|
|
102
|
+
throw new Error(`Document with id ${id} not found`);
|
|
103
|
+
}
|
|
104
|
+
const mergedOperations = mergeOperations(document.operations, operations);
|
|
105
|
+
await this.createDocument(drive, id, {
|
|
106
|
+
...document,
|
|
107
|
+
...header,
|
|
108
|
+
operations: mergedOperations,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async getDrives() {
|
|
112
|
+
const files = readdirSync(this.drivesPath, {
|
|
113
|
+
withFileTypes: true,
|
|
114
|
+
});
|
|
115
|
+
const drives = [];
|
|
116
|
+
for (const file of files.filter((file) => file.isFile())) {
|
|
117
|
+
try {
|
|
118
|
+
const driveId = path.parse(file.name).name;
|
|
119
|
+
// checks if file is drive
|
|
120
|
+
await this.getDrive(driveId);
|
|
121
|
+
drives.push(driveId);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
/* Ignore invalid drive document found on drives dir */
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return drives;
|
|
128
|
+
}
|
|
129
|
+
async getDrive(id) {
|
|
130
|
+
try {
|
|
131
|
+
return await this.getDocument(FilesystemStorage.DRIVES_DIR, id);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
throw new DriveNotFoundError(id);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async getDriveBySlug(slug) {
|
|
138
|
+
// get oldes drives first
|
|
139
|
+
const drives = (await this.getDrives()).reverse();
|
|
140
|
+
for (const drive of drives) {
|
|
141
|
+
const { initialState: { state: { global: { slug: driveSlug }, }, }, } = await this.getDrive(drive);
|
|
142
|
+
if (driveSlug === slug) {
|
|
143
|
+
return this.getDrive(drive);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
throw new Error(`Drive with slug ${slug} not found`);
|
|
147
|
+
}
|
|
148
|
+
createDrive(id, drive) {
|
|
149
|
+
return this.createDocument(FilesystemStorage.DRIVES_DIR, id, drive);
|
|
150
|
+
}
|
|
151
|
+
async deleteDrive(id) {
|
|
152
|
+
const documents = await this.getDocuments(id);
|
|
153
|
+
await this.deleteDocument(FilesystemStorage.DRIVES_DIR, id);
|
|
154
|
+
await Promise.all(documents.map((document) => this.deleteDocument(id, document)));
|
|
155
|
+
}
|
|
156
|
+
async addDriveOperations(id, operations, header) {
|
|
157
|
+
const drive = await this.getDrive(id);
|
|
158
|
+
const mergedOperations = mergeOperations(drive.operations, operations);
|
|
159
|
+
await this.createDrive(id, {
|
|
160
|
+
...drive,
|
|
161
|
+
...header,
|
|
162
|
+
operations: mergedOperations,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async getSynchronizationUnitsRevision(units) {
|
|
166
|
+
const results = await Promise.allSettled(units.map(async (unit) => {
|
|
167
|
+
try {
|
|
168
|
+
const document = await (unit.documentId
|
|
169
|
+
? this.getDocument(unit.driveId, unit.documentId)
|
|
170
|
+
: this.getDrive(unit.driveId));
|
|
171
|
+
if (!document) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
const operation = document.operations[unit.scope].at(-1);
|
|
175
|
+
if (operation) {
|
|
176
|
+
return {
|
|
177
|
+
driveId: unit.driveId,
|
|
178
|
+
documentId: unit.documentId,
|
|
179
|
+
scope: unit.scope,
|
|
180
|
+
branch: unit.branch,
|
|
181
|
+
lastUpdated: operation.timestamp,
|
|
182
|
+
revision: operation.index,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
}));
|
|
190
|
+
return results.reduce((acc, curr) => {
|
|
191
|
+
if (curr.status === "fulfilled" && curr.value !== undefined) {
|
|
192
|
+
acc.push(curr.value);
|
|
193
|
+
}
|
|
194
|
+
return acc;
|
|
195
|
+
}, []);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DocumentDriveDocument } from "#drive-document-model/gen/types";
|
|
2
|
+
import { SynchronizationUnitQuery } from "#server/types";
|
|
3
|
+
import { DocumentHeader, Operation, OperationFromDocument, PHDocument } from "document-model";
|
|
4
|
+
import { IDriveStorage } from "./types.js";
|
|
5
|
+
export declare class MemoryStorage implements IDriveStorage {
|
|
6
|
+
private documents;
|
|
7
|
+
private drives;
|
|
8
|
+
private slugToDriveId;
|
|
9
|
+
constructor();
|
|
10
|
+
checkDocumentExists(drive: string, id: string): Promise<boolean>;
|
|
11
|
+
getDocuments(drive: string): Promise<string[]>;
|
|
12
|
+
getDocument<TDocument extends PHDocument>(driveId: string, id: string): Promise<TDocument>;
|
|
13
|
+
saveDocument(drive: string, id: string, document: PHDocument): Promise<void>;
|
|
14
|
+
clearStorage(): Promise<void>;
|
|
15
|
+
createDocument(drive: string, id: string, document: PHDocument): Promise<void>;
|
|
16
|
+
addDocumentOperations(drive: string, id: string, operations: Operation[], header: DocumentHeader): Promise<void>;
|
|
17
|
+
deleteDocument(drive: string, id: string): Promise<void>;
|
|
18
|
+
getDrives(): Promise<string[]>;
|
|
19
|
+
getDrive(id: string): Promise<DocumentDriveDocument>;
|
|
20
|
+
getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
|
|
21
|
+
createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
|
|
22
|
+
addDriveOperations(id: string, operations: OperationFromDocument<DocumentDriveDocument>[], header: DocumentHeader): Promise<void>;
|
|
23
|
+
deleteDrive(id: string): Promise<void>;
|
|
24
|
+
getSynchronizationUnitsRevision(units: SynchronizationUnitQuery[]): Promise<{
|
|
25
|
+
driveId: string;
|
|
26
|
+
documentId: string;
|
|
27
|
+
scope: string;
|
|
28
|
+
branch: string;
|
|
29
|
+
lastUpdated: string;
|
|
30
|
+
revision: number;
|
|
31
|
+
}[]>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/storage/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,EACL,cAAc,EACd,SAAS,EACT,qBAAqB,EAErB,UAAU,EACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,aAAc,YAAW,aAAa;IACjD,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,aAAa,CAA8B;;IAOnD,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1D,YAAY,CAAC,KAAK,EAAE,MAAM;IAI1B,WAAW,CAAC,SAAS,SAAS,UAAU,EAC5C,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,SAAS,CAAC;IAaf,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU;IAK5D,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAK7B,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU;IA0B9D,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,SAAS,EAAE,EACvB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAeV,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAOxC,SAAS;IAIT,QAAQ,CAAC,EAAE,EAAE,MAAM;IAQnB,cAAc,CAAC,IAAI,EAAE,MAAM;IAQ3B,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,qBAAqB;IASpD,kBAAkB,CACtB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,EAAE,EAC1D,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAcV,WAAW,CAAC,EAAE,EAAE,MAAM;IAKtB,+BAA+B,CACnC,KAAK,EAAE,wBAAwB,EAAE,GAChC,OAAO,CACR;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CACJ;CA2CF"}
|