@verdant-web/server 2.1.3 → 3.0.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/esm/ClientConnection.d.ts +1 -0
- package/dist/esm/ClientConnection.js.map +1 -1
- package/dist/esm/Presence.js.map +1 -1
- package/dist/esm/Profiles.js.map +1 -1
- package/dist/esm/ReplicaKeepaliveTimers.js.map +1 -1
- package/dist/esm/Server.d.ts +15 -11
- package/dist/esm/Server.js +29 -30
- package/dist/esm/Server.js.map +1 -1
- package/dist/esm/ServerLibrary.d.ts +10 -17
- package/dist/esm/ServerLibrary.js +151 -127
- package/dist/esm/ServerLibrary.js.map +1 -1
- package/dist/esm/ServerLibrary.test.js +369 -0
- package/dist/esm/ServerLibrary.test.js.map +1 -0
- package/dist/esm/TokenVerifier.js.map +1 -1
- package/dist/esm/files/FileStorage.js.map +1 -1
- package/dist/esm/storage/Storage.d.ts +67 -0
- package/dist/esm/storage/Storage.js +2 -0
- package/dist/esm/storage/Storage.js.map +1 -0
- package/dist/esm/storage/index.d.ts +2 -0
- package/dist/esm/storage/index.js +3 -0
- package/dist/esm/storage/index.js.map +1 -0
- package/dist/esm/storage/sql/SqlBaselines.d.ts +22 -0
- package/dist/esm/storage/sql/SqlBaselines.js +101 -0
- package/dist/esm/storage/sql/SqlBaselines.js.map +1 -0
- package/dist/esm/storage/sql/SqlFileMetadata.d.ts +18 -0
- package/dist/esm/storage/sql/SqlFileMetadata.js +69 -0
- package/dist/esm/storage/sql/SqlFileMetadata.js.map +1 -0
- package/dist/esm/storage/sql/SqlOperations.d.ts +19 -0
- package/dist/esm/storage/sql/SqlOperations.js +104 -0
- package/dist/esm/storage/sql/SqlOperations.js.map +1 -0
- package/dist/esm/storage/sql/SqlReplicas.d.ts +32 -0
- package/dist/esm/storage/sql/SqlReplicas.js +163 -0
- package/dist/esm/storage/sql/SqlReplicas.js.map +1 -0
- package/dist/esm/storage/sql/migrations/v1.d.ts +3 -0
- package/dist/esm/storage/sql/migrations/v1.js +59 -0
- package/dist/esm/storage/sql/migrations/v1.js.map +1 -0
- package/dist/esm/storage/sql/migrations.d.ts +5 -0
- package/dist/esm/storage/sql/migrations.js +3 -0
- package/dist/esm/storage/sql/migrations.js.map +1 -0
- package/dist/esm/storage/sql/sqlStorage.d.ts +5 -0
- package/dist/esm/storage/sql/sqlStorage.js +43 -0
- package/dist/esm/storage/sql/sqlStorage.js.map +1 -0
- package/dist/esm/storage/sql/tables.d.ts +40 -0
- package/dist/esm/storage/sql/tables.js +2 -0
- package/dist/esm/storage/sql/tables.js.map +1 -0
- package/dist/esm/types.d.ts +14 -5
- package/package.json +20 -14
- package/src/Server.ts +37 -43
- package/src/ServerLibrary.test.ts +447 -0
- package/src/ServerLibrary.ts +239 -163
- package/src/storage/Storage.ts +118 -0
- package/src/storage/index.ts +2 -0
- package/src/storage/sql/SqlBaselines.ts +141 -0
- package/src/storage/sql/SqlFileMetadata.ts +94 -0
- package/src/storage/sql/SqlOperations.ts +149 -0
- package/src/storage/sql/SqlReplicas.ts +234 -0
- package/src/storage/sql/migrations/v1.ts +64 -0
- package/src/storage/sql/migrations.ts +3 -0
- package/src/storage/sql/sqlStorage.ts +59 -0
- package/src/storage/sql/tables.ts +45 -0
- package/src/types.ts +15 -4
- package/bin/server.mjs +0 -115
- package/dist/cjs/Baselines.d.ts +0 -16
- package/dist/cjs/Baselines.js +0 -128
- package/dist/cjs/Baselines.js.map +0 -1
- package/dist/cjs/ClientConnection.d.ts +0 -20
- package/dist/cjs/ClientConnection.js +0 -139
- package/dist/cjs/ClientConnection.js.map +0 -1
- package/dist/cjs/MessageSender.d.ts +0 -5
- package/dist/cjs/MessageSender.js +0 -3
- package/dist/cjs/MessageSender.js.map +0 -1
- package/dist/cjs/OperationHistory.d.ts +0 -36
- package/dist/cjs/OperationHistory.js +0 -165
- package/dist/cjs/OperationHistory.js.map +0 -1
- package/dist/cjs/Presence.d.ts +0 -15
- package/dist/cjs/Presence.js +0 -60
- package/dist/cjs/Presence.js.map +0 -1
- package/dist/cjs/Profiles.d.ts +0 -10
- package/dist/cjs/Profiles.js +0 -20
- package/dist/cjs/Profiles.js.map +0 -1
- package/dist/cjs/ReplicaKeepaliveTimers.d.ts +0 -17
- package/dist/cjs/ReplicaKeepaliveTimers.js +0 -31
- package/dist/cjs/ReplicaKeepaliveTimers.js.map +0 -1
- package/dist/cjs/Replicas.d.ts +0 -25
- package/dist/cjs/Replicas.js +0 -196
- package/dist/cjs/Replicas.js.map +0 -1
- package/dist/cjs/Server.d.ts +0 -167
- package/dist/cjs/Server.js +0 -552
- package/dist/cjs/Server.js.map +0 -1
- package/dist/cjs/ServerLibrary.d.ts +0 -65
- package/dist/cjs/ServerLibrary.js +0 -505
- package/dist/cjs/ServerLibrary.js.map +0 -1
- package/dist/cjs/TokenProvider.d.ts +0 -19
- package/dist/cjs/TokenProvider.js +0 -27
- package/dist/cjs/TokenProvider.js.map +0 -1
- package/dist/cjs/TokenVerifier.d.ts +0 -16
- package/dist/cjs/TokenVerifier.js +0 -40
- package/dist/cjs/TokenVerifier.js.map +0 -1
- package/dist/cjs/files/FileMetadata.d.ts +0 -28
- package/dist/cjs/files/FileMetadata.js +0 -69
- package/dist/cjs/files/FileMetadata.js.map +0 -1
- package/dist/cjs/files/FileStorage.d.ts +0 -35
- package/dist/cjs/files/FileStorage.js +0 -72
- package/dist/cjs/files/FileStorage.js.map +0 -1
- package/dist/cjs/index.d.ts +0 -10
- package/dist/cjs/index.js +0 -12
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/migrations/v0.d.ts +0 -1
- package/dist/cjs/migrations/v0.js +0 -30
- package/dist/cjs/migrations/v0.js.map +0 -1
- package/dist/cjs/migrations/v1.d.ts +0 -1
- package/dist/cjs/migrations/v1.js +0 -32
- package/dist/cjs/migrations/v1.js.map +0 -1
- package/dist/cjs/migrations/v2.d.ts +0 -1
- package/dist/cjs/migrations/v2.js +0 -29
- package/dist/cjs/migrations/v2.js.map +0 -1
- package/dist/cjs/migrations/v3.d.ts +0 -1
- package/dist/cjs/migrations/v3.js +0 -15
- package/dist/cjs/migrations/v3.js.map +0 -1
- package/dist/cjs/migrations/v4.d.ts +0 -1
- package/dist/cjs/migrations/v4.js +0 -9
- package/dist/cjs/migrations/v4.js.map +0 -1
- package/dist/cjs/migrations/v5.d.ts +0 -2
- package/dist/cjs/migrations/v5.js +0 -37
- package/dist/cjs/migrations/v5.js.map +0 -1
- package/dist/cjs/migrations/v6.d.ts +0 -1
- package/dist/cjs/migrations/v6.js +0 -8
- package/dist/cjs/migrations/v6.js.map +0 -1
- package/dist/cjs/migrations/v7.d.ts +0 -1
- package/dist/cjs/migrations/v7.js +0 -10
- package/dist/cjs/migrations/v7.js.map +0 -1
- package/dist/cjs/migrations.d.ts +0 -6
- package/dist/cjs/migrations.js +0 -72
- package/dist/cjs/migrations.js.map +0 -1
- package/dist/cjs/migrations.test.js +0 -121
- package/dist/cjs/migrations.test.js.map +0 -1
- package/dist/cjs/types.d.ts +0 -38
- package/dist/cjs/types.js +0 -3
- package/dist/cjs/types.js.map +0 -1
- package/dist/esm/Baselines.d.ts +0 -16
- package/dist/esm/Baselines.js +0 -124
- package/dist/esm/Baselines.js.map +0 -1
- package/dist/esm/OperationHistory.d.ts +0 -36
- package/dist/esm/OperationHistory.js +0 -161
- package/dist/esm/OperationHistory.js.map +0 -1
- package/dist/esm/Replicas.d.ts +0 -25
- package/dist/esm/Replicas.js +0 -192
- package/dist/esm/Replicas.js.map +0 -1
- package/dist/esm/files/FileMetadata.d.ts +0 -28
- package/dist/esm/files/FileMetadata.js +0 -65
- package/dist/esm/files/FileMetadata.js.map +0 -1
- package/dist/esm/migrations/v0.d.ts +0 -1
- package/dist/esm/migrations/v0.js +0 -27
- package/dist/esm/migrations/v0.js.map +0 -1
- package/dist/esm/migrations/v1.d.ts +0 -1
- package/dist/esm/migrations/v1.js +0 -29
- package/dist/esm/migrations/v1.js.map +0 -1
- package/dist/esm/migrations/v2.d.ts +0 -1
- package/dist/esm/migrations/v2.js +0 -26
- package/dist/esm/migrations/v2.js.map +0 -1
- package/dist/esm/migrations/v3.d.ts +0 -1
- package/dist/esm/migrations/v3.js +0 -12
- package/dist/esm/migrations/v3.js.map +0 -1
- package/dist/esm/migrations/v4.d.ts +0 -1
- package/dist/esm/migrations/v4.js +0 -6
- package/dist/esm/migrations/v4.js.map +0 -1
- package/dist/esm/migrations/v5.d.ts +0 -2
- package/dist/esm/migrations/v5.js +0 -33
- package/dist/esm/migrations/v5.js.map +0 -1
- package/dist/esm/migrations/v6.d.ts +0 -1
- package/dist/esm/migrations/v6.js +0 -5
- package/dist/esm/migrations/v6.js.map +0 -1
- package/dist/esm/migrations/v7.d.ts +0 -1
- package/dist/esm/migrations/v7.js +0 -7
- package/dist/esm/migrations/v7.js.map +0 -1
- package/dist/esm/migrations.d.ts +0 -6
- package/dist/esm/migrations.js +0 -45
- package/dist/esm/migrations.js.map +0 -1
- package/dist/esm/migrations.test.d.ts +0 -1
- package/dist/esm/migrations.test.js +0 -116
- package/dist/esm/migrations.test.js.map +0 -1
- package/dist/tsconfig-cjs.tsbuildinfo +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/Baselines.ts +0 -198
- package/src/OperationHistory.ts +0 -232
- package/src/Replicas.ts +0 -274
- package/src/files/FileMetadata.ts +0 -112
- package/src/migrations/v0.ts +0 -26
- package/src/migrations/v1.ts +0 -28
- package/src/migrations/v2.ts +0 -26
- package/src/migrations/v3.ts +0 -12
- package/src/migrations/v4.ts +0 -6
- package/src/migrations/v5.ts +0 -49
- package/src/migrations/v6.ts +0 -4
- package/src/migrations/v7.ts +0 -6
- package/src/migrations.test.ts +0 -133
- package/src/migrations.ts +0 -61
- /package/dist/{cjs/migrations.test.d.ts → esm/ServerLibrary.test.d.ts} +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { Kysely, SqliteDialect } from 'kysely';
|
|
3
|
+
import { SqlBaselines } from './SqlBaselines.js';
|
|
4
|
+
import { SqlOperations } from './SqlOperations.js';
|
|
5
|
+
import { SqlReplicas } from './SqlReplicas.js';
|
|
6
|
+
import { SqlFileMetadata } from './SqlFileMetadata.js';
|
|
7
|
+
import { migrateToLatest } from '@a-type/kysely';
|
|
8
|
+
import migrations from './migrations.js';
|
|
9
|
+
export const sqlStorage = ({ databaseFile: dbFile, skipMigrations, }) => {
|
|
10
|
+
const db = new Kysely({
|
|
11
|
+
dialect: new SqliteDialect({
|
|
12
|
+
database: new Database(dbFile),
|
|
13
|
+
}),
|
|
14
|
+
});
|
|
15
|
+
let ready = Promise.resolve(undefined);
|
|
16
|
+
if (!skipMigrations) {
|
|
17
|
+
ready = migrateToLatest(db, migrations);
|
|
18
|
+
}
|
|
19
|
+
return (options) => {
|
|
20
|
+
const baselines = new SqlBaselines(db, 'sqlite');
|
|
21
|
+
const operations = new SqlOperations(db, 'sqlite');
|
|
22
|
+
const replicas = new SqlReplicas(db, options.replicaTruancyMinutes, 'sqlite');
|
|
23
|
+
const fileMetadata = new SqlFileMetadata(db, options.fileDeleteExpirationDays, 'sqlite');
|
|
24
|
+
const close = async () => {
|
|
25
|
+
storage.open = false;
|
|
26
|
+
await db.destroy();
|
|
27
|
+
};
|
|
28
|
+
const storage = {
|
|
29
|
+
baselines,
|
|
30
|
+
operations,
|
|
31
|
+
replicas,
|
|
32
|
+
fileMetadata,
|
|
33
|
+
close,
|
|
34
|
+
open: false,
|
|
35
|
+
ready,
|
|
36
|
+
};
|
|
37
|
+
ready.then(() => {
|
|
38
|
+
storage.open = true;
|
|
39
|
+
});
|
|
40
|
+
return storage;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=sqlStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlStorage.js","sourceRoot":"","sources":["../../../../src/storage/sql/sqlStorage.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,UAAU,MAAM,iBAAiB,CAAC;AAEzC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAC1B,YAAY,EAAE,MAAM,EACpB,cAAc,GAId,EAAkB,EAAE;IACpB,MAAM,EAAE,GAAG,IAAI,MAAM,CAAgB;QACpC,OAAO,EAAE,IAAI,aAAa,CAAC;YAC1B,QAAQ,EAAE,IAAI,QAAQ,CAAC,MAAM,CAAC;SAC9B,CAAC;KACF,CAAC,CAAC;IACH,IAAI,KAAK,GAAG,OAAO,CAAC,OAAO,CAAO,SAAS,CAAC,CAAC;IAC7C,IAAI,CAAC,cAAc,EAAE,CAAC;QACrB,KAAK,GAAG,eAAe,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACjD,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,IAAI,WAAW,CAC/B,EAAE,EACF,OAAO,CAAC,qBAAqB,EAC7B,QAAQ,CACR,CAAC;QACF,MAAM,YAAY,GAAG,IAAI,eAAe,CACvC,EAAE,EACF,OAAO,CAAC,wBAAwB,EAChC,QAAQ,CACR,CAAC;QACF,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;YACxB,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC;YACrB,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;QACpB,CAAC,CAAC;QACF,MAAM,OAAO,GAAG;YACf,SAAS;YACT,UAAU;YACV,QAAQ;YACR,YAAY;YACZ,KAAK;YACL,IAAI,EAAE,KAAK;YACX,KAAK;SACL,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YACf,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IAChB,CAAC,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
+
import { Generated, Selectable } from 'kysely';
|
|
3
|
+
export interface Database {
|
|
4
|
+
OperationHistory: OperationHistoryTable;
|
|
5
|
+
DocumentBaseline: DocumentBaselineTable;
|
|
6
|
+
ReplicaInfo: ReplicaInfoTable;
|
|
7
|
+
FileMetadata: FileMetadataTable;
|
|
8
|
+
}
|
|
9
|
+
export interface OperationHistoryTable {
|
|
10
|
+
oid: string;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
data: string;
|
|
13
|
+
serverOrder: number;
|
|
14
|
+
replicaId: string;
|
|
15
|
+
libraryId: string;
|
|
16
|
+
}
|
|
17
|
+
export type OperationHistoryRow = Selectable<OperationHistoryTable>;
|
|
18
|
+
export interface DocumentBaselineTable {
|
|
19
|
+
oid: string;
|
|
20
|
+
snapshot: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
libraryId: string;
|
|
23
|
+
}
|
|
24
|
+
export type DocumentBaselineRow = Selectable<DocumentBaselineTable>;
|
|
25
|
+
export interface ReplicaInfoTable {
|
|
26
|
+
id: string;
|
|
27
|
+
libraryId: string;
|
|
28
|
+
clientId: string;
|
|
29
|
+
lastSeenWallClockTime: number | null;
|
|
30
|
+
ackedLogicalTime: string | null;
|
|
31
|
+
type: ReplicaType;
|
|
32
|
+
ackedServerOrder: Generated<number>;
|
|
33
|
+
}
|
|
34
|
+
export interface FileMetadataTable {
|
|
35
|
+
libraryId: string;
|
|
36
|
+
fileId: string;
|
|
37
|
+
name: string;
|
|
38
|
+
type: string;
|
|
39
|
+
pendingDeleteAt: number | null;
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../../src/storage/sql/tables.ts"],"names":[],"mappings":""}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { DocumentBaseline, Operation, ReplicaInfo, ReplicaType } from '@verdant-web/common';
|
|
2
|
-
export interface
|
|
2
|
+
export interface StoredOperation extends Operation {
|
|
3
3
|
serverOrder: number;
|
|
4
4
|
replicaId: string;
|
|
5
5
|
}
|
|
6
|
-
export interface
|
|
6
|
+
export interface StoredDocumentBaseline extends Omit<DocumentBaseline<any>, 'snapshot'> {
|
|
7
7
|
snapshot: string;
|
|
8
8
|
libraryId: string;
|
|
9
|
-
serverOrder: number;
|
|
10
9
|
}
|
|
11
|
-
export interface
|
|
10
|
+
export interface HydratedDocumentBaseline extends DocumentBaseline<any> {
|
|
11
|
+
libraryId: string;
|
|
12
|
+
}
|
|
13
|
+
export interface StoredReplicaInfo extends ReplicaInfo {
|
|
12
14
|
libraryId: string;
|
|
13
15
|
clientId: string;
|
|
14
16
|
lastSeenWallClockTime: number | null;
|
|
15
17
|
type: ReplicaType;
|
|
16
18
|
ackedServerOrder: number;
|
|
17
19
|
}
|
|
18
|
-
export
|
|
20
|
+
export type LibraryInfo<Profile = unknown> = {
|
|
19
21
|
id: string;
|
|
20
22
|
replicas: {
|
|
21
23
|
id: string;
|
|
@@ -30,6 +32,13 @@ export declare type LibraryInfo<Profile = unknown> = {
|
|
|
30
32
|
baselinesCount: number;
|
|
31
33
|
globalAck: string | null;
|
|
32
34
|
};
|
|
35
|
+
export interface FileMetadata {
|
|
36
|
+
libraryId: string;
|
|
37
|
+
fileId: string;
|
|
38
|
+
name: string;
|
|
39
|
+
type: string;
|
|
40
|
+
pendingDeleteAt: number | null;
|
|
41
|
+
}
|
|
33
42
|
declare global {
|
|
34
43
|
interface File {
|
|
35
44
|
readonly lastModified: number;
|
package/package.json
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdant-web/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"access": "public",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/cjs/index.js",
|
|
7
|
-
"module": "./dist/esm/index.js",
|
|
8
6
|
"bin": {
|
|
9
7
|
"verdant-server": "./bin/server.mjs"
|
|
10
8
|
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/esm/index.js",
|
|
12
|
+
"types": "./dist/esm/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./storage": {
|
|
15
|
+
"import": "./dist/esm/storage/index.js",
|
|
16
|
+
"types": "./dist/esm/storage/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
11
19
|
"publishConfig": {
|
|
12
20
|
"access": "public"
|
|
13
21
|
},
|
|
@@ -16,13 +24,16 @@
|
|
|
16
24
|
"src/"
|
|
17
25
|
],
|
|
18
26
|
"dependencies": {
|
|
27
|
+
"@a-type/kysely": "^1.0.1",
|
|
19
28
|
"async-lock": "^1.4.0",
|
|
20
29
|
"better-sqlite3": "^7.6.2",
|
|
21
30
|
"busboy": "^1.6.0",
|
|
22
31
|
"jsonwebtoken": "^8.5.1",
|
|
32
|
+
"kysely": "0.27.3",
|
|
33
|
+
"kysely-plugin-serialize": "^0.5.7",
|
|
23
34
|
"minimist": "^1.2.8",
|
|
24
35
|
"ws": "^8.9.0",
|
|
25
|
-
"@verdant-web/common": "2.
|
|
36
|
+
"@verdant-web/common": "2.3.0"
|
|
26
37
|
},
|
|
27
38
|
"devDependencies": {
|
|
28
39
|
"@types/async-lock": "^1.3.0",
|
|
@@ -31,20 +42,15 @@
|
|
|
31
42
|
"@types/jsonwebtoken": "^8.5.9",
|
|
32
43
|
"@types/node": "^20.11.5",
|
|
33
44
|
"@types/ws": "^8.5.3",
|
|
34
|
-
"
|
|
45
|
+
"cross-env": "7.0.3",
|
|
46
|
+
"typescript": "^5.4.2",
|
|
35
47
|
"vitest": "^1.1.0"
|
|
36
48
|
},
|
|
37
49
|
"scripts": {
|
|
38
|
-
"build": "tsc
|
|
50
|
+
"build": "tsc",
|
|
39
51
|
"prepublish": "pnpm run build",
|
|
40
52
|
"link": "pnpm link --global",
|
|
41
|
-
"test": "vitest"
|
|
42
|
-
|
|
43
|
-
"types": "./dist/esm/index.d.ts",
|
|
44
|
-
"exports": {
|
|
45
|
-
".": {
|
|
46
|
-
"import": "./dist/esm/index.js",
|
|
47
|
-
"require": "./dist/cjs/index.js"
|
|
48
|
-
}
|
|
53
|
+
"test": "vitest",
|
|
54
|
+
"perf": "pnpm run build && cross-env VERDANT_LOG=false node ./perf/perf.mjs"
|
|
49
55
|
}
|
|
50
56
|
}
|
package/src/Server.ts
CHANGED
|
@@ -9,28 +9,21 @@ import {
|
|
|
9
9
|
ServerMessage,
|
|
10
10
|
VerdantError,
|
|
11
11
|
} from '@verdant-web/common';
|
|
12
|
+
import busboy from 'busboy';
|
|
12
13
|
import EventEmitter from 'events';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import create from 'better-sqlite3';
|
|
17
|
-
import { MessageSender } from './MessageSender.js';
|
|
14
|
+
import { Server as HttpServer, IncomingMessage, ServerResponse } from 'http';
|
|
15
|
+
import { TransformStream } from 'node:stream/web';
|
|
16
|
+
import internal, { Readable } from 'stream';
|
|
18
17
|
import { URL } from 'url';
|
|
18
|
+
import { WebSocket, WebSocketServer } from 'ws';
|
|
19
19
|
import { ClientConnectionManager } from './ClientConnection.js';
|
|
20
|
-
import { ReplicaKeepaliveTimers } from './ReplicaKeepaliveTimers.js';
|
|
21
|
-
import { TokenInfo, TokenVerifier } from './TokenVerifier.js';
|
|
22
|
-
import busboy from 'busboy';
|
|
23
20
|
import { FileInfo, FileStorage } from './files/FileStorage.js';
|
|
24
|
-
import
|
|
25
|
-
import {
|
|
21
|
+
import { MessageSender } from './MessageSender.js';
|
|
22
|
+
import { UserProfileLoader, UserProfiles } from './Profiles.js';
|
|
23
|
+
import { ReplicaKeepaliveTimers } from './ReplicaKeepaliveTimers.js';
|
|
26
24
|
import { ServerLibrary } from './ServerLibrary.js';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
ReadableStream,
|
|
30
|
-
ReadableWritablePair,
|
|
31
|
-
TransformStream,
|
|
32
|
-
WritableStream,
|
|
33
|
-
} from 'node:stream/web';
|
|
25
|
+
import { TokenInfo, TokenVerifier } from './TokenVerifier.js';
|
|
26
|
+
import { Storage, StorageFactory } from './storage/Storage.js';
|
|
34
27
|
|
|
35
28
|
export interface ServerOptions {
|
|
36
29
|
/**
|
|
@@ -45,9 +38,10 @@ export interface ServerOptions {
|
|
|
45
38
|
*/
|
|
46
39
|
tokenSecret: string;
|
|
47
40
|
/**
|
|
48
|
-
*
|
|
41
|
+
* Your storage implementation. See the sqlStorage export for a built-in
|
|
42
|
+
* option.
|
|
49
43
|
*/
|
|
50
|
-
|
|
44
|
+
storage: StorageFactory;
|
|
51
45
|
/**
|
|
52
46
|
* Optionally provide an implementation of the UserProfiles interface to look up
|
|
53
47
|
* static user profile data to use in persistence. This data is considered trusted
|
|
@@ -76,7 +70,7 @@ export interface ServerOptions {
|
|
|
76
70
|
* of this library.
|
|
77
71
|
*/
|
|
78
72
|
fileStorage?: FileStorage;
|
|
79
|
-
fileConfig?:
|
|
73
|
+
fileConfig?: { deleteExpirationDays?: number };
|
|
80
74
|
}
|
|
81
75
|
|
|
82
76
|
class DefaultProfiles implements UserProfiles<{ id: string }> {
|
|
@@ -117,7 +111,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
117
111
|
private httpServer!: HttpServer;
|
|
118
112
|
private wss: WebSocketServer;
|
|
119
113
|
private fileStorage?: FileStorage;
|
|
120
|
-
private
|
|
114
|
+
private storage: Storage;
|
|
121
115
|
private library;
|
|
122
116
|
|
|
123
117
|
private clientConnections = new ClientConnectionManager();
|
|
@@ -144,23 +138,20 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
144
138
|
});
|
|
145
139
|
|
|
146
140
|
this.fileStorage = options.fileStorage;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
this.fileMetadata = new FileMetadata(db, options.fileConfig);
|
|
141
|
+
this.storage = options.storage({
|
|
142
|
+
fileDeleteExpirationDays: options.fileConfig?.deleteExpirationDays ?? 14,
|
|
143
|
+
replicaTruancyMinutes: options.replicaTruancyMinutes || 60 * 24 * 14,
|
|
144
|
+
});
|
|
152
145
|
|
|
153
146
|
this.library = new ServerLibrary({
|
|
154
|
-
|
|
147
|
+
storage: this.storage,
|
|
155
148
|
sender: this,
|
|
156
149
|
profiles: new UserProfileLoader(
|
|
157
150
|
options.profiles || new DefaultProfiles(),
|
|
158
151
|
),
|
|
159
152
|
log: this.log,
|
|
160
153
|
disableRebasing: options.disableRebasing,
|
|
161
|
-
fileMetadata: this.fileMetadata,
|
|
162
154
|
fileStorage: this.fileStorage,
|
|
163
|
-
replicaTruancyMinutes: options.replicaTruancyMinutes || 60 * 24 * 14,
|
|
164
155
|
});
|
|
165
156
|
|
|
166
157
|
this.library.subscribe(
|
|
@@ -396,7 +387,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
396
387
|
|
|
397
388
|
private writeErrorResponse(e: unknown, res: ServerResponse) {
|
|
398
389
|
this.emit('error', e);
|
|
399
|
-
this.log('Error handling request', e);
|
|
390
|
+
this.log('error', 'Error handling request', e);
|
|
400
391
|
|
|
401
392
|
if (e instanceof VerdantError) {
|
|
402
393
|
// write error data to response
|
|
@@ -416,7 +407,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
416
407
|
// for fetch-style
|
|
417
408
|
private getErrorResponse(e: unknown) {
|
|
418
409
|
this.emit('error', e);
|
|
419
|
-
this.log('Error handling request', e);
|
|
410
|
+
this.log('error', 'Error handling request', e);
|
|
420
411
|
|
|
421
412
|
if (e instanceof VerdantError) {
|
|
422
413
|
return new Response(JSON.stringify(e.toResponse()), {
|
|
@@ -467,7 +458,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
467
458
|
headers: req.headers,
|
|
468
459
|
id,
|
|
469
460
|
});
|
|
470
|
-
this.log('File upload complete');
|
|
461
|
+
this.log('info', 'File upload complete', id);
|
|
471
462
|
res.writeHead(200);
|
|
472
463
|
res.write(JSON.stringify({ success: true }));
|
|
473
464
|
res.end();
|
|
@@ -525,7 +516,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
525
516
|
headers: headersAsRecord,
|
|
526
517
|
id,
|
|
527
518
|
});
|
|
528
|
-
this.log('File upload complete');
|
|
519
|
+
this.log('info', 'File upload complete', id);
|
|
529
520
|
return new Response(JSON.stringify({ success: true }), {
|
|
530
521
|
status: 200,
|
|
531
522
|
headers: {
|
|
@@ -571,7 +562,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
571
562
|
return new Promise((resolve, reject) => {
|
|
572
563
|
const bb = busboy({ headers });
|
|
573
564
|
|
|
574
|
-
bb.on('file', (fieldName, stream, fileInfo) => {
|
|
565
|
+
bb.on('file', async (fieldName, stream, fileInfo) => {
|
|
575
566
|
// too many 'info's....
|
|
576
567
|
const lofiFileInfo: FileInfo = {
|
|
577
568
|
id,
|
|
@@ -581,7 +572,8 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
581
572
|
};
|
|
582
573
|
// write metadata to storage
|
|
583
574
|
try {
|
|
584
|
-
this.
|
|
575
|
+
await this.storage.ready;
|
|
576
|
+
await this.storage.fileMetadata.put(info.libraryId, lofiFileInfo);
|
|
585
577
|
fs.put(stream, lofiFileInfo);
|
|
586
578
|
} catch (e) {
|
|
587
579
|
reject(e);
|
|
@@ -620,7 +612,8 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
620
612
|
): Promise<FileData> => {
|
|
621
613
|
const fs = this.getFileStorageOrThrow();
|
|
622
614
|
|
|
623
|
-
|
|
615
|
+
await this.storage.ready;
|
|
616
|
+
const fileInfo = await this.storage.fileMetadata.get(info.libraryId, id);
|
|
624
617
|
if (!fileInfo) {
|
|
625
618
|
throw new VerdantError(
|
|
626
619
|
VerdantError.Code.NotFound,
|
|
@@ -663,6 +656,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
663
656
|
message: ClientMessage,
|
|
664
657
|
) => {
|
|
665
658
|
this.log(
|
|
659
|
+
'debug',
|
|
666
660
|
'Got message from user',
|
|
667
661
|
info.userId,
|
|
668
662
|
', library',
|
|
@@ -715,26 +709,26 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
715
709
|
await Promise.all([
|
|
716
710
|
new Promise<void>((resolve) => {
|
|
717
711
|
setTimeout(() => {
|
|
718
|
-
|
|
712
|
+
this.log('warn', 'HTTP server close timed out');
|
|
719
713
|
resolve();
|
|
720
714
|
}, 5 * 1000);
|
|
721
715
|
this.httpServer.close(() => {
|
|
722
716
|
resolve();
|
|
723
|
-
this.log('HTTP server closed');
|
|
717
|
+
this.log('info', 'HTTP server closed');
|
|
724
718
|
});
|
|
725
719
|
}),
|
|
726
720
|
new Promise<void>((resolve) => {
|
|
727
721
|
setTimeout(() => {
|
|
728
|
-
|
|
722
|
+
this.log('warn', 'Socket server close timed out');
|
|
729
723
|
resolve();
|
|
730
724
|
}, 5 * 1000);
|
|
731
725
|
this.wss.close(() => {
|
|
732
726
|
resolve();
|
|
733
|
-
this.log('Socket server closed');
|
|
727
|
+
this.log('info', 'Socket server closed');
|
|
734
728
|
});
|
|
735
729
|
}),
|
|
736
730
|
]);
|
|
737
|
-
this.
|
|
731
|
+
await this.storage.close();
|
|
738
732
|
};
|
|
739
733
|
|
|
740
734
|
/**
|
|
@@ -749,7 +743,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
749
743
|
// disconnect all clients
|
|
750
744
|
this.clientConnections.disconnectAll(libraryId);
|
|
751
745
|
this.library.destroy(libraryId);
|
|
752
|
-
this.log('Evicted library', libraryId);
|
|
746
|
+
this.log('info', 'Evicted library', libraryId);
|
|
753
747
|
};
|
|
754
748
|
|
|
755
749
|
/**
|
|
@@ -775,7 +769,7 @@ export class Server extends EventEmitter implements MessageSender {
|
|
|
775
769
|
*/
|
|
776
770
|
evictUser = (libraryId: string, userId: string) => {
|
|
777
771
|
this.library.evictUser(libraryId, userId);
|
|
778
|
-
this.log('Evicted user', userId, 'from library', libraryId);
|
|
772
|
+
this.log('info', 'Evicted user', userId, 'from library', libraryId);
|
|
779
773
|
};
|
|
780
774
|
|
|
781
775
|
/**
|