document-drive 6.0.0-dev.105 → 6.0.0-dev.106

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 (564) hide show
  1. package/dist/chunk-CX61OkwL.mjs +16 -0
  2. package/dist/index-HOJm2mt2.d.mts +205 -0
  3. package/dist/index-HOJm2mt2.d.mts.map +1 -0
  4. package/dist/index.d.ts +1944 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +5170 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/storage/filesystem.d.mts +49 -0
  9. package/dist/storage/filesystem.d.mts.map +1 -0
  10. package/dist/storage/filesystem.mjs +371 -0
  11. package/dist/storage/filesystem.mjs.map +1 -0
  12. package/dist/storage/prisma.d.mts +11508 -0
  13. package/dist/storage/prisma.d.mts.map +1 -0
  14. package/dist/storage/prisma.mjs +7582 -0
  15. package/dist/storage/prisma.mjs.map +1 -0
  16. package/dist/utils-BI7cwVSp.mjs +74 -0
  17. package/dist/utils-BI7cwVSp.mjs.map +1 -0
  18. package/package.json +21 -38
  19. package/dist/prisma/schema.prisma +0 -93
  20. package/dist/src/cache/index.d.ts +0 -4
  21. package/dist/src/cache/index.d.ts.map +0 -1
  22. package/dist/src/cache/index.js +0 -4
  23. package/dist/src/cache/index.js.map +0 -1
  24. package/dist/src/cache/lru.d.ts +0 -22
  25. package/dist/src/cache/lru.d.ts.map +0 -1
  26. package/dist/src/cache/lru.js +0 -40
  27. package/dist/src/cache/lru.js.map +0 -1
  28. package/dist/src/cache/memory.d.ts +0 -27
  29. package/dist/src/cache/memory.d.ts.map +0 -1
  30. package/dist/src/cache/memory.js +0 -104
  31. package/dist/src/cache/memory.js.map +0 -1
  32. package/dist/src/cache/redis.d.ts +0 -22
  33. package/dist/src/cache/redis.d.ts.map +0 -1
  34. package/dist/src/cache/redis.js +0 -91
  35. package/dist/src/cache/redis.js.map +0 -1
  36. package/dist/src/cache/types.d.ts +0 -37
  37. package/dist/src/cache/types.d.ts.map +0 -1
  38. package/dist/src/cache/types.js +0 -2
  39. package/dist/src/cache/types.js.map +0 -1
  40. package/dist/src/cache/util.d.ts +0 -3
  41. package/dist/src/cache/util.d.ts.map +0 -1
  42. package/dist/src/cache/util.js +0 -16
  43. package/dist/src/cache/util.js.map +0 -1
  44. package/dist/src/drive-document-model/constants.d.ts +0 -2
  45. package/dist/src/drive-document-model/constants.d.ts.map +0 -1
  46. package/dist/src/drive-document-model/constants.js +0 -2
  47. package/dist/src/drive-document-model/constants.js.map +0 -1
  48. package/dist/src/drive-document-model/gen/creators.d.ts +0 -3
  49. package/dist/src/drive-document-model/gen/creators.d.ts.map +0 -1
  50. package/dist/src/drive-document-model/gen/creators.js +0 -3
  51. package/dist/src/drive-document-model/gen/creators.js.map +0 -1
  52. package/dist/src/drive-document-model/gen/document-model.d.ts +0 -3
  53. package/dist/src/drive-document-model/gen/document-model.d.ts.map +0 -1
  54. package/dist/src/drive-document-model/gen/document-model.js +0 -210
  55. package/dist/src/drive-document-model/gen/document-model.js.map +0 -1
  56. package/dist/src/drive-document-model/gen/document-schema.d.ts +0 -68
  57. package/dist/src/drive-document-model/gen/document-schema.d.ts.map +0 -1
  58. package/dist/src/drive-document-model/gen/document-schema.js +0 -35
  59. package/dist/src/drive-document-model/gen/document-schema.js.map +0 -1
  60. package/dist/src/drive-document-model/gen/document-type.d.ts +0 -2
  61. package/dist/src/drive-document-model/gen/document-type.d.ts.map +0 -1
  62. package/dist/src/drive-document-model/gen/document-type.js +0 -2
  63. package/dist/src/drive-document-model/gen/document-type.js.map +0 -1
  64. package/dist/src/drive-document-model/gen/drive/actions.d.ts +0 -46
  65. package/dist/src/drive-document-model/gen/drive/actions.d.ts.map +0 -1
  66. package/dist/src/drive-document-model/gen/drive/actions.js +0 -2
  67. package/dist/src/drive-document-model/gen/drive/actions.js.map +0 -1
  68. package/dist/src/drive-document-model/gen/drive/creators.d.ts +0 -10
  69. package/dist/src/drive-document-model/gen/drive/creators.d.ts.map +0 -1
  70. package/dist/src/drive-document-model/gen/drive/creators.js +0 -11
  71. package/dist/src/drive-document-model/gen/drive/creators.js.map +0 -1
  72. package/dist/src/drive-document-model/gen/drive/error.d.ts +0 -2
  73. package/dist/src/drive-document-model/gen/drive/error.d.ts.map +0 -1
  74. package/dist/src/drive-document-model/gen/drive/error.js +0 -2
  75. package/dist/src/drive-document-model/gen/drive/error.js.map +0 -1
  76. package/dist/src/drive-document-model/gen/drive/index.d.ts +0 -2
  77. package/dist/src/drive-document-model/gen/drive/index.d.ts.map +0 -1
  78. package/dist/src/drive-document-model/gen/drive/index.js +0 -2
  79. package/dist/src/drive-document-model/gen/drive/index.js.map +0 -1
  80. package/dist/src/drive-document-model/gen/drive/types.d.ts +0 -2
  81. package/dist/src/drive-document-model/gen/drive/types.d.ts.map +0 -1
  82. package/dist/src/drive-document-model/gen/drive/types.js +0 -2
  83. package/dist/src/drive-document-model/gen/drive/types.js.map +0 -1
  84. package/dist/src/drive-document-model/gen/index.d.ts +0 -10
  85. package/dist/src/drive-document-model/gen/index.d.ts.map +0 -1
  86. package/dist/src/drive-document-model/gen/index.js +0 -10
  87. package/dist/src/drive-document-model/gen/index.js.map +0 -1
  88. package/dist/src/drive-document-model/gen/node/actions.d.ts +0 -41
  89. package/dist/src/drive-document-model/gen/node/actions.d.ts.map +0 -1
  90. package/dist/src/drive-document-model/gen/node/actions.js +0 -2
  91. package/dist/src/drive-document-model/gen/node/actions.js.map +0 -1
  92. package/dist/src/drive-document-model/gen/node/creators.d.ts +0 -13
  93. package/dist/src/drive-document-model/gen/node/creators.d.ts.map +0 -1
  94. package/dist/src/drive-document-model/gen/node/creators.js +0 -17
  95. package/dist/src/drive-document-model/gen/node/creators.js.map +0 -1
  96. package/dist/src/drive-document-model/gen/node/error.d.ts +0 -2
  97. package/dist/src/drive-document-model/gen/node/error.d.ts.map +0 -1
  98. package/dist/src/drive-document-model/gen/node/error.js +0 -2
  99. package/dist/src/drive-document-model/gen/node/error.js.map +0 -1
  100. package/dist/src/drive-document-model/gen/node/index.d.ts +0 -2
  101. package/dist/src/drive-document-model/gen/node/index.d.ts.map +0 -1
  102. package/dist/src/drive-document-model/gen/node/index.js +0 -2
  103. package/dist/src/drive-document-model/gen/node/index.js.map +0 -1
  104. package/dist/src/drive-document-model/gen/node/types.d.ts +0 -2
  105. package/dist/src/drive-document-model/gen/node/types.d.ts.map +0 -1
  106. package/dist/src/drive-document-model/gen/node/types.js +0 -2
  107. package/dist/src/drive-document-model/gen/node/types.js.map +0 -1
  108. package/dist/src/drive-document-model/gen/ph-factories.d.ts +0 -12
  109. package/dist/src/drive-document-model/gen/ph-factories.d.ts.map +0 -1
  110. package/dist/src/drive-document-model/gen/ph-factories.js +0 -46
  111. package/dist/src/drive-document-model/gen/ph-factories.js.map +0 -1
  112. package/dist/src/drive-document-model/gen/reducer.d.ts +0 -4
  113. package/dist/src/drive-document-model/gen/reducer.d.ts.map +0 -1
  114. package/dist/src/drive-document-model/gen/reducer.js +0 -76
  115. package/dist/src/drive-document-model/gen/reducer.js.map +0 -1
  116. package/dist/src/drive-document-model/gen/schema/index.d.ts +0 -2
  117. package/dist/src/drive-document-model/gen/schema/index.d.ts.map +0 -1
  118. package/dist/src/drive-document-model/gen/schema/index.js +0 -2
  119. package/dist/src/drive-document-model/gen/schema/index.js.map +0 -1
  120. package/dist/src/drive-document-model/gen/schema/types.d.ts +0 -283
  121. package/dist/src/drive-document-model/gen/schema/types.d.ts.map +0 -1
  122. package/dist/src/drive-document-model/gen/schema/types.js +0 -2
  123. package/dist/src/drive-document-model/gen/schema/types.js.map +0 -1
  124. package/dist/src/drive-document-model/gen/schema/zod.d.ts +0 -67
  125. package/dist/src/drive-document-model/gen/schema/zod.d.ts.map +0 -1
  126. package/dist/src/drive-document-model/gen/schema/zod.js +0 -229
  127. package/dist/src/drive-document-model/gen/schema/zod.js.map +0 -1
  128. package/dist/src/drive-document-model/gen/types.d.ts +0 -21
  129. package/dist/src/drive-document-model/gen/types.d.ts.map +0 -1
  130. package/dist/src/drive-document-model/gen/types.js +0 -4
  131. package/dist/src/drive-document-model/gen/types.js.map +0 -1
  132. package/dist/src/drive-document-model/gen/utils.d.ts +0 -13
  133. package/dist/src/drive-document-model/gen/utils.d.ts.map +0 -1
  134. package/dist/src/drive-document-model/gen/utils.js +0 -48
  135. package/dist/src/drive-document-model/gen/utils.js.map +0 -1
  136. package/dist/src/drive-document-model/index.d.ts +0 -5
  137. package/dist/src/drive-document-model/index.d.ts.map +0 -1
  138. package/dist/src/drive-document-model/index.js +0 -5
  139. package/dist/src/drive-document-model/index.js.map +0 -1
  140. package/dist/src/drive-document-model/module.d.ts +0 -3
  141. package/dist/src/drive-document-model/module.d.ts.map +0 -1
  142. package/dist/src/drive-document-model/module.js +0 -24
  143. package/dist/src/drive-document-model/module.js.map +0 -1
  144. package/dist/src/drive-document-model/src/index.d.ts +0 -3
  145. package/dist/src/drive-document-model/src/index.d.ts.map +0 -1
  146. package/dist/src/drive-document-model/src/index.js +0 -3
  147. package/dist/src/drive-document-model/src/index.js.map +0 -1
  148. package/dist/src/drive-document-model/src/reducers/drive.d.ts +0 -8
  149. package/dist/src/drive-document-model/src/reducers/drive.d.ts.map +0 -1
  150. package/dist/src/drive-document-model/src/reducers/drive.js +0 -66
  151. package/dist/src/drive-document-model/src/reducers/drive.js.map +0 -1
  152. package/dist/src/drive-document-model/src/reducers/index.d.ts +0 -3
  153. package/dist/src/drive-document-model/src/reducers/index.d.ts.map +0 -1
  154. package/dist/src/drive-document-model/src/reducers/index.js +0 -3
  155. package/dist/src/drive-document-model/src/reducers/index.js.map +0 -1
  156. package/dist/src/drive-document-model/src/reducers/node.d.ts +0 -8
  157. package/dist/src/drive-document-model/src/reducers/node.d.ts.map +0 -1
  158. package/dist/src/drive-document-model/src/reducers/node.js +0 -187
  159. package/dist/src/drive-document-model/src/reducers/node.js.map +0 -1
  160. package/dist/src/drive-document-model/src/tests/actions.test.d.ts +0 -2
  161. package/dist/src/drive-document-model/src/tests/actions.test.d.ts.map +0 -1
  162. package/dist/src/drive-document-model/src/tests/actions.test.js +0 -197
  163. package/dist/src/drive-document-model/src/tests/actions.test.js.map +0 -1
  164. package/dist/src/drive-document-model/src/tests/base.test.d.ts +0 -2
  165. package/dist/src/drive-document-model/src/tests/base.test.d.ts.map +0 -1
  166. package/dist/src/drive-document-model/src/tests/base.test.js +0 -44
  167. package/dist/src/drive-document-model/src/tests/base.test.js.map +0 -1
  168. package/dist/src/drive-document-model/src/tests/document-model.test.d.ts +0 -6
  169. package/dist/src/drive-document-model/src/tests/document-model.test.d.ts.map +0 -1
  170. package/dist/src/drive-document-model/src/tests/document-model.test.js +0 -19
  171. package/dist/src/drive-document-model/src/tests/document-model.test.js.map +0 -1
  172. package/dist/src/drive-document-model/src/tests/drive.test.d.ts +0 -6
  173. package/dist/src/drive-document-model/src/tests/drive.test.d.ts.map +0 -1
  174. package/dist/src/drive-document-model/src/tests/drive.test.js +0 -38
  175. package/dist/src/drive-document-model/src/tests/drive.test.js.map +0 -1
  176. package/dist/src/drive-document-model/src/tests/generate-mock.d.ts +0 -3
  177. package/dist/src/drive-document-model/src/tests/generate-mock.d.ts.map +0 -1
  178. package/dist/src/drive-document-model/src/tests/generate-mock.js +0 -5
  179. package/dist/src/drive-document-model/src/tests/generate-mock.js.map +0 -1
  180. package/dist/src/drive-document-model/src/tests/node.test.d.ts +0 -6
  181. package/dist/src/drive-document-model/src/tests/node.test.d.ts.map +0 -1
  182. package/dist/src/drive-document-model/src/tests/node.test.js +0 -343
  183. package/dist/src/drive-document-model/src/tests/node.test.js.map +0 -1
  184. package/dist/src/drive-document-model/src/tests/test-factories.d.ts +0 -9
  185. package/dist/src/drive-document-model/src/tests/test-factories.d.ts.map +0 -1
  186. package/dist/src/drive-document-model/src/tests/test-factories.js +0 -17
  187. package/dist/src/drive-document-model/src/tests/test-factories.js.map +0 -1
  188. package/dist/src/drive-document-model/src/tests/utils.test.d.ts +0 -2
  189. package/dist/src/drive-document-model/src/tests/utils.test.d.ts.map +0 -1
  190. package/dist/src/drive-document-model/src/tests/utils.test.js +0 -232
  191. package/dist/src/drive-document-model/src/tests/utils.test.js.map +0 -1
  192. package/dist/src/drive-document-model/src/types.d.ts +0 -8
  193. package/dist/src/drive-document-model/src/types.d.ts.map +0 -1
  194. package/dist/src/drive-document-model/src/types.js +0 -2
  195. package/dist/src/drive-document-model/src/types.js.map +0 -1
  196. package/dist/src/drive-document-model/src/utils.d.ts +0 -23
  197. package/dist/src/drive-document-model/src/utils.d.ts.map +0 -1
  198. package/dist/src/drive-document-model/src/utils.js +0 -102
  199. package/dist/src/drive-document-model/src/utils.js.map +0 -1
  200. package/dist/src/drive-document-model/types.d.ts +0 -10
  201. package/dist/src/drive-document-model/types.d.ts.map +0 -1
  202. package/dist/src/drive-document-model/types.js +0 -3
  203. package/dist/src/drive-document-model/types.js.map +0 -1
  204. package/dist/src/index.d.ts +0 -17
  205. package/dist/src/index.d.ts.map +0 -1
  206. package/dist/src/index.js +0 -17
  207. package/dist/src/index.js.map +0 -1
  208. package/dist/src/processors/index.d.ts +0 -4
  209. package/dist/src/processors/index.d.ts.map +0 -1
  210. package/dist/src/processors/index.js +0 -4
  211. package/dist/src/processors/index.js.map +0 -1
  212. package/dist/src/processors/processor-manager.d.ts +0 -21
  213. package/dist/src/processors/processor-manager.d.ts.map +0 -1
  214. package/dist/src/processors/processor-manager.js +0 -104
  215. package/dist/src/processors/processor-manager.js.map +0 -1
  216. package/dist/src/processors/relational.d.ts +0 -49
  217. package/dist/src/processors/relational.d.ts.map +0 -1
  218. package/dist/src/processors/relational.js +0 -57
  219. package/dist/src/processors/relational.js.map +0 -1
  220. package/dist/src/processors/types.d.ts +0 -94
  221. package/dist/src/processors/types.d.ts.map +0 -1
  222. package/dist/src/processors/types.js +0 -2
  223. package/dist/src/processors/types.js.map +0 -1
  224. package/dist/src/processors/utils.d.ts +0 -29
  225. package/dist/src/processors/utils.d.ts.map +0 -1
  226. package/dist/src/processors/utils.js +0 -72
  227. package/dist/src/processors/utils.js.map +0 -1
  228. package/dist/src/queue/base.d.ts +0 -22
  229. package/dist/src/queue/base.d.ts.map +0 -1
  230. package/dist/src/queue/base.js +0 -54
  231. package/dist/src/queue/base.js.map +0 -1
  232. package/dist/src/queue/event.d.ts +0 -40
  233. package/dist/src/queue/event.d.ts.map +0 -1
  234. package/dist/src/queue/event.js +0 -226
  235. package/dist/src/queue/event.js.map +0 -1
  236. package/dist/src/queue/index.d.ts +0 -5
  237. package/dist/src/queue/index.d.ts.map +0 -1
  238. package/dist/src/queue/index.js +0 -5
  239. package/dist/src/queue/index.js.map +0 -1
  240. package/dist/src/queue/redis.d.ts +0 -2
  241. package/dist/src/queue/redis.d.ts.map +0 -1
  242. package/dist/src/queue/redis.js +0 -123
  243. package/dist/src/queue/redis.js.map +0 -1
  244. package/dist/src/queue/types.d.ts +0 -59
  245. package/dist/src/queue/types.d.ts.map +0 -1
  246. package/dist/src/queue/types.js +0 -2
  247. package/dist/src/queue/types.js.map +0 -1
  248. package/dist/src/queue/utils.d.ts +0 -5
  249. package/dist/src/queue/utils.d.ts.map +0 -1
  250. package/dist/src/queue/utils.js +0 -10
  251. package/dist/src/queue/utils.js.map +0 -1
  252. package/dist/src/read-mode/errors.d.ts +0 -12
  253. package/dist/src/read-mode/errors.d.ts.map +0 -1
  254. package/dist/src/read-mode/errors.js +0 -18
  255. package/dist/src/read-mode/errors.js.map +0 -1
  256. package/dist/src/read-mode/index.d.ts +0 -4
  257. package/dist/src/read-mode/index.d.ts.map +0 -1
  258. package/dist/src/read-mode/index.js +0 -4
  259. package/dist/src/read-mode/index.js.map +0 -1
  260. package/dist/src/read-mode/server.d.ts +0 -3
  261. package/dist/src/read-mode/server.d.ts.map +0 -1
  262. package/dist/src/read-mode/server.js +0 -78
  263. package/dist/src/read-mode/server.js.map +0 -1
  264. package/dist/src/read-mode/service.d.ts +0 -17
  265. package/dist/src/read-mode/service.d.ts.map +0 -1
  266. package/dist/src/read-mode/service.js +0 -119
  267. package/dist/src/read-mode/service.js.map +0 -1
  268. package/dist/src/read-mode/types.d.ts +0 -31
  269. package/dist/src/read-mode/types.d.ts.map +0 -1
  270. package/dist/src/read-mode/types.js +0 -2
  271. package/dist/src/read-mode/types.js.map +0 -1
  272. package/dist/src/server/base-server.d.ts +0 -177
  273. package/dist/src/server/base-server.d.ts.map +0 -1
  274. package/dist/src/server/base-server.js +0 -2000
  275. package/dist/src/server/base-server.js.map +0 -1
  276. package/dist/src/server/builder.d.ts +0 -27
  277. package/dist/src/server/builder.d.ts.map +0 -1
  278. package/dist/src/server/builder.js +0 -97
  279. package/dist/src/server/builder.js.map +0 -1
  280. package/dist/src/server/error.d.ts +0 -34
  281. package/dist/src/server/error.d.ts.map +0 -1
  282. package/dist/src/server/error.js +0 -56
  283. package/dist/src/server/error.js.map +0 -1
  284. package/dist/src/server/event-emitter.d.ts +0 -8
  285. package/dist/src/server/event-emitter.d.ts.map +0 -1
  286. package/dist/src/server/event-emitter.js +0 -11
  287. package/dist/src/server/event-emitter.js.map +0 -1
  288. package/dist/src/server/index.d.ts +0 -10
  289. package/dist/src/server/index.d.ts.map +0 -1
  290. package/dist/src/server/index.js +0 -10
  291. package/dist/src/server/index.js.map +0 -1
  292. package/dist/src/server/listener/constants.d.ts +0 -4
  293. package/dist/src/server/listener/constants.d.ts.map +0 -1
  294. package/dist/src/server/listener/constants.js +0 -4
  295. package/dist/src/server/listener/constants.js.map +0 -1
  296. package/dist/src/server/listener/index.d.ts +0 -4
  297. package/dist/src/server/listener/index.d.ts.map +0 -1
  298. package/dist/src/server/listener/index.js +0 -4
  299. package/dist/src/server/listener/index.js.map +0 -1
  300. package/dist/src/server/listener/listener-manager.d.ts +0 -28
  301. package/dist/src/server/listener/listener-manager.d.ts.map +0 -1
  302. package/dist/src/server/listener/listener-manager.js +0 -415
  303. package/dist/src/server/listener/listener-manager.js.map +0 -1
  304. package/dist/src/server/listener/util.d.ts +0 -2
  305. package/dist/src/server/listener/util.d.ts.map +0 -1
  306. package/dist/src/server/listener/util.js +0 -23
  307. package/dist/src/server/listener/util.js.map +0 -1
  308. package/dist/src/server/sync-manager.d.ts +0 -28
  309. package/dist/src/server/sync-manager.d.ts.map +0 -1
  310. package/dist/src/server/sync-manager.js +0 -222
  311. package/dist/src/server/sync-manager.js.map +0 -1
  312. package/dist/src/server/sync-unit-map.d.ts +0 -116
  313. package/dist/src/server/sync-unit-map.d.ts.map +0 -1
  314. package/dist/src/server/sync-unit-map.js +0 -233
  315. package/dist/src/server/sync-unit-map.js.map +0 -1
  316. package/dist/src/server/transmitter/constants.d.ts +0 -2
  317. package/dist/src/server/transmitter/constants.d.ts.map +0 -1
  318. package/dist/src/server/transmitter/constants.js +0 -2
  319. package/dist/src/server/transmitter/constants.js.map +0 -1
  320. package/dist/src/server/transmitter/factory.d.ts +0 -7
  321. package/dist/src/server/transmitter/factory.d.ts.map +0 -1
  322. package/dist/src/server/transmitter/factory.js +0 -25
  323. package/dist/src/server/transmitter/factory.js.map +0 -1
  324. package/dist/src/server/transmitter/index.d.ts +0 -6
  325. package/dist/src/server/transmitter/index.d.ts.map +0 -1
  326. package/dist/src/server/transmitter/index.js +0 -5
  327. package/dist/src/server/transmitter/index.js.map +0 -1
  328. package/dist/src/server/transmitter/internal.d.ts +0 -12
  329. package/dist/src/server/transmitter/internal.d.ts.map +0 -1
  330. package/dist/src/server/transmitter/internal.js +0 -113
  331. package/dist/src/server/transmitter/internal.js.map +0 -1
  332. package/dist/src/server/transmitter/pull-responder.d.ts +0 -30
  333. package/dist/src/server/transmitter/pull-responder.d.ts.map +0 -1
  334. package/dist/src/server/transmitter/pull-responder.js +0 -543
  335. package/dist/src/server/transmitter/pull-responder.js.map +0 -1
  336. package/dist/src/server/transmitter/switchboard-push.d.ts +0 -11
  337. package/dist/src/server/transmitter/switchboard-push.d.ts.map +0 -1
  338. package/dist/src/server/transmitter/switchboard-push.js +0 -130
  339. package/dist/src/server/transmitter/switchboard-push.js.map +0 -1
  340. package/dist/src/server/transmitter/types.d.ts +0 -53
  341. package/dist/src/server/transmitter/types.d.ts.map +0 -1
  342. package/dist/src/server/transmitter/types.js +0 -2
  343. package/dist/src/server/transmitter/types.js.map +0 -1
  344. package/dist/src/server/types.d.ts +0 -419
  345. package/dist/src/server/types.d.ts.map +0 -1
  346. package/dist/src/server/types.js +0 -10
  347. package/dist/src/server/types.js.map +0 -1
  348. package/dist/src/server/utils.d.ts +0 -19
  349. package/dist/src/server/utils.d.ts.map +0 -1
  350. package/dist/src/server/utils.js +0 -110
  351. package/dist/src/server/utils.js.map +0 -1
  352. package/dist/src/storage/browser.d.ts +0 -52
  353. package/dist/src/storage/browser.d.ts.map +0 -1
  354. package/dist/src/storage/browser.js +0 -430
  355. package/dist/src/storage/browser.js.map +0 -1
  356. package/dist/src/storage/filesystem.d.ts +0 -45
  357. package/dist/src/storage/filesystem.d.ts.map +0 -1
  358. package/dist/src/storage/filesystem.js +0 -457
  359. package/dist/src/storage/filesystem.js.map +0 -1
  360. package/dist/src/storage/index.d.ts +0 -5
  361. package/dist/src/storage/index.d.ts.map +0 -1
  362. package/dist/src/storage/index.js +0 -5
  363. package/dist/src/storage/index.js.map +0 -1
  364. package/dist/src/storage/ipfs.d.ts +0 -2
  365. package/dist/src/storage/ipfs.d.ts.map +0 -1
  366. package/dist/src/storage/ipfs.js +0 -491
  367. package/dist/src/storage/ipfs.js.map +0 -1
  368. package/dist/src/storage/memory.d.ts +0 -42
  369. package/dist/src/storage/memory.d.ts.map +0 -1
  370. package/dist/src/storage/memory.js +0 -355
  371. package/dist/src/storage/memory.js.map +0 -1
  372. package/dist/src/storage/path-encoding.d.ts +0 -21
  373. package/dist/src/storage/path-encoding.d.ts.map +0 -1
  374. package/dist/src/storage/path-encoding.js +0 -53
  375. package/dist/src/storage/path-encoding.js.map +0 -1
  376. package/dist/src/storage/prisma/client/default.d.ts +0 -1
  377. package/dist/src/storage/prisma/client/default.js +0 -1
  378. package/dist/src/storage/prisma/client/edge.d.ts +0 -1
  379. package/dist/src/storage/prisma/client/edge.js +0 -263
  380. package/dist/src/storage/prisma/client/index-browser.js +0 -246
  381. package/dist/src/storage/prisma/client/index.d.ts +0 -10318
  382. package/dist/src/storage/prisma/client/index.js +0 -292
  383. package/dist/src/storage/prisma/client/libquery_engine-darwin-arm64.dylib.node +0 -0
  384. package/dist/src/storage/prisma/client/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  385. package/dist/src/storage/prisma/client/libquery_engine-linux-musl.so.node +0 -0
  386. package/dist/src/storage/prisma/client/package.json +0 -84
  387. package/dist/src/storage/prisma/client/runtime/edge-esm.js +0 -31
  388. package/dist/src/storage/prisma/client/runtime/edge.js +0 -31
  389. package/dist/src/storage/prisma/client/runtime/index-browser.d.ts +0 -365
  390. package/dist/src/storage/prisma/client/runtime/index-browser.js +0 -13
  391. package/dist/src/storage/prisma/client/runtime/library.d.ts +0 -3273
  392. package/dist/src/storage/prisma/client/runtime/library.js +0 -143
  393. package/dist/src/storage/prisma/client/runtime/react-native.js +0 -80
  394. package/dist/src/storage/prisma/client/runtime/wasm.js +0 -32
  395. package/dist/src/storage/prisma/client/schema.prisma +0 -93
  396. package/dist/src/storage/prisma/client/wasm.d.ts +0 -1
  397. package/dist/src/storage/prisma/client/wasm.js +0 -246
  398. package/dist/src/storage/prisma/factory.d.ts +0 -10
  399. package/dist/src/storage/prisma/factory.d.ts.map +0 -1
  400. package/dist/src/storage/prisma/factory.js +0 -23
  401. package/dist/src/storage/prisma/factory.js.map +0 -1
  402. package/dist/src/storage/prisma/index.d.ts +0 -3
  403. package/dist/src/storage/prisma/index.d.ts.map +0 -1
  404. package/dist/src/storage/prisma/index.js +0 -3
  405. package/dist/src/storage/prisma/index.js.map +0 -1
  406. package/dist/src/storage/prisma/prisma.d.ts +0 -73
  407. package/dist/src/storage/prisma/prisma.d.ts.map +0 -1
  408. package/dist/src/storage/prisma/prisma.js +0 -760
  409. package/dist/src/storage/prisma/prisma.js.map +0 -1
  410. package/dist/src/storage/types.d.ts +0 -187
  411. package/dist/src/storage/types.d.ts.map +0 -1
  412. package/dist/src/storage/types.js +0 -2
  413. package/dist/src/storage/types.js.map +0 -1
  414. package/dist/src/storage/utils.d.ts +0 -6
  415. package/dist/src/storage/utils.d.ts.map +0 -1
  416. package/dist/src/storage/utils.js +0 -33
  417. package/dist/src/storage/utils.js.map +0 -1
  418. package/dist/src/utils/default-drives-manager.d.ts +0 -18
  419. package/dist/src/utils/default-drives-manager.d.ts.map +0 -1
  420. package/dist/src/utils/default-drives-manager.js +0 -208
  421. package/dist/src/utils/default-drives-manager.js.map +0 -1
  422. package/dist/src/utils/errors.d.ts +0 -5
  423. package/dist/src/utils/errors.d.ts.map +0 -1
  424. package/dist/src/utils/errors.js +0 -10
  425. package/dist/src/utils/errors.js.map +0 -1
  426. package/dist/src/utils/gql-transformations.d.ts +0 -32
  427. package/dist/src/utils/gql-transformations.d.ts.map +0 -1
  428. package/dist/src/utils/gql-transformations.js +0 -39
  429. package/dist/src/utils/gql-transformations.js.map +0 -1
  430. package/dist/src/utils/graphql.d.ts +0 -13
  431. package/dist/src/utils/graphql.d.ts.map +0 -1
  432. package/dist/src/utils/graphql.js +0 -196
  433. package/dist/src/utils/graphql.js.map +0 -1
  434. package/dist/src/utils/index.d.ts +0 -9
  435. package/dist/src/utils/index.d.ts.map +0 -1
  436. package/dist/src/utils/index.js +0 -9
  437. package/dist/src/utils/index.js.map +0 -1
  438. package/dist/src/utils/logger.d.ts +0 -3
  439. package/dist/src/utils/logger.d.ts.map +0 -1
  440. package/dist/src/utils/logger.js +0 -2
  441. package/dist/src/utils/logger.js.map +0 -1
  442. package/dist/src/utils/migrations.d.ts +0 -4
  443. package/dist/src/utils/migrations.d.ts.map +0 -1
  444. package/dist/src/utils/migrations.js +0 -112
  445. package/dist/src/utils/migrations.js.map +0 -1
  446. package/dist/src/utils/misc.d.ts +0 -21
  447. package/dist/src/utils/misc.d.ts.map +0 -1
  448. package/dist/src/utils/misc.js +0 -55
  449. package/dist/src/utils/misc.js.map +0 -1
  450. package/dist/src/utils/run-asap.d.ts +0 -8
  451. package/dist/src/utils/run-asap.d.ts.map +0 -1
  452. package/dist/src/utils/run-asap.js +0 -120
  453. package/dist/src/utils/run-asap.js.map +0 -1
  454. package/dist/src/utils/test.d.ts +0 -63
  455. package/dist/src/utils/test.d.ts.map +0 -1
  456. package/dist/src/utils/test.js +0 -161
  457. package/dist/src/utils/test.js.map +0 -1
  458. package/dist/src/utils/types.d.ts +0 -44
  459. package/dist/src/utils/types.d.ts.map +0 -1
  460. package/dist/src/utils/types.js +0 -2
  461. package/dist/src/utils/types.js.map +0 -1
  462. package/dist/test/benchmarks/getDrive.json +0 -10
  463. package/dist/test/benchmarks/processOperations.bench.d.ts +0 -2
  464. package/dist/test/benchmarks/processOperations.bench.d.ts.map +0 -1
  465. package/dist/test/benchmarks/processOperations.bench.js +0 -148
  466. package/dist/test/benchmarks/processOperations.bench.js.map +0 -1
  467. package/dist/test/benchmarks/queue.bench.d.ts +0 -2
  468. package/dist/test/benchmarks/queue.bench.d.ts.map +0 -1
  469. package/dist/test/benchmarks/queue.bench.js +0 -55
  470. package/dist/test/benchmarks/queue.bench.js.map +0 -1
  471. package/dist/test/benchmarks/strands.small.json +0 -37085
  472. package/dist/test/cache.test.d.ts +0 -2
  473. package/dist/test/cache.test.d.ts.map +0 -1
  474. package/dist/test/cache.test.js +0 -276
  475. package/dist/test/cache.test.js.map +0 -1
  476. package/dist/test/default-remote-drives.test.d.ts +0 -2
  477. package/dist/test/default-remote-drives.test.d.ts.map +0 -1
  478. package/dist/test/default-remote-drives.test.js +0 -445
  479. package/dist/test/default-remote-drives.test.js.map +0 -1
  480. package/dist/test/drive-operations.test.d.ts +0 -2
  481. package/dist/test/drive-operations.test.d.ts.map +0 -1
  482. package/dist/test/drive-operations.test.js +0 -134
  483. package/dist/test/drive-operations.test.js.map +0 -1
  484. package/dist/test/dual-action-create.test.d.ts +0 -2
  485. package/dist/test/dual-action-create.test.d.ts.map +0 -1
  486. package/dist/test/dual-action-create.test.js +0 -187
  487. package/dist/test/dual-action-create.test.js.map +0 -1
  488. package/dist/test/dual-action-migration.test.d.ts +0 -2
  489. package/dist/test/dual-action-migration.test.d.ts.map +0 -1
  490. package/dist/test/dual-action-migration.test.js +0 -348
  491. package/dist/test/dual-action-migration.test.js.map +0 -1
  492. package/dist/test/graphql.test.d.ts +0 -2
  493. package/dist/test/graphql.test.d.ts.map +0 -1
  494. package/dist/test/graphql.test.js +0 -9
  495. package/dist/test/graphql.test.js.map +0 -1
  496. package/dist/test/internal-listener.test.d.ts +0 -2
  497. package/dist/test/internal-listener.test.d.ts.map +0 -1
  498. package/dist/test/internal-listener.test.js +0 -262
  499. package/dist/test/internal-listener.test.js.map +0 -1
  500. package/dist/test/path-encoding.test.d.ts +0 -2
  501. package/dist/test/path-encoding.test.d.ts.map +0 -1
  502. package/dist/test/path-encoding.test.js +0 -116
  503. package/dist/test/path-encoding.test.js.map +0 -1
  504. package/dist/test/queue.test.d.ts +0 -2
  505. package/dist/test/queue.test.d.ts.map +0 -1
  506. package/dist/test/queue.test.js +0 -325
  507. package/dist/test/queue.test.js.map +0 -1
  508. package/dist/test/reactor.test.d.ts +0 -2
  509. package/dist/test/reactor.test.d.ts.map +0 -1
  510. package/dist/test/reactor.test.js +0 -32
  511. package/dist/test/reactor.test.js.map +0 -1
  512. package/dist/test/read-mode.test.d.ts +0 -2
  513. package/dist/test/read-mode.test.d.ts.map +0 -1
  514. package/dist/test/read-mode.test.js +0 -569
  515. package/dist/test/read-mode.test.js.map +0 -1
  516. package/dist/test/server/driveOperationsConflictResolution.test.d.ts +0 -2
  517. package/dist/test/server/driveOperationsConflictResolution.test.d.ts.map +0 -1
  518. package/dist/test/server/driveOperationsConflictResolution.test.js +0 -486
  519. package/dist/test/server/driveOperationsConflictResolution.test.js.map +0 -1
  520. package/dist/test/server/mergeOperations.test.d.ts +0 -2
  521. package/dist/test/server/mergeOperations.test.d.ts.map +0 -1
  522. package/dist/test/server/mergeOperations.test.js +0 -131
  523. package/dist/test/server/mergeOperations.test.js.map +0 -1
  524. package/dist/test/server/processOperations.test.d.ts +0 -2
  525. package/dist/test/server/processOperations.test.d.ts.map +0 -1
  526. package/dist/test/server/processOperations.test.js +0 -392
  527. package/dist/test/server/processOperations.test.js.map +0 -1
  528. package/dist/test/server.test.d.ts +0 -2
  529. package/dist/test/server.test.d.ts.map +0 -1
  530. package/dist/test/server.test.js +0 -957
  531. package/dist/test/server.test.js.map +0 -1
  532. package/dist/test/signature-migration.test.d.ts +0 -2
  533. package/dist/test/signature-migration.test.d.ts.map +0 -1
  534. package/dist/test/signature-migration.test.js +0 -241
  535. package/dist/test/signature-migration.test.js.map +0 -1
  536. package/dist/test/storage.test.d.ts +0 -2
  537. package/dist/test/storage.test.d.ts.map +0 -1
  538. package/dist/test/storage.test.js +0 -457
  539. package/dist/test/storage.test.js.map +0 -1
  540. package/dist/test/switchboard-push-listener.test.d.ts +0 -2
  541. package/dist/test/switchboard-push-listener.test.d.ts.map +0 -1
  542. package/dist/test/switchboard-push-listener.test.js +0 -133
  543. package/dist/test/switchboard-push-listener.test.js.map +0 -1
  544. package/dist/test/sync-manager.test.d.ts +0 -2
  545. package/dist/test/sync-manager.test.d.ts.map +0 -1
  546. package/dist/test/sync-manager.test.js +0 -354
  547. package/dist/test/sync-manager.test.js.map +0 -1
  548. package/dist/test/undo-redo-clipboard.test.d.ts +0 -2
  549. package/dist/test/undo-redo-clipboard.test.d.ts.map +0 -1
  550. package/dist/test/undo-redo-clipboard.test.js +0 -108
  551. package/dist/test/undo-redo-clipboard.test.js.map +0 -1
  552. package/dist/test/utils.test.d.ts +0 -2
  553. package/dist/test/utils.test.d.ts.map +0 -1
  554. package/dist/test/utils.test.js +0 -86
  555. package/dist/test/utils.test.js.map +0 -1
  556. package/dist/test/vitest-setup.d.ts +0 -2
  557. package/dist/test/vitest-setup.d.ts.map +0 -1
  558. package/dist/test/vitest-setup.js +0 -5
  559. package/dist/test/vitest-setup.js.map +0 -1
  560. package/dist/tsconfig.tsbuildinfo +0 -1
  561. package/dist/vitest.config.d.ts +0 -3
  562. package/dist/vitest.config.d.ts.map +0 -1
  563. package/dist/vitest.config.js +0 -28
  564. package/dist/vitest.config.js.map +0 -1
@@ -1,2000 +0,0 @@
1
- import { isActionJob, isDocumentJob, isOperationJob, } from "document-drive/queue/utils";
2
- import { ReadModeServer } from "document-drive/read-mode/server";
3
- import { DefaultDrivesManager } from "document-drive/utils/default-drives-manager";
4
- import { requestPublicDriveWithTokenFromReactor } from "document-drive/utils/graphql";
5
- import { childLogger } from "document-drive/utils/logger";
6
- import { isDocumentDrive } from "document-drive/utils/misc";
7
- import { runAsap, runAsapAsync } from "document-drive/utils/run-asap";
8
- import { attachBranch, createPresignedHeader, defaultBaseState, deriveOperationId, diffOperations, garbageCollect, garbageCollectDocumentOperations, generateId, groupOperationsByScope, hashDocumentStateForScope, merge, precedes, removeExistingOperations, replayDocument, reshuffleByTimestamp, skipHeaderOperations, sortOperations, validateHeader, } from "document-model/core";
9
- import { ClientError } from "graphql-request";
10
- import { driveCreateDocument, driveCreateState, removeListener, removeTrigger, setSharingType, } from "../drive-document-model/index.js";
11
- import { ConflictOperationError, DocumentAlreadyExistsError, OperationError, } from "./error.js";
12
- import { DefaultListenerManagerOptions } from "./listener/constants.js";
13
- import { PullResponderTransmitter } from "./transmitter/pull-responder.js";
14
- import { SwitchboardPushTransmitter } from "./transmitter/switchboard-push.js";
15
- import { filterOperationsByRevision, isAtRevision, resolveCreateDocumentInput, } from "./utils.js";
16
- export class BaseDocumentDriveServer {
17
- logger = childLogger(["BaseDocumentDriveServer"]);
18
- // external dependencies
19
- documentModelModules;
20
- legacyStorage;
21
- documentStorage;
22
- cache;
23
- queueManager;
24
- eventEmitter;
25
- options;
26
- listenerManager;
27
- synchronizationManager;
28
- generateJwtHandler;
29
- // internal dependencies
30
- defaultDrivesManager;
31
- defaultDrivesManagerDelegate = {
32
- detachDrive: this.detachDrive.bind(this),
33
- emit: (...args) => this.eventEmitter.emit("defaultRemoteDrive", ...args),
34
- };
35
- queueDelegate = {
36
- exists: (documentId) => this.documentStorage.exists(documentId),
37
- processOperationJob: async ({ documentId, operations, options, }) => {
38
- const document = await this.getDocument(documentId);
39
- return isDocumentDrive(document)
40
- ? this.processDriveOperations(documentId, operations, options)
41
- : this.processOperations(documentId, operations, options);
42
- },
43
- processActionJob: async ({ documentId, actions, options }) => {
44
- const document = await this.getDocument(documentId);
45
- return isDocumentDrive(document)
46
- ? this.processDriveActions(documentId, actions, options)
47
- : this.processActions(documentId, actions, options);
48
- },
49
- processDocumentJob: async ({ documentId, documentType, header: inputHeader, initialState, options, }) => {
50
- const documentModelModule = this.getDocumentModelModule(documentType);
51
- const document = documentModelModule.utils.createDocument(initialState);
52
- // TODO: header must be included
53
- const header = createPresignedHeader(documentId, documentType);
54
- document.header.id = documentId;
55
- document.header.sig = header.sig;
56
- document.header.documentType = documentType;
57
- if (inputHeader) {
58
- document.header.meta = inputHeader.meta;
59
- }
60
- try {
61
- const createdDocument = await this.createDocument({ document }, options?.source ?? { type: "local" }, document.header.meta);
62
- return {
63
- status: "SUCCESS",
64
- operations: [],
65
- document: createdDocument,
66
- signals: [],
67
- };
68
- }
69
- catch (error) {
70
- const cause = error instanceof Error ? error : new Error(JSON.stringify(error));
71
- return {
72
- status: "ERROR",
73
- error: new OperationError("ERROR", undefined, `Error creating document: ${cause.message}`, cause),
74
- operations: [],
75
- document: undefined,
76
- signals: [],
77
- };
78
- }
79
- },
80
- processJob: async (job) => {
81
- if (isOperationJob(job)) {
82
- return this.queueDelegate.processOperationJob(job);
83
- }
84
- else if (isActionJob(job)) {
85
- return this.queueDelegate.processActionJob(job);
86
- }
87
- else if (isDocumentJob(job)) {
88
- return this.queueDelegate.processDocumentJob(job);
89
- }
90
- else {
91
- throw new Error("Unknown job type", job);
92
- }
93
- },
94
- };
95
- // internal state
96
- triggerMap = new Map();
97
- initializePromise;
98
- enableDualActionCreate;
99
- constructor(documentModelModules, storage, documentStorage, cache, queueManager, eventEmitter, synchronizationManager, listenerManager, options) {
100
- this.documentModelModules = documentModelModules;
101
- this.legacyStorage = storage;
102
- this.documentStorage = documentStorage;
103
- this.cache = cache;
104
- this.queueManager = queueManager;
105
- this.eventEmitter = eventEmitter;
106
- this.synchronizationManager = synchronizationManager;
107
- this.listenerManager = listenerManager;
108
- this.options = {
109
- ...options,
110
- defaultDrives: {
111
- ...options?.defaultDrives,
112
- },
113
- listenerManager: {
114
- ...DefaultListenerManagerOptions,
115
- ...options?.listenerManager,
116
- },
117
- jwtHandler: options?.jwtHandler === undefined
118
- ? () => Promise.resolve("")
119
- : options.jwtHandler,
120
- taskQueueMethod: options?.taskQueueMethod === undefined
121
- ? runAsap
122
- : options.taskQueueMethod,
123
- featureFlags: {
124
- ...options?.featureFlags,
125
- },
126
- };
127
- this.enableDualActionCreate =
128
- options?.featureFlags?.enableDualActionCreate ?? false;
129
- if (this.enableDualActionCreate) {
130
- this.logger.warn("Dual action create is enabled.");
131
- }
132
- // todo: move to external dependencies
133
- this.defaultDrivesManager = new DefaultDrivesManager(this, this.defaultDrivesManagerDelegate, options);
134
- this.initializePromise = this._initialize();
135
- }
136
- // workaround for testing the ephemeral listeners -- we don't have DI in place yet
137
- // todo: remove this once we have DI
138
- get listeners() {
139
- return this.listenerManager;
140
- }
141
- initialize() {
142
- return this.initializePromise;
143
- }
144
- async _initialize() {
145
- await this.listenerManager.initialize(this.handleListenerError.bind(this));
146
- await this.queueManager.init(this.queueDelegate, (error) => {
147
- this.logger.error("Error initializing queue manager: @error", error);
148
- // errors.push(error);
149
- });
150
- try {
151
- await this.defaultDrivesManager.removeOldremoteDrives();
152
- }
153
- catch (error) {
154
- this.logger.error("@error", error);
155
- }
156
- const errors = [];
157
- const drives = await this.getDrives();
158
- for (const drive of drives) {
159
- await this._initializeDrive(drive).catch((error) => {
160
- this.logger.error("Error initializing drive @drive: @error", drive, error);
161
- errors.push(error);
162
- });
163
- }
164
- if (this.options.defaultDrives.loadOnInit !== false) {
165
- await this.defaultDrivesManager.initializeDefaultRemoteDrives();
166
- }
167
- return errors.length === 0 ? null : errors;
168
- }
169
- setDocumentModelModules(modules) {
170
- this.documentModelModules = [...modules];
171
- this.synchronizationManager.setDocumentModelModules([...modules]);
172
- this.eventEmitter.emit("documentModelModules", [...modules]);
173
- }
174
- initializeDefaultRemoteDrives() {
175
- return this.defaultDrivesManager.initializeDefaultRemoteDrives();
176
- }
177
- getDefaultRemoteDrives() {
178
- return this.defaultDrivesManager.getDefaultRemoteDrives();
179
- }
180
- setDefaultDriveAccessLevel(url, level) {
181
- return this.defaultDrivesManager.setDefaultDriveAccessLevel(url, level);
182
- }
183
- setAllDefaultDrivesAccessLevel(level) {
184
- return this.defaultDrivesManager.setAllDefaultDrivesAccessLevel(level);
185
- }
186
- getOperationSource(source) {
187
- return source.type === "local" ? "push" : "pull";
188
- }
189
- handleListenerError(error, driveId, listener) {
190
- this.logger.error("Listener @listenerId error: @error", listener.listener.label ?? listener.listener.listenerId, error);
191
- const status = error instanceof OperationError ? error.status : "ERROR";
192
- this.synchronizationManager.updateSyncStatus(driveId, { push: status }, error);
193
- }
194
- shouldSyncRemoteDrive(drive) {
195
- return (drive.state.local.availableOffline &&
196
- drive.state.local.triggers.length > 0);
197
- }
198
- async startSyncRemoteDrive(driveId) {
199
- let driveTriggers = this.triggerMap.get(driveId);
200
- const syncUnits = await this.synchronizationManager.getSynchronizationUnitsIds(driveId);
201
- const drive = await this.getDrive(driveId);
202
- for (const trigger of drive.state.local.triggers) {
203
- if (driveTriggers?.get(trigger.id)) {
204
- continue;
205
- }
206
- if (!driveTriggers) {
207
- driveTriggers = new Map();
208
- }
209
- this.synchronizationManager.updateSyncStatus(driveId, {
210
- pull: "SYNCING",
211
- });
212
- for (const syncUnit of syncUnits) {
213
- this.synchronizationManager.updateSyncStatus(syncUnit, {
214
- pull: "SYNCING",
215
- });
216
- }
217
- if (PullResponderTransmitter.isPullResponderTrigger(trigger)) {
218
- let firstPull = true;
219
- const cancelPullLoop = PullResponderTransmitter.setupPull(driveId, trigger, this.saveStrand.bind(this), (error) => {
220
- const statusError = error instanceof OperationError ? error.status : "ERROR";
221
- this.synchronizationManager.updateSyncStatus(driveId, { pull: statusError }, error);
222
- if (error instanceof ClientError) {
223
- this.eventEmitter.emit("clientStrandsError", driveId, trigger, error.response.status, error.message);
224
- }
225
- }, async (revisions) => {
226
- const errorRevisions = revisions.filter((r) => r.status !== "SUCCESS");
227
- if (errorRevisions.length < 1) {
228
- this.synchronizationManager.updateSyncStatus(driveId, {
229
- pull: "SUCCESS",
230
- });
231
- }
232
- for (const revision of revisions) {
233
- const { documentId, scope, branch, status, error } = revision;
234
- this.synchronizationManager.updateSyncStatus({ documentId, scope, branch }, { pull: status }, error);
235
- }
236
- // if it is the first pull and returns empty
237
- // then updates drive documents to "SUCCESS" and
238
- // updates corresponding push transmitter
239
- if (firstPull) {
240
- firstPull = false;
241
- const syncUnitsIds = await this.synchronizationManager.getSynchronizationUnitsIds(driveId);
242
- const unchangedSyncUnits = syncUnitsIds.filter((syncUnit) => {
243
- return !revisions.find((revision) => {
244
- return (revision.documentId === syncUnit.documentId &&
245
- revision.scope === syncUnit.scope &&
246
- revision.branch === syncUnit.branch);
247
- });
248
- });
249
- unchangedSyncUnits.forEach((syncUnit) => {
250
- this.synchronizationManager.updateSyncStatus(syncUnit, {
251
- pull: "SUCCESS",
252
- });
253
- });
254
- const pushListener = drive.state.local.listeners.find((listener) => trigger.data.url === listener.callInfo?.data);
255
- if (pushListener) {
256
- for (const revision of revisions) {
257
- const { documentId, scope, branch } = revision;
258
- this.listenerManager
259
- .updateListenerRevision(pushListener.listenerId, driveId, { documentId, scope, branch }, revision.revision)
260
- .catch((e) => this.logger.error("@error", e));
261
- }
262
- }
263
- }
264
- }, undefined, this.listeners);
265
- driveTriggers.set(trigger.id, cancelPullLoop);
266
- this.triggerMap.set(driveId, driveTriggers);
267
- }
268
- }
269
- }
270
- async stopSyncRemoteDrive(driveId) {
271
- const triggers = this.triggerMap.get(driveId);
272
- triggers?.forEach((cancel) => cancel());
273
- this.synchronizationManager.updateSyncStatus(driveId, null);
274
- const syncUnits = await this.synchronizationManager.getSynchronizationUnitsIds(driveId);
275
- for (const syncUnit of syncUnits) {
276
- this.synchronizationManager.updateSyncStatus(syncUnit, null);
277
- }
278
- return this.triggerMap.delete(driveId);
279
- }
280
- async _initializeDrive(driveId) {
281
- const drive = await this.getDrive(driveId);
282
- this.logger.verbose('[SYNC DEBUG] Initializing drive @driveId with slug "@slug"', driveId, drive.header.slug);
283
- await this.synchronizationManager.initializeDriveSyncStatus(driveId, drive);
284
- if (this.shouldSyncRemoteDrive(drive)) {
285
- this.logger.verbose("[SYNC DEBUG] Starting sync for remote drive @driveId", driveId);
286
- await this.startSyncRemoteDrive(driveId);
287
- }
288
- // add switchboard push listeners
289
- this.logger.verbose("[SYNC DEBUG] Processing @count listeners for drive @driveId", drive.state.local.listeners.length, driveId);
290
- for (const zodListener of drive.state.local.listeners) {
291
- if (zodListener.callInfo?.transmitterType === "SwitchboardPush") {
292
- this.logger.verbose("[SYNC DEBUG] Setting up SwitchboardPush listener @listenerId for drive @driveId", zodListener.listenerId, driveId);
293
- const transmitter = new SwitchboardPushTransmitter(zodListener.callInfo.data ?? "", this.listeners);
294
- this.logger.verbose("[SYNC DEBUG] Created SwitchboardPush transmitter with URL: @url", zodListener.callInfo.data || "none");
295
- await this.listenerManager
296
- .setListener(driveId, {
297
- block: zodListener.block,
298
- driveId: drive.header.id,
299
- filter: {
300
- branch: zodListener.filter.branch ?? [],
301
- documentId: zodListener.filter.documentId ?? [],
302
- documentType: zodListener.filter.documentType ?? [],
303
- scope: zodListener.filter.scope ?? [],
304
- },
305
- listenerId: zodListener.listenerId,
306
- callInfo: zodListener.callInfo,
307
- system: zodListener.system,
308
- label: zodListener.label ?? "",
309
- transmitter,
310
- })
311
- .then(() => {
312
- this.logger.verbose("[SYNC DEBUG] Successfully set up listener @listenerId for drive @driveId", zodListener.listenerId, driveId);
313
- });
314
- }
315
- else if (zodListener.callInfo?.transmitterType === "PullResponder") {
316
- this.logger.verbose("[SYNC DEBUG] Setting up PullResponder listener @listenerId for drive @driveId", zodListener.listenerId, driveId);
317
- const pullResponderListener = {
318
- driveId,
319
- listenerId: zodListener.listenerId,
320
- block: false,
321
- filter: zodListener.filter,
322
- system: false,
323
- label: `PullResponder #${zodListener.listenerId}`,
324
- callInfo: {
325
- data: "",
326
- name: "PullResponder",
327
- transmitterType: "PullResponder",
328
- },
329
- };
330
- const pullResponder = new PullResponderTransmitter(pullResponderListener, this.listenerManager);
331
- pullResponderListener.transmitter = pullResponder;
332
- await this.listenerManager.setListener(driveId, pullResponderListener);
333
- }
334
- else {
335
- this.logger.error("Skipping listener @listenerId with unsupported type @transmitterType", zodListener.listenerId, zodListener.callInfo?.transmitterType || "unknown");
336
- }
337
- }
338
- }
339
- getDocumentModelModule(documentType) {
340
- const documentModelModule = this.documentModelModules.find((module) => module.documentModel.global.id === documentType);
341
- if (!documentModelModule) {
342
- throw new Error(`Document type ${documentType} not supported`);
343
- }
344
- return documentModelModule;
345
- }
346
- getDocumentModelModules() {
347
- return [...this.documentModelModules];
348
- }
349
- addDocument(documentOrType, meta) {
350
- const input = typeof documentOrType === "string"
351
- ? { documentType: documentOrType }
352
- : { document: documentOrType };
353
- return this.createDocument(input, { type: "local" }, meta);
354
- }
355
- async addDrive(input, preferredEditor) {
356
- // Create document with custom global and local state
357
- const { global } = driveCreateState();
358
- const document = driveCreateDocument({
359
- global: {
360
- ...global,
361
- name: input.global.name ?? global.name,
362
- icon: input.global.icon ?? global.icon,
363
- },
364
- local: {
365
- availableOffline: input.local?.availableOffline ?? false,
366
- sharingType: input.local?.sharingType ?? "public",
367
- listeners: input.local?.listeners ?? [],
368
- triggers: input.local?.triggers ?? [],
369
- },
370
- });
371
- if (input.id && input.id.length > 0) {
372
- document.header.id = input.id;
373
- }
374
- if (input.slug && input.slug.length > 0) {
375
- document.header.slug = input.slug;
376
- }
377
- if (input.global.name) {
378
- document.header.name = input.global.name;
379
- }
380
- const editorToUse = input.preferredEditor || preferredEditor;
381
- if (editorToUse) {
382
- document.header.meta = {
383
- preferredEditor: editorToUse,
384
- };
385
- }
386
- await this.documentStorage.create(document);
387
- if (input.slug && input.slug.length > 0) {
388
- await this.cache.deleteDriveBySlug(input.slug);
389
- }
390
- await this._initializeDrive(document.header.id);
391
- this.eventEmitter.emit("driveAdded", document);
392
- return document;
393
- }
394
- async addRemoteDrive(url, options) {
395
- const token = await this.generateJwtHandler?.(url);
396
- const headers = token
397
- ? { Authorization: `Bearer ${token}` }
398
- : {};
399
- const { id, name, slug, icon, meta } = options.expectedDriveInfo ||
400
- (await requestPublicDriveWithTokenFromReactor(url, this));
401
- const { pullFilter, pullInterval, availableOffline, sharingType, listeners, triggers, } = options;
402
- const pullTrigger = await PullResponderTransmitter.createPullResponderTrigger(id, url, {
403
- pullFilter,
404
- pullInterval,
405
- }, this.listeners);
406
- return await this.addDrive({
407
- id,
408
- slug,
409
- global: {
410
- name,
411
- icon,
412
- },
413
- local: {
414
- triggers: [...triggers, pullTrigger],
415
- listeners: listeners,
416
- availableOffline,
417
- sharingType,
418
- },
419
- }, meta?.preferredEditor);
420
- }
421
- async deleteDrive(driveId) {
422
- const result = await Promise.allSettled([
423
- this.stopSyncRemoteDrive(driveId),
424
- this.listenerManager.removeDrive(driveId),
425
- this.cache.deleteDrive(driveId),
426
- this.documentStorage.delete(driveId),
427
- ]);
428
- this.eventEmitter.emit("driveDeleted", driveId);
429
- result.forEach((r) => {
430
- if (r.status === "rejected") {
431
- throw r.reason;
432
- }
433
- });
434
- }
435
- // TODO: paginate
436
- async getDrives() {
437
- const drives = [];
438
- let cursor;
439
- do {
440
- const { documents, nextCursor } = await this.documentStorage.findByType("powerhouse/document-drive", 100, cursor);
441
- drives.push(...documents);
442
- cursor = nextCursor;
443
- } while (cursor);
444
- return drives;
445
- }
446
- // TODO: paginate, move into IReactorClient eventually
447
- async getDrivesSlugs() {
448
- const drives = await this.getDrives();
449
- return this.documentStorage.resolveSlugs(drives);
450
- }
451
- async getDrive(driveId, options) {
452
- let document;
453
- try {
454
- const cachedDocument = await this.cache.getDrive(driveId); // TODO support GetDocumentOptions
455
- if (cachedDocument && isDocumentDrive(cachedDocument)) {
456
- document = cachedDocument;
457
- if (isAtRevision(document, options?.revisions)) {
458
- return document;
459
- }
460
- }
461
- }
462
- catch (e) {
463
- this.logger.error("Error getting drive from cache: @error", e);
464
- }
465
- const driveStorage = document ?? (await this.documentStorage.get(driveId));
466
- const result = this._buildDocument(driveStorage, options);
467
- if (!isDocumentDrive(result)) {
468
- throw new Error(`Document with id ${driveId} is not a Document Drive`);
469
- }
470
- else {
471
- if (!options?.revisions) {
472
- this.cache
473
- .setDocument(driveId, result)
474
- .catch((e) => this.logger.error("@error", e));
475
- this.cache
476
- .setDrive(driveId, result)
477
- .catch((e) => this.logger.error("@error", e));
478
- }
479
- return result;
480
- }
481
- }
482
- async getDriveBySlug(slug, options) {
483
- try {
484
- const drive = await this.cache.getDriveBySlug(slug);
485
- if (drive) {
486
- return drive;
487
- }
488
- }
489
- catch (e) {
490
- this.logger.error("Error getting drive from cache: @error", e);
491
- }
492
- const driveStorage = await this.documentStorage.getBySlug(slug);
493
- const document = this._buildDocument(driveStorage, options);
494
- if (!isDocumentDrive(document)) {
495
- throw new Error(`Document with slug ${slug} is not a Document Drive`);
496
- }
497
- else {
498
- this.cache
499
- .setDriveBySlug(slug, document)
500
- .catch((e) => this.logger.error("@error", e));
501
- return document;
502
- }
503
- }
504
- async getDriveIdBySlug(slug) {
505
- try {
506
- const drive = await this.cache.getDriveBySlug(slug);
507
- if (drive) {
508
- return drive.header.id;
509
- }
510
- }
511
- catch (e) {
512
- this.logger.error("Error getting drive from cache: @error", e);
513
- }
514
- const driveStorage = await this.documentStorage.getBySlug(slug);
515
- return driveStorage.header.id;
516
- }
517
- getDocument(driveId, documentId, options) {
518
- const id = typeof documentId === "string" ? documentId : driveId;
519
- const resolvedOptions = typeof documentId === "object" ? documentId : options;
520
- return this._getDocument(id, resolvedOptions);
521
- }
522
- async _getDocument(documentId, options) {
523
- let cachedDocument;
524
- try {
525
- cachedDocument = await this.cache.getDocument(documentId); // TODO support GetDocumentOptions
526
- if (cachedDocument && isAtRevision(cachedDocument, options?.revisions)) {
527
- return cachedDocument;
528
- }
529
- }
530
- catch (e) {
531
- this.logger.error("Error getting document from cache: @error", e);
532
- }
533
- const documentStorage = cachedDocument ?? (await this.documentStorage.get(documentId));
534
- const document = this._buildDocument(documentStorage, options);
535
- if (!options?.revisions) {
536
- this.cache
537
- .setDocument(documentId, document)
538
- .catch((e) => this.logger.error("@error", e));
539
- }
540
- return document;
541
- }
542
- getDocuments(driveId) {
543
- return this.documentStorage.getChildren(driveId);
544
- }
545
- async addChild(parentId, documentId) {
546
- // TODO: check if document exists? Should that be a concern here?
547
- try {
548
- await this.documentStorage.addChild(parentId, documentId);
549
- // TODO: update listener manager?
550
- }
551
- catch (e) {
552
- this.logger.error("Error adding child document: @error", e);
553
- throw e;
554
- }
555
- }
556
- async removeChild(parentId, documentId) {
557
- // TODO: check if document exists? Should that be a concern here?
558
- // cleanup child sync units state from the parent listeners
559
- try {
560
- const childSynUnits = await this.synchronizationManager.getSynchronizationUnitsIds(parentId, [
561
- documentId,
562
- ]);
563
- await this.listenerManager.removeSyncUnits(parentId, childSynUnits);
564
- }
565
- catch (e) {
566
- this.logger.warn("Error removing sync units of child: @error", e);
567
- }
568
- // remove child relationship from storage
569
- try {
570
- await this.documentStorage.removeChild(parentId, documentId);
571
- }
572
- catch (e) {
573
- this.logger.error("Error adding child document: @error", e);
574
- throw e;
575
- }
576
- }
577
- async createDocument(input, source, meta) {
578
- if (this.enableDualActionCreate) {
579
- return this.createDocumentDualAction(input, source, meta);
580
- }
581
- else {
582
- return this.createDocumentLegacy(input, source, meta);
583
- }
584
- }
585
- async createDocumentLegacy(input, source, meta) {
586
- const { documentType, document: inputDocument } = resolveCreateDocumentInput(input);
587
- // if a document was provided then checks if it's valid
588
- let state = undefined;
589
- if (inputDocument) {
590
- if ("documentType" in input &&
591
- documentType !== inputDocument.header.documentType) {
592
- throw new Error(`Provided document is not ${documentType}`);
593
- }
594
- const doc = this._buildDocument(inputDocument);
595
- state = doc.state;
596
- }
597
- // if no document was provided then create a new one
598
- const document = inputDocument ??
599
- this.getDocumentModelModule(documentType).utils.createDocument(state);
600
- // get the header
601
- let header;
602
- // handle the legacy case where an id is provided
603
- if ("id" in input && input.id) {
604
- if (inputDocument) {
605
- header = document.header;
606
- document.header.id = input.id;
607
- this.logger.warn("Assigning an id to a document is deprecated. Use the header field instead.");
608
- }
609
- else {
610
- this.logger.warn("Creating a document with an id is deprecated. Use the header field instead.");
611
- header = createPresignedHeader(input.id, documentType);
612
- }
613
- }
614
- else if ("header" in input) {
615
- // validate the header passed in
616
- await validateHeader(input.header);
617
- header = input.header;
618
- }
619
- else if (inputDocument?.header) {
620
- if (!inputDocument.header.id) {
621
- throw new Error("Document header id is required");
622
- }
623
- if (!inputDocument.header.documentType) {
624
- throw new Error("Document header documentType is required");
625
- }
626
- if (!inputDocument.header.createdAtUtcIso) {
627
- throw new Error("Document header createdAtUtcIso is required");
628
- }
629
- if (!inputDocument.header.sig.nonce) {
630
- this.logger.warn("Creating a document with an unsigned id is deprecated. Use createSignedHeaderForSigner.");
631
- // throw new Error("Document header sig nonce is required"); TODO: uncomment when ready to enforce signed documents
632
- }
633
- else {
634
- await validateHeader(inputDocument.header);
635
- }
636
- header = inputDocument.header;
637
- }
638
- else {
639
- // otherwise, generate a header
640
- header = createPresignedHeader(undefined, documentType);
641
- }
642
- if (meta) {
643
- header.meta = { ...header.meta, ...meta };
644
- }
645
- // stores document information
646
- const documentStorage = {
647
- header,
648
- operations: { global: [], local: [] },
649
- initialState: document.initialState,
650
- clipboard: [],
651
- state: state ?? document.state,
652
- };
653
- await this.documentStorage.create(documentStorage);
654
- // TODO set initial state for document sync units
655
- // if (source.type === "trigger") {
656
- // for (const scope of Object.keys(document.state)) {
657
- // this.synchronizationManager.updateSyncStatus(
658
- // {
659
- // documentId: document.id,
660
- // scope,
661
- // branch: "main" /* TODO handle branches */,
662
- // },
663
- // {
664
- // pull: "INITIAL_SYNC",
665
- // push: this.listenerManager.driveHasListeners(driveId)
666
- // ? "SUCCESS"
667
- // : undefined,
668
- // },
669
- // );
670
- // }
671
- // }
672
- // if the document contains operations then
673
- // stores the operations in the storage
674
- const operations = Object.values(document.operations).flat();
675
- if (operations.length) {
676
- if (isDocumentDrive(document)) {
677
- await this.legacyStorage.addDriveOperations(header.id, operations, document);
678
- }
679
- else {
680
- await this.legacyStorage.addDocumentOperations(header.id, operations, document);
681
- }
682
- }
683
- const addedDocument = await this.getDocument(documentStorage.header.id);
684
- this.eventEmitter.emit("documentAdded", addedDocument);
685
- return addedDocument;
686
- }
687
- async createDocumentDualAction(input, source, meta) {
688
- const { documentType, document: inputDocument } = resolveCreateDocumentInput(input);
689
- // if a document was provided then checks if it's valid
690
- let state = undefined;
691
- if (inputDocument) {
692
- if ("documentType" in input &&
693
- documentType !== inputDocument.header.documentType) {
694
- throw new Error(`Provided document is not ${documentType}`);
695
- }
696
- const doc = this._buildDocument(inputDocument);
697
- state = doc.state;
698
- }
699
- // if no document was provided then create a new one
700
- const document = inputDocument ??
701
- this.getDocumentModelModule(documentType).utils.createDocument(state);
702
- // get the header
703
- let header;
704
- // handle the legacy case where an id is provided
705
- let isSigned = false;
706
- if ("id" in input && input.id) {
707
- if (inputDocument) {
708
- header = document.header;
709
- document.header.id = input.id;
710
- this.logger.warn("Assigning an id to a document is deprecated. Use the header field instead.");
711
- }
712
- else {
713
- this.logger.warn("Creating a document with an id is deprecated. Use the header field instead.");
714
- header = createPresignedHeader(input.id, documentType);
715
- }
716
- }
717
- else if ("header" in input) {
718
- // validate the header passed in
719
- await validateHeader(input.header);
720
- isSigned = true;
721
- header = input.header;
722
- }
723
- else if (inputDocument?.header) {
724
- if (!inputDocument.header.id) {
725
- throw new Error("Document header id is required");
726
- }
727
- if (!inputDocument.header.documentType) {
728
- throw new Error("Document header documentType is required");
729
- }
730
- if (!inputDocument.header.createdAtUtcIso) {
731
- throw new Error("Document header createdAtUtcIso is required");
732
- }
733
- if (!inputDocument.header.sig.nonce) {
734
- this.logger.warn("Creating a document with an unsigned id is deprecated. Use createSignedHeaderForSigner.");
735
- // throw new Error("Document header sig nonce is required"); TODO: uncomment when ready to enforce signed documents
736
- }
737
- else {
738
- await validateHeader(inputDocument.header);
739
- isSigned = true;
740
- }
741
- header = inputDocument.header;
742
- }
743
- else {
744
- // otherwise, generate a header
745
- header = createPresignedHeader(undefined, documentType);
746
- isSigned = false;
747
- }
748
- if (meta) {
749
- header.meta = { ...header.meta, ...meta };
750
- }
751
- const currentVersion = 1;
752
- // Get initial state from input or model's defaultState
753
- const initialState = state ?? document.state;
754
- // Check if the input document already has operations
755
- const existingOperations = Object.values(document.operations).flat();
756
- const shouldCreateOperations = existingOperations.length === 0;
757
- let operations = [];
758
- if (shouldCreateOperations) {
759
- const timestampUtcMs = new Date().toISOString();
760
- // Determine if this is a signed document
761
- const signing = isSigned
762
- ? {
763
- signature: header.id, // The document ID is the signature
764
- publicKey: header.sig.publicKey,
765
- nonce: header.sig.nonce,
766
- createdAtUtcIso: header.createdAtUtcIso,
767
- documentType: header.documentType,
768
- }
769
- : undefined;
770
- // Create actions for CREATE_DOCUMENT and UPGRADE_DOCUMENT
771
- const createDocumentInput = {
772
- model: documentType,
773
- version: 0,
774
- documentId: header.id,
775
- signing,
776
- };
777
- const createDocumentAction = {
778
- id: generateId(),
779
- type: "CREATE_DOCUMENT",
780
- timestampUtcMs,
781
- input: createDocumentInput,
782
- scope: "document",
783
- };
784
- const upgradeDocumentInput = {
785
- model: documentType,
786
- fromVersion: 0,
787
- toVersion: currentVersion,
788
- documentId: header.id,
789
- initialState,
790
- };
791
- const upgradeDocumentAction = {
792
- id: generateId(),
793
- type: "UPGRADE_DOCUMENT",
794
- timestampUtcMs,
795
- input: upgradeDocumentInput,
796
- scope: "document",
797
- };
798
- // we need to create hashes for later verification
799
- const baseState = defaultBaseState();
800
- const createStateForHash = {
801
- state: baseState,
802
- };
803
- const createHash = hashDocumentStateForScope(createStateForHash, "document");
804
- const upgradeStateForHash = {
805
- state: initialState,
806
- };
807
- const upgradeHash = hashDocumentStateForScope(upgradeStateForHash, "document");
808
- // Create operations from actions with computed hashes
809
- operations = [
810
- {
811
- id: deriveOperationId(header.id, "document", "main", createDocumentAction.id),
812
- index: 0,
813
- skip: 0,
814
- hash: createHash,
815
- timestampUtcMs,
816
- action: createDocumentAction,
817
- },
818
- {
819
- id: deriveOperationId(header.id, "document", "main", upgradeDocumentAction.id),
820
- index: 1,
821
- skip: 0,
822
- hash: upgradeHash,
823
- timestampUtcMs,
824
- action: upgradeDocumentAction,
825
- },
826
- ];
827
- }
828
- else {
829
- // Use existing operations from the input document
830
- operations = existingOperations;
831
- }
832
- // Group operations by scope before storing
833
- const groupedOps = groupOperationsByScope(operations);
834
- // Ensure backward compatibility by initializing missing scopes
835
- if (!groupedOps.header) {
836
- groupedOps.header = [];
837
- }
838
- if (!groupedOps.document) {
839
- groupedOps.document = [];
840
- }
841
- if (!groupedOps.global) {
842
- groupedOps.global = [];
843
- }
844
- if (!groupedOps.local) {
845
- groupedOps.local = [];
846
- }
847
- // After initialization, it's safe to treat as DocumentOperations
848
- const operationsByScope = groupedOps;
849
- // stores document information with operations
850
- const documentToStore = {
851
- header,
852
- operations: operationsByScope,
853
- initialState,
854
- clipboard: [],
855
- state: initialState,
856
- };
857
- await this.documentStorage.create(documentToStore);
858
- // Force rebuild to ensure operations are properly merged
859
- const addedDocument = await this.getDocument(documentToStore.header.id, {
860
- checkHashes: true,
861
- });
862
- this.eventEmitter.emit("documentAdded", addedDocument);
863
- return addedDocument;
864
- }
865
- async deleteDocument(documentId) {
866
- try {
867
- const syncUnits = await this.synchronizationManager.getSynchronizationUnitsIds(undefined, [documentId]);
868
- // remove document sync units status when a document is deleted
869
- for (const syncUnit of syncUnits) {
870
- this.synchronizationManager.updateSyncStatus(syncUnit, null);
871
- }
872
- const parents = await this.documentStorage.getParents(documentId);
873
- for (const parent of parents) {
874
- this.listenerManager
875
- .removeSyncUnits(parent, syncUnits)
876
- .catch(this.logger.warn);
877
- }
878
- }
879
- catch (error) {
880
- this.logger.warn("Error deleting document: @error", error);
881
- }
882
- await Promise.allSettled([
883
- this.cache.deleteDocument(documentId).catch(this.logger.warn),
884
- this.documentStorage.delete(documentId).catch(this.logger.warn),
885
- ]);
886
- this.eventEmitter.emit("documentDeleted", documentId);
887
- }
888
- async _processOperations(documentId, documentStorage, operations) {
889
- const operationsApplied = [];
890
- const signals = [];
891
- const documentStorageWithState = await this._addDocumentResultingStage(documentStorage, documentId);
892
- let document = this._buildDocument(documentStorageWithState);
893
- let error; // TODO: replace with an array of errors/consistency issues
894
- const operationsByScope = groupOperationsByScope(operations);
895
- for (const scope of Object.keys(operationsByScope)) {
896
- const storageDocumentOperations = documentStorage.operations[scope] || [];
897
- // TODO two equal operations done by two clients will be considered the same, ie: { type: "INCREMENT" }
898
- const branch = removeExistingOperations(operationsByScope[scope] || [], storageDocumentOperations);
899
- // No operations to apply
900
- if (branch.length < 1) {
901
- continue;
902
- }
903
- const trunk = garbageCollect(sortOperations(storageDocumentOperations));
904
- const [invertedTrunk, tail] = attachBranch(trunk, branch);
905
- const newHistory = tail.length < 1
906
- ? invertedTrunk
907
- : merge(trunk, invertedTrunk, reshuffleByTimestamp);
908
- const newOperations = newHistory.filter((op) => trunk.length < 1 || precedes(trunk[trunk.length - 1], op));
909
- for (const nextOperation of newOperations) {
910
- let skipHashValidation = false;
911
- // when dealing with a merge (tail.length > 0) we have to skip hash validation
912
- // for the operations that were re-indexed (previous hash becomes invalid due the new position in the history)
913
- if (tail.length > 0) {
914
- const sourceOperation = operations.find((op) => op.hash === nextOperation.hash);
915
- skipHashValidation =
916
- !sourceOperation ||
917
- sourceOperation.index !== nextOperation.index ||
918
- sourceOperation.skip !== nextOperation.skip;
919
- }
920
- try {
921
- // runs operation on next available tick, to avoid blocking the main thread
922
- const taskQueueMethod = this.options.taskQueueMethod;
923
- const task = () => this._performOperation(documentId, document, nextOperation, skipHashValidation);
924
- const appliedResult = await (taskQueueMethod
925
- ? runAsapAsync(task, taskQueueMethod)
926
- : task());
927
- document = appliedResult.document;
928
- signals.push(...appliedResult.signals);
929
- operationsApplied.push(appliedResult.operation);
930
- // TODO what to do if one of the applied operations has an error?
931
- }
932
- catch (e) {
933
- error =
934
- e instanceof OperationError
935
- ? e
936
- : new OperationError("ERROR", nextOperation, e.message, e.cause);
937
- // TODO: don't break on errors...
938
- break;
939
- }
940
- }
941
- }
942
- return {
943
- document,
944
- operationsApplied,
945
- signals,
946
- error,
947
- };
948
- }
949
- async _addDocumentResultingStage(document, documentId, options) {
950
- // apply skip header operations to all scopes
951
- const operations = options?.revisions !== undefined
952
- ? filterOperationsByRevision(document.operations, options.revisions)
953
- : document.operations;
954
- const documentOperations = garbageCollectDocumentOperations(operations);
955
- for (const scope of Object.keys(documentOperations)) {
956
- const scopeOps = documentOperations[scope];
957
- if (!scopeOps) {
958
- continue;
959
- }
960
- const lastRemainingOperation = scopeOps.at(-1);
961
- // if the latest operation doesn't have a resulting state then tries
962
- // to retrieve it from the db to avoid rerunning all the operations
963
- if (lastRemainingOperation && !lastRemainingOperation.resultingState) {
964
- lastRemainingOperation.resultingState = await (isDocumentDrive(document)
965
- ? this.legacyStorage.getOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main")
966
- : this.legacyStorage.getDriveOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main"));
967
- }
968
- }
969
- return {
970
- ...document,
971
- operations: documentOperations,
972
- };
973
- }
974
- _buildDocument(documentStorage, options) {
975
- if (documentStorage.state &&
976
- (!options || options.checkHashes === false) &&
977
- isAtRevision(documentStorage, options?.revisions)) {
978
- return documentStorage;
979
- }
980
- const documentModelModule = this.getDocumentModelModule(documentStorage.header.documentType);
981
- const revisionOperations = options?.revisions !== undefined
982
- ? filterOperationsByRevision(documentStorage.operations, options.revisions)
983
- : documentStorage.operations;
984
- const operations = garbageCollectDocumentOperations(revisionOperations);
985
- // Get all scopes from operations
986
- const allScopes = Object.keys(operations);
987
- // Initialize with all scopes found in operations, plus global and local for backward compatibility
988
- const scopesToInitialize = new Set([...allScopes, "global", "local"]);
989
- const headerOperations = {};
990
- const operationsToReplay = {};
991
- for (const scope of scopesToInitialize) {
992
- headerOperations[scope] = [];
993
- operationsToReplay[scope] = [];
994
- }
995
- // Filter out CREATE_DOCUMENT and UPGRADE_DOCUMENT operations
996
- // (these don't currently have reducers and should not be replayed)
997
- for (const [scope, scopeOps] of Object.entries(operations)) {
998
- if (!scopeOps) {
999
- continue;
1000
- }
1001
- for (const op of scopeOps) {
1002
- if (op.action.type === "CREATE_DOCUMENT" ||
1003
- op.action.type === "UPGRADE_DOCUMENT") {
1004
- const headerOps = headerOperations[scope];
1005
- if (headerOps) {
1006
- headerOps.push(op);
1007
- }
1008
- }
1009
- else {
1010
- const replayOps = operationsToReplay[scope];
1011
- if (replayOps) {
1012
- replayOps.push(op);
1013
- }
1014
- }
1015
- }
1016
- }
1017
- // If revisions filter is specified, compute header revision from filtered operations
1018
- // This ensures the returned document's header.revision reflects the requested revision,
1019
- // not the current storage state
1020
- let headerForReplay = documentStorage.header;
1021
- if (options?.revisions) {
1022
- const newRevision = {
1023
- ...documentStorage.header.revision,
1024
- };
1025
- // For each scope in the revision filter, compute actual revision from filtered ops
1026
- for (const scope of Object.keys(options.revisions)) {
1027
- const scopeOps = operations[scope] ?? [];
1028
- if (scopeOps.length === 0) {
1029
- // No ops means revision should not exist for this scope
1030
- delete newRevision[scope];
1031
- }
1032
- else {
1033
- const lastOp = scopeOps.at(-1);
1034
- newRevision[scope] = lastOp ? lastOp.index + 1 : 0;
1035
- }
1036
- }
1037
- headerForReplay = {
1038
- ...documentStorage.header,
1039
- revision: newRevision,
1040
- };
1041
- }
1042
- const replayed = replayDocument(documentStorage.initialState, operationsToReplay, documentModelModule.reducer, headerForReplay, undefined, {}, {
1043
- ...options,
1044
- checkHashes: options?.checkHashes ?? true,
1045
- reuseOperationResultingState: options?.checkHashes ?? true,
1046
- });
1047
- // merge header operations back into the result
1048
- // Include ALL scopes from input operations, header operations, and replayed operations
1049
- const allScopesForMerge = new Set([
1050
- ...Object.keys(operations), // From input storage
1051
- ...Object.keys(headerOperations),
1052
- ...Object.keys(replayed.operations),
1053
- ]);
1054
- const finalOperations = {};
1055
- for (const scope of allScopesForMerge) {
1056
- finalOperations[scope] = [
1057
- ...(headerOperations[scope] || []),
1058
- ...(replayed.operations[scope] || []),
1059
- ];
1060
- }
1061
- return {
1062
- ...replayed,
1063
- operations: finalOperations,
1064
- clipboard: documentStorage.clipboard ?? [],
1065
- };
1066
- }
1067
- async _performOperation(documentId, document, operation, skipHashValidation = false) {
1068
- const documentModelModule = this.getDocumentModelModule(document.header.documentType);
1069
- const signalResults = [];
1070
- let newDocument = document;
1071
- const scope = operation.action.scope;
1072
- const currentScopeOperations = document.operations[scope] || [];
1073
- const documentOperations = garbageCollectDocumentOperations({
1074
- ...document.operations,
1075
- [scope]: skipHeaderOperations(currentScopeOperations, operation),
1076
- });
1077
- const remainingScopeOps = documentOperations[scope];
1078
- const lastRemainingOperation = remainingScopeOps?.at(-1);
1079
- // if the latest operation doesn't have a resulting state then tries
1080
- // to retrieve it from the db to avoid rerunning all the operations
1081
- if (lastRemainingOperation && !lastRemainingOperation.resultingState) {
1082
- lastRemainingOperation.resultingState = await (isDocumentDrive(document)
1083
- ? this.legacyStorage.getOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main")
1084
- : this.legacyStorage.getDriveOperationResultingState?.(documentId, lastRemainingOperation.index, lastRemainingOperation.action.scope, "main"));
1085
- }
1086
- const operationsBeforeReducer = newDocument.operations[scope] || [];
1087
- const operationSignals = [];
1088
- newDocument = documentModelModule.reducer(newDocument, operation.action, (signal) => {
1089
- let handler = undefined;
1090
- switch (signal.type) {
1091
- case "CREATE_CHILD_DOCUMENT":
1092
- handler = () => this.addChild(documentId, signal.input.id);
1093
- break;
1094
- case "DELETE_CHILD_DOCUMENT":
1095
- handler = () => this.removeChild(documentId, signal.input.id);
1096
- break;
1097
- case "COPY_CHILD_DOCUMENT":
1098
- handler = () => this.addChild(documentId, signal.input.newId);
1099
- break;
1100
- }
1101
- if (handler) {
1102
- operationSignals.push(() => handler().then((result) => ({ signal, result })));
1103
- }
1104
- }, {
1105
- skip: operation.skip,
1106
- reuseOperationResultingState: true,
1107
- replayOptions: { operation },
1108
- });
1109
- // when we have NOOP operations with skip > 0 we need to populate the
1110
- // clipboard with the operations that were skipped to allow redo
1111
- if (operation.action.type === "NOOP" &&
1112
- operation.skip > 0 &&
1113
- newDocument.clipboard.length === 0) {
1114
- const scopeOperationsAfter = newDocument.operations[scope] || [];
1115
- // Get operations AFTER garbageCollect (with NOOP)
1116
- const afterOperations = garbageCollect(sortOperations(scopeOperationsAfter));
1117
- // Get operations BEFORE the reducer ran (before NOOP was applied)
1118
- const beforeOperations = garbageCollect(sortOperations(operationsBeforeReducer));
1119
- // Calculate what was removed by comparing before vs after
1120
- // The diff shows operations that were in "before" but not in "after"
1121
- const diff = diffOperations(beforeOperations, afterOperations);
1122
- // Populate clipboard with skipped operations (excluding NOOPs)
1123
- newDocument = {
1124
- ...newDocument,
1125
- clipboard: sortOperations(diff.filter((op) => op.action.type !== "NOOP")).reverse(),
1126
- };
1127
- }
1128
- const newDocScopeOperations = newDocument.operations[operation.action.scope];
1129
- if (!newDocScopeOperations) {
1130
- throw new OperationError("ERROR", operation, `No operations found for scope: ${operation.action.scope}`);
1131
- }
1132
- const appliedOperations = newDocScopeOperations.filter((op) => op.index == operation.index && op.skip == operation.skip);
1133
- const appliedOperation = appliedOperations.at(0);
1134
- if (!appliedOperation) {
1135
- throw new OperationError("ERROR", operation, `Operation with index ${operation.index}:${operation.skip} was not applied.`);
1136
- }
1137
- if (!appliedOperation.error &&
1138
- appliedOperation.hash !== operation.hash &&
1139
- !skipHashValidation) {
1140
- this.logger.warn("@appliedOperation", appliedOperation);
1141
- throw new ConflictOperationError(operation, appliedOperation);
1142
- }
1143
- for (const signalHandler of operationSignals) {
1144
- const result = await signalHandler();
1145
- signalResults.push(result);
1146
- }
1147
- return {
1148
- document: newDocument,
1149
- signals: signalResults,
1150
- operation: appliedOperation,
1151
- };
1152
- }
1153
- addOperation(driveIdOrDocumentId, documentIdOrOperation, operationOrOptions, maybeOptions) {
1154
- let documentId;
1155
- let operation;
1156
- let options;
1157
- if (typeof documentIdOrOperation === "string") {
1158
- // Deprecated overload: (driveId, documentId, operation, options)
1159
- documentId = documentIdOrOperation;
1160
- operation = operationOrOptions;
1161
- options = maybeOptions;
1162
- }
1163
- else {
1164
- // Standard overload: (documentId, operation, options)
1165
- documentId = driveIdOrDocumentId;
1166
- operation = documentIdOrOperation;
1167
- options = operationOrOptions;
1168
- }
1169
- return this.addOperations(documentId, [operation], options);
1170
- }
1171
- async _addOperations(documentId, callback) {
1172
- if (!this.legacyStorage.addDocumentOperationsWithTransaction) {
1173
- const documentStorage = await this.documentStorage.get(documentId);
1174
- const result = await callback(documentStorage);
1175
- // saves the applied operations to storage
1176
- if (result.operations.length > 0) {
1177
- await this.legacyStorage.addDocumentOperations(documentId, result.operations, result.document);
1178
- }
1179
- }
1180
- else {
1181
- await this.legacyStorage.addDocumentOperationsWithTransaction(documentId, callback);
1182
- }
1183
- }
1184
- async queueDocument(input, options) {
1185
- const { id, documentType, document } = resolveCreateDocumentInput(input);
1186
- if (!id) {
1187
- throw new Error("Document id is required", { cause: input });
1188
- }
1189
- if (!documentType) {
1190
- throw new Error("Document type is required", { cause: input });
1191
- }
1192
- const exists = await this.documentStorage.exists(id);
1193
- if (exists) {
1194
- throw new DocumentAlreadyExistsError(id);
1195
- }
1196
- // add listeners first
1197
- let jobId;
1198
- const promise = new Promise((resolve, reject) => {
1199
- const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
1200
- if (job.jobId === jobId) {
1201
- unsubscribe();
1202
- unsubscribeError();
1203
- resolve(result);
1204
- }
1205
- });
1206
- const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
1207
- if (job.jobId === jobId) {
1208
- unsubscribe();
1209
- unsubscribeError();
1210
- reject(error);
1211
- }
1212
- });
1213
- });
1214
- // now queue the job
1215
- try {
1216
- jobId = await this.queueManager.addJob({
1217
- documentId: id,
1218
- documentType,
1219
- initialState: document?.state,
1220
- header: document?.header,
1221
- options,
1222
- });
1223
- }
1224
- catch (error) {
1225
- this.logger.error("Error adding job: @error", error);
1226
- throw error;
1227
- }
1228
- return promise;
1229
- }
1230
- queueOperation(driveIdOrDocumentId, documentIdOrOperation, operationOrOptions, maybeOptions) {
1231
- let documentId;
1232
- let operation;
1233
- let options;
1234
- if (typeof documentIdOrOperation === "string") {
1235
- // Deprecated overload: (driveId, documentId, operation, options)
1236
- documentId = documentIdOrOperation;
1237
- operation = operationOrOptions;
1238
- options = maybeOptions;
1239
- }
1240
- else {
1241
- // Standard overload: (documentId, operation, options)
1242
- documentId = driveIdOrDocumentId;
1243
- operation = documentIdOrOperation;
1244
- options = operationOrOptions;
1245
- }
1246
- return this._queueOperations(documentId, [operation], options);
1247
- }
1248
- async resultIfExistingOperations(id, operations) {
1249
- try {
1250
- const document = await this.getDocument(id);
1251
- const newOperation = operations.find((op) => {
1252
- if (!op.id) {
1253
- return true;
1254
- }
1255
- const scopeOps = document.operations[op.action.scope];
1256
- if (!scopeOps) {
1257
- return true;
1258
- }
1259
- return !scopeOps.find((existingOp) => existingOp.id === op.id &&
1260
- existingOp.index === op.index &&
1261
- existingOp.action.type === op.action.type &&
1262
- existingOp.hash === op.hash);
1263
- });
1264
- if (!newOperation) {
1265
- return {
1266
- status: "SUCCESS",
1267
- document,
1268
- operations,
1269
- signals: [],
1270
- };
1271
- }
1272
- else {
1273
- return undefined;
1274
- }
1275
- }
1276
- catch (error) {
1277
- if (!error.message.includes(`Document with id ${id} not found`)) {
1278
- console.error(error);
1279
- }
1280
- return undefined;
1281
- }
1282
- }
1283
- queueOperations(driveIdOrDocumentId, documentIdOrOperations, operationsOrOptions, maybeOptions) {
1284
- let documentId;
1285
- let operations;
1286
- let options;
1287
- if (typeof documentIdOrOperations === "string") {
1288
- // Deprecated overload: (driveId, documentId, operations, options)
1289
- documentId = documentIdOrOperations;
1290
- operations = operationsOrOptions;
1291
- options = maybeOptions;
1292
- }
1293
- else {
1294
- // Standard overload: (documentId, operations, options)
1295
- documentId = driveIdOrDocumentId;
1296
- operations = documentIdOrOperations;
1297
- options = operationsOrOptions;
1298
- }
1299
- return this._queueOperations(documentId, operations, options);
1300
- }
1301
- async _queueOperations(documentId, operations, options) {
1302
- // if operations are already stored then returns cached document
1303
- const result = await this.resultIfExistingOperations(documentId, operations);
1304
- if (result) {
1305
- return result;
1306
- }
1307
- // add listeners first
1308
- let jobId;
1309
- const promise = new Promise((resolve, reject) => {
1310
- const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
1311
- if (job.jobId === jobId) {
1312
- unsubscribe();
1313
- unsubscribeError();
1314
- resolve(result);
1315
- }
1316
- });
1317
- const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
1318
- if (job.jobId === jobId) {
1319
- unsubscribe();
1320
- unsubscribeError();
1321
- reject(error);
1322
- }
1323
- });
1324
- });
1325
- // now queue the job
1326
- try {
1327
- jobId = await this.queueManager.addJob({
1328
- documentId,
1329
- operations,
1330
- options,
1331
- });
1332
- }
1333
- catch (error) {
1334
- this.logger.error("Error adding job: @error", error);
1335
- throw error;
1336
- }
1337
- return promise;
1338
- }
1339
- queueAction(driveIdOrDocumentId, documentIdOrAction, actionOrOptions, maybeOptions) {
1340
- let documentId;
1341
- let action;
1342
- let options;
1343
- if (typeof documentIdOrAction === "string") {
1344
- // Deprecated overload: (driveId, documentId, action, options)
1345
- documentId = documentIdOrAction;
1346
- action = actionOrOptions;
1347
- options = maybeOptions;
1348
- }
1349
- else {
1350
- // Standard overload: (documentId, action, options)
1351
- documentId = driveIdOrDocumentId;
1352
- action = documentIdOrAction;
1353
- options = actionOrOptions;
1354
- }
1355
- return this._queueActions(documentId, [action], options);
1356
- }
1357
- queueActions(driveIdOrDocumentId, documentIdOrActions, actionsOrOptions, maybeOptions) {
1358
- let documentId;
1359
- let actions;
1360
- let options;
1361
- if (typeof documentIdOrActions === "string") {
1362
- // Deprecated overload: (driveId, documentId, actions, options)
1363
- documentId = documentIdOrActions;
1364
- actions = actionsOrOptions;
1365
- options = maybeOptions;
1366
- }
1367
- else {
1368
- // Standard overload: (documentId, actions, options)
1369
- documentId = driveIdOrDocumentId;
1370
- actions = documentIdOrActions;
1371
- options = actionsOrOptions;
1372
- }
1373
- return this._queueActions(documentId, actions, options);
1374
- }
1375
- async _queueActions(documentId, actions, options) {
1376
- try {
1377
- const jobId = await this.queueManager.addJob({
1378
- documentId,
1379
- actions,
1380
- options,
1381
- });
1382
- return await new Promise((resolve, reject) => {
1383
- const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
1384
- if (job.jobId === jobId) {
1385
- unsubscribe();
1386
- unsubscribeError();
1387
- resolve(result);
1388
- }
1389
- });
1390
- const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
1391
- if (job.jobId === jobId) {
1392
- unsubscribe();
1393
- unsubscribeError();
1394
- reject(error);
1395
- }
1396
- });
1397
- });
1398
- }
1399
- catch (error) {
1400
- this.logger.error("Error adding job: @error", error);
1401
- throw error;
1402
- }
1403
- }
1404
- /**
1405
- * @deprecated Use the {@link queueAction} method instead.
1406
- */
1407
- async queueDriveAction(driveId, action, options) {
1408
- return this.queueDriveActions(driveId, [action], options);
1409
- }
1410
- /**
1411
- * @deprecated Use the {@link queueActions} method instead.
1412
- */
1413
- async queueDriveActions(driveId, actions, options) {
1414
- try {
1415
- const jobId = await this.queueManager.addJob({
1416
- documentId: driveId,
1417
- actions,
1418
- options,
1419
- });
1420
- return await new Promise((resolve, reject) => {
1421
- const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
1422
- if (job.jobId === jobId) {
1423
- unsubscribe();
1424
- unsubscribeError();
1425
- resolve(result);
1426
- }
1427
- });
1428
- const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
1429
- if (job.jobId === jobId) {
1430
- unsubscribe();
1431
- unsubscribeError();
1432
- reject(error);
1433
- }
1434
- });
1435
- });
1436
- }
1437
- catch (error) {
1438
- this.logger.error("Error adding drive job: @error", error);
1439
- throw error;
1440
- }
1441
- }
1442
- addOperations(driveIdOrDocumentId, documentIdOrOperations, operationsOrOptions, maybeOptions) {
1443
- let documentId;
1444
- let operations;
1445
- let options;
1446
- if (typeof documentIdOrOperations === "string") {
1447
- // Deprecated overload: (driveId, documentId, operations, options)
1448
- documentId = documentIdOrOperations;
1449
- operations = operationsOrOptions;
1450
- options = maybeOptions;
1451
- }
1452
- else {
1453
- // Standard overload: (documentId, operations, options)
1454
- documentId = driveIdOrDocumentId;
1455
- operations = documentIdOrOperations;
1456
- options = operationsOrOptions;
1457
- }
1458
- return this._queueOperations(documentId, operations, options);
1459
- }
1460
- async processOperations(documentId, operations, options) {
1461
- // if operations are already stored then returns the result
1462
- const result = await this.resultIfExistingOperations(documentId, operations);
1463
- if (result) {
1464
- return result;
1465
- }
1466
- let document;
1467
- const operationsApplied = [];
1468
- const signals = [];
1469
- let error;
1470
- try {
1471
- await this._addOperations(documentId, async (documentStorage) => {
1472
- const result = await this._processOperations(documentId, documentStorage, operations);
1473
- if (!result.document) {
1474
- this.logger.error("Invalid document");
1475
- throw result.error ?? new Error("Invalid document");
1476
- }
1477
- document = result.document;
1478
- error = result.error;
1479
- signals.push(...result.signals);
1480
- operationsApplied.push(...result.operationsApplied);
1481
- return {
1482
- operations: result.operationsApplied,
1483
- document: result.document,
1484
- };
1485
- });
1486
- const syncUnits = new Array();
1487
- if (document) {
1488
- this.cache
1489
- .setDocument(documentId, document)
1490
- .catch((e) => this.logger.error("@error", e));
1491
- // creates array of unique sync units from the applied operations
1492
- for (const operation of operationsApplied) {
1493
- const syncUnit = {
1494
- documentId,
1495
- documentType: document.header.documentType,
1496
- scope: operation.action.scope,
1497
- branch: "main", // TODO: handle branches
1498
- revision: operation.index + 1,
1499
- lastUpdated: operation.timestampUtcMs,
1500
- };
1501
- // checks if this sync unit was already added
1502
- const exists = syncUnits.some((unit) => unit.documentId === syncUnit.documentId &&
1503
- unit.scope === syncUnit.scope &&
1504
- unit.branch === syncUnit.branch);
1505
- if (!exists) {
1506
- syncUnits.push(syncUnit);
1507
- }
1508
- }
1509
- }
1510
- // checks if any of the provided operations where reshufled
1511
- const newOp = operationsApplied.find((appliedOp) => !operations.find((o) => o.id === appliedOp.id &&
1512
- o.index === appliedOp.index &&
1513
- o.skip === appliedOp.skip &&
1514
- o.hash === appliedOp.hash));
1515
- // if there are no new operations then reuses the provided source
1516
- // otherwise sets it to local so listeners know that there were
1517
- // new changes originating from this document drive server
1518
- const source = newOp
1519
- ? { type: "local" }
1520
- : (options?.source ?? { type: "local" });
1521
- // update listener cache
1522
- const operationSource = this.getOperationSource(source);
1523
- // TODO Decouple the operation processing from syncing it to the listeners?
1524
- // Listener manager should be the one keeping the sync status since it depends on the listeners
1525
- if (syncUnits.length) {
1526
- this.listenerManager
1527
- .updateSynchronizationRevisions(syncUnits, source, () => {
1528
- this.synchronizationManager.updateSyncStatus(documentId, {
1529
- [operationSource]: "SYNCING",
1530
- });
1531
- for (const syncUnit of syncUnits) {
1532
- this.synchronizationManager.updateSyncStatus(syncUnit, {
1533
- [operationSource]: "SYNCING",
1534
- });
1535
- }
1536
- }, this.handleListenerError.bind(this), options?.forceSync ?? source.type === "local")
1537
- .then((updates) => {
1538
- if (updates.length) {
1539
- this.synchronizationManager.updateSyncStatus(documentId, {
1540
- [operationSource]: "SUCCESS",
1541
- });
1542
- }
1543
- for (const syncUnit of syncUnits) {
1544
- this.synchronizationManager.updateSyncStatus(syncUnit, {
1545
- [operationSource]: "SUCCESS",
1546
- });
1547
- }
1548
- })
1549
- .catch((error) => {
1550
- this.logger.error("Non handled error updating sync revision: @error", error);
1551
- this.synchronizationManager.updateSyncStatus(documentId, {
1552
- [operationSource]: "ERROR",
1553
- }, error);
1554
- for (const syncUnit of syncUnits) {
1555
- this.synchronizationManager.updateSyncStatus(syncUnit, {
1556
- [operationSource]: "ERROR",
1557
- }, error);
1558
- }
1559
- });
1560
- }
1561
- // after applying all the valid operations,throws
1562
- // an error if there was an invalid operation
1563
- if (error) {
1564
- throw error;
1565
- }
1566
- this.eventEmitter.emit("documentOperationsAdded", documentId, operations);
1567
- this.eventEmitter.emit("operationsAdded", documentId, operations);
1568
- return {
1569
- status: "SUCCESS",
1570
- document,
1571
- operations: operationsApplied,
1572
- signals,
1573
- };
1574
- }
1575
- catch (error) {
1576
- const operationError = error instanceof OperationError
1577
- ? error
1578
- : new OperationError("ERROR", undefined, error.message, error.cause);
1579
- return {
1580
- status: operationError.status,
1581
- error: operationError,
1582
- document,
1583
- operations: operationsApplied,
1584
- signals,
1585
- };
1586
- }
1587
- }
1588
- /**
1589
- * @deprecated Use the {@link addOperation} method instead.
1590
- */
1591
- addDriveOperation(driveId, operation, options) {
1592
- return this.addDriveOperations(driveId, [operation], options);
1593
- }
1594
- async _addDriveOperations(driveId, callback) {
1595
- if (!this.legacyStorage.addDriveOperationsWithTransaction) {
1596
- const documentStorage = await this.documentStorage.get(driveId);
1597
- const result = await callback(documentStorage);
1598
- // saves the applied operations to storage
1599
- if (result.operations.length > 0) {
1600
- await this.legacyStorage.addDriveOperations(driveId, result.operations, result.document);
1601
- }
1602
- return result;
1603
- }
1604
- else {
1605
- return this.legacyStorage.addDriveOperationsWithTransaction(driveId, callback);
1606
- }
1607
- }
1608
- /**
1609
- * @deprecated Use the {@link queueOperation} method instead.
1610
- */
1611
- queueDriveOperation(driveId, operation, options) {
1612
- return this.queueDriveOperations(driveId, [operation], options);
1613
- }
1614
- async resultIfExistingDriveOperations(driveId, operations) {
1615
- try {
1616
- const drive = await this.getDrive(driveId);
1617
- const newOperation = operations.find((op) => {
1618
- if (!op.id) {
1619
- return true;
1620
- }
1621
- const scopeOps = drive.operations[op.action.scope];
1622
- if (!scopeOps) {
1623
- return true;
1624
- }
1625
- return !scopeOps.find((existingOp) => existingOp.id === op.id &&
1626
- existingOp.index === op.index &&
1627
- existingOp.action.type === op.action.type &&
1628
- existingOp.hash === op.hash);
1629
- });
1630
- if (!newOperation) {
1631
- return {
1632
- status: "SUCCESS",
1633
- document: drive,
1634
- operations: operations,
1635
- signals: [],
1636
- };
1637
- }
1638
- else {
1639
- return undefined;
1640
- }
1641
- }
1642
- catch (error) {
1643
- console.error(error); // TODO error
1644
- return undefined;
1645
- }
1646
- }
1647
- /**
1648
- * @deprecated Use the {@link queueOperations} method instead.
1649
- */
1650
- async queueDriveOperations(driveId, operations, options) {
1651
- // if operations are already stored then returns cached document
1652
- const result = await this.resultIfExistingDriveOperations(driveId, operations);
1653
- if (result) {
1654
- return result;
1655
- }
1656
- try {
1657
- const jobId = await this.queueManager.addJob({
1658
- documentId: driveId,
1659
- operations,
1660
- options,
1661
- });
1662
- return await new Promise((resolve, reject) => {
1663
- const unsubscribe = this.queueManager.on("jobCompleted", (job, result) => {
1664
- if (job.jobId === jobId) {
1665
- unsubscribe();
1666
- unsubscribeError();
1667
- resolve(result);
1668
- }
1669
- });
1670
- const unsubscribeError = this.queueManager.on("jobFailed", (job, error) => {
1671
- if (job.jobId === jobId) {
1672
- unsubscribe();
1673
- unsubscribeError();
1674
- reject(error);
1675
- }
1676
- });
1677
- });
1678
- }
1679
- catch (error) {
1680
- this.logger.error("Error adding drive job: @error", error);
1681
- throw error;
1682
- }
1683
- }
1684
- /**
1685
- * @deprecated Use the {@link addOperations} method instead.
1686
- */
1687
- async addDriveOperations(driveId, operations, options) {
1688
- return this.queueDriveOperations(driveId, operations, options);
1689
- }
1690
- async processDriveOperations(driveId, operations, options) {
1691
- let document;
1692
- const operationsApplied = [];
1693
- const signals = [];
1694
- let error;
1695
- // if operations are already stored then returns cached drive
1696
- const result = await this.resultIfExistingDriveOperations(driveId, operations);
1697
- if (result) {
1698
- return result;
1699
- }
1700
- try {
1701
- await this._addDriveOperations(driveId, async (documentStorage) => {
1702
- const result = await this._processOperations(driveId, documentStorage, operations.slice());
1703
- document = result.document;
1704
- operationsApplied.push(...result.operationsApplied);
1705
- signals.push(...result.signals);
1706
- error = result.error;
1707
- return {
1708
- operations: result.operationsApplied,
1709
- document: result.document,
1710
- };
1711
- });
1712
- if (!document || !isDocumentDrive(document)) {
1713
- throw error ?? new Error("Invalid Document Drive document");
1714
- }
1715
- this.cache
1716
- .setDocument(driveId, document)
1717
- .catch((e) => this.logger.error("@error", e));
1718
- this.cache
1719
- .setDrive(driveId, document)
1720
- .catch((e) => this.logger.error("@error", e));
1721
- // update listener cache
1722
- const lastOperation = operationsApplied
1723
- .filter((op) => op.action.scope === "global")
1724
- .slice()
1725
- .pop();
1726
- if (lastOperation) {
1727
- // checks if any of the provided operations where reshufled
1728
- const newOp = operationsApplied.find((appliedOp) => !operations.find((o) => o.id === appliedOp.id &&
1729
- o.index === appliedOp.index &&
1730
- o.skip === appliedOp.skip &&
1731
- o.hash === appliedOp.hash));
1732
- // if there are no new operations then reuses the provided source
1733
- // otherwise sets it to local so listeners know that there were
1734
- // new changes originating from this document drive server
1735
- const source = newOp
1736
- ? { type: "local" }
1737
- : (options?.source ?? { type: "local" });
1738
- const operationSource = this.getOperationSource(source);
1739
- this.listenerManager
1740
- .updateSynchronizationRevisions([
1741
- {
1742
- documentId: driveId,
1743
- documentType: document.header.documentType,
1744
- scope: "global",
1745
- branch: "main",
1746
- lastUpdated: lastOperation.timestampUtcMs,
1747
- revision: lastOperation.index,
1748
- },
1749
- ], source, () => {
1750
- this.synchronizationManager.updateSyncStatus(driveId, {
1751
- [operationSource]: "SYNCING",
1752
- });
1753
- }, this.handleListenerError.bind(this), options?.forceSync ?? source.type === "local")
1754
- .then((updates) => {
1755
- if (updates.length) {
1756
- this.synchronizationManager.updateSyncStatus(driveId, {
1757
- [operationSource]: "SUCCESS",
1758
- });
1759
- }
1760
- })
1761
- .catch((error) => {
1762
- this.logger.error("Non handled error updating sync revision: @error", error);
1763
- this.synchronizationManager.updateSyncStatus(driveId, {
1764
- [operationSource]: "ERROR",
1765
- }, error);
1766
- });
1767
- }
1768
- if (this.shouldSyncRemoteDrive(document)) {
1769
- this.startSyncRemoteDrive(driveId).catch((e) => this.logger.error("@error", e));
1770
- }
1771
- else {
1772
- this.stopSyncRemoteDrive(driveId).catch((e) => this.logger.error("@error", e));
1773
- }
1774
- // after applying all the valid operations,throws
1775
- // an error if there was an invalid operation
1776
- if (error) {
1777
- throw error;
1778
- }
1779
- this.eventEmitter.emit("driveOperationsAdded", driveId, operations);
1780
- this.eventEmitter.emit("operationsAdded", driveId, operations);
1781
- return {
1782
- status: "SUCCESS",
1783
- document,
1784
- operations: operationsApplied,
1785
- signals,
1786
- };
1787
- }
1788
- catch (error) {
1789
- const operationError = error instanceof OperationError
1790
- ? error
1791
- : new OperationError("ERROR", undefined, error.message, error);
1792
- return {
1793
- status: operationError.status,
1794
- error: operationError,
1795
- document,
1796
- operations: operationsApplied,
1797
- signals,
1798
- };
1799
- }
1800
- }
1801
- _buildOperations(documentId, actions) {
1802
- const operations = [];
1803
- const { reducer } = this.getDocumentModelModule(documentId.header.documentType);
1804
- for (const action of actions) {
1805
- documentId = reducer(documentId, action);
1806
- const scopeOps = documentId.operations[action.scope];
1807
- if (!scopeOps) {
1808
- throw new Error(`No operations found for scope: ${action.scope}`);
1809
- }
1810
- const operation = scopeOps.slice().pop();
1811
- if (!operation) {
1812
- throw new Error("Error creating operations");
1813
- }
1814
- operations.push(operation);
1815
- }
1816
- return operations;
1817
- }
1818
- addAction(driveIdOrDocumentId, documentIdOrAction, actionOrOptions, maybeOptions) {
1819
- let documentId;
1820
- let action;
1821
- let options;
1822
- if (typeof documentIdOrAction === "string") {
1823
- // Deprecated overload: (driveId, documentId, action, options)
1824
- documentId = documentIdOrAction;
1825
- action = actionOrOptions;
1826
- options = maybeOptions;
1827
- }
1828
- else {
1829
- // Standard overload: (documentId, action, options)
1830
- documentId = driveIdOrDocumentId;
1831
- action = documentIdOrAction;
1832
- options = actionOrOptions;
1833
- }
1834
- return this._addAction(documentId, action, options);
1835
- }
1836
- async _addAction(documentId, action, options) {
1837
- return this.addActions(documentId, [action], options);
1838
- }
1839
- addActions(driveIdOrDocumentId, documentIdOrActions, actionsOrOptions, maybeOptions) {
1840
- let documentId;
1841
- let actions;
1842
- let options;
1843
- if (typeof documentIdOrActions === "string") {
1844
- // Deprecated overload: (driveId, documentId, actions, options)
1845
- documentId = documentIdOrActions;
1846
- actions = actionsOrOptions;
1847
- options = maybeOptions;
1848
- }
1849
- else {
1850
- // Standard overload: (documentId, actions, options)
1851
- documentId = driveIdOrDocumentId;
1852
- actions = documentIdOrActions;
1853
- options = actionsOrOptions;
1854
- }
1855
- return this._queueActions(documentId, actions, options);
1856
- }
1857
- async processActions(documentId, actions, options) {
1858
- const document = await this.getDocument(documentId);
1859
- const operations = this._buildOperations(document, actions);
1860
- return this.processOperations(documentId, operations, options);
1861
- }
1862
- /**
1863
- * @deprecated Use the {@link addAction} method instead.
1864
- */
1865
- async addDriveAction(driveId, action, options) {
1866
- if ("synchronizationUnits" in action.input) {
1867
- return this._legacyAddFileAction(driveId, action, options);
1868
- }
1869
- return this.addDriveActions(driveId, [action], options);
1870
- }
1871
- async _legacyAddFileAction(driveId, action, options) {
1872
- // create document before adding it to the drive
1873
- const document = this.getDocumentModelModule(action.input.documentType).utils.createDocument(action.input.document?.state || undefined);
1874
- document.header.id = action.input.id;
1875
- document.header.name = action.input.name;
1876
- document.header.documentType = action.input.documentType;
1877
- await this.queueDocument({ document }, { source: options?.source || { type: "local" } });
1878
- // create updated version of the ADD_FILE action
1879
- const newAction = {
1880
- ...action,
1881
- input: {
1882
- id: action.input.id,
1883
- documentType: document.header.documentType,
1884
- name: action.input.name,
1885
- parentFolder: action.input.parentFolder,
1886
- },
1887
- };
1888
- return (await this.addAction(driveId, newAction, options));
1889
- }
1890
- /**
1891
- * @deprecated Use the {@link addActions} method instead.
1892
- */
1893
- async addDriveActions(driveId, actions, options) {
1894
- return this.queueDriveActions(driveId, actions, options);
1895
- }
1896
- async processDriveActions(driveId, actions, options) {
1897
- const document = await this.getDrive(driveId);
1898
- const operations = this._buildOperations(document, actions);
1899
- return this.processDriveOperations(driveId, operations, options);
1900
- }
1901
- async detachDrive(driveId) {
1902
- const documentDrive = await this.getDrive(driveId);
1903
- const listeners = documentDrive.state.local.listeners || [];
1904
- const triggers = documentDrive.state.local.triggers || [];
1905
- for (const listener of listeners) {
1906
- await this.addDriveAction(driveId, removeListener({ listenerId: listener.listenerId }));
1907
- }
1908
- for (const trigger of triggers) {
1909
- await this.addDriveAction(driveId, removeTrigger({ triggerId: trigger.id }));
1910
- }
1911
- await this.addDriveAction(driveId, setSharingType({ type: "LOCAL" }));
1912
- }
1913
- getSyncStatus(documentId, scope, branch) {
1914
- return this.synchronizationManager.getSyncStatus(documentId, scope, branch);
1915
- }
1916
- on(event, cb) {
1917
- return this.eventEmitter.on(event, cb);
1918
- }
1919
- emit(event, ...args) {
1920
- return this.eventEmitter.emit(event, ...args);
1921
- }
1922
- // Add delegated methods to properly implement ISynchronizationManager
1923
- updateSyncStatus(syncUnitId, status, error) {
1924
- this.synchronizationManager.updateSyncStatus(syncUnitId, status, error);
1925
- }
1926
- initializeDriveSyncStatus(driveId, drive) {
1927
- return this.synchronizationManager.initializeDriveSyncStatus(driveId, drive);
1928
- }
1929
- getCombinedSyncUnitStatus(syncUnitStatus) {
1930
- return this.synchronizationManager.getCombinedSyncUnitStatus(syncUnitStatus);
1931
- }
1932
- // Add back the saveStrand method that was accidentally removed
1933
- async saveStrand(strand, source) {
1934
- const isNewDocument = !(await this.documentStorage.exists(strand.documentId));
1935
- let result = undefined;
1936
- if (isNewDocument) {
1937
- result = await this.queueDocument({
1938
- id: strand.documentId,
1939
- documentType: strand.documentType,
1940
- });
1941
- }
1942
- const operations = strand.operations.map((op) => ({
1943
- ...op,
1944
- id: op.id ??
1945
- deriveOperationId(strand.documentId, strand.scope, strand.branch, op.actionId),
1946
- action: {
1947
- id: op.actionId,
1948
- timestampUtcMs: op.timestampUtcMs,
1949
- type: op.type,
1950
- input: op.input,
1951
- context: op.context,
1952
- scope: strand.scope,
1953
- },
1954
- scope: strand.scope,
1955
- branch: strand.branch,
1956
- }));
1957
- // if document already existed or queueDocument
1958
- // was successful, queues the operations
1959
- if ((!isNewDocument || result?.status === "SUCCESS") && operations.length) {
1960
- try {
1961
- result = await this.queueOperations(strand.documentId, operations, {
1962
- source,
1963
- });
1964
- }
1965
- catch (error) {
1966
- this.logger.error("Error queueing operations: @error", error);
1967
- throw error;
1968
- }
1969
- }
1970
- if (!result) {
1971
- this.logger.debug("Document @documentId already exists", strand.documentId);
1972
- return {
1973
- status: "SUCCESS",
1974
- document: await this.getDocument(strand.documentId),
1975
- operations: [],
1976
- signals: [],
1977
- };
1978
- }
1979
- if (result.status === "ERROR") {
1980
- const operationSource = this.getOperationSource(source);
1981
- this.synchronizationManager.updateSyncStatus({
1982
- documentId: strand.documentId || strand.driveId,
1983
- scope: strand.scope,
1984
- branch: strand.branch,
1985
- }, { [operationSource]: result.status }, result.error);
1986
- }
1987
- this.eventEmitter.emit("strandUpdate", strand);
1988
- return result;
1989
- }
1990
- setGenerateJwtHandler(handler) {
1991
- this.generateJwtHandler = handler;
1992
- this.listenerManager.setGenerateJwtHandler(handler);
1993
- }
1994
- removeJwtHandler() {
1995
- this.generateJwtHandler = undefined;
1996
- this.listenerManager.removeJwtHandler();
1997
- }
1998
- }
1999
- export const DocumentDriveServer = ReadModeServer(BaseDocumentDriveServer);
2000
- //# sourceMappingURL=base-server.js.map