@dxos/client-services 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/dist/lib/chunk-client-services-layer.mjs +11425 -0
  2. package/dist/lib/chunk-client-services-layer.mjs.map +1 -0
  3. package/dist/lib/chunk-decorate.mjs +9 -0
  4. package/dist/lib/index.mjs +731 -0
  5. package/dist/lib/index.mjs.map +1 -0
  6. package/dist/lib/packlets/diagnostics/browser-diagnostics-broadcast.mjs +72 -0
  7. package/dist/lib/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +1 -0
  8. package/dist/lib/packlets/diagnostics/diagnostics-broadcast.mjs +14 -0
  9. package/dist/lib/packlets/diagnostics/diagnostics-broadcast.mjs.map +1 -0
  10. package/dist/lib/packlets/locks/browser.mjs +105 -0
  11. package/dist/lib/packlets/locks/browser.mjs.map +1 -0
  12. package/dist/lib/packlets/locks/node.mjs +53 -0
  13. package/dist/lib/packlets/locks/node.mjs.map +1 -0
  14. package/dist/lib/testing.mjs +570 -0
  15. package/dist/lib/testing.mjs.map +1 -0
  16. package/dist/types/src/index.d.ts +2 -0
  17. package/dist/types/src/index.d.ts.map +1 -1
  18. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +21 -4
  19. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
  20. package/dist/types/src/packlets/agents/edge-agent-service.d.ts +8 -7
  21. package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
  22. package/dist/types/src/packlets/devices/devices-service.d.ts +7 -5
  23. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  24. package/dist/types/src/packlets/devtools/devtools.d.ts +30 -29
  25. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  26. package/dist/types/src/packlets/devtools/feeds.d.ts +1 -1
  27. package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
  28. package/dist/types/src/packlets/devtools/network.d.ts +2 -1
  29. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  30. package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
  31. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts +2 -2
  32. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
  33. package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts.map +1 -1
  34. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +1 -8
  35. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
  36. package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
  37. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  38. package/dist/types/src/packlets/identity/contacts-service.d.ts +9 -6
  39. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  40. package/dist/types/src/packlets/identity/identity-manager.d.ts +32 -3
  41. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  42. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +23 -4
  43. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
  44. package/dist/types/src/packlets/identity/identity-service.d.ts +15 -20
  45. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  46. package/dist/types/src/packlets/identity/identity.d.ts +2 -2
  47. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  48. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
  49. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +17 -0
  50. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  51. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +25 -4
  52. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  53. package/dist/types/src/packlets/invitations/invitations-service.d.ts +11 -11
  54. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  55. package/dist/types/src/packlets/logging/logging-service.d.ts +14 -12
  56. package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
  57. package/dist/types/src/packlets/metadata/index.d.ts +3 -0
  58. package/dist/types/src/packlets/metadata/index.d.ts.map +1 -0
  59. package/dist/types/src/packlets/metadata/metadata-store.d.ts +107 -0
  60. package/dist/types/src/packlets/metadata/metadata-store.d.ts.map +1 -0
  61. package/dist/types/src/packlets/metadata/metadata-store.test.d.ts +2 -0
  62. package/dist/types/src/packlets/metadata/metadata-store.test.d.ts.map +1 -0
  63. package/dist/types/src/packlets/metadata/sqlite-metadata-store.d.ts +65 -0
  64. package/dist/types/src/packlets/metadata/sqlite-metadata-store.d.ts.map +1 -0
  65. package/dist/types/src/packlets/network/network-service.d.ts +15 -14
  66. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  67. package/dist/types/src/packlets/pipeline/codec.d.ts +11 -0
  68. package/dist/types/src/packlets/pipeline/codec.d.ts.map +1 -0
  69. package/dist/types/src/packlets/pipeline/feeds.d.ts +7 -0
  70. package/dist/types/src/packlets/pipeline/feeds.d.ts.map +1 -0
  71. package/dist/types/src/packlets/pipeline/index.d.ts +5 -0
  72. package/dist/types/src/packlets/pipeline/index.d.ts.map +1 -0
  73. package/dist/types/src/packlets/pipeline/message-selector.d.ts +11 -0
  74. package/dist/types/src/packlets/pipeline/message-selector.d.ts.map +1 -0
  75. package/dist/types/src/packlets/pipeline/pipeline-stress.test.d.ts +2 -0
  76. package/dist/types/src/packlets/pipeline/pipeline-stress.test.d.ts.map +1 -0
  77. package/dist/types/src/packlets/pipeline/pipeline.d.ts +131 -0
  78. package/dist/types/src/packlets/pipeline/pipeline.d.ts.map +1 -0
  79. package/dist/types/src/packlets/pipeline/pipeline.test.d.ts +2 -0
  80. package/dist/types/src/packlets/pipeline/pipeline.test.d.ts.map +1 -0
  81. package/dist/types/src/packlets/pipeline/testing/index.d.ts +2 -0
  82. package/dist/types/src/packlets/pipeline/testing/index.d.ts.map +1 -0
  83. package/dist/types/src/packlets/pipeline/testing/test-feed-builder.d.ts +9 -0
  84. package/dist/types/src/packlets/pipeline/testing/test-feed-builder.d.ts.map +1 -0
  85. package/dist/types/src/packlets/pipeline/timeframe-clock.d.ts +31 -0
  86. package/dist/types/src/packlets/pipeline/timeframe-clock.d.ts.map +1 -0
  87. package/dist/types/src/packlets/services/client-services-layer.d.ts +21 -0
  88. package/dist/types/src/packlets/services/client-services-layer.d.ts.map +1 -0
  89. package/dist/types/src/packlets/services/cross-device-space-synchronizer.d.ts +28 -0
  90. package/dist/types/src/packlets/services/cross-device-space-synchronizer.d.ts.map +1 -0
  91. package/dist/types/src/packlets/services/effect-rpc.test.d.ts +2 -0
  92. package/dist/types/src/packlets/services/effect-rpc.test.d.ts.map +1 -0
  93. package/dist/types/src/packlets/services/feed-syncer.d.ts +22 -2
  94. package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -1
  95. package/dist/types/src/packlets/services/index.d.ts +2 -2
  96. package/dist/types/src/packlets/services/index.d.ts.map +1 -1
  97. package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
  98. package/dist/types/src/packlets/services/service-context.d.ts +38 -57
  99. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  100. package/dist/types/src/packlets/services/service-host.d.ts +82 -31
  101. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  102. package/dist/types/src/packlets/services/sqlite-storage.d.ts +29 -0
  103. package/dist/types/src/packlets/services/sqlite-storage.d.ts.map +1 -1
  104. package/dist/types/src/packlets/services/sqlite-storage.test.d.ts +2 -0
  105. package/dist/types/src/packlets/services/sqlite-storage.test.d.ts.map +1 -0
  106. package/dist/types/src/packlets/space/admission-discovery-extension.d.ts +30 -0
  107. package/dist/types/src/packlets/space/admission-discovery-extension.d.ts.map +1 -0
  108. package/dist/types/src/packlets/space/auth.d.ts +24 -0
  109. package/dist/types/src/packlets/space/auth.d.ts.map +1 -0
  110. package/dist/types/src/packlets/space/control-pipeline.d.ts +46 -0
  111. package/dist/types/src/packlets/space/control-pipeline.d.ts.map +1 -0
  112. package/dist/types/src/packlets/space/control-pipeline.test.d.ts +2 -0
  113. package/dist/types/src/packlets/space/control-pipeline.test.d.ts.map +1 -0
  114. package/dist/types/src/packlets/space/index.d.ts +6 -0
  115. package/dist/types/src/packlets/space/index.d.ts.map +1 -0
  116. package/dist/types/src/packlets/space/replication.browser.test.d.ts +2 -0
  117. package/dist/types/src/packlets/space/replication.browser.test.d.ts.map +1 -0
  118. package/dist/types/src/packlets/space/space-manager.browser.test.d.ts +2 -0
  119. package/dist/types/src/packlets/space/space-manager.browser.test.d.ts.map +1 -0
  120. package/dist/types/src/packlets/space/space-manager.d.ts +72 -0
  121. package/dist/types/src/packlets/space/space-manager.d.ts.map +1 -0
  122. package/dist/types/src/packlets/space/space-protocol.browser.test.d.ts +2 -0
  123. package/dist/types/src/packlets/space/space-protocol.browser.test.d.ts.map +1 -0
  124. package/dist/types/src/packlets/space/space-protocol.d.ts +99 -0
  125. package/dist/types/src/packlets/space/space-protocol.d.ts.map +1 -0
  126. package/dist/types/src/packlets/space/space-protocol.test.d.ts +2 -0
  127. package/dist/types/src/packlets/space/space-protocol.test.d.ts.map +1 -0
  128. package/dist/types/src/packlets/space/space.d.ts +65 -0
  129. package/dist/types/src/packlets/space/space.d.ts.map +1 -0
  130. package/dist/types/src/packlets/space/space.test.d.ts +2 -0
  131. package/dist/types/src/packlets/space/space.test.d.ts.map +1 -0
  132. package/dist/types/src/packlets/space/testing/change-metadata.d.ts +8 -0
  133. package/dist/types/src/packlets/space/testing/change-metadata.d.ts.map +1 -0
  134. package/dist/types/src/packlets/space/testing/index.d.ts +4 -0
  135. package/dist/types/src/packlets/space/testing/index.d.ts.map +1 -0
  136. package/dist/types/src/packlets/space/testing/test-agent-builder.d.ts +62 -0
  137. package/dist/types/src/packlets/space/testing/test-agent-builder.d.ts.map +1 -0
  138. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +1 -1
  139. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -1
  140. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -1
  141. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +40 -7
  142. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  143. package/dist/types/src/packlets/spaces/data-space.d.ts +3 -1
  144. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  145. package/dist/types/src/packlets/spaces/genesis.d.ts +1 -1
  146. package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
  147. package/dist/types/src/packlets/spaces/spaces-service.d.ts +25 -23
  148. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  149. package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
  150. package/dist/types/src/packlets/system/system-service.d.ts +18 -18
  151. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  152. package/dist/types/src/packlets/testing/invitation-utils.d.ts +1 -1
  153. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  154. package/dist/types/src/packlets/testing/test-builder.d.ts +7 -6
  155. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  156. package/dist/types/src/packlets/worker/worker-runtime.d.ts +41 -58
  157. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  158. package/dist/types/src/packlets/worker/worker-session.d.ts +21 -8
  159. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
  160. package/dist/types/src/testing/index.d.ts +1 -0
  161. package/dist/types/src/testing/index.d.ts.map +1 -1
  162. package/dist/types/src/version.d.ts +1 -1
  163. package/dist/types/tsconfig.tsbuildinfo +1 -1
  164. package/package.json +52 -48
  165. package/src/index.ts +2 -0
  166. package/src/packlets/agents/edge-agent-manager.ts +56 -15
  167. package/src/packlets/agents/edge-agent-service.ts +25 -15
  168. package/src/packlets/devices/devices-service.test.ts +20 -19
  169. package/src/packlets/devices/devices-service.ts +17 -17
  170. package/src/packlets/devtools/devtools.ts +133 -75
  171. package/src/packlets/devtools/feeds.ts +2 -1
  172. package/src/packlets/devtools/network.ts +42 -12
  173. package/src/packlets/devtools/spaces.ts +1 -1
  174. package/src/packlets/diagnostics/diagnostics-broadcast.ts +4 -2
  175. package/src/packlets/diagnostics/diagnostics-collector.ts +5 -18
  176. package/src/packlets/diagnostics/diagnostics.ts +0 -11
  177. package/src/packlets/identity/authenticator.ts +2 -1
  178. package/src/packlets/identity/contacts-service.ts +46 -37
  179. package/src/packlets/identity/identity-manager.test.ts +3 -1
  180. package/src/packlets/identity/identity-manager.ts +73 -5
  181. package/src/packlets/identity/identity-recovery-manager.ts +56 -7
  182. package/src/packlets/identity/identity-service.test.ts +27 -18
  183. package/src/packlets/identity/identity-service.ts +114 -71
  184. package/src/packlets/identity/identity.test.ts +4 -9
  185. package/src/packlets/identity/identity.ts +1 -2
  186. package/src/packlets/invitations/edge-invitation-handler.ts +0 -1
  187. package/src/packlets/invitations/invitations-handler.ts +39 -3
  188. package/src/packlets/invitations/invitations-manager.ts +52 -4
  189. package/src/packlets/invitations/invitations-service.ts +54 -28
  190. package/src/packlets/logging/logging-service.ts +41 -29
  191. package/src/packlets/logging/logging.test.ts +28 -15
  192. package/src/packlets/metadata/index.ts +6 -0
  193. package/src/packlets/metadata/metadata-store.test.ts +49 -0
  194. package/src/packlets/metadata/metadata-store.ts +446 -0
  195. package/src/packlets/metadata/sqlite-metadata-store.ts +409 -0
  196. package/src/packlets/network/network-service.test.ts +19 -12
  197. package/src/packlets/network/network-service.ts +96 -29
  198. package/src/packlets/pipeline/codec.ts +18 -0
  199. package/src/packlets/pipeline/feeds.ts +22 -0
  200. package/src/packlets/pipeline/index.ts +8 -0
  201. package/src/packlets/pipeline/message-selector.ts +35 -0
  202. package/src/packlets/pipeline/pipeline-stress.test.ts +230 -0
  203. package/src/packlets/pipeline/pipeline.test.ts +140 -0
  204. package/src/packlets/pipeline/pipeline.ts +439 -0
  205. package/src/packlets/pipeline/testing/index.ts +5 -0
  206. package/src/packlets/pipeline/testing/test-feed-builder.ts +19 -0
  207. package/src/packlets/pipeline/timeframe-clock.ts +81 -0
  208. package/src/packlets/services/client-services-layer.ts +186 -0
  209. package/src/packlets/services/cross-device-space-synchronizer.ts +132 -0
  210. package/src/packlets/services/effect-rpc.test.ts +314 -0
  211. package/src/packlets/services/feed-syncer.ts +57 -3
  212. package/src/packlets/services/index.ts +2 -2
  213. package/src/packlets/services/platform.ts +0 -6
  214. package/src/packlets/services/service-context.ts +219 -522
  215. package/src/packlets/services/service-host.test.ts +34 -11
  216. package/src/packlets/services/service-host.ts +693 -213
  217. package/src/packlets/services/spec.md +106 -0
  218. package/src/packlets/services/sqlite-storage.test.ts +48 -0
  219. package/src/packlets/services/sqlite-storage.ts +117 -20
  220. package/src/packlets/space/admission-discovery-extension.ts +91 -0
  221. package/src/packlets/space/auth.ts +92 -0
  222. package/src/packlets/space/control-pipeline.test.ts +165 -0
  223. package/src/packlets/space/control-pipeline.ts +229 -0
  224. package/src/packlets/space/index.ts +9 -0
  225. package/src/packlets/space/replication.browser.test.ts +58 -0
  226. package/src/packlets/space/space-manager.browser.test.ts +40 -0
  227. package/src/packlets/space/space-manager.ts +224 -0
  228. package/src/packlets/space/space-protocol.browser.test.ts +129 -0
  229. package/src/packlets/space/space-protocol.test.ts +158 -0
  230. package/src/packlets/space/space-protocol.ts +308 -0
  231. package/src/packlets/space/space.test.ts +181 -0
  232. package/src/packlets/space/space.ts +196 -0
  233. package/src/packlets/space/testing/change-metadata.ts +27 -0
  234. package/src/packlets/space/testing/index.ts +7 -0
  235. package/src/packlets/space/testing/test-agent-builder.ts +252 -0
  236. package/src/packlets/space-export/serialized-space-reader.ts +3 -1
  237. package/src/packlets/space-export/serialized-space-writer.ts +53 -30
  238. package/src/packlets/space-export/space-archive.test.ts +30 -0
  239. package/src/packlets/spaces/data-space-manager.test.ts +1 -1
  240. package/src/packlets/spaces/data-space-manager.ts +148 -33
  241. package/src/packlets/spaces/data-space.ts +29 -18
  242. package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
  243. package/src/packlets/spaces/genesis.ts +1 -1
  244. package/src/packlets/spaces/spaces-service.test.ts +35 -22
  245. package/src/packlets/spaces/spaces-service.ts +259 -180
  246. package/src/packlets/storage/level.ts +3 -1
  247. package/src/packlets/system/system-service.test.ts +31 -13
  248. package/src/packlets/system/system-service.ts +65 -37
  249. package/src/packlets/testing/invitation-utils.ts +3 -3
  250. package/src/packlets/testing/test-builder.ts +35 -20
  251. package/src/packlets/worker/worker-runtime.ts +222 -260
  252. package/src/packlets/worker/worker-session.ts +108 -91
  253. package/src/testing/index.ts +1 -0
  254. package/src/version.ts +1 -1
  255. package/dist/lib/browser/chunk-QCWEHHJW.mjs +0 -24
  256. package/dist/lib/browser/chunk-QCWEHHJW.mjs.map +0 -7
  257. package/dist/lib/browser/chunk-XJRPB3GA.mjs +0 -22
  258. package/dist/lib/browser/chunk-XJRPB3GA.mjs.map +0 -7
  259. package/dist/lib/browser/chunk-XU5R2BMF.mjs +0 -8837
  260. package/dist/lib/browser/chunk-XU5R2BMF.mjs.map +0 -7
  261. package/dist/lib/browser/index.mjs +0 -876
  262. package/dist/lib/browser/index.mjs.map +0 -7
  263. package/dist/lib/browser/meta.json +0 -1
  264. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +0 -88
  265. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +0 -7
  266. package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +0 -11
  267. package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs.map +0 -7
  268. package/dist/lib/browser/packlets/locks/browser.mjs +0 -86
  269. package/dist/lib/browser/packlets/locks/browser.mjs.map +0 -7
  270. package/dist/lib/browser/packlets/locks/node.mjs +0 -48
  271. package/dist/lib/browser/packlets/locks/node.mjs.map +0 -7
  272. package/dist/lib/browser/testing/index.mjs +0 -436
  273. package/dist/lib/browser/testing/index.mjs.map +0 -7
  274. package/dist/lib/node-esm/chunk-2DT3MZRL.mjs +0 -22
  275. package/dist/lib/node-esm/chunk-2DT3MZRL.mjs.map +0 -7
  276. package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +0 -24
  277. package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +0 -7
  278. package/dist/lib/node-esm/chunk-H5YTUD35.mjs +0 -8837
  279. package/dist/lib/node-esm/chunk-H5YTUD35.mjs.map +0 -7
  280. package/dist/lib/node-esm/index.mjs +0 -876
  281. package/dist/lib/node-esm/index.mjs.map +0 -7
  282. package/dist/lib/node-esm/meta.json +0 -1
  283. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +0 -88
  284. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +0 -7
  285. package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +0 -11
  286. package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs.map +0 -7
  287. package/dist/lib/node-esm/packlets/locks/browser.mjs +0 -86
  288. package/dist/lib/node-esm/packlets/locks/browser.mjs.map +0 -7
  289. package/dist/lib/node-esm/packlets/locks/node.mjs +0 -48
  290. package/dist/lib/node-esm/packlets/locks/node.mjs.map +0 -7
  291. package/dist/lib/node-esm/testing/index.mjs +0 -436
  292. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  293. package/dist/types/src/packlets/services/client-rpc-server.d.ts +0 -24
  294. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +0 -1
  295. package/dist/types/src/packlets/services/service-registry.d.ts +0 -15
  296. package/dist/types/src/packlets/services/service-registry.d.ts.map +0 -1
  297. package/dist/types/src/packlets/services/service-registry.test.d.ts +0 -2
  298. package/dist/types/src/packlets/services/service-registry.test.d.ts.map +0 -1
  299. package/dist/types/src/testing/setup.d.ts +0 -3
  300. package/dist/types/src/testing/setup.d.ts.map +0 -1
  301. package/src/packlets/services/client-rpc-server.ts +0 -111
  302. package/src/packlets/services/service-registry.test.ts +0 -78
  303. package/src/packlets/services/service-registry.ts +0 -36
  304. package/src/testing/setup.ts +0 -11
@@ -0,0 +1,446 @@
1
+ //
2
+ // Copyright 2021 DXOS.org
3
+ //
4
+
5
+ import CRC32 from 'crc-32';
6
+ import * as EffectContext from 'effect/Context';
7
+
8
+ import { Event, scheduleTaskInterval, synchronized } from '@dxos/async';
9
+ import { type Codec } from '@dxos/codec-protobuf';
10
+ import { Context } from '@dxos/context';
11
+ import { invariant } from '@dxos/invariant';
12
+ import { PublicKey } from '@dxos/keys';
13
+ import { log } from '@dxos/log';
14
+ import { DataCorruptionError, STORAGE_VERSION } from '@dxos/protocols';
15
+ import { schema } from '@dxos/protocols/proto';
16
+ import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
17
+ import {
18
+ type ControlPipelineSnapshot,
19
+ type EchoMetadata,
20
+ type EdgeReplicationSetting,
21
+ type IdentityRecord,
22
+ type LargeSpaceMetadata,
23
+ type SpaceCache,
24
+ type SpaceMetadata,
25
+ } from '@dxos/protocols/proto/dxos/echo/metadata';
26
+ import { type Directory, type File } from '@dxos/random-access-storage';
27
+ import { type Timeframe } from '@dxos/timeframe';
28
+ import { ComplexMap, arrayToBuffer, forEachAsync, isNonNullable } from '@dxos/util';
29
+
30
+ const EXPIRED_INVITATION_CLEANUP_INTERVAL = 60 * 60 * 1000; // 1 hour
31
+
32
+ /**
33
+ * Shared interface for file-based and SQLite-backed metadata stores.
34
+ */
35
+ export interface IMetadataStore {
36
+ readonly update: Event<EchoMetadata>;
37
+ readonly metadata: EchoMetadata;
38
+ readonly version: number;
39
+ readonly spaces: SpaceMetadata[];
40
+
41
+ load(): Promise<void>;
42
+ close(): Promise<void>;
43
+ flush(): Promise<void>;
44
+ clear(): Promise<void>;
45
+ hasSpace(spaceKey: PublicKey): boolean;
46
+
47
+ getIdentityRecord(): IdentityRecord | undefined;
48
+ setIdentityRecord(record: IdentityRecord): Promise<void>;
49
+
50
+ getInvitations(): Invitation[];
51
+ addInvitation(invitation: Invitation): Promise<void>;
52
+ removeInvitation(invitationId: string): Promise<void>;
53
+
54
+ addSpace(record: SpaceMetadata): Promise<void>;
55
+ setSpaceDataLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe): Promise<void>;
56
+ setSpaceControlLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe): Promise<void>;
57
+ setCache(spaceKey: PublicKey, cache: SpaceCache): Promise<void>;
58
+ setWritableFeedKeys(spaceKey: PublicKey, controlFeedKey: PublicKey, dataFeedKey: PublicKey): Promise<void>;
59
+ setSpaceState(spaceKey: PublicKey, state: SpaceState): Promise<void>;
60
+
61
+ getSpaceControlPipelineSnapshot(spaceKey: PublicKey): ControlPipelineSnapshot | undefined;
62
+ setSpaceControlPipelineSnapshot(spaceKey: PublicKey, snapshot: ControlPipelineSnapshot): Promise<void>;
63
+
64
+ getSpaceEdgeReplicationSetting(spaceKey: PublicKey): EdgeReplicationSetting | undefined;
65
+ setSpaceEdgeReplicationSetting(spaceKey: PublicKey, setting: EdgeReplicationSetting): Promise<void>;
66
+
67
+ readonly deletedSpaces: PublicKey[];
68
+ addDeletedSpace(spaceKey: PublicKey): Promise<void>;
69
+ }
70
+
71
+ /**
72
+ * Effect service tag for {@link IMetadataStore}.
73
+ */
74
+ export class IMetadataStoreService extends EffectContext.Tag('@dxos/client-services/IMetadataStore')<
75
+ IMetadataStoreService,
76
+ IMetadataStore
77
+ >() {}
78
+
79
+ export interface AddSpaceOptions {
80
+ key: PublicKey;
81
+ genesisFeed: PublicKey;
82
+ }
83
+
84
+ const emptyEchoMetadata = (): EchoMetadata => ({
85
+ version: STORAGE_VERSION,
86
+ spaces: [],
87
+ created: new Date(),
88
+ updated: new Date(),
89
+ });
90
+
91
+ const emptyLargeSpaceMetadata = (): LargeSpaceMetadata => ({});
92
+
93
+ const EchoMetadata = schema.getCodecForType('dxos.echo.metadata.EchoMetadata');
94
+ const LargeSpaceMetadata = schema.getCodecForType('dxos.echo.metadata.LargeSpaceMetadata');
95
+
96
+ export class MetadataStore implements IMetadataStore {
97
+ private _metadata: EchoMetadata = emptyEchoMetadata();
98
+ private _spaceLargeMetadata = new ComplexMap<PublicKey, LargeSpaceMetadata>(PublicKey.hash);
99
+
100
+ private _metadataFile?: File = undefined;
101
+
102
+ public readonly update = new Event<EchoMetadata>();
103
+ private readonly _invitationCleanupCtx = new Context();
104
+
105
+ /**
106
+ * @internal
107
+ */
108
+ readonly _directory: Directory;
109
+
110
+ constructor(directory: Directory) {
111
+ this._directory = directory;
112
+ }
113
+
114
+ get metadata(): EchoMetadata {
115
+ return this._metadata;
116
+ }
117
+
118
+ get version(): number {
119
+ return this._metadata.version ?? 0;
120
+ }
121
+
122
+ /**
123
+ * Returns a list of currently saved spaces. The list and objects in it can be modified addSpace and
124
+ * addSpaceFeed functions.
125
+ */
126
+ get spaces(): SpaceMetadata[] {
127
+ return this._metadata.spaces ?? [];
128
+ }
129
+
130
+ /**
131
+ * Returns the keys of spaces that have been tombstoned (soft-deleted).
132
+ */
133
+ get deletedSpaces(): PublicKey[] {
134
+ return this._metadata.deletedSpaces ?? [];
135
+ }
136
+
137
+ private async _readFile<T>(file: File, codec: Codec<T>): Promise<T | undefined> {
138
+ try {
139
+ const { size: fileLength } = await file.stat();
140
+ if (fileLength < 8) {
141
+ return;
142
+ }
143
+ // Loading file size from first 4 bytes.
144
+ const dataSize = fromBytesInt32(await file.read(0, 4));
145
+ const checksum = fromBytesInt32(await file.read(4, 4));
146
+ log('loaded', { size: dataSize, checksum, name: file.filename });
147
+
148
+ if (fileLength < dataSize + 8) {
149
+ throw new DataCorruptionError({
150
+ message: 'Metadata size is smaller than expected.',
151
+ context: { fileLength, dataSize },
152
+ });
153
+ }
154
+
155
+ const data = await file.read(8, dataSize);
156
+
157
+ const calculatedChecksum = CRC32.buf(data);
158
+ if (calculatedChecksum !== checksum) {
159
+ throw new DataCorruptionError({ message: 'Metadata checksum is invalid.' });
160
+ }
161
+
162
+ return codec.decode(data);
163
+ } finally {
164
+ await file.close();
165
+ }
166
+ }
167
+
168
+ /**
169
+ * @internal
170
+ */
171
+ async _writeFile<T>(file: File, codec: Codec<T>, data: T): Promise<void> {
172
+ const encoded = arrayToBuffer(codec.encode(data));
173
+ const checksum = CRC32.buf(encoded);
174
+
175
+ const result = Buffer.alloc(8 + encoded.length);
176
+
177
+ result.writeInt32LE(encoded.length, 0);
178
+ result.writeInt32LE(checksum, 4);
179
+ encoded.copy(result, 8);
180
+
181
+ // NOTE: This must be done in one write operation, otherwise the file can be corrupted.
182
+ await file.write(0, result);
183
+
184
+ log('saved', { size: encoded.length, checksum });
185
+ }
186
+
187
+ async close(): Promise<void> {
188
+ await this._invitationCleanupCtx.dispose();
189
+ await this.flush();
190
+ await this._metadataFile?.close();
191
+ this._metadataFile = undefined;
192
+ this._metadata = emptyEchoMetadata();
193
+ this._spaceLargeMetadata.clear();
194
+ }
195
+
196
+ /**
197
+ * Loads metadata from persistent storage.
198
+ */
199
+ @synchronized
200
+ async load(): Promise<void> {
201
+ if (!this._metadataFile || this._metadataFile.closed) {
202
+ this._metadataFile = this._directory.getOrCreateFile('EchoMetadata');
203
+ }
204
+
205
+ try {
206
+ const metadata = await this._readFile(this._metadataFile, EchoMetadata);
207
+ if (metadata) {
208
+ this._metadata = metadata;
209
+ }
210
+
211
+ // post-processing
212
+ this._metadata.spaces?.forEach((space) => {
213
+ space.state ??= SpaceState.SPACE_ACTIVE;
214
+ });
215
+ } catch (err: any) {
216
+ log.error('failed to load metadata', { err });
217
+ this._metadata = emptyEchoMetadata();
218
+ }
219
+
220
+ await forEachAsync(
221
+ [this._metadata.identity?.haloSpace.key, ...(this._metadata.spaces?.map((space) => space.key) ?? [])].filter(
222
+ isNonNullable,
223
+ ),
224
+ async (key) => {
225
+ try {
226
+ await this._loadSpaceLargeMetadata(key);
227
+ } catch (err: any) {
228
+ log.error('failed to load space large metadata', { err });
229
+ }
230
+ },
231
+ );
232
+
233
+ // Cleanup expired persistent invitations.
234
+ scheduleTaskInterval(
235
+ this._invitationCleanupCtx,
236
+ async () => {
237
+ for (const invitation of this._metadata.invitations ?? []) {
238
+ if (hasInvitationExpired(invitation) || isLegacyInvitationFormat(invitation)) {
239
+ await this.removeInvitation(invitation.invitationId);
240
+ }
241
+ }
242
+ },
243
+ EXPIRED_INVITATION_CLEANUP_INTERVAL,
244
+ );
245
+ }
246
+
247
+ @synchronized
248
+ private async _save(): Promise<void> {
249
+ const data: EchoMetadata = {
250
+ ...this._metadata,
251
+ version: STORAGE_VERSION,
252
+ created: this._metadata.created ?? new Date(),
253
+ updated: new Date(),
254
+ };
255
+ this.update.emit(data);
256
+
257
+ const file = this._directory.getOrCreateFile('EchoMetadata');
258
+
259
+ await this._writeFile(file, EchoMetadata, data);
260
+ }
261
+
262
+ private async _loadSpaceLargeMetadata(key: PublicKey): Promise<void> {
263
+ const file = this._directory.getOrCreateFile(`space_${key.toHex()}_large`);
264
+ try {
265
+ const metadata = await this._readFile(file, LargeSpaceMetadata);
266
+ if (metadata) {
267
+ this._spaceLargeMetadata.set(key, metadata);
268
+ }
269
+ } catch (err: any) {
270
+ log.error('failed to load space large metadata', { err });
271
+ }
272
+ }
273
+
274
+ @synchronized
275
+ private async _saveSpaceLargeMetadata(key: PublicKey): Promise<void> {
276
+ const data = this._getLargeSpaceMetadata(key);
277
+ const file = this._directory.getOrCreateFile(`space_${key.toHex()}_large`);
278
+ await this._writeFile(file, LargeSpaceMetadata, data);
279
+ }
280
+
281
+ async flush(): Promise<void> {
282
+ await this._directory.flush();
283
+ }
284
+
285
+ _getSpace(spaceKey: PublicKey): SpaceMetadata {
286
+ if (this._metadata.identity?.haloSpace.key.equals(spaceKey)) {
287
+ // Check if the space is the identity space.
288
+ return this._metadata.identity.haloSpace;
289
+ }
290
+
291
+ const space = this.spaces.find((space) => space.key.equals(spaceKey));
292
+ invariant(space, 'Space not found');
293
+ return space;
294
+ }
295
+
296
+ hasSpace(spaceKey: PublicKey): boolean {
297
+ if (this._metadata.identity?.haloSpace.key.equals(spaceKey)) {
298
+ // Check if the space is the identity space.
299
+ return true;
300
+ }
301
+
302
+ return !!this.spaces.find((space) => space.key.equals(spaceKey));
303
+ }
304
+
305
+ private _getLargeSpaceMetadata(key: PublicKey): LargeSpaceMetadata {
306
+ let entry = this._spaceLargeMetadata.get(key);
307
+ if (entry) {
308
+ return entry;
309
+ }
310
+
311
+ entry = emptyLargeSpaceMetadata();
312
+ this._spaceLargeMetadata.set(key, entry);
313
+ return entry;
314
+ }
315
+
316
+ /**
317
+ * Clears storage - doesn't work for now.
318
+ */
319
+ async clear(): Promise<void> {
320
+ log('clearing all metadata');
321
+ await this._directory.delete();
322
+ this._metadata = emptyEchoMetadata();
323
+ }
324
+
325
+ getIdentityRecord(): IdentityRecord | undefined {
326
+ return this._metadata.identity;
327
+ }
328
+
329
+ async setIdentityRecord(record: IdentityRecord): Promise<void> {
330
+ invariant(!this._metadata.identity, 'Cannot overwrite existing identity in metadata');
331
+
332
+ this._metadata.identity = record;
333
+ await this._save();
334
+ await this.flush();
335
+ }
336
+
337
+ getInvitations(): Invitation[] {
338
+ return this._metadata.invitations ?? [];
339
+ }
340
+
341
+ async addInvitation(invitation: Invitation): Promise<void> {
342
+ if (this._metadata.invitations?.find((i) => i.invitationId === invitation.invitationId)) {
343
+ return;
344
+ }
345
+
346
+ (this._metadata.invitations ??= []).push(invitation);
347
+ await this._save();
348
+ await this.flush();
349
+ }
350
+
351
+ async removeInvitation(invitationId: string): Promise<void> {
352
+ this._metadata.invitations = (this._metadata.invitations ?? []).filter((i) => i.invitationId !== invitationId);
353
+ await this._save();
354
+ await this.flush();
355
+ }
356
+
357
+ /**
358
+ * Records a space as tombstoned (soft-deleted) so it is never re-accepted or auto-opened.
359
+ */
360
+ async addDeletedSpace(spaceKey: PublicKey): Promise<void> {
361
+ if ((this._metadata.deletedSpaces ?? []).some((key) => key.equals(spaceKey))) {
362
+ return;
363
+ }
364
+
365
+ (this._metadata.deletedSpaces ??= []).push(spaceKey);
366
+ await this._save();
367
+ await this.flush();
368
+ }
369
+
370
+ async addSpace(record: SpaceMetadata): Promise<void> {
371
+ invariant(
372
+ !(this._metadata.spaces ?? []).find((space) => space.key.equals(record.key)),
373
+ 'Cannot overwrite existing space in metadata',
374
+ );
375
+
376
+ (this._metadata.spaces ??= []).push(record);
377
+ await this._save();
378
+ await this.flush();
379
+ }
380
+
381
+ async setSpaceDataLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe): Promise<void> {
382
+ this._getSpace(spaceKey).dataTimeframe = timeframe;
383
+ await this._save();
384
+ }
385
+
386
+ async setSpaceControlLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe): Promise<void> {
387
+ this._getSpace(spaceKey).controlTimeframe = timeframe;
388
+ await this._save();
389
+ await this.flush();
390
+ }
391
+
392
+ async setCache(spaceKey: PublicKey, cache: SpaceCache): Promise<void> {
393
+ this._getSpace(spaceKey).cache = cache;
394
+ await this._save();
395
+ }
396
+
397
+ async setWritableFeedKeys(spaceKey: PublicKey, controlFeedKey: PublicKey, dataFeedKey: PublicKey): Promise<void> {
398
+ const space = this._getSpace(spaceKey);
399
+ space.controlFeedKey = controlFeedKey;
400
+ space.dataFeedKey = dataFeedKey;
401
+ await this._save();
402
+ await this.flush();
403
+ }
404
+
405
+ async setSpaceState(spaceKey: PublicKey, state: SpaceState): Promise<void> {
406
+ this._getSpace(spaceKey).state = state;
407
+ await this._save();
408
+ await this.flush();
409
+ }
410
+
411
+ getSpaceControlPipelineSnapshot(spaceKey: PublicKey): ControlPipelineSnapshot | undefined {
412
+ return this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot;
413
+ }
414
+
415
+ async setSpaceControlPipelineSnapshot(spaceKey: PublicKey, snapshot: ControlPipelineSnapshot): Promise<void> {
416
+ this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot = snapshot;
417
+ await this._saveSpaceLargeMetadata(spaceKey);
418
+ await this.flush();
419
+ }
420
+
421
+ getSpaceEdgeReplicationSetting(spaceKey: PublicKey): EdgeReplicationSetting | undefined {
422
+ return this.hasSpace(spaceKey) ? this._getSpace(spaceKey).edgeReplication : undefined;
423
+ }
424
+
425
+ async setSpaceEdgeReplicationSetting(spaceKey: PublicKey, setting: EdgeReplicationSetting): Promise<void> {
426
+ this._getSpace(spaceKey).edgeReplication = setting;
427
+ await this._save();
428
+ await this.flush();
429
+ }
430
+ }
431
+
432
+ const fromBytesInt32 = (buf: Buffer) => buf.readInt32LE(0);
433
+
434
+ export const hasInvitationExpired = (invitation: Invitation): boolean => {
435
+ return Boolean(
436
+ invitation.created &&
437
+ invitation.lifetime &&
438
+ invitation.lifetime !== 0 &&
439
+ invitation.created.getTime() + invitation.lifetime * 1000 < Date.now(),
440
+ );
441
+ };
442
+
443
+ // TODO: remove once "multiuse" type invitations get removed from local metadata of existing profiles
444
+ const isLegacyInvitationFormat = (invitation: Invitation): boolean => {
445
+ return invitation.type === Invitation.Type.MULTIUSE;
446
+ };