@dxos/client-services 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5

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 (239) hide show
  1. package/dist/lib/browser/{chunk-ERQJUBAW.mjs → chunk-HYGNOM23.mjs} +4279 -3342
  2. package/dist/lib/browser/chunk-HYGNOM23.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-NQSC7HOE.mjs +22 -0
  4. package/dist/lib/browser/chunk-NQSC7HOE.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-QCWEHHJW.mjs +24 -0
  6. package/dist/lib/browser/chunk-QCWEHHJW.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +539 -98
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
  11. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
  12. package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
  13. package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
  14. package/dist/lib/browser/packlets/locks/browser.mjs +126 -0
  15. package/dist/lib/browser/packlets/locks/browser.mjs.map +7 -0
  16. package/dist/lib/browser/packlets/locks/node.mjs +66 -0
  17. package/dist/lib/browser/packlets/locks/node.mjs.map +7 -0
  18. package/dist/lib/browser/testing/index.mjs +45 -26
  19. package/dist/lib/browser/testing/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +24 -0
  21. package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +7 -0
  22. package/dist/lib/node-esm/{chunk-TMEG7JOG.mjs → chunk-GFT7MAQE.mjs} +3764 -2695
  23. package/dist/lib/node-esm/chunk-GFT7MAQE.mjs.map +7 -0
  24. package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs +22 -0
  25. package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs.map +7 -0
  26. package/dist/lib/node-esm/index.mjs +539 -98
  27. package/dist/lib/node-esm/index.mjs.map +4 -4
  28. package/dist/lib/node-esm/meta.json +1 -1
  29. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
  30. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
  31. package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
  32. package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
  33. package/dist/lib/node-esm/packlets/locks/browser.mjs +126 -0
  34. package/dist/lib/node-esm/packlets/locks/browser.mjs.map +7 -0
  35. package/dist/lib/node-esm/packlets/locks/node.mjs +66 -0
  36. package/dist/lib/node-esm/packlets/locks/node.mjs.map +7 -0
  37. package/dist/lib/node-esm/testing/index.mjs +45 -26
  38. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  39. package/dist/types/src/index.d.ts +1 -0
  40. package/dist/types/src/index.d.ts.map +1 -1
  41. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +3 -2
  42. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
  43. package/dist/types/src/packlets/agents/edge-agent-service.d.ts +3 -2
  44. package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
  45. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  46. package/dist/types/src/packlets/devtools/devtools.d.ts +20 -20
  47. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  48. package/dist/types/src/packlets/devtools/feeds.d.ts +1 -1
  49. package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
  50. package/dist/types/src/packlets/devtools/network.d.ts +1 -1
  51. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  52. package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts +1 -1
  53. package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts.map +1 -1
  54. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts +1 -1
  55. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
  56. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +2 -3
  57. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
  58. package/dist/types/src/packlets/diagnostics/index.d.ts +1 -1
  59. package/dist/types/src/packlets/diagnostics/index.d.ts.map +1 -1
  60. package/dist/types/src/packlets/identity/authenticator.d.ts +2 -2
  61. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  62. package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
  63. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  64. package/dist/types/src/packlets/identity/identity-manager.d.ts +7 -7
  65. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  66. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +7 -6
  67. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
  68. package/dist/types/src/packlets/identity/identity-service.d.ts +6 -10
  69. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  70. package/dist/types/src/packlets/identity/identity.d.ts +9 -12
  71. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  72. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +6 -5
  73. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  74. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +2 -2
  75. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
  76. package/dist/types/src/packlets/invitations/index.d.ts +1 -1
  77. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  78. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
  79. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  80. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +8 -5
  81. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
  82. package/dist/types/src/packlets/invitations/invitation-state.d.ts.map +1 -1
  83. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -4
  84. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  85. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +3 -3
  86. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  87. package/dist/types/src/packlets/invitations/invitations-service.d.ts +4 -4
  88. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  89. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +5 -4
  90. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  91. package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -1
  92. package/dist/types/src/packlets/locks/index.d.ts +2 -2
  93. package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
  94. package/dist/types/src/packlets/logging/logging-service.d.ts +5 -1
  95. package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
  96. package/dist/types/src/packlets/network/network-service.d.ts +7 -6
  97. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  98. package/dist/types/src/packlets/services/client-rpc-server.d.ts +5 -5
  99. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
  100. package/dist/types/src/packlets/services/feed-syncer.d.ts +59 -0
  101. package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -0
  102. package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
  103. package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
  104. package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
  105. package/dist/types/src/packlets/services/service-context.d.ts +14 -9
  106. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  107. package/dist/types/src/packlets/services/service-host.d.ts +21 -8
  108. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  109. package/dist/types/src/packlets/space-export/archive-format.d.ts +9 -0
  110. package/dist/types/src/packlets/space-export/archive-format.d.ts.map +1 -0
  111. package/dist/types/src/packlets/space-export/index.d.ts +4 -1
  112. package/dist/types/src/packlets/space-export/index.d.ts.map +1 -1
  113. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +23 -0
  114. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -0
  115. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +36 -0
  116. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -0
  117. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
  118. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
  119. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +8 -2
  120. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
  121. package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
  122. package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
  123. package/dist/types/src/packlets/spaces/automerge-space-state.d.ts +1 -1
  124. package/dist/types/src/packlets/spaces/automerge-space-state.d.ts.map +1 -1
  125. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +29 -17
  126. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  127. package/dist/types/src/packlets/spaces/data-space.d.ts +30 -13
  128. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  129. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +2 -2
  130. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  131. package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
  132. package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
  133. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +6 -6
  134. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  135. package/dist/types/src/packlets/spaces/spaces-service.d.ts +18 -8
  136. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  137. package/dist/types/src/packlets/storage/profile-archive.d.ts.map +1 -1
  138. package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
  139. package/dist/types/src/packlets/system/system-service.d.ts +1 -1
  140. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  141. package/dist/types/src/packlets/testing/invitation-utils.d.ts +6 -3
  142. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  143. package/dist/types/src/packlets/testing/test-builder.d.ts +8 -7
  144. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  145. package/dist/types/src/packlets/worker/worker-runtime.d.ts +41 -4
  146. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  147. package/dist/types/src/packlets/worker/worker-session.d.ts +2 -4
  148. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
  149. package/dist/types/src/version.d.ts +1 -1
  150. package/dist/types/src/version.d.ts.map +1 -1
  151. package/dist/types/tsconfig.tsbuildinfo +1 -1
  152. package/package.json +72 -48
  153. package/src/index.ts +1 -0
  154. package/src/packlets/agents/edge-agent-manager.ts +10 -7
  155. package/src/packlets/agents/edge-agent-service.ts +17 -5
  156. package/src/packlets/devices/devices-service.test.ts +3 -3
  157. package/src/packlets/devices/devices-service.ts +2 -2
  158. package/src/packlets/devtools/devtools.ts +29 -29
  159. package/src/packlets/devtools/feeds.ts +2 -2
  160. package/src/packlets/devtools/network.ts +1 -1
  161. package/src/packlets/diagnostics/browser-diagnostics-broadcast.ts +1 -1
  162. package/src/packlets/diagnostics/diagnostics-broadcast.ts +1 -1
  163. package/src/packlets/diagnostics/diagnostics-collector.ts +1 -1
  164. package/src/packlets/diagnostics/diagnostics.ts +2 -3
  165. package/src/packlets/diagnostics/index.ts +1 -1
  166. package/src/packlets/identity/authenticator.node.test.ts +1 -1
  167. package/src/packlets/identity/authenticator.ts +3 -3
  168. package/src/packlets/identity/contacts-service.ts +2 -2
  169. package/src/packlets/identity/identity-manager.test.ts +8 -8
  170. package/src/packlets/identity/identity-manager.ts +23 -20
  171. package/src/packlets/identity/identity-recovery-manager.ts +22 -18
  172. package/src/packlets/identity/identity-service.test.ts +8 -28
  173. package/src/packlets/identity/identity-service.ts +13 -80
  174. package/src/packlets/identity/identity.test.ts +11 -11
  175. package/src/packlets/identity/identity.ts +17 -39
  176. package/src/packlets/invitations/device-invitation-protocol.test.ts +4 -4
  177. package/src/packlets/invitations/device-invitation-protocol.ts +8 -6
  178. package/src/packlets/invitations/edge-invitation-handler.ts +10 -6
  179. package/src/packlets/invitations/index.ts +1 -1
  180. package/src/packlets/invitations/invitation-guest-extenstion.ts +7 -5
  181. package/src/packlets/invitations/invitation-host-extension.ts +8 -6
  182. package/src/packlets/invitations/invitation-protocol.ts +8 -5
  183. package/src/packlets/invitations/invitation-state.ts +0 -10
  184. package/src/packlets/invitations/invitations-handler.test.ts +301 -292
  185. package/src/packlets/invitations/invitations-handler.ts +72 -16
  186. package/src/packlets/invitations/invitations-manager.ts +43 -18
  187. package/src/packlets/invitations/invitations-service.ts +10 -10
  188. package/src/packlets/invitations/space-invitation-protocol.test.ts +26 -25
  189. package/src/packlets/invitations/space-invitation-protocol.ts +13 -17
  190. package/src/packlets/invitations/utils.ts +1 -1
  191. package/src/packlets/locks/browser.ts +1 -1
  192. package/src/packlets/locks/index.ts +2 -2
  193. package/src/packlets/logging/logging-service.ts +8 -3
  194. package/src/packlets/logging/logging.test.ts +1 -1
  195. package/src/packlets/network/network-service.test.ts +3 -3
  196. package/src/packlets/network/network-service.ts +12 -10
  197. package/src/packlets/services/client-rpc-server.ts +20 -17
  198. package/src/packlets/services/feed-syncer.test.ts +340 -0
  199. package/src/packlets/services/feed-syncer.ts +337 -0
  200. package/src/packlets/services/platform.ts +7 -1
  201. package/src/packlets/services/service-context.test.ts +4 -3
  202. package/src/packlets/services/service-context.ts +145 -59
  203. package/src/packlets/services/service-host.test.ts +10 -9
  204. package/src/packlets/services/service-host.ts +85 -38
  205. package/src/packlets/services/service-registry.test.ts +1 -1
  206. package/src/packlets/space-export/archive-format.ts +42 -0
  207. package/src/packlets/space-export/index.ts +4 -1
  208. package/src/packlets/space-export/serialized-space-reader.ts +111 -0
  209. package/src/packlets/space-export/serialized-space-writer.ts +246 -0
  210. package/src/packlets/space-export/space-archive-reader.ts +65 -4
  211. package/src/packlets/space-export/space-archive-writer.ts +44 -6
  212. package/src/packlets/space-export/space-archive.test.ts +461 -0
  213. package/src/packlets/space-export/tar.test.ts +1 -1
  214. package/src/packlets/spaces/automerge-space-state.ts +1 -1
  215. package/src/packlets/spaces/data-space-manager.test.ts +79 -13
  216. package/src/packlets/spaces/data-space-manager.ts +131 -118
  217. package/src/packlets/spaces/data-space.ts +65 -39
  218. package/src/packlets/spaces/edge-feed-replicator.test.ts +4 -4
  219. package/src/packlets/spaces/edge-feed-replicator.ts +13 -11
  220. package/src/packlets/spaces/epoch-migrations.ts +5 -5
  221. package/src/packlets/spaces/genesis.ts +6 -1
  222. package/src/packlets/spaces/notarization-plugin.test.ts +3 -3
  223. package/src/packlets/spaces/notarization-plugin.ts +13 -12
  224. package/src/packlets/spaces/spaces-service.test.ts +20 -12
  225. package/src/packlets/spaces/spaces-service.ts +138 -38
  226. package/src/packlets/storage/profile-archive.ts +1 -1
  227. package/src/packlets/storage/storage.ts +7 -8
  228. package/src/packlets/system/system-service.test.ts +1 -1
  229. package/src/packlets/system/system-service.ts +4 -4
  230. package/src/packlets/testing/invitation-utils.ts +11 -7
  231. package/src/packlets/testing/test-builder.ts +39 -13
  232. package/src/packlets/worker/worker-runtime.ts +180 -17
  233. package/src/packlets/worker/worker-session.ts +15 -21
  234. package/src/version.ts +1 -1
  235. package/dist/lib/browser/chunk-ERQJUBAW.mjs.map +0 -7
  236. package/dist/lib/node-esm/chunk-TMEG7JOG.mjs.map +0 -7
  237. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
  238. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
  239. package/src/packlets/identity/default-space-state-machine.ts +0 -44
@@ -2,5 +2,5 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './resource-lock';
6
- export * from './node';
5
+ export type * from './resource-lock';
6
+ export * from '#locks-platform';
@@ -13,12 +13,12 @@ import {
13
13
  log,
14
14
  } from '@dxos/log';
15
15
  import {
16
+ type ControlMetricsRequest,
17
+ type ControlMetricsResponse,
16
18
  type LogEntry,
17
19
  type LoggingService,
18
20
  type Metrics,
19
21
  QueryLogsRequest,
20
- type ControlMetricsRequest,
21
- type ControlMetricsResponse,
22
22
  type QueryMetricsRequest,
23
23
  type QueryMetricsResponse,
24
24
  } from '@dxos/protocols/proto/dxos/client/services';
@@ -26,6 +26,10 @@ import { getDebugName, jsonify, numericalValues, tracer } from '@dxos/util';
26
26
 
27
27
  /**
28
28
  * Logging service used to spy on logs of the host.
29
+ *
30
+ * @deprecated This was created so that logs from the shared worker (WorkerClientServices) could be
31
+ * seen in the main window console without opening the shared worker DevTools. Shared worker client
32
+ * services is deprecated; dedicated worker logs already show in the main window console.
29
33
  */
30
34
  export class LoggingServiceImpl implements LoggingService {
31
35
  private readonly _logs = new Event<NaturalLogEntry>();
@@ -37,7 +41,7 @@ export class LoggingServiceImpl implements LoggingService {
37
41
  }
38
42
 
39
43
  async close(): Promise<void> {
40
- const index = log.runtimeConfig.processors.findIndex((processor) => processor === this._logProcessor);
44
+ const index = log.runtimeConfig.processors.findIndex((processor: LogProcessor) => processor === this._logProcessor);
41
45
  log.runtimeConfig.processors.splice(index, 1);
42
46
  }
43
47
 
@@ -112,6 +116,7 @@ export class LoggingServiceImpl implements LoggingService {
112
116
 
113
117
  const record: LogEntry = {
114
118
  ...entry,
119
+ message: entry.message ?? (entry.error ? (entry.error.message ?? String(entry.error)) : ''),
115
120
  context: jsonify(getContextFromEntry(entry)),
116
121
  timestamp: new Date(),
117
122
  meta: {
@@ -5,7 +5,7 @@
5
5
  import { afterEach, beforeEach, describe, expect, test } from 'vitest';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
- import { log, LogLevel } from '@dxos/log';
8
+ import { LogLevel, log } from '@dxos/log';
9
9
  import { type LogEntry } from '@dxos/protocols/proto/dxos/client/services';
10
10
 
11
11
  import { LoggingServiceImpl } from './logging-service';
@@ -2,15 +2,15 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { afterEach, onTestFinished, beforeEach, describe, expect, test } from 'vitest';
5
+ import { afterEach, beforeEach, describe, expect, onTestFinished, test } from 'vitest';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
8
  import { Context } from '@dxos/context';
9
- import { type NetworkService, ConnectionState } from '@dxos/protocols/proto/dxos/client/services';
9
+ import { ConnectionState, type NetworkService } from '@dxos/protocols/proto/dxos/client/services';
10
10
 
11
- import { NetworkServiceImpl } from './network-service';
12
11
  import { type ServiceContext } from '../services';
13
12
  import { createServiceContext } from '../testing';
13
+ import { NetworkServiceImpl } from './network-service';
14
14
 
15
15
  describe('NetworkService', () => {
16
16
  let serviceContext: ServiceContext;
@@ -2,20 +2,22 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
+ import { type RequestOptions } from '@dxos/codec-protobuf';
5
6
  import { Stream } from '@dxos/codec-protobuf/stream';
7
+ import { Context } from '@dxos/context';
6
8
  import { type EdgeConnection } from '@dxos/edge-client';
7
9
  import { type SignalManager } from '@dxos/messaging';
8
10
  import { type SwarmNetworkManager } from '@dxos/network-manager';
9
11
  import {
10
- type SubscribeSwarmStateRequest,
11
12
  type NetworkService,
12
13
  type NetworkStatus,
14
+ type SubscribeSwarmStateRequest,
13
15
  type UpdateConfigRequest,
14
16
  } from '@dxos/protocols/proto/dxos/client/services';
15
17
  import { type Peer, type SwarmResponse } from '@dxos/protocols/proto/dxos/edge/messenger';
16
18
  import {
17
- type LeaveRequest,
18
19
  type JoinRequest,
20
+ type LeaveRequest,
19
21
  type Message,
20
22
  type QueryRequest,
21
23
  } from '@dxos/protocols/proto/dxos/edge/signal';
@@ -47,16 +49,16 @@ export class NetworkServiceImpl implements NetworkService {
47
49
  await this.networkManager.setConnectionState(request.swarm);
48
50
  }
49
51
 
50
- async joinSwarm(request: JoinRequest): Promise<void> {
51
- return this.signalManager.join(request);
52
+ async joinSwarm(request: JoinRequest, options?: RequestOptions): Promise<void> {
53
+ return this.signalManager.join(options?.ctx ?? Context.default(), request);
52
54
  }
53
55
 
54
- async leaveSwarm(request: LeaveRequest): Promise<void> {
55
- return this.signalManager.leave(request);
56
+ async leaveSwarm(request: LeaveRequest, options?: RequestOptions): Promise<void> {
57
+ return this.signalManager.leave(options?.ctx ?? Context.default(), request);
56
58
  }
57
59
 
58
- async querySwarm(request: QueryRequest): Promise<SwarmResponse> {
59
- return this.signalManager.query(request);
60
+ async querySwarm(request: QueryRequest, options?: RequestOptions): Promise<SwarmResponse> {
61
+ return this.signalManager.query(options?.ctx ?? Context.default(), request);
60
62
  }
61
63
 
62
64
  subscribeSwarmState(request: SubscribeSwarmStateRequest): Stream<SwarmResponse> {
@@ -69,8 +71,8 @@ export class NetworkServiceImpl implements NetworkService {
69
71
  });
70
72
  }
71
73
 
72
- async sendMessage(message: Message): Promise<void> {
73
- return this.signalManager.sendMessage(message);
74
+ async sendMessage(message: Message, options?: RequestOptions): Promise<void> {
75
+ return this.signalManager.sendMessage(options?.ctx ?? Context.default(), message);
74
76
  }
75
77
 
76
78
  subscribeMessages(peer: Peer): Stream<Message> {
@@ -3,25 +3,27 @@
3
3
  //
4
4
 
5
5
  import { type ClientServices } from '@dxos/client-protocol';
6
- import { type Any, type ServiceHandler, Stream } from '@dxos/codec-protobuf';
6
+ import { type Any, type RequestOptions, type ServiceHandler, Stream } from '@dxos/codec-protobuf';
7
7
  import { raise } from '@dxos/debug';
8
- import { parseMethodName, RpcPeer, type RpcPeerOptions, type ServiceBundle } from '@dxos/rpc';
8
+ import { RpcPeer, type RpcPeerOptions, type ServiceBundle, parseMethodName } from '@dxos/rpc';
9
9
  import { MapCounter, trace } from '@dxos/tracing';
10
10
  import { type MaybePromise } from '@dxos/util';
11
11
 
12
12
  import { type ServiceRegistry } from './service-registry';
13
13
 
14
- export type ClientRpcServerParams = {
14
+ export type ClientRpcServerProps = {
15
15
  serviceRegistry: ServiceRegistry<ClientServices>;
16
16
  handleCall?: (
17
17
  method: string,
18
18
  params: Any,
19
- handler: (method: string, params: Any) => MaybePromise<Any>,
19
+ handler: (method: string, params: Any, options?: RequestOptions) => MaybePromise<Any>,
20
+ options?: RequestOptions,
20
21
  ) => Promise<Any>;
21
22
  handleStream?: (
22
23
  method: string,
23
24
  params: Any,
24
- handler: (method: string, params: Any) => Stream<Any>,
25
+ handler: (method: string, params: Any, options?: RequestOptions) => Stream<Any>,
26
+ options?: RequestOptions,
25
27
  ) => MaybePromise<Stream<Any>>;
26
28
  } & Omit<RpcPeerOptions, 'callHandler' | 'streamHandler'>;
27
29
 
@@ -30,8 +32,8 @@ export class ClientRpcServer {
30
32
  private readonly _serviceRegistry: ServiceRegistry<ClientServices>;
31
33
  private readonly _rpcPeer: RpcPeer;
32
34
  private readonly _handlerCache = new Map<string, ServiceHandler<any>>();
33
- private readonly _handleCall: ClientRpcServerParams['handleCall'];
34
- private readonly _handleStream: ClientRpcServerParams['handleStream'];
35
+ private readonly _handleCall: ClientRpcServerProps['handleCall'];
36
+ private readonly _handleStream: ClientRpcServerProps['handleStream'];
35
37
 
36
38
  @trace.metricsCounter()
37
39
  private readonly _callMetrics = new MapCounter();
@@ -41,7 +43,7 @@ export class ClientRpcServer {
41
43
  return Object.keys(this._serviceRegistry.services);
42
44
  }
43
45
 
44
- constructor(params: ClientRpcServerParams) {
46
+ constructor(params: ClientRpcServerProps) {
45
47
  const { serviceRegistry, handleCall, handleStream, ...rpcOptions } = params;
46
48
  this._handleCall = handleCall;
47
49
  this._handleStream = handleStream;
@@ -49,32 +51,33 @@ export class ClientRpcServer {
49
51
  this._serviceRegistry = serviceRegistry;
50
52
  this._rpcPeer = new RpcPeer({
51
53
  ...rpcOptions,
52
- callHandler: (method, params) => {
54
+ callHandler: (method, params, options) => {
53
55
  const [serviceName, methodName] = parseMethodName(method);
54
- const handler = (method: string, params: Any) => this._getServiceHandler(serviceName).call(method, params);
56
+ const handler = (method: string, params: Any, handlerOptions?: RequestOptions) =>
57
+ this._getServiceHandler(serviceName).call(method, params, handlerOptions);
55
58
 
56
59
  this._callMetrics.inc(`${serviceName}.${methodName} request`);
57
60
 
58
61
  if (this._handleCall) {
59
- return this._handleCall(methodName, params, handler);
62
+ return this._handleCall(methodName, params, handler, options);
60
63
  } else {
61
- return handler(methodName, params);
64
+ return handler(methodName, params, options);
62
65
  }
63
66
  },
64
- streamHandler: (method, params) => {
67
+ streamHandler: (method, params, options) => {
65
68
  const [serviceName, methodName] = parseMethodName(method);
66
- const handler = (method: string, params: Any) =>
67
- this._getServiceHandler(serviceName).callStream(method, params);
69
+ const handler = (method: string, params: Any, handlerOptions?: RequestOptions) =>
70
+ this._getServiceHandler(serviceName).callStream(method, params, handlerOptions);
68
71
 
69
72
  this._callMetrics.inc(`${serviceName}.${methodName} request stream`);
70
73
 
71
74
  if (this._handleStream) {
72
- return Stream.map(Stream.unwrapPromise(this._handleStream(methodName, params, handler)), (data) => {
75
+ return Stream.map(Stream.unwrapPromise(this._handleStream(methodName, params, handler, options)), (data) => {
73
76
  this._callMetrics.inc(`${serviceName}.${methodName} response stream`);
74
77
  return data;
75
78
  });
76
79
  } else {
77
- return handler(methodName, params);
80
+ return handler(methodName, params, options);
78
81
  }
79
82
  },
80
83
  });
@@ -0,0 +1,340 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { Encoder, decode as cborDecode } from 'cbor-x';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Layer from 'effect/Layer';
8
+ import * as ManagedRuntime from 'effect/ManagedRuntime';
9
+ import { describe, expect, onTestFinished, test, vi } from 'vitest';
10
+
11
+ import { Event } from '@dxos/async';
12
+ import { Context } from '@dxos/context';
13
+ import { type EdgeConnection, MessageSchema } from '@dxos/edge-client';
14
+ import { RuntimeProvider } from '@dxos/effect';
15
+ import { FeedStore, SyncServer } from '@dxos/feed';
16
+ import { ObjectId, SpaceId } from '@dxos/keys';
17
+ import { FeedProtocol } from '@dxos/protocols';
18
+ import { EdgeService } from '@dxos/protocols';
19
+ import { createBuf } from '@dxos/protocols/buf';
20
+ import { type Message as RouterMessage } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
21
+ import { EdgeStatus } from '@dxos/protocols/proto/dxos/client/services';
22
+ import { SqlTransaction } from '@dxos/sql-sqlite';
23
+ import { layerMemory } from '@dxos/sql-sqlite/platform';
24
+ import { bufferToArray } from '@dxos/util';
25
+
26
+ import { FeedSyncer } from './feed-syncer';
27
+
28
+ type ProtocolMessage = FeedProtocol.ProtocolMessage;
29
+
30
+ const encoder = new Encoder({ tagUint8Array: false, useRecords: false });
31
+ const syncNamespace = FeedProtocol.WellKnownNamespaces.data;
32
+ const syncNamespaces = [FeedProtocol.WellKnownNamespaces.data, FeedProtocol.WellKnownNamespaces.trace];
33
+
34
+ const createRuntime = () => {
35
+ const baseLayer = layerMemory;
36
+ const transactionLayer = SqlTransaction.layer.pipe(Layer.provide(baseLayer));
37
+ return ManagedRuntime.make(Layer.merge(baseLayer, transactionLayer).pipe(Layer.orDie));
38
+ };
39
+
40
+ const createFeedStore = (localActorId: string, assignPositions: boolean) =>
41
+ new FeedStore({ localActorId, assignPositions });
42
+
43
+ const createEdgeConnection = ({
44
+ syncServer,
45
+ serverRuntime,
46
+ messageListeners,
47
+ }: {
48
+ syncServer: SyncServer;
49
+ serverRuntime: ReturnType<typeof createRuntime>;
50
+ messageListeners: Set<(message: RouterMessage) => void>;
51
+ }): EdgeConnection => {
52
+ const reconnectListeners = new Set<() => void>();
53
+
54
+ return {
55
+ statusChanged: new Event<any>(),
56
+ info: {},
57
+ identityKey: 'client-identity',
58
+ peerKey: 'client-peer',
59
+ isOpen: true,
60
+ status: {
61
+ state: EdgeStatus.ConnectionState.CONNECTED,
62
+ rtt: 0,
63
+ uptime: 0,
64
+ rateBytesUp: 0,
65
+ rateBytesDown: 0,
66
+ messagesSent: 0,
67
+ messagesReceived: 0,
68
+ },
69
+ setIdentity: () => {},
70
+ open: async () => {},
71
+ close: async () => {},
72
+ send: async (ctx, routerMessage: RouterMessage) => {
73
+ const decoded = cborDecode(routerMessage.payload!.value) as ProtocolMessage;
74
+ await syncServer.handleMessage(ctx, decoded).pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
75
+ },
76
+ onMessage: (listener: (message: RouterMessage) => void) => {
77
+ messageListeners.add(listener);
78
+ return () => messageListeners.delete(listener);
79
+ },
80
+ onReconnected: (listener: () => void) => {
81
+ reconnectListeners.add(listener);
82
+ return () => reconnectListeners.delete(listener);
83
+ },
84
+ };
85
+ };
86
+
87
+ const createFeedSyncHarness = async ({
88
+ spaceId,
89
+ pollingInterval,
90
+ syncNamespaces: namespaces = [syncNamespace],
91
+ }: {
92
+ spaceId: SpaceId;
93
+ pollingInterval?: number;
94
+ syncNamespaces?: string[];
95
+ }) => {
96
+ const serverRuntime = createRuntime();
97
+ const clientRuntime = createRuntime();
98
+ const serverFeedStore = createFeedStore('server', true);
99
+ const clientFeedStore = createFeedStore('client', false);
100
+
101
+ await serverFeedStore.migrate().pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
102
+ await clientFeedStore.migrate().pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
103
+
104
+ const messageListeners = new Set<(message: RouterMessage) => void>();
105
+ const syncServer = new SyncServer({
106
+ peerId: 'server',
107
+ feedStore: serverFeedStore,
108
+ sendMessage: (_ctx, message) =>
109
+ Effect.promise(async () => {
110
+ const routerMessage = createBuf(MessageSchema, {
111
+ source: {
112
+ identityKey: 'server-identity',
113
+ peerKey: 'server-peer',
114
+ },
115
+ serviceId: `${EdgeService.QUEUE_REPLICATOR}:test`,
116
+ payload: { value: bufferToArray(encoder.encode(message)) },
117
+ });
118
+
119
+ for (const listener of messageListeners) {
120
+ listener(routerMessage);
121
+ }
122
+ }),
123
+ });
124
+
125
+ const edgeClient = createEdgeConnection({ syncServer, serverRuntime, messageListeners });
126
+
127
+ const syncer = new FeedSyncer({
128
+ runtime: clientRuntime.runtimeEffect,
129
+ feedStore: clientFeedStore,
130
+ edgeClient: edgeClient as any,
131
+ peerId: 'client',
132
+ getSpaceIds: () => [spaceId],
133
+ syncNamespaces: namespaces,
134
+ pollingInterval,
135
+ });
136
+
137
+ const close = async () => {
138
+ await syncer.close();
139
+ await clientRuntime.dispose();
140
+ await serverRuntime.dispose();
141
+ };
142
+
143
+ onTestFinished(close);
144
+
145
+ return { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer, close };
146
+ };
147
+
148
+ describe('FeedSyncer', () => {
149
+ test('syncs mixed pull and push traffic', async () => {
150
+ const spaceId = SpaceId.random();
151
+ const { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer } = await createFeedSyncHarness({
152
+ spaceId,
153
+ });
154
+ const serverFeedId = ObjectId.random();
155
+ const clientFeedId = ObjectId.random();
156
+
157
+ await serverFeedStore
158
+ .appendLocal([
159
+ {
160
+ spaceId,
161
+ feedId: serverFeedId,
162
+ feedNamespace: syncNamespace,
163
+ data: new Uint8Array([1, 2, 3]),
164
+ },
165
+ ])
166
+ .pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
167
+
168
+ await syncer.open(new Context());
169
+
170
+ await vi.waitFor(async () => {
171
+ const { blocks } = await clientFeedStore
172
+ .query({
173
+ spaceId,
174
+ feedNamespace: syncNamespace,
175
+ position: -1,
176
+ query: { feedIds: [serverFeedId] },
177
+ })
178
+ .pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
179
+
180
+ expect(blocks).toHaveLength(1);
181
+ expect(blocks[0].data).toEqual(new Uint8Array([1, 2, 3]));
182
+ expect(blocks[0].position).toBeDefined();
183
+ });
184
+
185
+ await clientFeedStore
186
+ .appendLocal([
187
+ {
188
+ spaceId,
189
+ feedId: clientFeedId,
190
+ feedNamespace: syncNamespace,
191
+ data: new Uint8Array([9, 8, 7]),
192
+ },
193
+ ])
194
+ .pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
195
+
196
+ await vi.waitFor(async () => {
197
+ const { blocks } = await serverFeedStore
198
+ .query({
199
+ spaceId,
200
+ feedNamespace: syncNamespace,
201
+ position: -1,
202
+ query: { feedIds: [clientFeedId] },
203
+ })
204
+ .pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
205
+
206
+ expect(blocks).toHaveLength(1);
207
+ expect(blocks[0].data).toEqual(new Uint8Array([9, 8, 7]));
208
+ expect(blocks[0].position).toBeDefined();
209
+ });
210
+ });
211
+
212
+ test('requestPoll triggers best-effort pull for a space', async () => {
213
+ const spaceId = SpaceId.random();
214
+ const { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer } = await createFeedSyncHarness({
215
+ spaceId,
216
+ pollingInterval: 60_000,
217
+ });
218
+ const serverFeedId = ObjectId.random();
219
+
220
+ await serverFeedStore
221
+ .appendLocal([
222
+ {
223
+ spaceId,
224
+ feedId: serverFeedId,
225
+ feedNamespace: syncNamespace,
226
+ data: new Uint8Array([1, 2, 3]),
227
+ },
228
+ ])
229
+ .pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
230
+
231
+ await syncer.open(new Context());
232
+
233
+ await vi.waitFor(async () => {
234
+ const { blocks } = await clientFeedStore
235
+ .query({
236
+ spaceId,
237
+ feedNamespace: syncNamespace,
238
+ position: -1,
239
+ query: { feedIds: [serverFeedId] },
240
+ })
241
+ .pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
242
+
243
+ expect(blocks).toHaveLength(1);
244
+ expect(blocks[0].data).toEqual(new Uint8Array([1, 2, 3]));
245
+ });
246
+
247
+ await serverFeedStore
248
+ .appendLocal([
249
+ {
250
+ spaceId,
251
+ feedId: serverFeedId,
252
+ feedNamespace: syncNamespace,
253
+ data: new Uint8Array([4, 5, 6]),
254
+ },
255
+ ])
256
+ .pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
257
+
258
+ await new Promise((resolve) => setTimeout(resolve, 250));
259
+ {
260
+ const { blocks } = await clientFeedStore
261
+ .query({
262
+ spaceId,
263
+ feedNamespace: syncNamespace,
264
+ position: -1,
265
+ query: { feedIds: [serverFeedId] },
266
+ })
267
+ .pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
268
+ expect(blocks).toHaveLength(1);
269
+ }
270
+
271
+ syncer.schedulePoll();
272
+
273
+ await vi.waitFor(async () => {
274
+ const { blocks } = await clientFeedStore
275
+ .query({
276
+ spaceId,
277
+ feedNamespace: syncNamespace,
278
+ position: -1,
279
+ query: { feedIds: [serverFeedId] },
280
+ })
281
+ .pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
282
+
283
+ expect(blocks).toHaveLength(2);
284
+ expect(blocks[1].data).toEqual(new Uint8Array([4, 5, 6]));
285
+ });
286
+ });
287
+
288
+ test('syncs all configured namespaces', async () => {
289
+ const spaceId = SpaceId.random();
290
+ const { serverRuntime, clientRuntime, serverFeedStore, clientFeedStore, syncer } = await createFeedSyncHarness({
291
+ spaceId,
292
+ syncNamespaces,
293
+ });
294
+ const serverDataFeedId = ObjectId.random();
295
+ const serverTraceFeedId = ObjectId.random();
296
+
297
+ await serverFeedStore
298
+ .appendLocal([
299
+ {
300
+ spaceId,
301
+ feedId: serverDataFeedId,
302
+ feedNamespace: FeedProtocol.WellKnownNamespaces.data,
303
+ data: new Uint8Array([1, 2, 3]),
304
+ },
305
+ {
306
+ spaceId,
307
+ feedId: serverTraceFeedId,
308
+ feedNamespace: FeedProtocol.WellKnownNamespaces.trace,
309
+ data: new Uint8Array([7, 8, 9]),
310
+ },
311
+ ])
312
+ .pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
313
+
314
+ await syncer.open(new Context());
315
+
316
+ await vi.waitFor(async () => {
317
+ const dataResult = await clientFeedStore
318
+ .query({
319
+ spaceId,
320
+ feedNamespace: FeedProtocol.WellKnownNamespaces.data,
321
+ position: -1,
322
+ query: { feedIds: [serverDataFeedId] },
323
+ })
324
+ .pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
325
+ const traceResult = await clientFeedStore
326
+ .query({
327
+ spaceId,
328
+ feedNamespace: FeedProtocol.WellKnownNamespaces.trace,
329
+ position: -1,
330
+ query: { feedIds: [serverTraceFeedId] },
331
+ })
332
+ .pipe(RuntimeProvider.runPromise(clientRuntime.runtimeEffect));
333
+
334
+ expect(dataResult.blocks).toHaveLength(1);
335
+ expect(traceResult.blocks).toHaveLength(1);
336
+ expect(dataResult.blocks[0].data).toEqual(new Uint8Array([1, 2, 3]));
337
+ expect(traceResult.blocks[0].data).toEqual(new Uint8Array([7, 8, 9]));
338
+ });
339
+ });
340
+ });