@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.
Files changed (198) hide show
  1. package/dist/esm/ClientConnection.d.ts +1 -0
  2. package/dist/esm/ClientConnection.js.map +1 -1
  3. package/dist/esm/Presence.js.map +1 -1
  4. package/dist/esm/Profiles.js.map +1 -1
  5. package/dist/esm/ReplicaKeepaliveTimers.js.map +1 -1
  6. package/dist/esm/Server.d.ts +15 -11
  7. package/dist/esm/Server.js +29 -30
  8. package/dist/esm/Server.js.map +1 -1
  9. package/dist/esm/ServerLibrary.d.ts +10 -17
  10. package/dist/esm/ServerLibrary.js +151 -127
  11. package/dist/esm/ServerLibrary.js.map +1 -1
  12. package/dist/esm/ServerLibrary.test.js +369 -0
  13. package/dist/esm/ServerLibrary.test.js.map +1 -0
  14. package/dist/esm/TokenVerifier.js.map +1 -1
  15. package/dist/esm/files/FileStorage.js.map +1 -1
  16. package/dist/esm/storage/Storage.d.ts +67 -0
  17. package/dist/esm/storage/Storage.js +2 -0
  18. package/dist/esm/storage/Storage.js.map +1 -0
  19. package/dist/esm/storage/index.d.ts +2 -0
  20. package/dist/esm/storage/index.js +3 -0
  21. package/dist/esm/storage/index.js.map +1 -0
  22. package/dist/esm/storage/sql/SqlBaselines.d.ts +22 -0
  23. package/dist/esm/storage/sql/SqlBaselines.js +101 -0
  24. package/dist/esm/storage/sql/SqlBaselines.js.map +1 -0
  25. package/dist/esm/storage/sql/SqlFileMetadata.d.ts +18 -0
  26. package/dist/esm/storage/sql/SqlFileMetadata.js +69 -0
  27. package/dist/esm/storage/sql/SqlFileMetadata.js.map +1 -0
  28. package/dist/esm/storage/sql/SqlOperations.d.ts +19 -0
  29. package/dist/esm/storage/sql/SqlOperations.js +104 -0
  30. package/dist/esm/storage/sql/SqlOperations.js.map +1 -0
  31. package/dist/esm/storage/sql/SqlReplicas.d.ts +32 -0
  32. package/dist/esm/storage/sql/SqlReplicas.js +163 -0
  33. package/dist/esm/storage/sql/SqlReplicas.js.map +1 -0
  34. package/dist/esm/storage/sql/migrations/v1.d.ts +3 -0
  35. package/dist/esm/storage/sql/migrations/v1.js +59 -0
  36. package/dist/esm/storage/sql/migrations/v1.js.map +1 -0
  37. package/dist/esm/storage/sql/migrations.d.ts +5 -0
  38. package/dist/esm/storage/sql/migrations.js +3 -0
  39. package/dist/esm/storage/sql/migrations.js.map +1 -0
  40. package/dist/esm/storage/sql/sqlStorage.d.ts +5 -0
  41. package/dist/esm/storage/sql/sqlStorage.js +43 -0
  42. package/dist/esm/storage/sql/sqlStorage.js.map +1 -0
  43. package/dist/esm/storage/sql/tables.d.ts +40 -0
  44. package/dist/esm/storage/sql/tables.js +2 -0
  45. package/dist/esm/storage/sql/tables.js.map +1 -0
  46. package/dist/esm/types.d.ts +14 -5
  47. package/package.json +20 -14
  48. package/src/Server.ts +37 -43
  49. package/src/ServerLibrary.test.ts +447 -0
  50. package/src/ServerLibrary.ts +239 -163
  51. package/src/storage/Storage.ts +118 -0
  52. package/src/storage/index.ts +2 -0
  53. package/src/storage/sql/SqlBaselines.ts +141 -0
  54. package/src/storage/sql/SqlFileMetadata.ts +94 -0
  55. package/src/storage/sql/SqlOperations.ts +149 -0
  56. package/src/storage/sql/SqlReplicas.ts +234 -0
  57. package/src/storage/sql/migrations/v1.ts +64 -0
  58. package/src/storage/sql/migrations.ts +3 -0
  59. package/src/storage/sql/sqlStorage.ts +59 -0
  60. package/src/storage/sql/tables.ts +45 -0
  61. package/src/types.ts +15 -4
  62. package/bin/server.mjs +0 -115
  63. package/dist/cjs/Baselines.d.ts +0 -16
  64. package/dist/cjs/Baselines.js +0 -128
  65. package/dist/cjs/Baselines.js.map +0 -1
  66. package/dist/cjs/ClientConnection.d.ts +0 -20
  67. package/dist/cjs/ClientConnection.js +0 -139
  68. package/dist/cjs/ClientConnection.js.map +0 -1
  69. package/dist/cjs/MessageSender.d.ts +0 -5
  70. package/dist/cjs/MessageSender.js +0 -3
  71. package/dist/cjs/MessageSender.js.map +0 -1
  72. package/dist/cjs/OperationHistory.d.ts +0 -36
  73. package/dist/cjs/OperationHistory.js +0 -165
  74. package/dist/cjs/OperationHistory.js.map +0 -1
  75. package/dist/cjs/Presence.d.ts +0 -15
  76. package/dist/cjs/Presence.js +0 -60
  77. package/dist/cjs/Presence.js.map +0 -1
  78. package/dist/cjs/Profiles.d.ts +0 -10
  79. package/dist/cjs/Profiles.js +0 -20
  80. package/dist/cjs/Profiles.js.map +0 -1
  81. package/dist/cjs/ReplicaKeepaliveTimers.d.ts +0 -17
  82. package/dist/cjs/ReplicaKeepaliveTimers.js +0 -31
  83. package/dist/cjs/ReplicaKeepaliveTimers.js.map +0 -1
  84. package/dist/cjs/Replicas.d.ts +0 -25
  85. package/dist/cjs/Replicas.js +0 -196
  86. package/dist/cjs/Replicas.js.map +0 -1
  87. package/dist/cjs/Server.d.ts +0 -167
  88. package/dist/cjs/Server.js +0 -552
  89. package/dist/cjs/Server.js.map +0 -1
  90. package/dist/cjs/ServerLibrary.d.ts +0 -65
  91. package/dist/cjs/ServerLibrary.js +0 -505
  92. package/dist/cjs/ServerLibrary.js.map +0 -1
  93. package/dist/cjs/TokenProvider.d.ts +0 -19
  94. package/dist/cjs/TokenProvider.js +0 -27
  95. package/dist/cjs/TokenProvider.js.map +0 -1
  96. package/dist/cjs/TokenVerifier.d.ts +0 -16
  97. package/dist/cjs/TokenVerifier.js +0 -40
  98. package/dist/cjs/TokenVerifier.js.map +0 -1
  99. package/dist/cjs/files/FileMetadata.d.ts +0 -28
  100. package/dist/cjs/files/FileMetadata.js +0 -69
  101. package/dist/cjs/files/FileMetadata.js.map +0 -1
  102. package/dist/cjs/files/FileStorage.d.ts +0 -35
  103. package/dist/cjs/files/FileStorage.js +0 -72
  104. package/dist/cjs/files/FileStorage.js.map +0 -1
  105. package/dist/cjs/index.d.ts +0 -10
  106. package/dist/cjs/index.js +0 -12
  107. package/dist/cjs/index.js.map +0 -1
  108. package/dist/cjs/migrations/v0.d.ts +0 -1
  109. package/dist/cjs/migrations/v0.js +0 -30
  110. package/dist/cjs/migrations/v0.js.map +0 -1
  111. package/dist/cjs/migrations/v1.d.ts +0 -1
  112. package/dist/cjs/migrations/v1.js +0 -32
  113. package/dist/cjs/migrations/v1.js.map +0 -1
  114. package/dist/cjs/migrations/v2.d.ts +0 -1
  115. package/dist/cjs/migrations/v2.js +0 -29
  116. package/dist/cjs/migrations/v2.js.map +0 -1
  117. package/dist/cjs/migrations/v3.d.ts +0 -1
  118. package/dist/cjs/migrations/v3.js +0 -15
  119. package/dist/cjs/migrations/v3.js.map +0 -1
  120. package/dist/cjs/migrations/v4.d.ts +0 -1
  121. package/dist/cjs/migrations/v4.js +0 -9
  122. package/dist/cjs/migrations/v4.js.map +0 -1
  123. package/dist/cjs/migrations/v5.d.ts +0 -2
  124. package/dist/cjs/migrations/v5.js +0 -37
  125. package/dist/cjs/migrations/v5.js.map +0 -1
  126. package/dist/cjs/migrations/v6.d.ts +0 -1
  127. package/dist/cjs/migrations/v6.js +0 -8
  128. package/dist/cjs/migrations/v6.js.map +0 -1
  129. package/dist/cjs/migrations/v7.d.ts +0 -1
  130. package/dist/cjs/migrations/v7.js +0 -10
  131. package/dist/cjs/migrations/v7.js.map +0 -1
  132. package/dist/cjs/migrations.d.ts +0 -6
  133. package/dist/cjs/migrations.js +0 -72
  134. package/dist/cjs/migrations.js.map +0 -1
  135. package/dist/cjs/migrations.test.js +0 -121
  136. package/dist/cjs/migrations.test.js.map +0 -1
  137. package/dist/cjs/types.d.ts +0 -38
  138. package/dist/cjs/types.js +0 -3
  139. package/dist/cjs/types.js.map +0 -1
  140. package/dist/esm/Baselines.d.ts +0 -16
  141. package/dist/esm/Baselines.js +0 -124
  142. package/dist/esm/Baselines.js.map +0 -1
  143. package/dist/esm/OperationHistory.d.ts +0 -36
  144. package/dist/esm/OperationHistory.js +0 -161
  145. package/dist/esm/OperationHistory.js.map +0 -1
  146. package/dist/esm/Replicas.d.ts +0 -25
  147. package/dist/esm/Replicas.js +0 -192
  148. package/dist/esm/Replicas.js.map +0 -1
  149. package/dist/esm/files/FileMetadata.d.ts +0 -28
  150. package/dist/esm/files/FileMetadata.js +0 -65
  151. package/dist/esm/files/FileMetadata.js.map +0 -1
  152. package/dist/esm/migrations/v0.d.ts +0 -1
  153. package/dist/esm/migrations/v0.js +0 -27
  154. package/dist/esm/migrations/v0.js.map +0 -1
  155. package/dist/esm/migrations/v1.d.ts +0 -1
  156. package/dist/esm/migrations/v1.js +0 -29
  157. package/dist/esm/migrations/v1.js.map +0 -1
  158. package/dist/esm/migrations/v2.d.ts +0 -1
  159. package/dist/esm/migrations/v2.js +0 -26
  160. package/dist/esm/migrations/v2.js.map +0 -1
  161. package/dist/esm/migrations/v3.d.ts +0 -1
  162. package/dist/esm/migrations/v3.js +0 -12
  163. package/dist/esm/migrations/v3.js.map +0 -1
  164. package/dist/esm/migrations/v4.d.ts +0 -1
  165. package/dist/esm/migrations/v4.js +0 -6
  166. package/dist/esm/migrations/v4.js.map +0 -1
  167. package/dist/esm/migrations/v5.d.ts +0 -2
  168. package/dist/esm/migrations/v5.js +0 -33
  169. package/dist/esm/migrations/v5.js.map +0 -1
  170. package/dist/esm/migrations/v6.d.ts +0 -1
  171. package/dist/esm/migrations/v6.js +0 -5
  172. package/dist/esm/migrations/v6.js.map +0 -1
  173. package/dist/esm/migrations/v7.d.ts +0 -1
  174. package/dist/esm/migrations/v7.js +0 -7
  175. package/dist/esm/migrations/v7.js.map +0 -1
  176. package/dist/esm/migrations.d.ts +0 -6
  177. package/dist/esm/migrations.js +0 -45
  178. package/dist/esm/migrations.js.map +0 -1
  179. package/dist/esm/migrations.test.d.ts +0 -1
  180. package/dist/esm/migrations.test.js +0 -116
  181. package/dist/esm/migrations.test.js.map +0 -1
  182. package/dist/tsconfig-cjs.tsbuildinfo +0 -1
  183. package/dist/tsconfig.tsbuildinfo +0 -1
  184. package/src/Baselines.ts +0 -198
  185. package/src/OperationHistory.ts +0 -232
  186. package/src/Replicas.ts +0 -274
  187. package/src/files/FileMetadata.ts +0 -112
  188. package/src/migrations/v0.ts +0 -26
  189. package/src/migrations/v1.ts +0 -28
  190. package/src/migrations/v2.ts +0 -26
  191. package/src/migrations/v3.ts +0 -12
  192. package/src/migrations/v4.ts +0 -6
  193. package/src/migrations/v5.ts +0 -49
  194. package/src/migrations/v6.ts +0 -4
  195. package/src/migrations/v7.ts +0 -6
  196. package/src/migrations.test.ts +0 -133
  197. package/src/migrations.ts +0 -61
  198. /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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../../src/storage/sql/tables.ts"],"names":[],"mappings":""}
@@ -1,21 +1,23 @@
1
1
  import { DocumentBaseline, Operation, ReplicaInfo, ReplicaType } from '@verdant-web/common';
2
- export interface OperationSpec extends Operation {
2
+ export interface StoredOperation extends Operation {
3
3
  serverOrder: number;
4
4
  replicaId: string;
5
5
  }
6
- export interface DocumentBaselineSpec extends Omit<DocumentBaseline<any>, 'snapshot'> {
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 ReplicaInfoSpec extends ReplicaInfo {
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 declare type LibraryInfo<Profile = unknown> = {
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": "2.1.3",
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.2.0"
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
- "typescript": "^4.7.4",
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 -p tsconfig.json && tsc -p tsconfig-cjs.json",
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 { IncomingMessage, Server as HttpServer, ServerResponse } from 'http';
14
- import { WebSocketServer, WebSocket } from 'ws';
15
- import { UserProfileLoader, UserProfiles } from './Profiles.js';
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 internal, { Readable } from 'stream';
25
- import { FileMetadata, FileMetadataConfig } from './files/FileMetadata.js';
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 { migrations } from './migrations.js';
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
- * The path to your SQLite database.
41
+ * Your storage implementation. See the sqlStorage export for a built-in
42
+ * option.
49
43
  */
50
- databaseFile: string;
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?: FileMetadataConfig;
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 fileMetadata;
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
- const db = create(options.databaseFile);
149
- migrations(db);
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
- db,
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.fileMetadata.put(info.libraryId, lofiFileInfo);
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
- const fileInfo = this.fileMetadata.get(info.libraryId, id);
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
- console.warn('HTTP server close timed out');
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
- console.warn('Socket server close timed out');
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.library.close();
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
  /**