@dxos/client-services 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
@@ -3,67 +3,72 @@
3
3
  //
4
4
 
5
5
  import * as SqlClient from '@effect/sql/SqlClient';
6
+ import type * as SqlError from '@effect/sql/SqlError';
7
+ import * as EffectContext from 'effect/Context';
6
8
  import * as Effect from 'effect/Effect';
9
+ import * as Layer from 'effect/Layer';
7
10
 
8
- import { Mutex, Trigger } from '@dxos/async';
9
- import { Context, Resource } from '@dxos/context';
10
- import { type CredentialProcessor, getCredentialAssertion } from '@dxos/credentials';
11
- import { failUndefined, warnAfterTimeout } from '@dxos/debug';
12
11
  import {
13
- EchoEdgeReplicator,
14
- EchoEdgeSubductionReplicator,
15
- EchoHost,
16
- type EdgeAutomergeReplicator,
17
- MeshEchoReplicator,
18
- SpaceManager,
19
- SqliteMetadataStore,
20
- runSqliteHealthCheck,
21
- valueEncoding,
12
+ EchoEdgeReplicatorLayer,
13
+ EchoEdgeSubductionReplicatorLayer,
14
+ EchoHostLayer,
15
+ EchoHostService,
16
+ MeshEchoReplicatorLayer,
22
17
  } from '@dxos/echo-host';
23
- import { createChainEdgeIdentity, createEphemeralEdgeIdentity } from '@dxos/edge-client';
24
- import type { EdgeConnection, EdgeHttpClient, EdgeIdentity } from '@dxos/edge-client';
18
+ import {
19
+ type EdgeConnection,
20
+ EdgeConnectionService,
21
+ type EdgeHttpClient,
22
+ EdgeHttpClientService,
23
+ } from '@dxos/edge-client';
25
24
  import { RuntimeProvider } from '@dxos/effect';
26
- import { FeedFactory, FeedStore } from '@dxos/feed-store';
27
- import { invariant } from '@dxos/invariant';
28
- import { SqliteKeyring } from '@dxos/keyring';
29
- import { type SpaceId } from '@dxos/keys';
30
- import { log } from '@dxos/log';
31
- import { type SignalManager } from '@dxos/messaging';
32
- import { type SwarmNetworkManager } from '@dxos/network-manager';
33
- import { InvalidStorageVersionError, STORAGE_VERSION } from '@dxos/protocols';
25
+ import { FeedFactoryLayer, FeedStoreLayer, FeedStoreService } from '@dxos/feed-store';
26
+ import { KeyringApiService, SqliteKeyring, SqliteKeyringLayer } from '@dxos/keyring';
27
+ import { SignalManagerService } from '@dxos/messaging';
28
+ import { SwarmNetworkManagerService } from '@dxos/network-manager';
34
29
  import { FeedProtocol } from '@dxos/protocols';
35
- import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
36
30
  import { type Runtime } from '@dxos/protocols/proto/dxos/config';
37
- import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
38
- import { type Credential, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
39
31
  import { SqlTransaction } from '@dxos/sql-sqlite';
40
- import { SqliteBlobStore } from '@dxos/teleport-extension-object-sync';
41
- import { trace as Trace } from '@dxos/tracing';
42
- import { safeInstanceof } from '@dxos/util';
43
-
44
- // SqlTransaction.SqlTransaction is the Tag class exported from the SqlTransaction namespace.
45
- type SqlTransactionTag = SqlTransaction.SqlTransaction;
32
+ import { BlobStoreApiService, SqliteBlobStore, SqliteBlobStoreLayer } from '@dxos/teleport-extension-object-sync';
46
33
 
47
- import { EdgeAgentManager } from '../agents';
34
+ import { EdgeAgentManagerLayer, EdgeAgentManagerService } from '../agents';
48
35
  import {
49
- type CreateIdentityOptions,
50
- type Identity,
51
- IdentityManager,
36
+ IdentityManagerLayer,
52
37
  type IdentityManagerProps,
53
- type JoinIdentityProps,
38
+ IdentityManagerService,
39
+ IdentityProviderService,
40
+ identityProviderFromManager,
54
41
  } from '../identity';
55
- import { EdgeIdentityRecoveryManager } from '../identity/identity-recovery-manager';
56
42
  import {
57
- DeviceInvitationProtocol,
43
+ EdgeIdentityRecoveryManagerLayer,
44
+ EdgeIdentityRecoveryManagerService,
45
+ } from '../identity/identity-recovery-manager';
46
+ import {
58
47
  type InvitationConnectionProps,
59
- type InvitationProtocol,
60
- InvitationsHandler,
61
- InvitationsManager,
62
- SpaceInvitationProtocol,
48
+ InvitationsHandlerLayer,
49
+ InvitationsHandlerService,
50
+ InvitationsManagerLayer,
51
+ InvitationsManagerService,
63
52
  } from '../invitations';
64
- import { DataSpaceManager, type DataSpaceManagerRuntimeProps, type SigningContext } from '../spaces';
65
- import { FeedSyncer } from './feed-syncer';
66
- import { SqliteStorage } from './sqlite-storage';
53
+ import { IMetadataStoreService, SqliteMetadataStore, SqliteMetadataStoreLayer } from '../metadata';
54
+ import { valueEncoding } from '../pipeline';
55
+ import { SpaceManagerLayer, SpaceManagerService } from '../space';
56
+ import {
57
+ DataSpaceManagerLayer,
58
+ type DataSpaceManagerRuntimeProps,
59
+ DataSpaceManagerService,
60
+ SigningContextProviderLayer,
61
+ SigningContextProviderService,
62
+ } from '../spaces';
63
+ import {
64
+ CrossDeviceSpaceSynchronizerLayer,
65
+ CrossDeviceSpaceSynchronizerService,
66
+ } from './cross-device-space-synchronizer';
67
+ import { FeedSyncerLayer } from './feed-syncer';
68
+ import { FeedStorageDirectoryLayer, SqliteStorage, SqliteStorageLayer } from './sqlite-storage';
69
+
70
+ // SqlTransaction.SqlTransaction is the Tag class exported from the SqlTransaction namespace.
71
+ type SqlTransactionTag = SqlTransaction.SqlTransaction;
67
72
 
68
73
  export type ServiceContextRuntimeProps = Pick<
69
74
  IdentityManagerProps,
@@ -74,493 +79,185 @@ export type ServiceContextRuntimeProps = Pick<
74
79
  disableP2pReplication?: boolean;
75
80
  enableVectorIndexing?: boolean;
76
81
  };
82
+
77
83
  /**
78
- * Shared backend for all client services.
84
+ * Combined storage migration effect gathered from the concrete SQLite stores.
85
+ * Run by {@link ClientServicesHost} during open (storage migration stage).
79
86
  */
80
- // TODO(burdon): Rename/break-up into smaller components. And/or make members private.
81
- // TODO(dmaretskyi): Gets duplicated in CJS build between normal and testing bundles.
82
- @safeInstanceof('dxos.client-services.ServiceContext')
83
- @Trace.resource({ lifecycle: true })
84
- export class ServiceContext extends Resource {
85
- private readonly _edgeIdentityUpdateMutex = new Mutex();
86
-
87
- public readonly initialized = new Trigger();
88
- public readonly metadataStore: SqliteMetadataStore;
89
- public readonly blobStore: SqliteBlobStore;
90
- public readonly feedStore: FeedStore<FeedMessage>;
91
- public readonly keyring: SqliteKeyring;
92
- public readonly spaceManager: SpaceManager;
93
- public readonly identityManager: IdentityManager;
94
- public readonly recoveryManager: EdgeIdentityRecoveryManager;
95
- public readonly invitations: InvitationsHandler;
96
- public readonly invitationsManager: InvitationsManager;
97
- public readonly echoHost: EchoHost;
98
- private readonly _meshReplicator?: MeshEchoReplicator = undefined;
99
- private readonly _echoEdgeReplicator?: EdgeAutomergeReplicator = undefined;
100
- private readonly _feedSyncer?: FeedSyncer = undefined;
101
- private readonly _feedStorage: SqliteStorage;
87
+ export class StorageMigrationService extends EffectContext.Tag('@dxos/client-services/StorageMigration')<
88
+ StorageMigrationService,
89
+ Effect.Effect<void, SqlError.SqlError, SqlClient.SqlClient | SqlTransactionTag>
90
+ >() {}
102
91
 
103
- // Initialized after identity is initialized.
104
- public dataSpaceManager?: DataSpaceManager;
105
- public edgeAgentManager?: EdgeAgentManager;
92
+ export type ServiceContextLayerOptions = ServiceContextRuntimeProps & {
93
+ edgeFeatures?: Runtime.Client.EdgeFeatures;
94
+ edgeConnection?: EdgeConnection;
95
+ edgeHttpClient?: EdgeHttpClient;
96
+ };
106
97
 
107
- private readonly _handlerFactories = new Map<
108
- Invitation.Kind,
109
- (invitation: Partial<Invitation>) => InvitationProtocol
110
- >();
111
-
112
- private _deviceSpaceSync?: CredentialProcessor;
113
-
114
- constructor(
115
- public readonly networkManager: SwarmNetworkManager,
116
- public readonly signalManager: SignalManager,
117
- private readonly _edgeConnection: EdgeConnection | undefined,
118
- private readonly _edgeHttpClient: EdgeHttpClient | undefined,
119
- private readonly _runtime: RuntimeProvider.RuntimeProvider<SqlClient.SqlClient | SqlTransactionTag>,
120
- public readonly _runtimeProps?: ServiceContextRuntimeProps,
121
- private readonly _edgeFeatures?: Runtime.Client.EdgeFeatures,
122
- ) {
123
- super();
124
-
125
- log('runtimeProps', this._runtimeProps);
126
- log('edgeFeatures', this._edgeFeatures);
98
+ /**
99
+ * Component tags the composed stack exposes so {@link ClientServicesHost} and the client RPC service
100
+ * layers can depend on each component directly.
101
+ */
102
+ export type ServiceContextStackContext =
103
+ | EchoHostService
104
+ | IdentityManagerService
105
+ | IdentityProviderService
106
+ | SpaceManagerService
107
+ | InvitationsManagerService
108
+ | InvitationsHandlerService
109
+ | EdgeIdentityRecoveryManagerService
110
+ | KeyringApiService
111
+ | DataSpaceManagerService
112
+ | EdgeAgentManagerService
113
+ | CrossDeviceSpaceSynchronizerService
114
+ | SigningContextProviderService
115
+ | IMetadataStoreService
116
+ | BlobStoreApiService
117
+ | FeedStoreService
118
+ | StorageMigrationService;
127
119
 
128
- this.metadataStore = new SqliteMetadataStore({ runtime: this._runtime });
129
- this.blobStore = new SqliteBlobStore({ runtime: this._runtime });
130
- this.keyring = new SqliteKeyring({ runtime: this._runtime });
131
- this._feedStorage = new SqliteStorage({ runtime: this._runtime });
132
- const feedStorage = this._feedStorage;
133
- this.feedStore = new FeedStore<FeedMessage>({
134
- factory: new FeedFactory<FeedMessage>({
135
- root: feedStorage.createDirectory('feeds'),
136
- signer: this.keyring,
137
- hypercore: {
138
- valueEncoding,
139
- stats: true,
140
- },
120
+ /**
121
+ * Effect Layer composing the dormant client-stack components, constructed before identity is ready.
122
+ * {@link ClientServicesHost} resolves these tags and drives their lifecycle.
123
+ */
124
+ export const ServiceContextLayer = (
125
+ options: ServiceContextLayerOptions,
126
+ ): Layer.Layer<
127
+ ServiceContextStackContext,
128
+ never,
129
+ SwarmNetworkManagerService | SignalManagerService | SqlClient.SqlClient | SqlTransactionTag
130
+ > => {
131
+ const { edgeConnection, edgeHttpClient } = options;
132
+
133
+ // Core stack, flattened into a single pipe. Optional replicators expose their service via
134
+ // `provideMerge` and are read with `serviceOption` down the stack; their absence is modelled by
135
+ // not wiring the layer, not by a null value.
136
+ const core = CrossDeviceSpaceSynchronizerLayer.pipe(
137
+ Layer.provideMerge(EdgeAgentManagerLayer({ edgeFeatures: options.edgeFeatures })),
138
+ Layer.provideMerge(DataSpaceManagerLayer({ runtimeProps: options, edgeFeatures: options.edgeFeatures })),
139
+ Layer.provideMerge(SigningContextProviderLayer),
140
+ Layer.provideMerge(identityProviderLayer),
141
+ Layer.provideMerge(options.disableP2pReplication ? Layer.empty : MeshEchoReplicatorLayer()),
142
+ Layer.provideMerge(echoHostLayer({ useSubduction: options.edgeFeatures?.subductionReplicator })),
143
+ Layer.provideMerge(InvitationsManagerLayer()),
144
+ Layer.provideMerge(InvitationsHandlerLayer({ connectionProps: options.invitationConnectionDefaultProps })),
145
+ Layer.provideMerge(EdgeIdentityRecoveryManagerLayer()),
146
+ Layer.provideMerge(
147
+ IdentityManagerLayer({
148
+ devicePresenceOfflineTimeout: options.devicePresenceOfflineTimeout,
149
+ devicePresenceAnnounceInterval: options.devicePresenceAnnounceInterval,
150
+ edgeFeatures: options.edgeFeatures,
141
151
  }),
142
- });
143
-
144
- this.spaceManager = new SpaceManager({
145
- feedStore: this.feedStore,
146
- networkManager: this.networkManager,
147
- blobStore: this.blobStore,
148
- metadataStore: this.metadataStore,
149
- disableP2pReplication: this._runtimeProps?.disableP2pReplication,
150
- });
151
-
152
- this.identityManager = new IdentityManager({
153
- metadataStore: this.metadataStore,
154
- keyring: this.keyring,
155
- feedStore: this.feedStore,
156
- spaceManager: this.spaceManager,
157
- devicePresenceOfflineTimeout: this._runtimeProps?.devicePresenceOfflineTimeout,
158
- devicePresenceAnnounceInterval: this._runtimeProps?.devicePresenceAnnounceInterval,
159
- edgeConnection: this._edgeConnection,
160
- edgeFeatures: this._edgeFeatures,
161
- });
162
-
163
- this.recoveryManager = new EdgeIdentityRecoveryManager(
164
- this.keyring,
165
- this._edgeHttpClient,
166
- () => this.identityManager.identity,
167
- this._acceptIdentity.bind(this),
168
- );
169
-
170
- this.echoHost = new EchoHost({
171
- peerIdProvider: () => this.identityManager.identity?.deviceKey?.toHex(),
172
- getSpaceKeyByRootDocumentId: (documentId) => this.spaceManager.findSpaceByRootDocumentId(documentId)?.key,
173
- runtime: this._runtime,
174
- useSubduction: this._edgeFeatures?.subductionReplicator,
175
- syncQueue: async (ctx, request) => {
176
- return this._feedSyncer?.syncBlocking(ctx, {
177
- spaceId: request.spaceId as SpaceId,
178
- subspaceTag: request.subspaceTag,
179
- shouldPush: request.shouldPush,
180
- shouldPull: request.shouldPull,
181
- });
182
- },
183
- getSyncState: async (ctx, request) => {
184
- // Mirror `syncQueue` above: in non-edge / partially-initialised modes the
185
- // feed syncer is absent. Return an empty state instead of throwing so
186
- // callers (e.g. devtools sync panel) keep working.
187
- if (!this._feedSyncer) {
188
- return { namespaces: [] };
189
- }
190
- return this._feedSyncer.getSyncState(ctx, request);
191
- },
192
- });
193
-
194
- this.invitations = new InvitationsHandler(
195
- this.networkManager, //
196
- this._edgeHttpClient,
197
- _runtimeProps?.invitationConnectionDefaultProps,
198
- );
199
- this.invitationsManager = new InvitationsManager(
200
- this.invitations,
201
- (invitation) => this.getInvitationHandler(invitation),
202
- this.metadataStore,
203
- );
204
-
205
- // TODO(burdon): _initialize called in multiple places.
206
- // TODO(burdon): Call _initialize on success.
207
- this._handlerFactories.set(
208
- Invitation.Kind.DEVICE,
209
- () =>
210
- new DeviceInvitationProtocol(
211
- this.keyring,
212
- () => this.identityManager.identity ?? failUndefined(),
213
- this._acceptIdentity.bind(this),
214
- ),
215
- );
216
-
217
- if (!this._runtimeProps?.disableP2pReplication) {
218
- this._meshReplicator = new MeshEchoReplicator();
219
- }
220
- if (this._edgeConnection && this._edgeHttpClient) {
221
- if (this._edgeFeatures?.subductionReplicator) {
222
- this._echoEdgeReplicator = new EchoEdgeSubductionReplicator({
223
- edgeConnection: this._edgeConnection,
224
- edgeHttpClient: this._edgeHttpClient,
225
- });
226
- } else if (this._edgeFeatures?.echoReplicator) {
227
- this._echoEdgeReplicator = new EchoEdgeReplicator({
228
- edgeConnection: this._edgeConnection,
229
- edgeHttpClient: this._edgeHttpClient,
230
- });
231
- }
232
- }
233
-
234
- if (this.echoHost.feedStore && this._edgeConnection) {
235
- this._feedSyncer = new FeedSyncer({
236
- runtime: this._runtime,
237
- feedStore: this.echoHost.feedStore,
238
- edgeClient: this._edgeConnection,
239
- peerId: this.identityManager.identity?.deviceKey?.toHex() ?? '',
240
- getSpaceIds: () => this.echoHost!.spaceIds,
241
- syncNamespaces: [FeedProtocol.WellKnownNamespaces.data, FeedProtocol.WellKnownNamespaces.trace],
242
- });
243
- }
152
+ ),
153
+ Layer.provideMerge(SpaceManagerLayer({ disableP2pReplication: options.disableP2pReplication })),
154
+ Layer.provideMerge(storageLayer),
155
+ );
156
+
157
+ // Non-edge: just the core.
158
+ if (!edgeConnection || !edgeHttpClient) {
159
+ return core;
244
160
  }
245
161
 
246
- @Trace.span({ op: 'lifecycle' })
247
- protected override async _open(ctx: Context): Promise<void> {
248
- await RuntimeProvider.runPromise(this._runtime)(
249
- Effect.all([this.metadataStore.migrate, this.blobStore.migrate, this.keyring.migrate, this._feedStorage.migrate]),
250
- );
251
-
252
- await this._checkStorageVersion();
253
-
254
- log('running sqlite health check...');
255
- await runSqliteHealthCheck(this._runtime);
256
- log('sqlite health check passed');
257
-
258
- log('opening...');
259
-
260
- log('opening identityManager...');
261
- await this.identityManager.open(ctx);
262
- log('identityManager opened', { hasIdentity: !!this.identityManager.identity });
263
-
264
- log('setting network identity...');
265
- await this._setNetworkIdentity({ identity: this.identityManager.identity });
266
- log('network identity set');
267
-
268
- log('opening edge connection...');
269
- await this._edgeConnection?.open(ctx);
270
- log('edge connection opened');
271
-
272
- log('opening signal manager...');
273
- await this.signalManager.open(ctx);
274
- log('signal manager opened');
275
-
276
- log('opening network manager...');
277
- await this.networkManager.open();
278
- log('network manager opened');
279
-
280
- log('opening echo host...');
281
- await this.echoHost.open(ctx);
282
- log('echo host opened');
283
-
284
- if (this._meshReplicator) {
285
- log('adding mesh replicator...');
286
- await this.echoHost.addReplicator(ctx, this._meshReplicator);
287
- log('mesh replicator added');
288
- }
289
- if (this._echoEdgeReplicator) {
290
- log('adding edge replicator...');
291
- await this.echoHost.addReplicator(ctx, this._echoEdgeReplicator);
292
- log('edge replicator added');
293
- }
294
-
295
- log('loading metadata store...');
296
- await this.metadataStore.load();
297
- log('metadata store loaded');
298
-
299
- log('opening space manager...');
300
- await this.spaceManager.open();
301
- log('space manager opened');
302
-
303
- if (this.identityManager.identity) {
304
- log('joining network...');
305
- await this.identityManager.identity.joinNetwork(ctx);
306
- log('network joined');
162
+ // Edge: the feed syncer sits above the core for its `EchoHostService` requirement; the edge
163
+ // replicator sits below it needs only the edge inputs, resolved via `serviceOption` inside the
164
+ // core. Edge inputs are provided internally so they never surface as stack requirements.
165
+ return FeedSyncerLayer({
166
+ peerId: '',
167
+ syncNamespaces: [FeedProtocol.WellKnownNamespaces.data, FeedProtocol.WellKnownNamespaces.trace],
168
+ }).pipe(
169
+ Layer.provideMerge(core),
170
+ Layer.provideMerge(
171
+ options.edgeFeatures?.subductionReplicator
172
+ ? EchoEdgeSubductionReplicatorLayer()
173
+ : options.edgeFeatures?.echoReplicator
174
+ ? EchoEdgeReplicatorLayer()
175
+ : Layer.empty,
176
+ ),
177
+ Layer.provideMerge(
178
+ Layer.mergeAll(
179
+ Layer.succeed(EdgeConnectionService, edgeConnection),
180
+ Layer.succeed(EdgeHttpClientService, edgeHttpClient),
181
+ ),
182
+ ),
183
+ );
184
+ };
307
185
 
308
- log('initializing spaces...(calling _initialize)');
309
- await this._initialize(ctx);
310
- log('spaces initialized');
311
- } else {
312
- log('no identity, skipping network join and space initialization');
313
- }
314
-
315
- log('opening feed syncer...');
316
- await this._feedSyncer?.open(ctx);
317
- log('feed syncer opened');
318
-
319
- log('loading persistent invitations...');
320
- const loadedInvitations = await this.invitationsManager.loadPersistentInvitations(ctx);
321
- log('loaded persistent invitations', { count: loadedInvitations.invitations?.length });
322
-
323
- log('opened');
324
- }
325
-
326
- protected override async _close(ctx: Context): Promise<void> {
327
- log('closing...');
328
-
329
- await this._feedSyncer?.close();
330
-
331
- if (this._deviceSpaceSync && this.identityManager.identity) {
332
- await this.identityManager.identity.space.spaceState.removeCredentialProcessor(this._deviceSpaceSync);
333
- }
334
- await this.dataSpaceManager?.close(ctx);
335
- await this.edgeAgentManager?.close();
336
- await this.identityManager.close(ctx);
337
- await this.spaceManager.close();
338
- await this.echoHost.close(ctx);
339
-
340
- await this.networkManager.close(ctx);
341
- await this.signalManager.close();
342
- await this._edgeConnection?.close();
343
- await this.feedStore.close();
344
- await this.metadataStore.close();
345
-
346
- log('closed');
347
- }
348
-
349
- async createIdentity(params: CreateIdentityOptions = {}, ctx?: Context) {
350
- ctx ??= this._ctx;
351
- const identity = await this.identityManager.createIdentity(params, ctx);
352
- await this._setNetworkIdentity({ identity });
353
- await identity.joinNetwork(ctx);
354
- await this._initialize(ctx);
355
- return identity;
356
- }
357
-
358
- getInvitationHandler(invitation: Partial<Invitation> & Pick<Invitation, 'kind'>): InvitationProtocol {
359
- if (this.identityManager.identity == null && invitation.kind === Invitation.Kind.SPACE) {
360
- throw new Error('Identity must be created before joining a space.');
361
- }
362
- const factory = this._handlerFactories.get(invitation.kind);
363
- invariant(factory, `Unknown invitation kind: ${invitation.kind}`);
364
- return factory(invitation);
365
- }
366
-
367
- async broadcastProfileUpdate(profile: ProfileDocument | undefined): Promise<void> {
368
- if (!profile || !this.dataSpaceManager) {
369
- return;
370
- }
371
-
372
- for (const space of this.dataSpaceManager.spaces.values()) {
373
- await space.updateOwnProfile(profile);
374
- }
375
- }
376
-
377
- private async _acceptIdentity(params: JoinIdentityProps) {
378
- const { identity, identityRecord } = await this.identityManager.prepareIdentity(params, this._ctx);
379
- await this._setNetworkIdentity({ deviceCredential: params.authorizedDeviceCredential!, identity });
380
- await identity.joinNetwork(this._ctx);
381
- await this.identityManager.acceptIdentity(identity, identityRecord, params.deviceProfile);
382
- await this._initialize(this._ctx);
383
- return identity;
384
- }
385
-
386
- private async _checkStorageVersion(): Promise<void> {
387
- await this.metadataStore.load();
388
- if (this.metadataStore.version !== STORAGE_VERSION) {
389
- throw new InvalidStorageVersionError(STORAGE_VERSION, this.metadataStore.version);
390
- // TODO(mykola): Migrate storage to a new version if incompatibility is detected.
391
- }
392
- }
393
-
394
- // Called when identity is created.
395
- @Trace.span()
396
- private async _initialize(ctx: Context): Promise<void> {
397
- log('_initialize: start');
398
- const identity = this.identityManager.identity ?? failUndefined();
399
- const signingContext: SigningContext = {
400
- credentialSigner: identity.getIdentityCredentialSigner(),
401
- identityKey: identity.identityKey,
402
- deviceKey: identity.deviceKey,
403
- getProfile: () => identity.profileDocument,
404
- recordCredential: async (credential) => {
405
- await identity.controlPipeline.writer.write({ credential: { credential } });
406
- },
407
- };
408
-
409
- log('_initialize: creating DataSpaceManager');
410
- this.dataSpaceManager = new DataSpaceManager({
411
- spaceManager: this.spaceManager,
412
- metadataStore: this.metadataStore,
413
- keyring: this.keyring,
414
- signingContext,
415
- feedStore: this.feedStore,
416
- echoHost: this.echoHost,
417
- invitationsManager: this.invitationsManager,
418
- edgeConnection: this._edgeConnection,
419
- edgeHttpClient: this._edgeHttpClient,
420
- echoEdgeReplicator: this._echoEdgeReplicator,
421
- meshReplicator: this._meshReplicator,
422
- runtimeProps: this._runtimeProps as DataSpaceManagerRuntimeProps,
423
- edgeFeatures: this._edgeFeatures,
424
- });
425
- log('_initialize: opening DataSpaceManager...');
426
- await this.dataSpaceManager.open(ctx);
427
- log('_initialize: DataSpaceManager opened');
186
+ /**
187
+ * Provides the {@link IdentityProviderService} from the resolved {@link IdentityManager}.
188
+ */
189
+ const identityProviderLayer = Layer.effect(
190
+ IdentityProviderService,
191
+ Effect.gen(function* () {
192
+ const identityManager = yield* IdentityManagerService;
193
+ return identityProviderFromManager(identityManager);
194
+ }),
195
+ );
428
196
 
429
- this.edgeAgentManager = new EdgeAgentManager(
430
- this._edgeFeatures,
431
- this._edgeHttpClient,
432
- this.dataSpaceManager,
433
- identity,
197
+ /**
198
+ * Combined storage migration effect. Storage migrations are idempotent `CREATE TABLE` effects that
199
+ * do not depend on store instance state, so they are extracted from throwaway instances to keep the
200
+ * store layers individual. Run by {@link ClientServicesHost} during open.
201
+ */
202
+ const storageMigrationLayer = Layer.effect(
203
+ StorageMigrationService,
204
+ Effect.gen(function* () {
205
+ const runtime = yield* RuntimeProvider.currentRuntime<SqlClient.SqlClient | SqlTransactionTag>();
206
+ return Effect.all(
207
+ [
208
+ new SqliteMetadataStore({ runtime }).migrate,
209
+ new SqliteBlobStore({ runtime }).migrate,
210
+ new SqliteKeyring({ runtime }).migrate,
211
+ new SqliteStorage({ runtime }).migrate,
212
+ ],
213
+ { discard: true },
434
214
  );
435
- log('_initialize: opening EdgeAgentManager...');
436
- await this.edgeAgentManager.open(ctx);
437
- log('_initialize: EdgeAgentManager opened');
438
-
439
- this._handlerFactories.set(Invitation.Kind.SPACE, (invitation) => {
440
- invariant(this.dataSpaceManager, 'dataSpaceManager not initialized yet');
441
- return new SpaceInvitationProtocol(this.dataSpaceManager, signingContext, this.keyring, invitation.spaceKey);
442
- });
443
- this.initialized.wake();
444
- log('_initialize: initialized.wake() called');
215
+ }),
216
+ );
445
217
 
446
- this._deviceSpaceSync = {
447
- processCredential: async (credential: Credential) => {
448
- const assertion = getCredentialAssertion(credential);
449
-
450
- // A space was tombstoned on another device: replicate the deletion locally.
451
- if (assertion['@type'] === 'dxos.halo.credentials.SpaceDeleted') {
452
- if (assertion.spaceKey.equals(identity.space.key)) {
453
- // ignore halo space
454
- return;
455
- }
456
- if (!this.dataSpaceManager) {
457
- log('dataSpaceManager not initialized yet, ignoring space deletion', { details: assertion });
458
- return;
459
- }
460
-
461
- try {
462
- log('tombstoning space recorded in halo', { details: assertion });
463
- await this.dataSpaceManager.handleRemoteSpaceDeleted(this._ctx, assertion.spaceKey);
464
- } catch (err) {
465
- log.catch(err);
466
- }
467
- return;
468
- }
469
-
470
- if (assertion['@type'] !== 'dxos.halo.credentials.SpaceMember') {
471
- return;
472
- }
473
- if (assertion.spaceKey.equals(identity.space.key)) {
474
- // ignore halo space
475
- return;
476
- }
477
- if (!this.dataSpaceManager) {
478
- log('dataSpaceManager not initialized yet, ignoring space admission', { details: assertion });
479
- return;
480
- }
481
- // Do not re-accept a space that has been tombstoned (handles out-of-order credential replay).
482
- if (this.dataSpaceManager.isSpaceDeleted(assertion.spaceKey)) {
483
- log('space is deleted, ignoring space admission', { details: assertion });
484
- return;
485
- }
486
- if (this.dataSpaceManager.spaces.has(assertion.spaceKey)) {
487
- log('space already exists, ignoring space admission', { details: assertion });
488
- return;
489
- }
218
+ /**
219
+ * Storage / feed layers composed from the individual store layers plus the combined migration.
220
+ */
221
+ const storageLayer = Layer.empty.pipe(
222
+ Layer.provideMerge(FeedStoreLayer()),
223
+ Layer.provideMerge(FeedFactoryLayer({ hypercore: { valueEncoding, stats: true } })),
224
+ Layer.provideMerge(FeedStorageDirectoryLayer()),
225
+ Layer.provideMerge(SqliteMetadataStoreLayer()),
226
+ Layer.provideMerge(SqliteBlobStoreLayer()),
227
+ Layer.provideMerge(SqliteKeyringLayer()),
228
+ Layer.provideMerge(SqliteStorageLayer()),
229
+ Layer.provideMerge(storageMigrationLayer),
230
+ );
490
231
 
491
- try {
492
- log('accepting space recorded in halo', { details: assertion });
493
- await this.dataSpaceManager.acceptSpace(this._ctx, {
494
- spaceKey: assertion.spaceKey,
495
- genesisFeedKey: assertion.genesisFeedKey,
496
- tags: assertion.tags,
232
+ /**
233
+ * Constructs the {@link EchoHost}, resolving the identity/space callbacks that point down the stack.
234
+ * The feed sync handlers (which point up) are wired later via `EchoHost.setFeedSyncHandlers`.
235
+ *
236
+ * The host is self-contained (runs its own migrations, owns its feed/automerge stores), so its
237
+ * open/close is owned by the layer scope: it opens when the stack is built and closes when the
238
+ * runtime is disposed. Identity-, network-, and storage-bound lifecycle stays in `ClientServicesHost`.
239
+ */
240
+ const echoHostLayer = (options: { useSubduction?: boolean }) =>
241
+ Layer.scopedDiscard(
242
+ Effect.gen(function* () {
243
+ const echoHost = yield* EchoHostService;
244
+ yield* Effect.acquireRelease(
245
+ Effect.promise(() => echoHost.open()),
246
+ () => Effect.promise(() => echoHost.close()),
247
+ );
248
+ }),
249
+ ).pipe(
250
+ Layer.provideMerge(
251
+ Layer.unwrapEffect(
252
+ Effect.gen(function* () {
253
+ const identityManager = yield* IdentityManagerService;
254
+ const spaceManager = yield* SpaceManagerService;
255
+ return EchoHostLayer({
256
+ peerIdProvider: () => identityManager.identity?.deviceKey?.toHex(),
257
+ getSpaceKeyByRootDocumentId: (documentId) => spaceManager.findSpaceByRootDocumentId(documentId)?.key,
258
+ useSubduction: options.useSubduction,
497
259
  });
498
- } catch (err) {
499
- log.catch(err);
500
- }
501
- },
502
- };
503
-
504
- await identity.space.spaceState.addCredentialProcessor(this._deviceSpaceSync);
505
- }
506
-
507
- private async _setNetworkIdentity(params?: { deviceCredential?: Credential; identity?: Identity }): Promise<void> {
508
- log('_setNetworkIdentity: acquiring mutex...');
509
- using _ = await this._edgeIdentityUpdateMutex.acquire();
510
- log('_setNetworkIdentity: mutex acquired');
511
-
512
- let edgeIdentity: EdgeIdentity;
513
- const identity = params?.identity;
514
- if (identity) {
515
- log('_setNetworkIdentity: has identity', {
516
- identity: identity.identityKey.toHex(),
517
- hasDeviceCredential: !!params?.deviceCredential,
518
- });
519
-
520
- if (params?.deviceCredential) {
521
- log('_setNetworkIdentity: creating chain edge identity with device credential...');
522
- edgeIdentity = await createChainEdgeIdentity(
523
- identity.signer,
524
- identity.identityKey,
525
- identity.deviceKey,
526
- { credential: params.deviceCredential },
527
- [], // TODO(dmaretskyi): Service access credentials.
528
- );
529
- log('_setNetworkIdentity: chain edge identity created');
530
- } else {
531
- log('_setNetworkIdentity: waiting for identity.ready()...');
532
- // TODO: throw here or from identity if device chain can't be loaded, to avoid indefinite hangup
533
- await warnAfterTimeout(10_000, 'Waiting for identity to be ready for edge connection', async () => {
534
- await identity.ready();
535
- });
536
- log('_setNetworkIdentity: identity.ready() resolved', {
537
- hasDeviceCredentialChain: !!identity.deviceCredentialChain,
538
- });
539
-
540
- invariant(identity.deviceCredentialChain);
541
-
542
- log('_setNetworkIdentity: creating chain edge identity...');
543
- edgeIdentity = await createChainEdgeIdentity(
544
- identity.signer,
545
- identity.identityKey,
546
- identity.deviceKey,
547
- identity.deviceCredentialChain,
548
- [], // TODO(dmaretskyi): Service access credentials.
549
- );
550
- log('_setNetworkIdentity: chain edge identity created');
551
- }
552
- } else {
553
- log('_setNetworkIdentity: no identity, creating ephemeral edge identity...');
554
- edgeIdentity = await createEphemeralEdgeIdentity();
555
- log('_setNetworkIdentity: ephemeral edge identity created');
556
- }
557
-
558
- this._edgeConnection?.setIdentity(edgeIdentity);
559
- this._edgeHttpClient?.setIdentity(edgeIdentity);
560
- this.networkManager.setPeerInfo({
561
- identityDid: edgeIdentity.identityDid,
562
- peerKey: edgeIdentity.peerKey,
563
- });
564
- log('_setNetworkIdentity: done');
565
- }
566
- }
260
+ }),
261
+ ),
262
+ ),
263
+ );