document-drive 1.19.1 → 1.20.1

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,256 @@
1
+ import { childLogger, generateUUID, } from "document-drive";
2
+ import { PULL_DRIVE_INTERVAL } from "#server/constants";
3
+ import { OperationError } from "#server/error";
4
+ import { requestGraphql } from "#utils/graphql";
5
+ import { gql } from "graphql-request";
6
+ const ENABLE_SYNC_DEBUG = false;
7
+ export class PullResponderTransmitter {
8
+ static staticLogger = childLogger([
9
+ "PullResponderTransmitter",
10
+ "static",
11
+ ]);
12
+ logger = childLogger([
13
+ "PullResponderTransmitter",
14
+ Math.floor(Math.random() * 999).toString(),
15
+ ]);
16
+ listener;
17
+ manager;
18
+ constructor(listener, manager) {
19
+ this.listener = listener;
20
+ this.manager = manager;
21
+ this.logger.verbose(`constructor(listener: ${listener.listenerId})`);
22
+ }
23
+ getStrands(options) {
24
+ this.logger.verbose(`getStrands(drive: ${this.listener.driveId}, listener: ${this.listener.listenerId})`);
25
+ return this.manager.getStrands(this.listener.driveId, this.listener.listenerId, options);
26
+ }
27
+ disconnect() {
28
+ // TODO remove listener from switchboard
29
+ return Promise.resolve();
30
+ }
31
+ async processAcknowledge(driveId, listenerId, revisions) {
32
+ this.logger.verbose(`processAcknowledge(drive: ${driveId}, listener: ${listenerId})`, revisions);
33
+ const syncUnits = await this.manager.getListenerSyncUnitIds(driveId, listenerId);
34
+ let success = true;
35
+ for (const revision of revisions) {
36
+ const syncUnit = syncUnits.find((s) => s.scope === revision.scope &&
37
+ s.branch === revision.branch &&
38
+ s.driveId === revision.driveId &&
39
+ s.documentId == revision.documentId);
40
+ if (!syncUnit) {
41
+ this.logger.warn("Unknown sync unit was acknowledged", revision);
42
+ success = false;
43
+ continue;
44
+ }
45
+ await this.manager.updateListenerRevision(listenerId, driveId, syncUnit.syncId, revision.revision);
46
+ }
47
+ return success;
48
+ }
49
+ static async registerPullResponder(driveId, url, filter) {
50
+ PullResponderTransmitter.staticLogger.verbose(`registerPullResponder(url: ${url})`, filter);
51
+ // graphql request to switchboard
52
+ const result = await requestGraphql(url, gql `
53
+ mutation registerPullResponderListener($filter: InputListenerFilter!) {
54
+ registerPullResponderListener(filter: $filter) {
55
+ listenerId
56
+ }
57
+ }
58
+ `, { filter });
59
+ const error = result.errors?.at(0);
60
+ if (error) {
61
+ throw error;
62
+ }
63
+ if (!result.registerPullResponderListener) {
64
+ throw new Error("Error registering listener");
65
+ }
66
+ return result.registerPullResponderListener.listenerId;
67
+ }
68
+ static async pullStrands(driveId, url, listenerId, options) {
69
+ this.staticLogger.verbose(`pullStrands(url: ${url}, listener: ${listenerId})`);
70
+ const result = await requestGraphql(url, gql `
71
+ query strands($listenerId: ID!) {
72
+ system {
73
+ sync {
74
+ strands(listenerId: $listenerId) {
75
+ driveId
76
+ documentId
77
+ scope
78
+ branch
79
+ operations {
80
+ id
81
+ timestamp
82
+ skip
83
+ type
84
+ input
85
+ hash
86
+ index
87
+ context {
88
+ signer {
89
+ user {
90
+ address
91
+ networkId
92
+ chainId
93
+ }
94
+ app {
95
+ name
96
+ key
97
+ }
98
+ signatures
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ `, { listenerId });
107
+ const error = result.errors?.at(0);
108
+ if (error) {
109
+ throw error;
110
+ }
111
+ if (!result.system) {
112
+ return [];
113
+ }
114
+ return result.system.sync.strands.map((s) => ({
115
+ ...s,
116
+ operations: s.operations.map((o) => ({
117
+ ...o,
118
+ input: JSON.parse(o.input),
119
+ })),
120
+ }));
121
+ }
122
+ static async acknowledgeStrands(driveId, url, listenerId, revisions) {
123
+ this.staticLogger.verbose(`acknowledgeStrands(url: ${url}, listener: ${listenerId})`, revisions);
124
+ const result = await requestGraphql(url, gql `
125
+ mutation acknowledge(
126
+ $listenerId: String!
127
+ $revisions: [ListenerRevisionInput]
128
+ ) {
129
+ acknowledge(listenerId: $listenerId, revisions: $revisions)
130
+ }
131
+ `, { listenerId, revisions });
132
+ const error = result.errors?.at(0);
133
+ if (error) {
134
+ throw error;
135
+ }
136
+ if (result.acknowledge === null) {
137
+ throw new Error("Error acknowledging strands");
138
+ }
139
+ return result.acknowledge;
140
+ }
141
+ static async executePull(driveId, trigger, onStrandUpdate, onError, onRevisions, onAcknowledge) {
142
+ this.staticLogger.verbose(`executePull(driveId: ${driveId}), trigger:`, trigger);
143
+ try {
144
+ const { url, listenerId } = trigger.data;
145
+ const strands = await PullResponderTransmitter.pullStrands(driveId, url, listenerId);
146
+ // if there are no new strands then do nothing
147
+ if (!strands.length) {
148
+ onRevisions?.([]);
149
+ return;
150
+ }
151
+ const listenerRevisions = [];
152
+ for (const strand of strands) {
153
+ const operations = strand.operations.map((op) => ({
154
+ ...op,
155
+ scope: strand.scope,
156
+ branch: strand.branch,
157
+ }));
158
+ let error = undefined;
159
+ try {
160
+ const result = await onStrandUpdate(strand, {
161
+ type: "trigger",
162
+ trigger,
163
+ });
164
+ if (result.error) {
165
+ throw result.error;
166
+ }
167
+ }
168
+ catch (e) {
169
+ error = e;
170
+ onError(error);
171
+ }
172
+ listenerRevisions.push({
173
+ branch: strand.branch,
174
+ documentId: strand.documentId || "",
175
+ driveId: strand.driveId,
176
+ revision: operations.pop()?.index ?? -1,
177
+ scope: strand.scope,
178
+ status: error
179
+ ? error instanceof OperationError
180
+ ? error.status
181
+ : "ERROR"
182
+ : "SUCCESS",
183
+ error,
184
+ });
185
+ }
186
+ onRevisions?.(listenerRevisions);
187
+ await PullResponderTransmitter.acknowledgeStrands(driveId, url, listenerId, listenerRevisions.map((revision) => {
188
+ const { error, ...rest } = revision;
189
+ return rest;
190
+ }))
191
+ .then((result) => onAcknowledge?.(result))
192
+ .catch((error) => this.staticLogger.error("ACK error", error));
193
+ }
194
+ catch (error) {
195
+ onError(error);
196
+ }
197
+ }
198
+ static setupPull(driveId, trigger, onStrandUpdate, onError, onRevisions, onAcknowledge) {
199
+ this.staticLogger.verbose(`setupPull(drive: ${driveId}), trigger:`, trigger);
200
+ const { interval } = trigger.data;
201
+ let loopInterval = PULL_DRIVE_INTERVAL;
202
+ if (interval) {
203
+ try {
204
+ const intervalNumber = parseInt(interval);
205
+ if (intervalNumber) {
206
+ loopInterval = intervalNumber;
207
+ }
208
+ }
209
+ catch {
210
+ // ignore invalid interval
211
+ }
212
+ }
213
+ let isCancelled = false;
214
+ let timeout;
215
+ const executeLoop = async () => {
216
+ while (!isCancelled) {
217
+ this.staticLogger.verbose("Execute loop...");
218
+ await this.executePull(driveId, trigger, onStrandUpdate, onError, onRevisions, onAcknowledge);
219
+ await new Promise((resolve) => {
220
+ this.staticLogger.verbose(`Scheduling next pull in ${loopInterval} ms`);
221
+ timeout = setTimeout(resolve, loopInterval);
222
+ });
223
+ }
224
+ };
225
+ executeLoop().catch(this.staticLogger.error);
226
+ return () => {
227
+ isCancelled = true;
228
+ if (timeout !== undefined) {
229
+ clearTimeout(timeout);
230
+ }
231
+ };
232
+ }
233
+ static async createPullResponderTrigger(driveId, url, options) {
234
+ this.staticLogger.verbose(`createPullResponderTrigger(drive: ${driveId}, url: ${url})`);
235
+ const { pullFilter, pullInterval } = options;
236
+ const listenerId = await PullResponderTransmitter.registerPullResponder(driveId, url, pullFilter ?? {
237
+ documentId: ["*"],
238
+ documentType: ["*"],
239
+ branch: ["*"],
240
+ scope: ["*"],
241
+ });
242
+ const pullTrigger = {
243
+ id: generateUUID(),
244
+ type: "PullResponder",
245
+ data: {
246
+ url,
247
+ listenerId,
248
+ interval: pullInterval?.toString() ?? "",
249
+ },
250
+ };
251
+ return pullTrigger;
252
+ }
253
+ static isPullResponderTrigger(trigger) {
254
+ return trigger.type === "PullResponder";
255
+ }
256
+ }
@@ -0,0 +1,9 @@
1
+ import { ListenerRevision, StrandUpdate } from "#server/types";
2
+ import { ITransmitter, StrandUpdateSource } from "./types.js";
3
+ export declare class SwitchboardPushTransmitter implements ITransmitter {
4
+ private targetURL;
5
+ private logger;
6
+ constructor(targetURL: string);
7
+ transmit(strands: StrandUpdate[], source: StrandUpdateSource): Promise<ListenerRevision[]>;
8
+ }
9
+ //# sourceMappingURL=switchboard-push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switchboard-push.d.ts","sourceRoot":"","sources":["../../../../../src/server/listener/transmitter/switchboard-push.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAI9D,qBAAa,0BAA2B,YAAW,YAAY;IAC7D,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAGX;gBAES,SAAS,EAAE,MAAM;IAIvB,QAAQ,CACZ,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,gBAAgB,EAAE,CAAC;CA2F/B"}
@@ -0,0 +1,77 @@
1
+ import stringify from "json-stringify-deterministic";
2
+ import { gql, requestGraphql } from "#utils/graphql";
3
+ import { childLogger } from "#utils/logger";
4
+ const SYNC_OPS_BATCH_LIMIT = 10;
5
+ export class SwitchboardPushTransmitter {
6
+ targetURL;
7
+ logger = childLogger([
8
+ "SwitchboardPushTransmitter",
9
+ Math.floor(Math.random() * 999).toString(),
10
+ ]);
11
+ constructor(targetURL) {
12
+ this.targetURL = targetURL;
13
+ }
14
+ async transmit(strands, source) {
15
+ if (source.type === "trigger" &&
16
+ source.trigger.data?.url === this.targetURL) {
17
+ this.logger.verbose(`Cutting trigger loop from ${this.targetURL}.`);
18
+ return strands.map((strand) => ({
19
+ driveId: strand.driveId,
20
+ documentId: strand.documentId,
21
+ scope: strand.scope,
22
+ branch: strand.branch,
23
+ status: "SUCCESS",
24
+ revision: strand.operations.at(-1)?.index ?? -1,
25
+ }));
26
+ }
27
+ const culledStrands = [];
28
+ let opsCounter = 0;
29
+ for (let s = 0; opsCounter <= SYNC_OPS_BATCH_LIMIT && s < strands.length; s++) {
30
+ const currentStrand = strands.at(s);
31
+ if (!currentStrand) {
32
+ break;
33
+ }
34
+ const newOps = Math.min(SYNC_OPS_BATCH_LIMIT - opsCounter, currentStrand.operations.length);
35
+ culledStrands.push({
36
+ ...currentStrand,
37
+ operations: currentStrand.operations.slice(0, newOps),
38
+ });
39
+ opsCounter += newOps;
40
+ }
41
+ this.logger.verbose(` Total update: [${strands.map((s) => s.operations.length).join(", ")}] operations`);
42
+ this.logger.verbose(`Culled update: [${culledStrands.map((s) => s.operations.length).join(", ")}] operations`);
43
+ // Send Graphql mutation to switchboard
44
+ try {
45
+ const { pushUpdates } = await requestGraphql(this.targetURL, gql `
46
+ mutation pushUpdates($strands: [InputStrandUpdate!]) {
47
+ pushUpdates(strands: $strands) {
48
+ driveId
49
+ documentId
50
+ scope
51
+ branch
52
+ status
53
+ revision
54
+ error
55
+ }
56
+ }
57
+ `, {
58
+ strands: culledStrands.map((strand) => ({
59
+ ...strand,
60
+ operations: strand.operations.map((op) => ({
61
+ ...op,
62
+ input: stringify(op.input),
63
+ })),
64
+ })),
65
+ });
66
+ if (!pushUpdates) {
67
+ throw new Error("Couldn't update listener revision");
68
+ }
69
+ return pushUpdates;
70
+ }
71
+ catch (e) {
72
+ this.logger.error(e);
73
+ throw e;
74
+ }
75
+ return [];
76
+ }
77
+ }
@@ -0,0 +1,20 @@
1
+ import { PullResponderTriggerData, Trigger } from "#drive-document-model/gen/types";
2
+ import { ListenerRevision, StrandUpdate } from "#server/types";
3
+ export type StrandUpdateSource = {
4
+ type: "local";
5
+ } | {
6
+ type: "trigger";
7
+ trigger: Trigger;
8
+ };
9
+ export interface ITransmitter {
10
+ transmit?(strands: StrandUpdate[], source: StrandUpdateSource): Promise<ListenerRevision[]>;
11
+ disconnect?(): Promise<void>;
12
+ }
13
+ export interface InternalTransmitterService extends ITransmitter {
14
+ getName(): string;
15
+ }
16
+ export type PullResponderTrigger = Omit<Trigger, "data" | "type"> & {
17
+ data: PullResponderTriggerData;
18
+ type: "PullResponder";
19
+ };
20
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/server/listener/transmitter/types.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,OAAO,EACR,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/D,MAAM,MAAM,kBAAkB,GAC1B;IACE,IAAI,EAAE,OAAO,CAAC;CACf,GACD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,CACP,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC/B,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AACD,MAAM,WAAW,0BAA2B,SAAQ,YAAY;IAC9D,OAAO,IAAI,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG;IAClE,IAAI,EAAE,wBAAwB,CAAC;IAC/B,IAAI,EAAE,eAAe,CAAC;CACvB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function debounce<T extends unknown[], R>(func: (...args: T) => Promise<R>, delay?: number): (immediate: boolean, ...args: T) => Promise<R>;
2
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/server/listener/util.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,EAC7C,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAChC,KAAK,SAAM,eAGQ,OAAO,WAAW,CAAC,gBAkBvC"}
@@ -0,0 +1,22 @@
1
+ export function debounce(func, delay = 250) {
2
+ let timer;
3
+ return (immediate, ...args) => {
4
+ if (timer) {
5
+ clearTimeout(timer);
6
+ }
7
+ return new Promise((resolve, reject) => {
8
+ if (immediate) {
9
+ func(...args)
10
+ .then(resolve)
11
+ .catch(reject);
12
+ }
13
+ else {
14
+ timer = setTimeout(() => {
15
+ func(...args)
16
+ .then(resolve)
17
+ .catch(reject);
18
+ }, delay);
19
+ }
20
+ });
21
+ };
22
+ }
@@ -0,0 +1,30 @@
1
+ import { ICache } from "#cache/types";
2
+ import { DocumentDriveDocument } from "#drive-document-model/gen/types";
3
+ import { IDriveStorage } from "#storage/types";
4
+ import { DocumentModelModule } from "document-model";
5
+ import { SynchronizationUnitNotFoundError } from "./error.js";
6
+ import { GetStrandsOptions, IEventEmitter, ISynchronizationManager, OperationUpdate, SyncStatus, SyncUnitStatusObject, SynchronizationUnit, SynchronizationUnitQuery } from "./types.js";
7
+ export default class SynchronizationManager implements ISynchronizationManager {
8
+ private readonly storage;
9
+ private readonly cache;
10
+ private readonly documentModelModules;
11
+ private readonly eventEmitter?;
12
+ private syncStatus;
13
+ constructor(storage: IDriveStorage, cache: ICache, documentModelModules: DocumentModelModule[], eventEmitter?: IEventEmitter | undefined);
14
+ getSynchronizationUnits(driveId: string, documentId?: string[], scope?: string[], branch?: string[], documentType?: string[]): Promise<SynchronizationUnit[]>;
15
+ getSynchronizationUnitsRevision(driveId: string, syncUnitsQuery: SynchronizationUnitQuery[]): Promise<SynchronizationUnit[]>;
16
+ getSynchronizationUnitsIds(driveId: string, documentId?: string[], scope?: string[], branch?: string[], documentType?: string[]): Promise<SynchronizationUnitQuery[]>;
17
+ getSynchronizationUnitIdInfo(driveId: string, syncId: string): Promise<SynchronizationUnitQuery | undefined>;
18
+ getSynchronizationUnit(driveId: string, syncId: string): Promise<SynchronizationUnit | undefined>;
19
+ getOperationData(driveId: string, syncId: string, filter: GetStrandsOptions): Promise<OperationUpdate[]>;
20
+ private getDrive;
21
+ private getDocument;
22
+ private _buildDocument;
23
+ private getDocumentModelModule;
24
+ getCombinedSyncUnitStatus(syncUnitStatus: SyncUnitStatusObject): SyncStatus;
25
+ getSyncStatus(syncUnitId: string): SyncStatus | SynchronizationUnitNotFoundError;
26
+ updateSyncStatus(syncUnitId: string, status: Partial<SyncUnitStatusObject> | null, error?: Error): void;
27
+ private initSyncStatus;
28
+ initializeDriveSyncStatus(driveId: string, drive: DocumentDriveDocument): Promise<void>;
29
+ }
30
+ //# sourceMappingURL=sync-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-manager.d.ts","sourceRoot":"","sources":["../../../src/server/sync-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EACL,qBAAqB,EAEtB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EACL,mBAAmB,EAKpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,uBAAuB,EACvB,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,OAAO,OAAO,sBAAuB,YAAW,uBAAuB;IAI1E,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IANhC,OAAO,CAAC,UAAU,CAA2C;gBAG1C,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,oBAAoB,EAAE,mBAAmB,EAAE,EAC3C,YAAY,CAAC,EAAE,aAAa,YAAA;IAGzC,uBAAuB,CAC3B,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,MAAM,CAAC,EAAE,MAAM,EAAE,EACjB,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAe3B,+BAA+B,CACnC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,wBAAwB,EAAE,GACzC,OAAO,CAAC,mBAAmB,EAAE,CAAC;IA6B3B,0BAA0B,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,MAAM,CAAC,EAAE,MAAM,EAAE,EACjB,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAmEhC,4BAA4B,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC;IA6B1C,sBAAsB,CAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IA0BrC,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,eAAe,EAAE,CAAC;YA2Cf,QAAQ;YAiBR,WAAW;IAgBzB,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,sBAAsB;IAU9B,yBAAyB,CAAC,cAAc,EAAE,oBAAoB,GAAG,UAAU;IAoB3E,aAAa,CACX,UAAU,EAAE,MAAM,GACjB,UAAU,GAAG,gCAAgC;IAWhD,gBAAgB,CACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI,EAC5C,KAAK,CAAC,EAAE,KAAK,GACZ,IAAI;IAiDP,OAAO,CAAC,cAAc;IAyBhB,yBAAyB,CAC7B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,IAAI,CAAC;CAejB"}