document-drive 1.19.1 → 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
@@ -1,143 +0,0 @@
1
- import { Document, Operation, OperationScope } from "document-model/document";
2
- import { logger } from "../../../utils/logger";
3
- import {
4
- GetDocumentOptions,
5
- IBaseDocumentDriveServer,
6
- Listener,
7
- ListenerRevision,
8
- StrandUpdate,
9
- } from "../../types";
10
- import { ITransmitter, StrandUpdateSource } from "./types";
11
- import { InferDocumentOperation } from "../../../read-mode/types";
12
-
13
- export interface IReceiver<
14
- T extends Document = Document,
15
- S extends OperationScope = OperationScope,
16
- > {
17
- onStrands: (strands: InternalTransmitterUpdate<T, S>[]) => Promise<void>;
18
- onDisconnect: () => Promise<void>;
19
- }
20
-
21
- export type InternalOperationUpdate<
22
- D extends Document = Document,
23
- S extends OperationScope = OperationScope,
24
- > = Omit<Operation<InferDocumentOperation<D>>, "scope"> & {
25
- state: D["state"][S];
26
- previousState: D["state"][S];
27
- };
28
-
29
- export type InternalTransmitterUpdate<
30
- D extends Document = Document,
31
- S extends OperationScope = OperationScope,
32
- > = {
33
- driveId: string;
34
- documentId: string;
35
- scope: S;
36
- branch: string;
37
- operations: InternalOperationUpdate<D, S>[];
38
- state: D["state"][S];
39
- };
40
-
41
- export interface IInternalTransmitter extends ITransmitter {
42
- setReceiver(receiver: IReceiver): void;
43
- }
44
-
45
- export class InternalTransmitter implements ITransmitter {
46
- protected drive: IBaseDocumentDriveServer;
47
- protected listener: Listener;
48
- protected receiver: IReceiver | undefined;
49
-
50
- constructor(listener: Listener, drive: IBaseDocumentDriveServer) {
51
- this.listener = listener;
52
- this.drive = drive;
53
- }
54
-
55
- async #buildInternalOperationUpdate(strand: StrandUpdate) {
56
- const operations: InternalOperationUpdate[] = [];
57
- const stateByIndex = new Map<number, unknown>();
58
- const getStateByIndex = async (index: number) => {
59
- const state = stateByIndex.get(index);
60
- if (state) {
61
- return state;
62
- }
63
-
64
- const getDocumentOptions: GetDocumentOptions = {
65
- revisions: {
66
- [strand.scope]: index,
67
- },
68
- checkHashes: false,
69
- };
70
- const document = await (strand.documentId
71
- ? this.drive.getDocument(
72
- strand.driveId,
73
- strand.documentId,
74
- getDocumentOptions,
75
- )
76
- : this.drive.getDrive(strand.driveId, getDocumentOptions));
77
-
78
- if (index < 0) {
79
- stateByIndex.set(index, document.initialState.state[strand.scope]);
80
- } else {
81
- stateByIndex.set(index, document.state[strand.scope]);
82
- }
83
- return stateByIndex.get(index);
84
- };
85
- for (const operation of strand.operations) {
86
- operations.push({
87
- ...operation,
88
- state: await getStateByIndex(operation.index),
89
- previousState: await getStateByIndex(operation.index - 1),
90
- });
91
- }
92
- return operations;
93
- }
94
-
95
- async transmit(
96
- strands: StrandUpdate[],
97
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
98
- _source: StrandUpdateSource,
99
- ): Promise<ListenerRevision[]> {
100
- if (!this.receiver) {
101
- return [];
102
- }
103
-
104
- const updates: InternalTransmitterUpdate[] = [];
105
- for (const strand of strands) {
106
- const operations = await this.#buildInternalOperationUpdate(strand);
107
- const state = operations.at(-1)?.state ?? {};
108
- updates.push({
109
- ...strand,
110
- operations,
111
- state,
112
- });
113
- }
114
- try {
115
- await this.receiver.onStrands(updates);
116
- return strands.map(({ operations, ...s }) => ({
117
- ...s,
118
- status: "SUCCESS",
119
- revision: operations.at(operations.length - 1)?.index ?? -1,
120
- }));
121
- } catch (error) {
122
- logger.error(error);
123
- // TODO check which strand caused an error
124
- return strands.map(({ operations, ...s }) => ({
125
- ...s,
126
- status: "ERROR",
127
- revision: (operations.at(0)?.index ?? 0) - 1,
128
- }));
129
- }
130
- }
131
-
132
- setReceiver(receiver: IReceiver) {
133
- this.receiver = receiver;
134
- }
135
-
136
- async disconnect(): Promise<void> {
137
- await this.receiver?.onDisconnect();
138
- }
139
-
140
- getListener(): Listener {
141
- return this.listener;
142
- }
143
- }
@@ -1,462 +0,0 @@
1
- import { ListenerFilter, Trigger } from "document-model-libs/document-drive";
2
- import { Operation } from "document-model/document";
3
- import { PULL_DRIVE_INTERVAL } from "../..";
4
- import { generateUUID } from "../../../utils";
5
- import { gql, requestGraphql } from "../../../utils/graphql";
6
- import { logger as defaultLogger } from "../../../utils/logger";
7
- import { OperationError } from "../../error";
8
- import {
9
- GetStrandsOptions,
10
- IListenerManager,
11
- IOperationResult,
12
- Listener,
13
- ListenerRevision,
14
- ListenerRevisionWithError,
15
- OperationUpdate,
16
- RemoteDriveOptions,
17
- StrandUpdate,
18
- } from "../../types";
19
- import {
20
- ITransmitter,
21
- PullResponderTrigger,
22
- StrandUpdateSource,
23
- } from "./types";
24
-
25
- const ENABLE_SYNC_DEBUG = false;
26
-
27
- export type OperationUpdateGraphQL = Omit<OperationUpdate, "input"> & {
28
- input: string;
29
- };
30
-
31
- export type PullStrandsGraphQL = {
32
- system: {
33
- sync: {
34
- strands: StrandUpdateGraphQL[];
35
- };
36
- };
37
- };
38
-
39
- export type CancelPullLoop = () => void;
40
-
41
- export type StrandUpdateGraphQL = Omit<StrandUpdate, "operations"> & {
42
- operations: OperationUpdateGraphQL[];
43
- };
44
-
45
- export interface IPullResponderTransmitter extends ITransmitter {
46
- getStrands(options?: GetStrandsOptions): Promise<StrandUpdate[]>;
47
- }
48
-
49
- const STATIC_DEBUG_ID = `[PRT #static]`;
50
-
51
- function staticDebugLog(...data: any[]) {
52
- if (!ENABLE_SYNC_DEBUG) {
53
- return;
54
- }
55
-
56
- if (data.length > 0 && typeof data[0] === "string") {
57
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
58
- console.log(`${STATIC_DEBUG_ID} ${data[0]}`, ...data.slice(1));
59
- } else {
60
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
61
- console.log(STATIC_DEBUG_ID, ...data);
62
- }
63
- }
64
-
65
- export class PullResponderTransmitter implements IPullResponderTransmitter {
66
- private debugID = `[PRT #${Math.floor(Math.random() * 999)}]`;
67
- private listener: Listener;
68
- private manager: IListenerManager;
69
-
70
- constructor(listener: Listener, manager: IListenerManager) {
71
- this.listener = listener;
72
- this.manager = manager;
73
- this.debugLog(`constructor(listener: ${listener.listenerId})`);
74
- }
75
-
76
- private debugLog(...data: any[]) {
77
- if (!ENABLE_SYNC_DEBUG) {
78
- return;
79
- }
80
-
81
- if (data.length > 0 && typeof data[0] === "string") {
82
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
83
- console.log(`${this.debugID} ${data[0]}`, ...data.slice(1));
84
- } else {
85
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
86
- console.log(this.debugID, ...data);
87
- }
88
- }
89
-
90
- getStrands(options?: GetStrandsOptions): Promise<StrandUpdate[]> {
91
- this.debugLog(
92
- `getStrands(drive: ${this.listener.driveId}, listener: ${this.listener.listenerId})`,
93
- );
94
-
95
- return this.manager.getStrands(
96
- this.listener.driveId,
97
- this.listener.listenerId,
98
- options,
99
- );
100
- }
101
-
102
- disconnect(): Promise<void> {
103
- // TODO remove listener from switchboard
104
- return Promise.resolve();
105
- }
106
-
107
- async processAcknowledge(
108
- driveId: string,
109
- listenerId: string,
110
- revisions: ListenerRevision[],
111
- ): Promise<boolean> {
112
- this.debugLog(
113
- `processAcknowledge(drive: ${driveId}, listener: ${listenerId})`,
114
- revisions,
115
- );
116
-
117
- const syncUnits = await this.manager.getListenerSyncUnitIds(
118
- driveId,
119
- listenerId,
120
- );
121
- let success = true;
122
- for (const revision of revisions) {
123
- const syncUnit = syncUnits.find(
124
- (s) =>
125
- s.scope === revision.scope &&
126
- s.branch === revision.branch &&
127
- s.driveId === revision.driveId &&
128
- s.documentId == revision.documentId,
129
- );
130
- if (!syncUnit) {
131
- defaultLogger.warn("Unknown sync unit was acknowledged", revision);
132
- success = false;
133
- continue;
134
- }
135
-
136
- await this.manager.updateListenerRevision(
137
- listenerId,
138
- driveId,
139
- syncUnit.syncId,
140
- revision.revision,
141
- );
142
- }
143
-
144
- return success;
145
- }
146
-
147
- static async registerPullResponder(
148
- driveId: string,
149
- url: string,
150
- filter: ListenerFilter,
151
- ): Promise<Listener["listenerId"]> {
152
- staticDebugLog(`registerPullResponder(url: ${url})`, filter);
153
- // graphql request to switchboard
154
- const result = await requestGraphql<{
155
- registerPullResponderListener: {
156
- listenerId: Listener["listenerId"];
157
- };
158
- }>(
159
- url,
160
- gql`
161
- mutation registerPullResponderListener($filter: InputListenerFilter!) {
162
- registerPullResponderListener(filter: $filter) {
163
- listenerId
164
- }
165
- }
166
- `,
167
- { filter },
168
- );
169
-
170
- const error = result.errors?.at(0);
171
- if (error) {
172
- throw error;
173
- }
174
-
175
- if (!result.registerPullResponderListener) {
176
- throw new Error("Error registering listener");
177
- }
178
-
179
- return result.registerPullResponderListener.listenerId;
180
- }
181
-
182
- static async pullStrands(
183
- driveId: string,
184
- url: string,
185
- listenerId: string,
186
- options?: GetStrandsOptions, // TODO add support for since
187
- ): Promise<StrandUpdate[]> {
188
- staticDebugLog(`pullStrands(url: ${url}, listener: ${listenerId})`);
189
- const result = await requestGraphql<PullStrandsGraphQL>(
190
- url,
191
- gql`
192
- query strands($listenerId: ID!) {
193
- system {
194
- sync {
195
- strands(listenerId: $listenerId) {
196
- driveId
197
- documentId
198
- scope
199
- branch
200
- operations {
201
- id
202
- timestamp
203
- skip
204
- type
205
- input
206
- hash
207
- index
208
- context {
209
- signer {
210
- user {
211
- address
212
- networkId
213
- chainId
214
- }
215
- app {
216
- name
217
- key
218
- }
219
- signatures
220
- }
221
- }
222
- }
223
- }
224
- }
225
- }
226
- }
227
- `,
228
- { listenerId },
229
- );
230
-
231
- const error = result.errors?.at(0);
232
- if (error) {
233
- throw error;
234
- }
235
-
236
- if (!result.system) {
237
- return [];
238
- }
239
-
240
- return result.system.sync.strands.map((s) => ({
241
- ...s,
242
- operations: s.operations.map((o) => ({
243
- ...o,
244
- input: JSON.parse(o.input) as object,
245
- })),
246
- }));
247
- }
248
-
249
- static async acknowledgeStrands(
250
- driveId: string,
251
- url: string,
252
- listenerId: string,
253
- revisions: ListenerRevision[],
254
- ): Promise<boolean> {
255
- staticDebugLog(
256
- `acknowledgeStrands(url: ${url}, listener: ${listenerId})`,
257
- revisions,
258
- );
259
-
260
- const result = await requestGraphql<{ acknowledge: boolean }>(
261
- url,
262
- gql`
263
- mutation acknowledge(
264
- $listenerId: String!
265
- $revisions: [ListenerRevisionInput]
266
- ) {
267
- acknowledge(listenerId: $listenerId, revisions: $revisions)
268
- }
269
- `,
270
- { listenerId, revisions },
271
- );
272
- const error = result.errors?.at(0);
273
- if (error) {
274
- throw error;
275
- }
276
-
277
- if (result.acknowledge === null) {
278
- throw new Error("Error acknowledging strands");
279
- }
280
- return result.acknowledge;
281
- }
282
-
283
- private static async executePull(
284
- driveId: string,
285
- trigger: PullResponderTrigger,
286
- onStrandUpdate: (
287
- strand: StrandUpdate,
288
- source: StrandUpdateSource,
289
- ) => Promise<IOperationResult>,
290
- onError: (error: Error) => void,
291
- onRevisions?: (revisions: ListenerRevisionWithError[]) => void,
292
- onAcknowledge?: (success: boolean) => void,
293
- ) {
294
- staticDebugLog(`executePull(driveId: ${driveId}), trigger:`, trigger);
295
-
296
- try {
297
- const { url, listenerId } = trigger.data;
298
- const strands = await PullResponderTransmitter.pullStrands(
299
- driveId,
300
- url,
301
- listenerId,
302
- // since ?
303
- );
304
-
305
- // if there are no new strands then do nothing
306
- if (!strands.length) {
307
- onRevisions?.([]);
308
- return;
309
- }
310
-
311
- const listenerRevisions: ListenerRevisionWithError[] = [];
312
-
313
- for (const strand of strands) {
314
- const operations: Operation[] = strand.operations.map((op) => ({
315
- ...op,
316
- scope: strand.scope,
317
- branch: strand.branch,
318
- }));
319
-
320
- let error: Error | undefined = undefined;
321
- try {
322
- const result = await onStrandUpdate(strand, {
323
- type: "trigger",
324
- trigger,
325
- });
326
- if (result.error) {
327
- throw result.error;
328
- }
329
- } catch (e) {
330
- error = e as Error;
331
- onError(error);
332
- }
333
-
334
- listenerRevisions.push({
335
- branch: strand.branch,
336
- documentId: strand.documentId || "",
337
- driveId: strand.driveId,
338
- revision: operations.pop()?.index ?? -1,
339
- scope: strand.scope,
340
- status: error
341
- ? error instanceof OperationError
342
- ? error.status
343
- : "ERROR"
344
- : "SUCCESS",
345
- error,
346
- });
347
- }
348
-
349
- onRevisions?.(listenerRevisions);
350
-
351
- await PullResponderTransmitter.acknowledgeStrands(
352
- driveId,
353
- url,
354
- listenerId,
355
- listenerRevisions.map((revision) => {
356
- const { error, ...rest } = revision;
357
- return rest;
358
- }),
359
- )
360
- .then((result) => onAcknowledge?.(result))
361
- .catch((error) => defaultLogger.error("ACK error", error));
362
- } catch (error) {
363
- onError(error as Error);
364
- }
365
- }
366
-
367
- static setupPull(
368
- driveId: string,
369
- trigger: PullResponderTrigger,
370
- onStrandUpdate: (
371
- strand: StrandUpdate,
372
- source: StrandUpdateSource,
373
- ) => Promise<IOperationResult>,
374
- onError: (error: Error) => void,
375
- onRevisions?: (revisions: ListenerRevisionWithError[]) => void,
376
- onAcknowledge?: (success: boolean) => void,
377
- ): CancelPullLoop {
378
- staticDebugLog(`setupPull(drive: ${driveId}), trigger:`, trigger);
379
-
380
- const { interval } = trigger.data;
381
- let loopInterval = PULL_DRIVE_INTERVAL;
382
- if (interval) {
383
- try {
384
- const intervalNumber = parseInt(interval);
385
- if (intervalNumber) {
386
- loopInterval = intervalNumber;
387
- }
388
- } catch {
389
- // ignore invalid interval
390
- }
391
- }
392
-
393
- let isCancelled = false;
394
- let timeout: number | undefined;
395
-
396
- const executeLoop = async () => {
397
- while (!isCancelled) {
398
- staticDebugLog("Execute loop...");
399
- await this.executePull(
400
- driveId,
401
- trigger,
402
- onStrandUpdate,
403
- onError,
404
- onRevisions,
405
- onAcknowledge,
406
- );
407
- await new Promise((resolve) => {
408
- staticDebugLog(`Scheduling next pull in ${loopInterval} ms`);
409
- timeout = setTimeout(resolve, loopInterval) as unknown as number;
410
- });
411
- }
412
- };
413
-
414
- executeLoop().catch(defaultLogger.error);
415
-
416
- return () => {
417
- isCancelled = true;
418
- if (timeout !== undefined) {
419
- clearTimeout(timeout);
420
- }
421
- };
422
- }
423
-
424
- static async createPullResponderTrigger(
425
- driveId: string,
426
- url: string,
427
- options: Pick<RemoteDriveOptions, "pullInterval" | "pullFilter">,
428
- ): Promise<PullResponderTrigger> {
429
- staticDebugLog(
430
- `createPullResponderTrigger(drive: ${driveId}, url: ${url})`,
431
- );
432
-
433
- const { pullFilter, pullInterval } = options;
434
- const listenerId = await PullResponderTransmitter.registerPullResponder(
435
- driveId,
436
- url,
437
- pullFilter ?? {
438
- documentId: ["*"],
439
- documentType: ["*"],
440
- branch: ["*"],
441
- scope: ["*"],
442
- },
443
- );
444
-
445
- const pullTrigger: PullResponderTrigger = {
446
- id: generateUUID(),
447
- type: "PullResponder",
448
- data: {
449
- url,
450
- listenerId,
451
- interval: pullInterval?.toString() ?? "",
452
- },
453
- };
454
- return pullTrigger;
455
- }
456
-
457
- static isPullResponderTrigger(
458
- trigger: Trigger,
459
- ): trigger is PullResponderTrigger {
460
- return trigger.type === "PullResponder";
461
- }
462
- }