@verdant-web/server 1.8.13 → 1.8.14-next.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/dist/cjs/Baselines.d.ts +15 -15
- package/dist/cjs/Baselines.js +83 -83
- package/dist/cjs/ClientConnection.d.ts +18 -18
- package/dist/cjs/ClientConnection.js +105 -105
- package/dist/cjs/MessageSender.d.ts +5 -5
- package/dist/cjs/MessageSender.js +2 -2
- package/dist/cjs/OperationHistory.d.ts +36 -36
- package/dist/cjs/OperationHistory.js +120 -120
- package/dist/cjs/Presence.d.ts +15 -15
- package/dist/cjs/Presence.js +59 -59
- package/dist/cjs/Profiles.d.ts +10 -10
- package/dist/cjs/Profiles.js +19 -19
- package/dist/cjs/ReplicaKeepaliveTimers.d.ts +17 -17
- package/dist/cjs/ReplicaKeepaliveTimers.js +30 -30
- package/dist/cjs/Replicas.d.ts +24 -24
- package/dist/cjs/Replicas.js +137 -137
- package/dist/cjs/Server.d.ts +143 -143
- package/dist/cjs/Server.js +396 -396
- package/dist/cjs/ServerLibrary.d.ts +77 -77
- package/dist/cjs/ServerLibrary.js +487 -487
- package/dist/cjs/ServerStorage.d.ts +35 -0
- package/dist/cjs/ServerStorage.js +60 -0
- package/dist/cjs/ServerStorage.js.map +1 -0
- package/dist/cjs/TokenProvider.d.ts +16 -16
- package/dist/cjs/TokenProvider.js +26 -26
- package/dist/cjs/TokenVerifier.d.ts +16 -16
- package/dist/cjs/TokenVerifier.js +28 -28
- package/dist/cjs/files/FileMetadata.d.ts +28 -28
- package/dist/cjs/files/FileMetadata.js +46 -46
- package/dist/cjs/files/FileStorage.d.ts +35 -35
- package/dist/cjs/files/FileStorage.js +71 -71
- package/dist/cjs/index.d.ts +9 -9
- package/dist/cjs/index.js +11 -11
- package/dist/cjs/migrations/v0.d.ts +1 -0
- package/dist/cjs/migrations/v0.js +30 -0
- package/dist/cjs/migrations/v0.js.map +1 -0
- package/dist/cjs/migrations/v0.sql.d.ts +2 -2
- package/dist/cjs/migrations/v0.sql.js +3 -3
- package/dist/cjs/migrations/v1.d.ts +1 -0
- package/dist/cjs/migrations/v1.js +32 -0
- package/dist/cjs/migrations/v1.js.map +1 -0
- package/dist/cjs/migrations/v1.sql.d.ts +2 -2
- package/dist/cjs/migrations/v1.sql.js +3 -3
- package/dist/cjs/migrations/v2.d.ts +1 -0
- package/dist/cjs/migrations/v2.js +29 -0
- package/dist/cjs/migrations/v2.js.map +1 -0
- package/dist/cjs/migrations/v2.sql.d.ts +2 -2
- package/dist/cjs/migrations/v2.sql.js +4 -4
- package/dist/cjs/migrations/v3.d.ts +1 -0
- package/dist/cjs/migrations/v3.js +15 -0
- package/dist/cjs/migrations/v3.js.map +1 -0
- package/dist/cjs/migrations/v3.sql.d.ts +2 -2
- package/dist/cjs/migrations/v3.sql.js +4 -4
- package/dist/cjs/migrations/v4.d.ts +1 -0
- package/dist/cjs/migrations/v4.js +9 -0
- package/dist/cjs/migrations/v4.js.map +1 -0
- package/dist/cjs/migrations/v4.sql.d.ts +2 -2
- package/dist/cjs/migrations/v4.sql.js +4 -4
- package/dist/cjs/migrations/v5.d.ts +2 -0
- package/dist/cjs/migrations/v5.js +35 -0
- package/dist/cjs/migrations/v5.js.map +1 -0
- package/dist/cjs/migrations.d.ts +6 -2
- package/dist/cjs/migrations.js +62 -32
- package/dist/cjs/migrations.js.map +1 -1
- package/dist/cjs/migrations.test.d.ts +1 -0
- package/dist/cjs/migrations.test.js +121 -0
- package/dist/cjs/migrations.test.js.map +1 -0
- package/dist/cjs/types.d.ts +22 -22
- package/dist/cjs/types.js +2 -2
- package/dist/esm/Baselines.d.ts +15 -15
- package/dist/esm/Baselines.js +79 -79
- package/dist/esm/ClientConnection.d.ts +18 -18
- package/dist/esm/ClientConnection.js +101 -101
- package/dist/esm/MessageSender.d.ts +5 -5
- package/dist/esm/MessageSender.js +1 -1
- package/dist/esm/OperationHistory.d.ts +36 -36
- package/dist/esm/OperationHistory.js +116 -116
- package/dist/esm/Presence.d.ts +15 -15
- package/dist/esm/Presence.js +52 -52
- package/dist/esm/Profiles.d.ts +10 -10
- package/dist/esm/Profiles.js +15 -15
- package/dist/esm/ReplicaKeepaliveTimers.d.ts +17 -17
- package/dist/esm/ReplicaKeepaliveTimers.js +26 -26
- package/dist/esm/Replicas.d.ts +24 -24
- package/dist/esm/Replicas.js +133 -133
- package/dist/esm/Server.d.ts +143 -143
- package/dist/esm/Server.js +389 -389
- package/dist/esm/ServerLibrary.d.ts +77 -77
- package/dist/esm/ServerLibrary.js +483 -483
- package/dist/esm/ServerStorage.d.ts +44 -0
- package/dist/esm/ServerStorage.js +58 -0
- package/dist/esm/ServerStorage.js.map +1 -0
- package/dist/esm/TokenProvider.d.ts +16 -16
- package/dist/esm/TokenProvider.js +19 -19
- package/dist/esm/TokenVerifier.d.ts +16 -16
- package/dist/esm/TokenVerifier.js +21 -21
- package/dist/esm/files/FileMetadata.d.ts +28 -28
- package/dist/esm/files/FileMetadata.js +42 -42
- package/dist/esm/files/FileStorage.d.ts +35 -35
- package/dist/esm/files/FileStorage.js +44 -44
- package/dist/esm/index.d.ts +9 -9
- package/dist/esm/index.js +4 -4
- package/dist/esm/migrations/v0.d.ts +1 -0
- package/dist/esm/migrations/v0.js +27 -0
- package/dist/esm/migrations/v0.js.map +1 -0
- package/dist/esm/migrations/v0.sql.d.ts +2 -2
- package/dist/esm/migrations/v0.sql.js +1 -1
- package/dist/esm/migrations/v1.d.ts +1 -0
- package/dist/esm/migrations/v1.js +29 -0
- package/dist/esm/migrations/v1.js.map +1 -0
- package/dist/esm/migrations/v1.sql.d.ts +2 -2
- package/dist/esm/migrations/v1.sql.js +1 -1
- package/dist/esm/migrations/v2.d.ts +1 -0
- package/dist/esm/migrations/v2.js +26 -0
- package/dist/esm/migrations/v2.js.map +1 -0
- package/dist/esm/migrations/v2.sql.d.ts +2 -2
- package/dist/esm/migrations/v2.sql.js +2 -2
- package/dist/esm/migrations/v3.d.ts +1 -0
- package/dist/esm/migrations/v3.js +12 -0
- package/dist/esm/migrations/v3.js.map +1 -0
- package/dist/esm/migrations/v3.sql.d.ts +2 -2
- package/dist/esm/migrations/v3.sql.js +2 -2
- package/dist/esm/migrations/v4.d.ts +1 -0
- package/dist/esm/migrations/v4.js +6 -0
- package/dist/esm/migrations/v4.js.map +1 -0
- package/dist/esm/migrations/v4.sql.d.ts +2 -2
- package/dist/esm/migrations/v4.sql.js +2 -2
- package/dist/esm/migrations/v5.d.ts +2 -0
- package/dist/esm/migrations/v5.js +31 -0
- package/dist/esm/migrations/v5.js.map +1 -0
- package/dist/esm/migrations.d.ts +6 -2
- package/dist/esm/migrations.js +35 -25
- package/dist/esm/migrations.js.map +1 -1
- package/dist/esm/migrations.test.d.ts +1 -0
- package/dist/esm/migrations.test.js +116 -0
- package/dist/esm/migrations.test.js.map +1 -0
- package/dist/esm/types.d.ts +22 -22
- package/dist/esm/types.js +1 -1
- package/dist/tsconfig-cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -4
- package/src/__snapshots__/migrations.test.ts.snap +55 -0
- package/src/migrations/{v0.sql.ts → v0.ts} +1 -1
- package/src/migrations/{v1.sql.ts → v1.ts} +1 -1
- package/src/migrations/{v2.sql.ts → v2.ts} +1 -1
- package/src/migrations/{v3.sql.ts → v3.ts} +1 -1
- package/src/migrations/{v4.sql.ts → v4.ts} +1 -1
- package/src/migrations/v5.ts +47 -0
- package/src/migrations.test.ts +133 -0
- package/src/migrations.ts +28 -19
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Database } from 'better-sqlite3';
|
|
2
|
+
import { ClientMessage } from '@lo-fi/common';
|
|
3
|
+
import { MessageSender } from './MessageSender.js';
|
|
4
|
+
import { UserProfiles } from './Profiles.js';
|
|
5
|
+
import { TokenInfo } from './TokenVerifier.js';
|
|
6
|
+
import { FileInfo } from './files/FileStorage.js';
|
|
7
|
+
interface ServerStorageOptions {
|
|
8
|
+
db: Database;
|
|
9
|
+
sender: MessageSender;
|
|
10
|
+
profiles: UserProfiles<any>;
|
|
11
|
+
replicaTruancyMinutes: number;
|
|
12
|
+
log?: (...args: any[]) => void;
|
|
13
|
+
disableRebasing?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare class ServerStorage {
|
|
16
|
+
private profileLoader;
|
|
17
|
+
private library;
|
|
18
|
+
private db;
|
|
19
|
+
private sender;
|
|
20
|
+
private fileMetadata;
|
|
21
|
+
constructor({ db, sender, profiles, replicaTruancyMinutes, disableRebasing, log, }: ServerStorageOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Call with any message from any replica
|
|
24
|
+
*/
|
|
25
|
+
receive: (libraryId: string, clientKey: string, message: ClientMessage, info: TokenInfo) => Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Call when a replica disconnects from the server
|
|
28
|
+
*/
|
|
29
|
+
remove: (libraryId: string, replicaId: string) => void;
|
|
30
|
+
evictLibrary: (libraryId: string) => void;
|
|
31
|
+
evictUser: (libraryId: string, userId: string) => void;
|
|
32
|
+
private createSchema;
|
|
33
|
+
close: () => Promise<void>;
|
|
34
|
+
getLibraryPresence: (libraryId: string) => Record<string, import("@lo-fi/common").UserInfo<any, any>>;
|
|
35
|
+
getDocumentSnapshot: (libraryId: string, oid: string) => any;
|
|
36
|
+
putFileInfo: (libraryId: string, fileInfo: FileInfo) => void;
|
|
37
|
+
getFileInfo: (libraryId: string, fileId: string) => {
|
|
38
|
+
libraryId: string;
|
|
39
|
+
fileId: string;
|
|
40
|
+
name: string;
|
|
41
|
+
type: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ServerLibrary } from './ServerLibrary.js';
|
|
2
|
+
import { UserProfileLoader } from './Profiles.js';
|
|
3
|
+
import { migrations } from './migrations.js';
|
|
4
|
+
import { FileMetadata } from './files/FileMetadata.js';
|
|
5
|
+
export class ServerStorage {
|
|
6
|
+
constructor({ db, sender, profiles, replicaTruancyMinutes, disableRebasing = false, log = () => { }, }) {
|
|
7
|
+
/**
|
|
8
|
+
* Call with any message from any replica
|
|
9
|
+
*/
|
|
10
|
+
this.receive = (libraryId, clientKey, message, info) => {
|
|
11
|
+
return this.library.receive(message, clientKey, info);
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Call when a replica disconnects from the server
|
|
15
|
+
*/
|
|
16
|
+
this.remove = (libraryId, replicaId) => {
|
|
17
|
+
this.library.remove(libraryId, replicaId);
|
|
18
|
+
};
|
|
19
|
+
this.evictLibrary = (libraryId) => {
|
|
20
|
+
this.library.destroy(libraryId);
|
|
21
|
+
};
|
|
22
|
+
this.evictUser = (libraryId, userId) => {
|
|
23
|
+
this.library.evictUser(libraryId, userId);
|
|
24
|
+
};
|
|
25
|
+
this.createSchema = () => {
|
|
26
|
+
migrations(this.db);
|
|
27
|
+
};
|
|
28
|
+
this.close = async () => {
|
|
29
|
+
this.db.close();
|
|
30
|
+
};
|
|
31
|
+
this.getLibraryPresence = (libraryId) => {
|
|
32
|
+
return this.library.getPresence(libraryId);
|
|
33
|
+
};
|
|
34
|
+
this.getDocumentSnapshot = (libraryId, oid) => {
|
|
35
|
+
return this.library.getDocumentSnapshot(libraryId, oid);
|
|
36
|
+
};
|
|
37
|
+
this.putFileInfo = (libraryId, fileInfo) => {
|
|
38
|
+
this.fileMetadata.put(libraryId, fileInfo);
|
|
39
|
+
};
|
|
40
|
+
this.getFileInfo = (libraryId, fileId) => {
|
|
41
|
+
return this.fileMetadata.get(libraryId, fileId);
|
|
42
|
+
};
|
|
43
|
+
this.db = db;
|
|
44
|
+
this.sender = sender;
|
|
45
|
+
this.createSchema();
|
|
46
|
+
this.profileLoader = new UserProfileLoader(profiles);
|
|
47
|
+
this.library = new ServerLibrary({
|
|
48
|
+
db: this.db,
|
|
49
|
+
sender: this.sender,
|
|
50
|
+
profiles: this.profileLoader,
|
|
51
|
+
replicaTruancyMinutes,
|
|
52
|
+
log,
|
|
53
|
+
disableRebasing,
|
|
54
|
+
});
|
|
55
|
+
this.fileMetadata = new FileMetadata(this.db);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=ServerStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServerStorage.js","sourceRoot":"","sources":["../../src/ServerStorage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAgB,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAWvD,MAAM,OAAO,aAAa;IAOzB,YAAY,EACX,EAAE,EACF,MAAM,EACN,QAAQ,EACR,qBAAqB,EACrB,eAAe,GAAG,KAAK,EACvB,GAAG,GAAG,GAAG,EAAE,GAAE,CAAC,GACQ;QAgBvB;;WAEG;QACH,YAAO,GAAG,CACT,SAAiB,EACjB,SAAiB,EACjB,OAAsB,EACtB,IAAe,EACd,EAAE;YACH,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACvD,CAAC,CAAC;QAEF;;WAEG;QACH,WAAM,GAAG,CAAC,SAAiB,EAAE,SAAiB,EAAE,EAAE;YACjD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC3C,CAAC,CAAC;QAEF,iBAAY,GAAG,CAAC,SAAiB,EAAE,EAAE;YACpC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC,CAAC;QAEF,cAAS,GAAG,CAAC,SAAiB,EAAE,MAAc,EAAE,EAAE;YACjD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC,CAAC;QAEM,iBAAY,GAAG,GAAG,EAAE;YAC3B,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC,CAAC;QAEF,UAAK,GAAG,KAAK,IAAI,EAAE;YAClB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC,CAAC;QAEF,uBAAkB,GAAG,CAAC,SAAiB,EAAE,EAAE;YAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,wBAAmB,GAAG,CAAC,SAAiB,EAAE,GAAW,EAAE,EAAE;YACxD,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACzD,CAAC,CAAC;QAEF,gBAAW,GAAG,CAAC,SAAiB,EAAE,QAAkB,EAAE,EAAE;YACvD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,gBAAW,GAAG,CAAC,SAAiB,EAAE,MAAc,EAAE,EAAE;YACnD,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC,CAAC;QAhED,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,aAAa,GAAG,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,GAAG,IAAI,aAAa,CAAC;YAChC,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,aAAa;YAC5B,qBAAqB;YACrB,GAAG;YACH,eAAe;SACf,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;CAoDD"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
-
export declare class TokenProvider {
|
|
3
|
-
private config;
|
|
4
|
-
constructor(config: {
|
|
5
|
-
secret: string;
|
|
6
|
-
});
|
|
7
|
-
getToken: ({ userId, libraryId, syncEndpoint, role, type, expiresIn, fileEndpoint, }: {
|
|
8
|
-
userId: string;
|
|
9
|
-
libraryId: string;
|
|
10
|
-
syncEndpoint: string;
|
|
11
|
-
fileEndpoint?: string | undefined;
|
|
12
|
-
role?: string | undefined;
|
|
13
|
-
type?: ReplicaType | undefined;
|
|
14
|
-
expiresIn?: string | number | undefined;
|
|
15
|
-
}) => string;
|
|
16
|
-
}
|
|
1
|
+
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
+
export declare class TokenProvider {
|
|
3
|
+
private config;
|
|
4
|
+
constructor(config: {
|
|
5
|
+
secret: string;
|
|
6
|
+
});
|
|
7
|
+
getToken: ({ userId, libraryId, syncEndpoint, role, type, expiresIn, fileEndpoint, }: {
|
|
8
|
+
userId: string;
|
|
9
|
+
libraryId: string;
|
|
10
|
+
syncEndpoint: string;
|
|
11
|
+
fileEndpoint?: string | undefined;
|
|
12
|
+
role?: string | undefined;
|
|
13
|
+
type?: ReplicaType | undefined;
|
|
14
|
+
expiresIn?: string | number | undefined;
|
|
15
|
+
}) => string;
|
|
16
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
-
import jwt from 'jsonwebtoken';
|
|
3
|
-
export class TokenProvider {
|
|
4
|
-
constructor(config) {
|
|
5
|
-
this.config = config;
|
|
6
|
-
this.getToken = ({ userId, libraryId, syncEndpoint, role, type = ReplicaType.Realtime, expiresIn = '1d', fileEndpoint, }) => {
|
|
7
|
-
return jwt.sign({
|
|
8
|
-
sub: userId,
|
|
9
|
-
lib: libraryId,
|
|
10
|
-
url: syncEndpoint,
|
|
11
|
-
file: fileEndpoint,
|
|
12
|
-
role,
|
|
13
|
-
type,
|
|
14
|
-
}, this.config.secret, {
|
|
15
|
-
expiresIn,
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
}
|
|
1
|
+
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
export class TokenProvider {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
this.getToken = ({ userId, libraryId, syncEndpoint, role, type = ReplicaType.Realtime, expiresIn = '1d', fileEndpoint, }) => {
|
|
7
|
+
return jwt.sign({
|
|
8
|
+
sub: userId,
|
|
9
|
+
lib: libraryId,
|
|
10
|
+
url: syncEndpoint,
|
|
11
|
+
file: fileEndpoint,
|
|
12
|
+
role,
|
|
13
|
+
type,
|
|
14
|
+
}, this.config.secret, {
|
|
15
|
+
expiresIn,
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
20
|
//# sourceMappingURL=TokenProvider.js.map
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
-
export declare class TokenVerifier {
|
|
3
|
-
private config;
|
|
4
|
-
constructor(config: {
|
|
5
|
-
secret: string;
|
|
6
|
-
});
|
|
7
|
-
verifyToken: (token: string) => TokenInfo;
|
|
8
|
-
}
|
|
9
|
-
export interface TokenInfo {
|
|
10
|
-
userId: string;
|
|
11
|
-
libraryId: string;
|
|
12
|
-
syncEndpoint: string;
|
|
13
|
-
role?: string;
|
|
14
|
-
type: ReplicaType;
|
|
15
|
-
token: string;
|
|
16
|
-
}
|
|
1
|
+
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
+
export declare class TokenVerifier {
|
|
3
|
+
private config;
|
|
4
|
+
constructor(config: {
|
|
5
|
+
secret: string;
|
|
6
|
+
});
|
|
7
|
+
verifyToken: (token: string) => TokenInfo;
|
|
8
|
+
}
|
|
9
|
+
export interface TokenInfo {
|
|
10
|
+
userId: string;
|
|
11
|
+
libraryId: string;
|
|
12
|
+
syncEndpoint: string;
|
|
13
|
+
role?: string;
|
|
14
|
+
type: ReplicaType;
|
|
15
|
+
token: string;
|
|
16
|
+
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { assert } from '@verdant-web/common';
|
|
2
|
-
import jwt from 'jsonwebtoken';
|
|
3
|
-
export class TokenVerifier {
|
|
4
|
-
constructor(config) {
|
|
5
|
-
this.config = config;
|
|
6
|
-
this.verifyToken = (token) => {
|
|
7
|
-
const decoded = jwt.verify(token, this.config.secret, {
|
|
8
|
-
complete: false,
|
|
9
|
-
});
|
|
10
|
-
assert(decoded.sub);
|
|
11
|
-
return {
|
|
12
|
-
userId: decoded.sub,
|
|
13
|
-
libraryId: decoded.lib,
|
|
14
|
-
syncEndpoint: decoded.url,
|
|
15
|
-
role: decoded.role,
|
|
16
|
-
type: decoded.type,
|
|
17
|
-
token,
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
}
|
|
1
|
+
import { assert } from '@verdant-web/common';
|
|
2
|
+
import jwt from 'jsonwebtoken';
|
|
3
|
+
export class TokenVerifier {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
this.verifyToken = (token) => {
|
|
7
|
+
const decoded = jwt.verify(token, this.config.secret, {
|
|
8
|
+
complete: false,
|
|
9
|
+
});
|
|
10
|
+
assert(decoded.sub);
|
|
11
|
+
return {
|
|
12
|
+
userId: decoded.sub,
|
|
13
|
+
libraryId: decoded.lib,
|
|
14
|
+
syncEndpoint: decoded.url,
|
|
15
|
+
role: decoded.role,
|
|
16
|
+
type: decoded.type,
|
|
17
|
+
token,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
22
|
//# sourceMappingURL=TokenVerifier.js.map
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { Database } from 'better-sqlite3';
|
|
2
|
-
import { FileInfo } from './FileStorage.js';
|
|
3
|
-
export interface FileMetadataConfig {
|
|
4
|
-
deleteExpirationDays?: number;
|
|
5
|
-
}
|
|
6
|
-
export declare class FileMetadata {
|
|
7
|
-
private db;
|
|
8
|
-
private deleteExpirationDays;
|
|
9
|
-
constructor(db: Database, { deleteExpirationDays }?: FileMetadataConfig);
|
|
10
|
-
get: (libraryId: string, fileId: string) => {
|
|
11
|
-
libraryId: string;
|
|
12
|
-
fileId: string;
|
|
13
|
-
name: string;
|
|
14
|
-
type: string;
|
|
15
|
-
};
|
|
16
|
-
getAll: (libraryId: string) => any[];
|
|
17
|
-
deleteAll: (libraryId: string) => import("better-sqlite3").RunResult;
|
|
18
|
-
put: (libraryId: string, fileInfo: FileInfo) => import("better-sqlite3").RunResult;
|
|
19
|
-
markPendingDelete: (libraryId: string, fileId: string) => import("better-sqlite3").RunResult;
|
|
20
|
-
delete: (libraryId: string, fileId: string) => import("better-sqlite3").RunResult;
|
|
21
|
-
getPendingDeletes: (libraryId: string) => {
|
|
22
|
-
libraryId: string;
|
|
23
|
-
fileId: string;
|
|
24
|
-
name: string;
|
|
25
|
-
type: string;
|
|
26
|
-
pendingDeleteAt: number;
|
|
27
|
-
}[];
|
|
28
|
-
}
|
|
1
|
+
import { Database } from 'better-sqlite3';
|
|
2
|
+
import { FileInfo } from './FileStorage.js';
|
|
3
|
+
export interface FileMetadataConfig {
|
|
4
|
+
deleteExpirationDays?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class FileMetadata {
|
|
7
|
+
private db;
|
|
8
|
+
private deleteExpirationDays;
|
|
9
|
+
constructor(db: Database, { deleteExpirationDays }?: FileMetadataConfig);
|
|
10
|
+
get: (libraryId: string, fileId: string) => {
|
|
11
|
+
libraryId: string;
|
|
12
|
+
fileId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
type: string;
|
|
15
|
+
};
|
|
16
|
+
getAll: (libraryId: string) => any[];
|
|
17
|
+
deleteAll: (libraryId: string) => import("better-sqlite3").RunResult;
|
|
18
|
+
put: (libraryId: string, fileInfo: FileInfo) => import("better-sqlite3").RunResult;
|
|
19
|
+
markPendingDelete: (libraryId: string, fileId: string) => import("better-sqlite3").RunResult;
|
|
20
|
+
delete: (libraryId: string, fileId: string) => import("better-sqlite3").RunResult;
|
|
21
|
+
getPendingDeletes: (libraryId: string) => {
|
|
22
|
+
libraryId: string;
|
|
23
|
+
fileId: string;
|
|
24
|
+
name: string;
|
|
25
|
+
type: string;
|
|
26
|
+
pendingDeleteAt: number;
|
|
27
|
+
}[];
|
|
28
|
+
}
|
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
export class FileMetadata {
|
|
2
|
-
constructor(db, { deleteExpirationDays = 1 } = {}) {
|
|
3
|
-
this.db = db;
|
|
4
|
-
this.deleteExpirationDays = 1;
|
|
5
|
-
this.get = (libraryId, fileId) => {
|
|
6
|
-
return this.db
|
|
1
|
+
export class FileMetadata {
|
|
2
|
+
constructor(db, { deleteExpirationDays = 1 } = {}) {
|
|
3
|
+
this.db = db;
|
|
4
|
+
this.deleteExpirationDays = 1;
|
|
5
|
+
this.get = (libraryId, fileId) => {
|
|
6
|
+
return this.db
|
|
7
7
|
.prepare(`
|
|
8
8
|
SELECT * FROM FileMetadata
|
|
9
9
|
WHERE libraryId = ? AND fileId = ?
|
|
10
|
-
`)
|
|
11
|
-
.get(libraryId, fileId);
|
|
12
|
-
};
|
|
13
|
-
this.getAll = (libraryId) => {
|
|
14
|
-
return this.db
|
|
10
|
+
`)
|
|
11
|
+
.get(libraryId, fileId);
|
|
12
|
+
};
|
|
13
|
+
this.getAll = (libraryId) => {
|
|
14
|
+
return this.db
|
|
15
15
|
.prepare(`
|
|
16
16
|
SELECT * FROM FileMetadata
|
|
17
17
|
WHERE libraryId = ?
|
|
18
|
-
`)
|
|
19
|
-
.all(libraryId);
|
|
20
|
-
};
|
|
21
|
-
this.deleteAll = (libraryId) => {
|
|
22
|
-
return this.db
|
|
18
|
+
`)
|
|
19
|
+
.all(libraryId);
|
|
20
|
+
};
|
|
21
|
+
this.deleteAll = (libraryId) => {
|
|
22
|
+
return this.db
|
|
23
23
|
.prepare(`
|
|
24
24
|
DELETE FROM FileMetadata
|
|
25
25
|
WHERE libraryId = ?
|
|
26
|
-
`)
|
|
27
|
-
.run(libraryId);
|
|
28
|
-
};
|
|
29
|
-
this.put = (libraryId, fileInfo) => {
|
|
30
|
-
return this.db
|
|
26
|
+
`)
|
|
27
|
+
.run(libraryId);
|
|
28
|
+
};
|
|
29
|
+
this.put = (libraryId, fileInfo) => {
|
|
30
|
+
return this.db
|
|
31
31
|
.prepare(`
|
|
32
32
|
INSERT OR REPLACE INTO FileMetadata (libraryId, fileId, name, type)
|
|
33
33
|
VALUES (?, ?, ?, ?)
|
|
34
|
-
`)
|
|
35
|
-
.run(libraryId, fileInfo.id, fileInfo.fileName, fileInfo.type);
|
|
36
|
-
};
|
|
37
|
-
this.markPendingDelete = (libraryId, fileId) => {
|
|
38
|
-
return this.db
|
|
34
|
+
`)
|
|
35
|
+
.run(libraryId, fileInfo.id, fileInfo.fileName, fileInfo.type);
|
|
36
|
+
};
|
|
37
|
+
this.markPendingDelete = (libraryId, fileId) => {
|
|
38
|
+
return this.db
|
|
39
39
|
.prepare(`
|
|
40
40
|
UPDATE FileMetadata
|
|
41
41
|
SET pendingDeleteAt = ?
|
|
42
42
|
WHERE libraryId = ? AND fileId = ?
|
|
43
|
-
`)
|
|
44
|
-
.run(Date.now(), libraryId, fileId);
|
|
45
|
-
};
|
|
46
|
-
this.delete = (libraryId, fileId) => {
|
|
47
|
-
return this.db
|
|
43
|
+
`)
|
|
44
|
+
.run(Date.now(), libraryId, fileId);
|
|
45
|
+
};
|
|
46
|
+
this.delete = (libraryId, fileId) => {
|
|
47
|
+
return this.db
|
|
48
48
|
.prepare(`
|
|
49
49
|
DELETE FROM FileMetadata
|
|
50
50
|
WHERE libraryId = ? AND fileId = ?
|
|
51
|
-
`)
|
|
52
|
-
.run(libraryId, fileId);
|
|
53
|
-
};
|
|
54
|
-
this.getPendingDeletes = (libraryId) => {
|
|
55
|
-
return this.db
|
|
51
|
+
`)
|
|
52
|
+
.run(libraryId, fileId);
|
|
53
|
+
};
|
|
54
|
+
this.getPendingDeletes = (libraryId) => {
|
|
55
|
+
return this.db
|
|
56
56
|
.prepare(`
|
|
57
57
|
SELECT * FROM FileMetadata
|
|
58
58
|
WHERE libraryId = ? AND pendingDeleteAt < ?
|
|
59
|
-
`)
|
|
60
|
-
.all(libraryId, Date.now() - 1000 * 60 * 60 * 24 * this.deleteExpirationDays);
|
|
61
|
-
};
|
|
62
|
-
this.deleteExpirationDays = deleteExpirationDays;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
59
|
+
`)
|
|
60
|
+
.all(libraryId, Date.now() - 1000 * 60 * 60 * 24 * this.deleteExpirationDays);
|
|
61
|
+
};
|
|
62
|
+
this.deleteExpirationDays = deleteExpirationDays;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
65
|
//# sourceMappingURL=FileMetadata.js.map
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
-
import { Readable } from 'stream';
|
|
3
|
-
export interface FileInfo {
|
|
4
|
-
fileName: string;
|
|
5
|
-
id: string;
|
|
6
|
-
libraryId: string;
|
|
7
|
-
type: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* The interface for implementing a file storage backend.
|
|
11
|
-
* verdant will supply file Blobs and metadata, and the storage backend
|
|
12
|
-
* must store them somewhere.
|
|
13
|
-
*
|
|
14
|
-
* The storage backend must also provide a way to get a URL for the file,
|
|
15
|
-
* even if the file is not yet uploaded, based on its metadata.
|
|
16
|
-
*/
|
|
17
|
-
export interface FileStorage {
|
|
18
|
-
put(fileStream: Readable, data: FileInfo): Promise<void>;
|
|
19
|
-
getUrl(data: FileInfo): string | Promise<string>;
|
|
20
|
-
delete(data: FileInfo): Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
export declare class LocalFileStorage implements FileStorage {
|
|
23
|
-
private readonly host;
|
|
24
|
-
private readonly rootDirectory;
|
|
25
|
-
constructor({ rootDirectory, host, }: {
|
|
26
|
-
rootDirectory: string;
|
|
27
|
-
host: string;
|
|
28
|
-
});
|
|
29
|
-
private prepareHost;
|
|
30
|
-
put(fileStream: Readable, data: FileInfo): Promise<void>;
|
|
31
|
-
getUrl(data: FileInfo): string;
|
|
32
|
-
delete(data: FileInfo): Promise<void>;
|
|
33
|
-
private getPath;
|
|
34
|
-
private getStorageLocation;
|
|
35
|
-
}
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
export interface FileInfo {
|
|
4
|
+
fileName: string;
|
|
5
|
+
id: string;
|
|
6
|
+
libraryId: string;
|
|
7
|
+
type: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The interface for implementing a file storage backend.
|
|
11
|
+
* verdant will supply file Blobs and metadata, and the storage backend
|
|
12
|
+
* must store them somewhere.
|
|
13
|
+
*
|
|
14
|
+
* The storage backend must also provide a way to get a URL for the file,
|
|
15
|
+
* even if the file is not yet uploaded, based on its metadata.
|
|
16
|
+
*/
|
|
17
|
+
export interface FileStorage {
|
|
18
|
+
put(fileStream: Readable, data: FileInfo): Promise<void>;
|
|
19
|
+
getUrl(data: FileInfo): string | Promise<string>;
|
|
20
|
+
delete(data: FileInfo): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export declare class LocalFileStorage implements FileStorage {
|
|
23
|
+
private readonly host;
|
|
24
|
+
private readonly rootDirectory;
|
|
25
|
+
constructor({ rootDirectory, host, }: {
|
|
26
|
+
rootDirectory: string;
|
|
27
|
+
host: string;
|
|
28
|
+
});
|
|
29
|
+
private prepareHost;
|
|
30
|
+
put(fileStream: Readable, data: FileInfo): Promise<void>;
|
|
31
|
+
getUrl(data: FileInfo): string;
|
|
32
|
+
delete(data: FileInfo): Promise<void>;
|
|
33
|
+
private getPath;
|
|
34
|
+
private getStorageLocation;
|
|
35
|
+
}
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
export class LocalFileStorage {
|
|
4
|
-
constructor({ rootDirectory, host, }) {
|
|
5
|
-
this.prepareHost = (host) => {
|
|
6
|
-
if (host.endsWith('/')) {
|
|
7
|
-
return host.slice(0, -1);
|
|
8
|
-
}
|
|
9
|
-
return host;
|
|
10
|
-
};
|
|
11
|
-
this.host = this.prepareHost(host);
|
|
12
|
-
this.rootDirectory = rootDirectory;
|
|
13
|
-
}
|
|
14
|
-
async put(fileStream, data) {
|
|
15
|
-
const filePath = this.getPath(data);
|
|
16
|
-
const containingDirectory = path.dirname(path.join(this.rootDirectory, filePath));
|
|
17
|
-
await fs.promises.mkdir(containingDirectory, {
|
|
18
|
-
recursive: true,
|
|
19
|
-
});
|
|
20
|
-
const dest = fs.createWriteStream(this.getStorageLocation(data));
|
|
21
|
-
fileStream.pipe(dest);
|
|
22
|
-
}
|
|
23
|
-
getUrl(data) {
|
|
24
|
-
return `${this.host}/${this.getPath(data)}`;
|
|
25
|
-
}
|
|
26
|
-
async delete(data) {
|
|
27
|
-
await fs.promises.unlink(this.getStorageLocation(data));
|
|
28
|
-
const containingDirectory = path.dirname(path.join(this.rootDirectory, this.getPath(data)));
|
|
29
|
-
// delete the containing folder if it's empty
|
|
30
|
-
try {
|
|
31
|
-
await fs.promises.rmdir(containingDirectory);
|
|
32
|
-
}
|
|
33
|
-
catch (e) {
|
|
34
|
-
// ignore
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
getPath(data) {
|
|
38
|
-
// retain the file extension
|
|
39
|
-
return `${data.libraryId}/${data.id}/${data.fileName}`;
|
|
40
|
-
}
|
|
41
|
-
getStorageLocation(data) {
|
|
42
|
-
return path.join(this.rootDirectory, this.getPath(data));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
export class LocalFileStorage {
|
|
4
|
+
constructor({ rootDirectory, host, }) {
|
|
5
|
+
this.prepareHost = (host) => {
|
|
6
|
+
if (host.endsWith('/')) {
|
|
7
|
+
return host.slice(0, -1);
|
|
8
|
+
}
|
|
9
|
+
return host;
|
|
10
|
+
};
|
|
11
|
+
this.host = this.prepareHost(host);
|
|
12
|
+
this.rootDirectory = rootDirectory;
|
|
13
|
+
}
|
|
14
|
+
async put(fileStream, data) {
|
|
15
|
+
const filePath = this.getPath(data);
|
|
16
|
+
const containingDirectory = path.dirname(path.join(this.rootDirectory, filePath));
|
|
17
|
+
await fs.promises.mkdir(containingDirectory, {
|
|
18
|
+
recursive: true,
|
|
19
|
+
});
|
|
20
|
+
const dest = fs.createWriteStream(this.getStorageLocation(data));
|
|
21
|
+
fileStream.pipe(dest);
|
|
22
|
+
}
|
|
23
|
+
getUrl(data) {
|
|
24
|
+
return `${this.host}/${this.getPath(data)}`;
|
|
25
|
+
}
|
|
26
|
+
async delete(data) {
|
|
27
|
+
await fs.promises.unlink(this.getStorageLocation(data));
|
|
28
|
+
const containingDirectory = path.dirname(path.join(this.rootDirectory, this.getPath(data)));
|
|
29
|
+
// delete the containing folder if it's empty
|
|
30
|
+
try {
|
|
31
|
+
await fs.promises.rmdir(containingDirectory);
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
// ignore
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
getPath(data) {
|
|
38
|
+
// retain the file extension
|
|
39
|
+
return `${data.libraryId}/${data.id}/${data.fileName}`;
|
|
40
|
+
}
|
|
41
|
+
getStorageLocation(data) {
|
|
42
|
+
return path.join(this.rootDirectory, this.getPath(data));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
45
|
//# sourceMappingURL=FileStorage.js.map
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export type { MessageSender } from './MessageSender.js';
|
|
2
|
-
export type { UserProfiles } from './Profiles.js';
|
|
3
|
-
export type { ClientMessage, ServerMessage } from '@verdant-web/common';
|
|
4
|
-
export { ReplicaType } from '@verdant-web/common';
|
|
5
|
-
export { Server } from './Server.js';
|
|
6
|
-
export { TokenProvider } from './TokenProvider.js';
|
|
7
|
-
export { LocalFileStorage } from './files/FileStorage.js';
|
|
8
|
-
export type { FileStorage, FileInfo } from './files/FileStorage.js';
|
|
9
|
-
export type { TokenInfo } from './TokenVerifier.js';
|
|
1
|
+
export type { MessageSender } from './MessageSender.js';
|
|
2
|
+
export type { UserProfiles } from './Profiles.js';
|
|
3
|
+
export type { ClientMessage, ServerMessage } from '@verdant-web/common';
|
|
4
|
+
export { ReplicaType } from '@verdant-web/common';
|
|
5
|
+
export { Server } from './Server.js';
|
|
6
|
+
export { TokenProvider } from './TokenProvider.js';
|
|
7
|
+
export { LocalFileStorage } from './files/FileStorage.js';
|
|
8
|
+
export type { FileStorage, FileInfo } from './files/FileStorage.js';
|
|
9
|
+
export type { TokenInfo } from './TokenVerifier.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { ReplicaType } from '@verdant-web/common';
|
|
2
|
-
export { Server } from './Server.js';
|
|
3
|
-
export { TokenProvider } from './TokenProvider.js';
|
|
4
|
-
export { LocalFileStorage } from './files/FileStorage.js';
|
|
1
|
+
export { ReplicaType } from '@verdant-web/common';
|
|
2
|
+
export { Server } from './Server.js';
|
|
3
|
+
export { TokenProvider } from './TokenProvider.js';
|
|
4
|
+
export { LocalFileStorage } from './files/FileStorage.js';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sql = "\nCREATE TABLE IF NOT EXISTS ReplicaInfo (\n id TEXT PRIMARY KEY NOT NULL,\n libraryId TEXT NOT NULL,\n clientId TEXT NOT NULL,\n lastSeenWallClockTime INTEGER,\n ackedLogicalTime TEXT,\n type INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE TABLE IF NOT EXISTS OperationHistory (\n libraryId TEXT NOT NULL,\n replicaId TEXT NOT NULL,\n oid TEXT NOT NULL,\n data TEXT NOT NULL,\n timestamp INTEGER NOT NULL,\n PRIMARY KEY (libraryId, replicaId, oid, timestamp)\n);\n\nCREATE TABLE IF NOT EXISTS DocumentBaseline (\n oid TEXT PRIMARY KEY NOT NULL,\n snapshot TEXT,\n timestamp TEXT NOT NULL,\n libraryId TEXT NOT NULL\n);\n";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const sql = `
|
|
2
|
+
CREATE TABLE IF NOT EXISTS ReplicaInfo (
|
|
3
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
4
|
+
libraryId TEXT NOT NULL,
|
|
5
|
+
clientId TEXT NOT NULL,
|
|
6
|
+
lastSeenWallClockTime INTEGER,
|
|
7
|
+
ackedLogicalTime TEXT,
|
|
8
|
+
type INTEGER NOT NULL DEFAULT 0
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
CREATE TABLE IF NOT EXISTS OperationHistory (
|
|
12
|
+
libraryId TEXT NOT NULL,
|
|
13
|
+
replicaId TEXT NOT NULL,
|
|
14
|
+
oid TEXT NOT NULL,
|
|
15
|
+
data TEXT NOT NULL,
|
|
16
|
+
timestamp INTEGER NOT NULL,
|
|
17
|
+
PRIMARY KEY (libraryId, replicaId, oid, timestamp)
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS DocumentBaseline (
|
|
21
|
+
oid TEXT PRIMARY KEY NOT NULL,
|
|
22
|
+
snapshot TEXT,
|
|
23
|
+
timestamp TEXT NOT NULL,
|
|
24
|
+
libraryId TEXT NOT NULL
|
|
25
|
+
);
|
|
26
|
+
`;
|
|
27
|
+
//# sourceMappingURL=v0.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v0.js","sourceRoot":"","sources":["../../../src/migrations/v0.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;CAyBlB,CAAC"}
|