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.
Files changed (252) hide show
  1. package/README.md +4 -0
  2. package/dist/index.d.ts +28 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +18 -0
  5. package/dist/src/cache/memory.d.ts +10 -0
  6. package/dist/src/cache/memory.d.ts.map +1 -0
  7. package/dist/src/cache/memory.js +26 -0
  8. package/dist/src/cache/redis.d.ts +14 -0
  9. package/dist/src/cache/redis.d.ts.map +1 -0
  10. package/dist/src/cache/redis.js +40 -0
  11. package/dist/src/cache/types.d.ts +7 -0
  12. package/dist/src/cache/types.d.ts.map +1 -0
  13. package/dist/src/cache/types.js +1 -0
  14. package/dist/src/drive-document-model/constants.d.ts +2 -0
  15. package/dist/src/drive-document-model/constants.d.ts.map +1 -0
  16. package/dist/src/drive-document-model/constants.js +1 -0
  17. package/dist/src/drive-document-model/gen/actions.d.ts +7 -0
  18. package/dist/src/drive-document-model/gen/actions.d.ts.map +1 -0
  19. package/dist/src/drive-document-model/gen/actions.js +2 -0
  20. package/dist/src/drive-document-model/gen/constants.d.ts +7 -0
  21. package/dist/src/drive-document-model/gen/constants.d.ts.map +1 -0
  22. package/dist/src/drive-document-model/gen/constants.js +16 -0
  23. package/dist/src/drive-document-model/gen/creators.d.ts +3 -0
  24. package/dist/src/drive-document-model/gen/creators.d.ts.map +1 -0
  25. package/dist/src/drive-document-model/gen/creators.js +2 -0
  26. package/dist/src/drive-document-model/gen/document-model.d.ts +3 -0
  27. package/dist/src/drive-document-model/gen/document-model.d.ts.map +1 -0
  28. package/dist/src/drive-document-model/gen/document-model.js +210 -0
  29. package/dist/src/drive-document-model/gen/drive/actions.d.ts +12 -0
  30. package/dist/src/drive-document-model/gen/drive/actions.d.ts.map +1 -0
  31. package/dist/src/drive-document-model/gen/drive/actions.js +1 -0
  32. package/dist/src/drive-document-model/gen/drive/creators.d.ts +11 -0
  33. package/dist/src/drive-document-model/gen/drive/creators.d.ts.map +1 -0
  34. package/dist/src/drive-document-model/gen/drive/creators.js +10 -0
  35. package/dist/src/drive-document-model/gen/drive/error.d.ts +2 -0
  36. package/dist/src/drive-document-model/gen/drive/error.d.ts.map +1 -0
  37. package/dist/src/drive-document-model/gen/drive/error.js +1 -0
  38. package/dist/src/drive-document-model/gen/drive/object.d.ts +14 -0
  39. package/dist/src/drive-document-model/gen/drive/object.d.ts.map +1 -0
  40. package/dist/src/drive-document-model/gen/drive/object.js +28 -0
  41. package/dist/src/drive-document-model/gen/drive/operations.d.ts +14 -0
  42. package/dist/src/drive-document-model/gen/drive/operations.d.ts.map +1 -0
  43. package/dist/src/drive-document-model/gen/drive/operations.js +1 -0
  44. package/dist/src/drive-document-model/gen/node/actions.d.ts +11 -0
  45. package/dist/src/drive-document-model/gen/node/actions.d.ts.map +1 -0
  46. package/dist/src/drive-document-model/gen/node/actions.js +1 -0
  47. package/dist/src/drive-document-model/gen/node/creators.d.ts +10 -0
  48. package/dist/src/drive-document-model/gen/node/creators.d.ts.map +1 -0
  49. package/dist/src/drive-document-model/gen/node/creators.js +9 -0
  50. package/dist/src/drive-document-model/gen/node/error.d.ts +2 -0
  51. package/dist/src/drive-document-model/gen/node/error.d.ts.map +1 -0
  52. package/dist/src/drive-document-model/gen/node/error.js +1 -0
  53. package/dist/src/drive-document-model/gen/node/object.d.ts +13 -0
  54. package/dist/src/drive-document-model/gen/node/object.d.ts.map +1 -0
  55. package/dist/src/drive-document-model/gen/node/object.js +25 -0
  56. package/dist/src/drive-document-model/gen/node/operations.d.ts +13 -0
  57. package/dist/src/drive-document-model/gen/node/operations.d.ts.map +1 -0
  58. package/dist/src/drive-document-model/gen/node/operations.js +1 -0
  59. package/dist/src/drive-document-model/gen/object.d.ts +21 -0
  60. package/dist/src/drive-document-model/gen/object.d.ts.map +1 -0
  61. package/dist/src/drive-document-model/gen/object.js +28 -0
  62. package/dist/src/drive-document-model/gen/reducer.d.ts +4 -0
  63. package/dist/src/drive-document-model/gen/reducer.d.ts.map +1 -0
  64. package/dist/src/drive-document-model/gen/reducer.js +74 -0
  65. package/dist/src/drive-document-model/gen/schema/types.d.ts +176 -0
  66. package/dist/src/drive-document-model/gen/schema/types.d.ts.map +1 -0
  67. package/dist/src/drive-document-model/gen/schema/types.js +1 -0
  68. package/dist/src/drive-document-model/gen/schema/zod.d.ts +87 -0
  69. package/dist/src/drive-document-model/gen/schema/zod.d.ts.map +1 -0
  70. package/dist/src/drive-document-model/gen/schema/zod.js +203 -0
  71. package/dist/src/drive-document-model/gen/types.d.ts +9 -0
  72. package/dist/src/drive-document-model/gen/types.d.ts.map +1 -0
  73. package/dist/src/drive-document-model/gen/types.js +1 -0
  74. package/dist/src/drive-document-model/gen/utils.d.ts +10 -0
  75. package/dist/src/drive-document-model/gen/utils.d.ts.map +1 -0
  76. package/dist/src/drive-document-model/gen/utils.js +27 -0
  77. package/dist/src/drive-document-model/index.d.ts +2 -0
  78. package/dist/src/drive-document-model/index.d.ts.map +1 -0
  79. package/dist/src/drive-document-model/index.js +1 -0
  80. package/dist/src/drive-document-model/module.d.ts +3 -0
  81. package/dist/src/drive-document-model/module.d.ts.map +1 -0
  82. package/dist/src/drive-document-model/module.js +12 -0
  83. package/dist/src/drive-document-model/src/reducers/drive.d.ts +8 -0
  84. package/dist/src/drive-document-model/src/reducers/drive.d.ts.map +1 -0
  85. package/dist/src/drive-document-model/src/reducers/drive.js +37 -0
  86. package/dist/src/drive-document-model/src/reducers/node.d.ts +8 -0
  87. package/dist/src/drive-document-model/src/reducers/node.d.ts.map +1 -0
  88. package/dist/src/drive-document-model/src/reducers/node.js +185 -0
  89. package/dist/src/drive-document-model/src/utils.d.ts +34 -0
  90. package/dist/src/drive-document-model/src/utils.d.ts.map +1 -0
  91. package/dist/src/drive-document-model/src/utils.js +146 -0
  92. package/dist/src/queue/base.d.ts +43 -0
  93. package/dist/src/queue/base.d.ts.map +1 -0
  94. package/dist/src/queue/base.js +241 -0
  95. package/dist/src/queue/redis.d.ts +28 -0
  96. package/dist/src/queue/redis.d.ts.map +1 -0
  97. package/dist/src/queue/redis.js +110 -0
  98. package/dist/src/queue/types.d.ts +55 -0
  99. package/dist/src/queue/types.d.ts.map +1 -0
  100. package/dist/src/queue/types.js +6 -0
  101. package/dist/src/read-mode/errors.d.ts +12 -0
  102. package/dist/src/read-mode/errors.d.ts.map +1 -0
  103. package/dist/src/read-mode/errors.js +17 -0
  104. package/dist/src/read-mode/server.d.ts +4 -0
  105. package/dist/src/read-mode/server.d.ts.map +1 -0
  106. package/dist/src/read-mode/server.js +78 -0
  107. package/dist/src/read-mode/service.d.ts +18 -0
  108. package/dist/src/read-mode/service.d.ts.map +1 -0
  109. package/dist/src/read-mode/service.js +112 -0
  110. package/dist/src/read-mode/types.d.ts +35 -0
  111. package/dist/src/read-mode/types.d.ts.map +1 -0
  112. package/dist/src/read-mode/types.js +1 -0
  113. package/dist/src/server/base-server.d.ts +112 -0
  114. package/dist/src/server/base-server.d.ts.map +1 -0
  115. package/dist/src/server/base-server.js +1280 -0
  116. package/dist/src/server/builder.d.ts +30 -0
  117. package/dist/src/server/builder.d.ts.map +1 -0
  118. package/dist/src/server/builder.js +89 -0
  119. package/dist/src/server/constants.d.ts +2 -0
  120. package/dist/src/server/constants.d.ts.map +1 -0
  121. package/dist/src/server/constants.js +1 -0
  122. package/dist/src/server/error.d.ts +30 -0
  123. package/dist/src/server/error.d.ts.map +1 -0
  124. package/dist/src/server/error.js +47 -0
  125. package/dist/src/server/event-emitter.d.ts +8 -0
  126. package/dist/src/server/event-emitter.d.ts.map +1 -0
  127. package/dist/src/server/event-emitter.js +10 -0
  128. package/dist/src/server/listener/index.d.ts +2 -0
  129. package/dist/src/server/listener/index.d.ts.map +1 -0
  130. package/dist/src/server/listener/index.js +1 -0
  131. package/dist/src/server/listener/listener-manager.d.ts +27 -0
  132. package/dist/src/server/listener/listener-manager.d.ts.map +1 -0
  133. package/dist/src/server/listener/listener-manager.js +401 -0
  134. package/dist/src/server/listener/transmitter/factory.d.ts +8 -0
  135. package/dist/src/server/listener/transmitter/factory.d.ts.map +1 -0
  136. package/dist/src/server/listener/transmitter/factory.js +25 -0
  137. package/dist/src/server/listener/transmitter/internal.d.ts +34 -0
  138. package/dist/src/server/listener/transmitter/internal.d.ts.map +1 -0
  139. package/dist/src/server/listener/transmitter/internal.js +87 -0
  140. package/dist/src/server/listener/transmitter/pull-responder.d.ts +38 -0
  141. package/dist/src/server/listener/transmitter/pull-responder.d.ts.map +1 -0
  142. package/dist/src/server/listener/transmitter/pull-responder.js +256 -0
  143. package/dist/src/server/listener/transmitter/switchboard-push.d.ts +9 -0
  144. package/dist/src/server/listener/transmitter/switchboard-push.d.ts.map +1 -0
  145. package/dist/src/server/listener/transmitter/switchboard-push.js +77 -0
  146. package/dist/src/server/listener/transmitter/types.d.ts +20 -0
  147. package/dist/src/server/listener/transmitter/types.d.ts.map +1 -0
  148. package/dist/src/server/listener/transmitter/types.js +1 -0
  149. package/dist/src/server/listener/util.d.ts +2 -0
  150. package/dist/src/server/listener/util.d.ts.map +1 -0
  151. package/dist/src/server/listener/util.js +22 -0
  152. package/dist/src/server/sync-manager.d.ts +30 -0
  153. package/dist/src/server/sync-manager.d.ts.map +1 -0
  154. package/dist/src/server/sync-manager.js +287 -0
  155. package/dist/src/server/types.d.ts +308 -0
  156. package/dist/src/server/types.d.ts.map +1 -0
  157. package/dist/src/server/types.js +12 -0
  158. package/dist/src/server/utils.d.ts +8 -0
  159. package/dist/src/server/utils.d.ts.map +1 -0
  160. package/dist/src/server/utils.js +47 -0
  161. package/dist/src/storage/base.d.ts +36 -0
  162. package/dist/src/storage/base.d.ts.map +1 -0
  163. package/dist/src/storage/base.js +4 -0
  164. package/dist/src/storage/browser.d.ts +36 -0
  165. package/dist/src/storage/browser.d.ts.map +1 -0
  166. package/dist/src/storage/browser.js +155 -0
  167. package/dist/src/storage/filesystem.d.ts +33 -0
  168. package/dist/src/storage/filesystem.d.ts.map +1 -0
  169. package/dist/src/storage/filesystem.js +197 -0
  170. package/dist/src/storage/memory.d.ts +33 -0
  171. package/dist/src/storage/memory.d.ts.map +1 -0
  172. package/dist/src/storage/memory.js +139 -0
  173. package/dist/src/storage/prisma.d.ts +67 -0
  174. package/dist/src/storage/prisma.d.ts.map +1 -0
  175. package/dist/src/storage/prisma.js +445 -0
  176. package/dist/src/storage/sequelize.d.ts +32 -0
  177. package/dist/src/storage/sequelize.d.ts.map +1 -0
  178. package/dist/src/storage/sequelize.js +373 -0
  179. package/dist/src/storage/types.d.ts +43 -0
  180. package/dist/src/storage/types.d.ts.map +1 -0
  181. package/dist/src/storage/types.js +1 -0
  182. package/dist/src/utils/default-drives-manager.d.ts +29 -0
  183. package/dist/src/utils/default-drives-manager.d.ts.map +1 -0
  184. package/dist/src/utils/default-drives-manager.js +208 -0
  185. package/dist/src/utils/graphql.d.ts +34 -0
  186. package/dist/src/utils/graphql.d.ts.map +1 -0
  187. package/dist/src/utils/graphql.js +183 -0
  188. package/dist/src/utils/logger.d.ts +27 -0
  189. package/dist/src/utils/logger.d.ts.map +1 -0
  190. package/dist/src/utils/logger.js +105 -0
  191. package/dist/src/utils/migrations.d.ts +4 -0
  192. package/dist/src/utils/migrations.d.ts.map +1 -0
  193. package/dist/src/utils/migrations.js +41 -0
  194. package/dist/src/utils/misc.d.ts +11 -0
  195. package/dist/src/utils/misc.d.ts.map +1 -0
  196. package/dist/src/utils/misc.js +43 -0
  197. package/dist/src/utils/run-asap.d.ts +12 -0
  198. package/dist/src/utils/run-asap.d.ts.map +1 -0
  199. package/dist/src/utils/run-asap.js +131 -0
  200. package/dist/test/document-helpers/utils.d.ts +8 -0
  201. package/dist/test/document-helpers/utils.d.ts.map +1 -0
  202. package/dist/test/document-helpers/utils.js +21 -0
  203. package/dist/test/utils.d.ts +48 -0
  204. package/dist/test/utils.d.ts.map +1 -0
  205. package/dist/test/utils.js +132 -0
  206. package/dist/test/vitest-setup.d.ts +2 -0
  207. package/dist/test/vitest-setup.d.ts.map +1 -0
  208. package/dist/test/vitest-setup.js +4 -0
  209. package/dist/tsconfig.tsbuildinfo +1 -0
  210. package/dist/vitest.config.d.ts +3 -0
  211. package/dist/vitest.config.d.ts.map +1 -0
  212. package/dist/vitest.config.js +20 -0
  213. package/package.json +20 -38
  214. package/src/cache/index.ts +0 -2
  215. package/src/cache/memory.ts +0 -33
  216. package/src/cache/redis.ts +0 -56
  217. package/src/cache/types.ts +0 -9
  218. package/src/index.ts +0 -4
  219. package/src/queue/base.ts +0 -320
  220. package/src/queue/index.ts +0 -2
  221. package/src/queue/redis.ts +0 -144
  222. package/src/queue/types.ts +0 -79
  223. package/src/read-mode/errors.ts +0 -19
  224. package/src/read-mode/index.ts +0 -125
  225. package/src/read-mode/service.ts +0 -207
  226. package/src/read-mode/types.ts +0 -108
  227. package/src/server/error.ts +0 -70
  228. package/src/server/index.ts +0 -2444
  229. package/src/server/listener/index.ts +0 -2
  230. package/src/server/listener/manager.ts +0 -652
  231. package/src/server/listener/transmitter/index.ts +0 -4
  232. package/src/server/listener/transmitter/internal.ts +0 -143
  233. package/src/server/listener/transmitter/pull-responder.ts +0 -462
  234. package/src/server/listener/transmitter/switchboard-push.ts +0 -125
  235. package/src/server/listener/transmitter/types.ts +0 -27
  236. package/src/server/types.ts +0 -596
  237. package/src/server/utils.ts +0 -82
  238. package/src/storage/base.ts +0 -81
  239. package/src/storage/browser.ts +0 -238
  240. package/src/storage/filesystem.ts +0 -297
  241. package/src/storage/index.ts +0 -2
  242. package/src/storage/memory.ts +0 -211
  243. package/src/storage/prisma.ts +0 -653
  244. package/src/storage/sequelize.ts +0 -498
  245. package/src/storage/types.ts +0 -97
  246. package/src/utils/default-drives-manager.ts +0 -341
  247. package/src/utils/document-helpers.ts +0 -21
  248. package/src/utils/graphql.ts +0 -301
  249. package/src/utils/index.ts +0 -90
  250. package/src/utils/logger.ts +0 -38
  251. package/src/utils/migrations.ts +0 -58
  252. package/src/utils/run-asap.ts +0 -156
@@ -0,0 +1,139 @@
1
+ import { DriveNotFoundError } from "#server/error";
2
+ import { mergeOperations } from "#utils/misc";
3
+ export class MemoryStorage {
4
+ documents;
5
+ drives;
6
+ slugToDriveId = {};
7
+ constructor() {
8
+ this.documents = {};
9
+ this.drives = {};
10
+ }
11
+ checkDocumentExists(drive, id) {
12
+ return Promise.resolve(this.documents[drive][id] !== undefined);
13
+ }
14
+ async getDocuments(drive) {
15
+ return Object.keys(this.documents[drive] ?? {});
16
+ }
17
+ async getDocument(driveId, id) {
18
+ const drive = this.documents[driveId];
19
+ if (!drive) {
20
+ throw new DriveNotFoundError(driveId);
21
+ }
22
+ const document = drive[id];
23
+ if (!document) {
24
+ throw new Error(`Document with id ${id} not found`);
25
+ }
26
+ return document;
27
+ }
28
+ async saveDocument(drive, id, document) {
29
+ this.documents[drive] = this.documents[drive] ?? {};
30
+ this.documents[drive][id] = document;
31
+ }
32
+ async clearStorage() {
33
+ this.documents = {};
34
+ this.drives = {};
35
+ }
36
+ async createDocument(drive, id, document) {
37
+ this.documents[drive] = this.documents[drive] ?? {};
38
+ const { operations, initialState, name, revision, documentType, created, lastModified, clipboard, state, } = document;
39
+ this.documents[drive][id] = {
40
+ operations,
41
+ initialState,
42
+ name,
43
+ revision,
44
+ documentType,
45
+ created,
46
+ lastModified,
47
+ clipboard,
48
+ state,
49
+ };
50
+ }
51
+ async addDocumentOperations(drive, id, operations, header) {
52
+ const document = await this.getDocument(drive, id);
53
+ if (!document) {
54
+ throw new Error(`Document with id ${id} not found`);
55
+ }
56
+ const mergedOperations = mergeOperations(document.operations, operations);
57
+ this.documents[drive][id] = {
58
+ ...document,
59
+ ...header,
60
+ operations: mergedOperations,
61
+ };
62
+ }
63
+ async deleteDocument(drive, id) {
64
+ if (!this.documents[drive]) {
65
+ throw new DriveNotFoundError(drive);
66
+ }
67
+ delete this.documents[drive][id];
68
+ }
69
+ async getDrives() {
70
+ return Object.keys(this.drives);
71
+ }
72
+ async getDrive(id) {
73
+ const drive = this.drives[id];
74
+ if (!drive) {
75
+ throw new DriveNotFoundError(id);
76
+ }
77
+ return drive;
78
+ }
79
+ async getDriveBySlug(slug) {
80
+ const driveId = this.slugToDriveId[slug];
81
+ if (!driveId) {
82
+ throw new Error(`Drive with slug ${slug} not found`);
83
+ }
84
+ return this.getDrive(driveId);
85
+ }
86
+ async createDrive(id, drive) {
87
+ this.drives[id] = drive;
88
+ this.documents[id] = {};
89
+ const { slug } = drive.initialState.state.global;
90
+ if (slug) {
91
+ this.slugToDriveId[slug] = id;
92
+ }
93
+ }
94
+ async addDriveOperations(id, operations, header) {
95
+ const drive = await this.getDrive(id);
96
+ const mergedOperations = mergeOperations(drive.operations, operations);
97
+ this.drives[id] = {
98
+ ...drive,
99
+ ...header,
100
+ operations: mergedOperations,
101
+ };
102
+ }
103
+ async deleteDrive(id) {
104
+ delete this.documents[id];
105
+ delete this.drives[id];
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
+ }
@@ -0,0 +1,67 @@
1
+ import { Prisma, PrismaClient } from "@prisma/client";
2
+ import type { BaseStateFromDocument, DocumentHeader, Operation, OperationFromDocument, PHDocument } from "document-model";
3
+ import { IBackOffOptions } from "exponential-backoff";
4
+ import { DocumentDriveAction, DocumentDriveDocument } from "../drive-document-model/gen/types.js";
5
+ import { SynchronizationUnitQuery } from "../server/types.js";
6
+ import { IDriveStorage, IStorageDelegate } from "./types.js";
7
+ type Transaction = Omit<PrismaClient<Prisma.PrismaClientOptions, never>, "$connect" | "$disconnect" | "$on" | "$transaction" | "$use" | "$extends"> | ExtendedPrismaClient;
8
+ export type PrismaStorageOptions = {
9
+ transactionRetryBackoff?: IBackOffOptions;
10
+ };
11
+ declare function getRetryTransactionsClient<T extends PrismaClient>(prisma: T, backOffOptions?: Partial<IBackOffOptions>): import("@prisma/client/runtime/library").DynamicClientExtensionThis<Prisma.TypeMap<import("@prisma/client/runtime/library").InternalArgs & {
12
+ result: {};
13
+ model: {};
14
+ query: {};
15
+ client: {
16
+ $transaction: () => (...args: Parameters<T["$transaction"]>) => Promise<unknown>;
17
+ };
18
+ }, Prisma.PrismaClientOptions>, Prisma.TypeMapCb, {
19
+ result: {};
20
+ model: {};
21
+ query: {};
22
+ client: {
23
+ $transaction: () => (...args: Parameters<T["$transaction"]>) => Promise<unknown>;
24
+ };
25
+ }, {}>;
26
+ type ExtendedPrismaClient = ReturnType<typeof getRetryTransactionsClient<PrismaClient>>;
27
+ export declare class PrismaStorage implements IDriveStorage {
28
+ private db;
29
+ private delegate;
30
+ constructor(db: PrismaClient, options?: PrismaStorageOptions);
31
+ setStorageDelegate(delegate: IStorageDelegate): void;
32
+ createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
33
+ addDriveOperations(id: string, operations: Operation<DocumentDriveAction>[], header: DocumentHeader): Promise<void>;
34
+ addDriveOperationsWithTransaction(drive: string, callback: (document: DocumentDriveDocument) => Promise<{
35
+ operations: Operation[];
36
+ header: DocumentHeader;
37
+ }>): Promise<never>;
38
+ createDocument(drive: string, id: string, document: PHDocument): Promise<void>;
39
+ private _addDocumentOperations;
40
+ addDocumentOperationsWithTransaction<TDocument extends PHDocument>(drive: string, id: string, callback: (document: TDocument) => Promise<{
41
+ operations: OperationFromDocument<TDocument>[];
42
+ header: DocumentHeader;
43
+ newState?: BaseStateFromDocument<TDocument> | undefined;
44
+ }>): Promise<never>;
45
+ addDocumentOperations(drive: string, id: string, operations: Operation[], header: DocumentHeader): Promise<void>;
46
+ getDocuments(drive: string): Promise<string[]>;
47
+ checkDocumentExists(driveId: string, id: string): Promise<boolean>;
48
+ getDocument<TDocument extends PHDocument>(driveId: string, id: string, tx?: Transaction): Promise<TDocument>;
49
+ deleteDocument(drive: string, id: string): Promise<void>;
50
+ getDrives(): Promise<string[]>;
51
+ getDrive(id: string): Promise<DocumentDriveDocument>;
52
+ getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
53
+ deleteDrive(id: string): Promise<void>;
54
+ getOperationResultingState(driveId: string, documentId: string, index: number, scope: string, branch: string): Promise<string | undefined>;
55
+ getDriveOperationResultingState(drive: string, index: number, scope: string, branch: string): Promise<string | undefined>;
56
+ getSynchronizationUnitsRevision(units: SynchronizationUnitQuery[]): Promise<{
57
+ driveId: string;
58
+ documentId: string;
59
+ scope: string;
60
+ branch: string;
61
+ lastUpdated: string;
62
+ revision: number;
63
+ }[]>;
64
+ migrateOperationSignatures(): Promise<void>;
65
+ }
66
+ export {};
67
+ //# sourceMappingURL=prisma.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma.d.ts","sourceRoot":"","sources":["../../../src/storage/prisma.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,445 @@
1
+ import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
2
+ import { backOff } from "exponential-backoff";
3
+ import { ConflictOperationError, DriveNotFoundError } from "../server/error.js";
4
+ import { logger } from "../utils/logger.js";
5
+ function storageToOperation(op) {
6
+ const operation = {
7
+ id: op.opId || undefined,
8
+ skip: op.skip,
9
+ hash: op.hash,
10
+ index: op.index,
11
+ timestamp: new Date(op.timestamp).toISOString(),
12
+ input: JSON.parse(op.input),
13
+ type: op.type,
14
+ scope: op.scope,
15
+ resultingState: op.resultingState
16
+ ? op.resultingState.toString()
17
+ : undefined,
18
+ attachments: op.attachments,
19
+ };
20
+ if (op.context) {
21
+ operation.context = op.context;
22
+ }
23
+ return operation;
24
+ }
25
+ function getRetryTransactionsClient(prisma, backOffOptions) {
26
+ return prisma.$extends({
27
+ client: {
28
+ $transaction: (...args) => {
29
+ // eslint-disable-next-line prefer-spread
30
+ return backOff(() => prisma.$transaction.apply(prisma, args), {
31
+ retry: (e) => {
32
+ const code = e.code;
33
+ // Retry the transaction only if the error was due to a write conflict or deadlock
34
+ // See: https://www.prisma.io/docs/reference/api-reference/error-reference#p2034
35
+ if (code !== "P2034") {
36
+ logger.error("TRANSACTION ERROR", e);
37
+ }
38
+ return code === "P2034";
39
+ },
40
+ ...backOffOptions,
41
+ });
42
+ },
43
+ },
44
+ });
45
+ }
46
+ export class PrismaStorage {
47
+ db;
48
+ delegate;
49
+ constructor(db, options) {
50
+ const backOffOptions = options?.transactionRetryBackoff;
51
+ this.db = getRetryTransactionsClient(db, {
52
+ ...backOffOptions,
53
+ jitter: backOffOptions?.jitter ?? "full",
54
+ });
55
+ }
56
+ setStorageDelegate(delegate) {
57
+ this.delegate = delegate;
58
+ }
59
+ async createDrive(id, drive) {
60
+ // drive for all drive documents
61
+ await this.createDocument("drives", id, drive);
62
+ await this.db.drive.upsert({
63
+ where: {
64
+ slug: drive.initialState.state.global.slug ?? id,
65
+ },
66
+ create: {
67
+ id: id,
68
+ slug: drive.initialState.state.global.slug ?? id,
69
+ },
70
+ update: {
71
+ id,
72
+ },
73
+ });
74
+ }
75
+ async addDriveOperations(id, operations, header) {
76
+ await this.addDocumentOperations("drives", id, operations, header);
77
+ }
78
+ async addDriveOperationsWithTransaction(drive, callback) {
79
+ return this.addDocumentOperationsWithTransaction("drives", drive, (document) => callback(document));
80
+ }
81
+ async createDocument(drive, id, document) {
82
+ await this.db.document.upsert({
83
+ where: {
84
+ id_driveId: {
85
+ id,
86
+ driveId: drive,
87
+ },
88
+ },
89
+ update: {},
90
+ create: {
91
+ name: document.name,
92
+ documentType: document.documentType,
93
+ driveId: drive,
94
+ initialState: JSON.stringify(document.initialState),
95
+ lastModified: document.lastModified,
96
+ revision: JSON.stringify(document.revision),
97
+ id,
98
+ },
99
+ });
100
+ }
101
+ async _addDocumentOperations(tx, drive, id, operations, header) {
102
+ try {
103
+ await tx.operation.createMany({
104
+ data: operations.map((op) => ({
105
+ driveId: drive,
106
+ documentId: id,
107
+ hash: op.hash,
108
+ index: op.index,
109
+ input: JSON.stringify(op.input),
110
+ timestamp: op.timestamp,
111
+ type: op.type,
112
+ scope: op.scope,
113
+ branch: "main",
114
+ opId: op.id,
115
+ skip: op.skip,
116
+ context: op.context,
117
+ resultingState: op.resultingState
118
+ ? Buffer.from(JSON.stringify(op.resultingState))
119
+ : undefined,
120
+ })),
121
+ });
122
+ await tx.document.updateMany({
123
+ where: {
124
+ id,
125
+ driveId: drive,
126
+ },
127
+ data: {
128
+ lastModified: header.lastModified,
129
+ revision: JSON.stringify(header.revision),
130
+ },
131
+ });
132
+ await Promise.all(operations
133
+ .filter((o) => o.attachments?.length)
134
+ .map((op) => {
135
+ return tx.operation.update({
136
+ where: {
137
+ unique_operation: {
138
+ driveId: drive,
139
+ documentId: id,
140
+ index: op.index,
141
+ scope: op.scope,
142
+ branch: "main",
143
+ },
144
+ },
145
+ data: {
146
+ attachments: {
147
+ createMany: {
148
+ data: op.attachments ?? [],
149
+ },
150
+ },
151
+ },
152
+ });
153
+ }));
154
+ }
155
+ catch (e) {
156
+ // P2002: Unique constraint failed
157
+ // Operation with existing index
158
+ if (e instanceof PrismaClientKnownRequestError && e.code === "P2002") {
159
+ const existingOperation = await this.db.operation.findFirst({
160
+ where: {
161
+ AND: operations.map((op) => ({
162
+ driveId: drive,
163
+ documentId: id,
164
+ scope: op.scope,
165
+ branch: "main",
166
+ index: op.index,
167
+ })),
168
+ },
169
+ });
170
+ const conflictOp = operations.find((op) => existingOperation?.index === op.index &&
171
+ existingOperation.scope === op.scope);
172
+ if (!existingOperation || !conflictOp) {
173
+ console.error(e);
174
+ throw e;
175
+ }
176
+ else {
177
+ throw new ConflictOperationError(storageToOperation(existingOperation), conflictOp);
178
+ }
179
+ }
180
+ else {
181
+ throw e;
182
+ }
183
+ }
184
+ }
185
+ async addDocumentOperationsWithTransaction(drive, id, callback) {
186
+ let result = null;
187
+ await this.db.$transaction(async (tx) => {
188
+ const document = await this.getDocument(drive, id, tx);
189
+ if (!document) {
190
+ throw new Error(`Document with id ${id} not found`);
191
+ }
192
+ result = await callback(document);
193
+ const { operations, header, newState } = result;
194
+ return this._addDocumentOperations(tx, drive, id, operations, header);
195
+ }, { isolationLevel: "Serializable", maxWait: 10000, timeout: 20000 });
196
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
197
+ if (!result) {
198
+ throw new Error("No operations were provided");
199
+ }
200
+ return result;
201
+ }
202
+ async addDocumentOperations(drive, id, operations, header) {
203
+ return this._addDocumentOperations(this.db, drive, id, operations, header);
204
+ }
205
+ async getDocuments(drive) {
206
+ const docs = await this.db.document.findMany({
207
+ select: {
208
+ id: true,
209
+ },
210
+ where: {
211
+ AND: {
212
+ driveId: drive,
213
+ NOT: {
214
+ id: "drives",
215
+ },
216
+ },
217
+ },
218
+ });
219
+ return docs.map((doc) => doc.id);
220
+ }
221
+ async checkDocumentExists(driveId, id) {
222
+ const count = await this.db.document.count({
223
+ where: {
224
+ id: id,
225
+ driveId: driveId,
226
+ },
227
+ });
228
+ return count > 0;
229
+ }
230
+ async getDocument(driveId, id, tx) {
231
+ const prisma = tx ?? this.db;
232
+ const result = await prisma.document.findUnique({
233
+ where: {
234
+ id_driveId: {
235
+ driveId,
236
+ id,
237
+ },
238
+ },
239
+ });
240
+ if (result === null) {
241
+ throw new Error(`Document with id ${id} not found`);
242
+ }
243
+ const cachedOperations = (await this.delegate?.getCachedOperations(driveId, id)) ?? {
244
+ global: [],
245
+ local: [],
246
+ };
247
+ const scopeIndex = Object.keys(cachedOperations).reduceRight((acc, value) => {
248
+ const scope = value;
249
+ const lastIndex = cachedOperations[scope].at(-1)?.index ?? -1;
250
+ acc[scope] = lastIndex;
251
+ return acc;
252
+ }, { global: -1, local: -1 });
253
+ const conditions = Object.entries(scopeIndex).map(([scope, index]) => `("scope" = '${scope}' AND "index" > ${index})`);
254
+ conditions.push(`("scope" NOT IN (${Object.keys(cachedOperations)
255
+ .map((s) => `'${s}'`)
256
+ .join(", ")}))`);
257
+ // retrieves operations with resulting state
258
+ // for the last operation of each scope
259
+ // TODO prevent SQL injection
260
+ const queryOperations = await prisma.$queryRawUnsafe(`WITH ranked_operations AS (
261
+ SELECT
262
+ *,
263
+ ROW_NUMBER() OVER (PARTITION BY scope ORDER BY index DESC) AS rn
264
+ FROM "Operation"
265
+ )
266
+ SELECT
267
+ "id",
268
+ "opId",
269
+ "scope",
270
+ "branch",
271
+ "index",
272
+ "skip",
273
+ "hash",
274
+ "timestamp",
275
+ "input",
276
+ "type",
277
+ "context",
278
+ CASE
279
+ WHEN rn = 1 THEN "resultingState"
280
+ ELSE NULL
281
+ END AS "resultingState"
282
+ FROM ranked_operations
283
+ WHERE "driveId" = $1 AND "documentId" = $2
284
+ AND (${conditions.join(" OR ")})
285
+ ORDER BY scope, index;
286
+ `, driveId, id);
287
+ const operationIds = queryOperations.map((o) => o.id);
288
+ const attachments = await prisma.attachment.findMany({
289
+ where: {
290
+ operationId: {
291
+ in: operationIds,
292
+ },
293
+ },
294
+ });
295
+ // TODO add attachments from cached operations
296
+ const fileRegistry = {};
297
+ const operationsByScope = queryOperations.reduce((acc, operation) => {
298
+ const scope = operation.scope;
299
+ if (!acc[scope]) {
300
+ acc[scope] = [];
301
+ }
302
+ const result = storageToOperation(operation);
303
+ result.attachments = attachments.filter((a) => a.operationId === operation.id);
304
+ result.attachments.forEach(({ hash, ...file }) => {
305
+ fileRegistry[hash] = file;
306
+ });
307
+ acc[scope].push(result);
308
+ return acc;
309
+ }, cachedOperations);
310
+ const dbDoc = result;
311
+ const doc = {
312
+ created: dbDoc.created.toISOString(),
313
+ name: dbDoc.name ? dbDoc.name : "",
314
+ documentType: dbDoc.documentType,
315
+ initialState: JSON.parse(dbDoc.initialState),
316
+ state: undefined,
317
+ lastModified: new Date(dbDoc.lastModified).toISOString(),
318
+ operations: operationsByScope,
319
+ clipboard: [],
320
+ revision: JSON.parse(dbDoc.revision),
321
+ attachments: {},
322
+ };
323
+ return doc;
324
+ }
325
+ async deleteDocument(drive, id) {
326
+ try {
327
+ await this.db.document.deleteMany({
328
+ where: {
329
+ driveId: drive,
330
+ id: id,
331
+ },
332
+ });
333
+ }
334
+ catch (e) {
335
+ const prismaError = e;
336
+ // Ignore Error: P2025: An operation failed because it depends on one or more records that were required but not found.
337
+ if ((prismaError.code && prismaError.code === "P2025") ||
338
+ prismaError.message?.includes("An operation failed because it depends on one or more records that were required but not found.")) {
339
+ return;
340
+ }
341
+ throw e;
342
+ }
343
+ }
344
+ async getDrives() {
345
+ return this.getDocuments("drives");
346
+ }
347
+ async getDrive(id) {
348
+ try {
349
+ const doc = await this.getDocument("drives", id);
350
+ return doc;
351
+ }
352
+ catch (e) {
353
+ logger.error(e);
354
+ throw new DriveNotFoundError(id);
355
+ }
356
+ }
357
+ async getDriveBySlug(slug) {
358
+ const driveEntity = await this.db.drive.findFirst({
359
+ where: {
360
+ slug,
361
+ },
362
+ });
363
+ if (!driveEntity) {
364
+ throw new Error(`Drive with slug ${slug} not found`);
365
+ }
366
+ return this.getDrive(driveEntity.id);
367
+ }
368
+ async deleteDrive(id) {
369
+ // delete drive and associated slug
370
+ await this.db.drive.deleteMany({
371
+ where: {
372
+ id,
373
+ },
374
+ });
375
+ // delete drive document and its operations
376
+ await this.deleteDocument("drives", id);
377
+ // deletes all documents of the drive
378
+ await this.db.document.deleteMany({
379
+ where: {
380
+ driveId: id,
381
+ },
382
+ });
383
+ }
384
+ async getOperationResultingState(driveId, documentId, index, scope, branch) {
385
+ const operation = await this.db.operation.findUnique({
386
+ where: {
387
+ unique_operation: {
388
+ driveId,
389
+ documentId,
390
+ index,
391
+ scope,
392
+ branch,
393
+ },
394
+ },
395
+ });
396
+ return operation?.resultingState?.toString();
397
+ }
398
+ getDriveOperationResultingState(drive, index, scope, branch) {
399
+ return this.getOperationResultingState("drives", drive, index, scope, branch);
400
+ }
401
+ async getSynchronizationUnitsRevision(units) {
402
+ // TODO add branch condition
403
+ const whereClauses = units
404
+ .map((_, index) => {
405
+ return `("driveId" = $${index * 3 + 1} AND "documentId" = $${index * 3 + 2} AND "scope" = $${index * 3 + 3})`;
406
+ })
407
+ .join(" OR ");
408
+ const query = `
409
+ SELECT "driveId", "documentId", "scope", "branch", MAX("timestamp") as "lastUpdated", MAX("index") as revision FROM "Operation"
410
+ WHERE ${whereClauses}
411
+ GROUP BY "driveId", "documentId", "scope", "branch"
412
+ `;
413
+ const params = units
414
+ .map((unit) => [
415
+ unit.documentId ? unit.driveId : "drives",
416
+ unit.documentId || unit.driveId,
417
+ unit.scope,
418
+ ])
419
+ .flat();
420
+ const results = await this.db.$queryRawUnsafe(query, ...params);
421
+ return results.map((row) => ({
422
+ ...row,
423
+ driveId: row.driveId === "drives" ? row.documentId : row.driveId,
424
+ documentId: row.driveId === "drives" ? "" : row.documentId,
425
+ lastUpdated: new Date(row.lastUpdated).toISOString(),
426
+ }));
427
+ }
428
+ // migrates all stored operations from legacy signature to signatures array
429
+ async migrateOperationSignatures() {
430
+ const count = await this.db.$executeRaw `
431
+ UPDATE "Operation"
432
+ SET context = jsonb_set(
433
+ context #- '{signer,signature}', -- Remove the old 'signature' field
434
+ '{signer,signatures}', -- Path to the new 'signatures' field
435
+ CASE
436
+ WHEN context->'signer'->>'signature' = '' THEN '[]'::jsonb
437
+ ELSE to_jsonb(array[context->'signer'->>'signature'])
438
+ END
439
+ )
440
+ WHERE context->'signer' ? 'signature' -- Check if the 'signature' key exists
441
+ `;
442
+ logger.info(`Migrated ${count} operations`);
443
+ return;
444
+ }
445
+ }
@@ -0,0 +1,32 @@
1
+ import { DocumentDriveAction, DocumentDriveDocument } from "#drive-document-model/gen/types";
2
+ import { SynchronizationUnitQuery } from "#server/types";
3
+ import { AttachmentInput, DocumentHeader, Operation, PHDocument } from "document-model";
4
+ import { Options, Sequelize } from "sequelize";
5
+ import { IDriveStorage } from "./types.js";
6
+ export declare class SequelizeStorage implements IDriveStorage {
7
+ private db;
8
+ constructor(options: Options);
9
+ syncModels(): Promise<Sequelize>;
10
+ createDrive(id: string, drive: DocumentDriveDocument): Promise<void>;
11
+ addDriveOperations(id: string, operations: Operation<DocumentDriveAction>[], header: DocumentHeader): Promise<void>;
12
+ createDocument(drive: string, id: string, document: PHDocument): Promise<void>;
13
+ addDocumentOperations(drive: string, id: string, operations: Operation[], header: DocumentHeader): Promise<void>;
14
+ _addDocumentOperationAttachments(driveId: string, documentId: string, operation: Operation, attachments: AttachmentInput[]): Promise<import("sequelize").Model<any, any>[]>;
15
+ getDocuments(drive: string): Promise<string[]>;
16
+ checkDocumentExists(driveId: string, id: string): Promise<boolean>;
17
+ getDocument<TDocument extends PHDocument>(driveId: string, id: string): Promise<TDocument>;
18
+ deleteDocument(drive: string, id: string): Promise<void>;
19
+ getDrives(): Promise<string[]>;
20
+ getDrive(id: string): Promise<DocumentDriveDocument>;
21
+ getDriveBySlug(slug: string): Promise<DocumentDriveDocument>;
22
+ deleteDrive(id: string): Promise<void>;
23
+ getSynchronizationUnitsRevision(units: SynchronizationUnitQuery[]): Promise<{
24
+ driveId: string;
25
+ documentId: string;
26
+ scope: string;
27
+ branch: string;
28
+ lastUpdated: string;
29
+ revision: number;
30
+ }[]>;
31
+ }
32
+ //# sourceMappingURL=sequelize.d.ts.map