@dxos/client-services 0.8.4-main.8360d9e660 → 0.8.4-main.8baae0fced

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 (201) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/browser/{chunk-FRMIC6UB.mjs → chunk-KBMYCFTL.mjs} +1636 -3392
  4. package/dist/lib/browser/chunk-KBMYCFTL.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-NQSC7HOE.mjs → chunk-XJRPB3GA.mjs} +1 -1
  6. package/dist/lib/browser/index.mjs +106 -194
  7. package/dist/lib/browser/index.mjs.map +3 -3
  8. package/dist/lib/browser/meta.json +1 -1
  9. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +1 -6
  10. package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +2 -2
  11. package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +1 -1
  12. package/dist/lib/browser/packlets/locks/browser.mjs +9 -49
  13. package/dist/lib/browser/packlets/locks/browser.mjs.map +2 -2
  14. package/dist/lib/browser/packlets/locks/node.mjs +4 -22
  15. package/dist/lib/browser/packlets/locks/node.mjs.map +2 -2
  16. package/dist/lib/browser/testing/index.mjs +9 -22
  17. package/dist/lib/browser/testing/index.mjs.map +3 -3
  18. package/dist/lib/node-esm/{chunk-PKEGMOQ4.mjs → chunk-2DT3MZRL.mjs} +1 -1
  19. package/dist/lib/node-esm/{chunk-6ONWVRY5.mjs → chunk-TCS4PMDH.mjs} +1636 -3392
  20. package/dist/lib/node-esm/chunk-TCS4PMDH.mjs.map +7 -0
  21. package/dist/lib/node-esm/index.mjs +106 -194
  22. package/dist/lib/node-esm/index.mjs.map +3 -3
  23. package/dist/lib/node-esm/meta.json +1 -1
  24. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +1 -6
  25. package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +2 -2
  26. package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +1 -1
  27. package/dist/lib/node-esm/packlets/locks/browser.mjs +9 -49
  28. package/dist/lib/node-esm/packlets/locks/browser.mjs.map +2 -2
  29. package/dist/lib/node-esm/packlets/locks/node.mjs +4 -22
  30. package/dist/lib/node-esm/packlets/locks/node.mjs.map +2 -2
  31. package/dist/lib/node-esm/testing/index.mjs +9 -22
  32. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  33. package/dist/types/src/index.d.ts +1 -0
  34. package/dist/types/src/index.d.ts.map +1 -1
  35. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +3 -2
  36. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
  37. package/dist/types/src/packlets/agents/edge-agent-service.d.ts +2 -1
  38. package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
  39. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  40. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  41. package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
  42. package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
  43. package/dist/types/src/packlets/devtools/metadata.d.ts.map +1 -1
  44. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  45. package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
  46. package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts.map +1 -1
  47. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
  48. package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts.map +1 -1
  49. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +2 -3
  50. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
  51. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  52. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  53. package/dist/types/src/packlets/identity/identity-manager.d.ts +3 -3
  54. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  55. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +6 -5
  56. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
  57. package/dist/types/src/packlets/identity/identity-service.d.ts +6 -10
  58. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  59. package/dist/types/src/packlets/identity/identity.d.ts +6 -9
  60. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  61. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +2 -1
  62. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  63. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +1 -1
  64. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
  65. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
  66. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  67. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +5 -1
  68. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
  69. package/dist/types/src/packlets/invitations/invitation-state.d.ts.map +1 -1
  70. package/dist/types/src/packlets/invitations/invitation-topology.d.ts.map +1 -1
  71. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  72. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +3 -3
  73. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  74. package/dist/types/src/packlets/invitations/invitations-service.d.ts +3 -3
  75. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  76. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +2 -1
  77. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  78. package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -1
  79. package/dist/types/src/packlets/locks/browser.d.ts.map +1 -1
  80. package/dist/types/src/packlets/locks/node.d.ts.map +1 -1
  81. package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
  82. package/dist/types/src/packlets/network/network-service.d.ts +5 -4
  83. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  84. package/dist/types/src/packlets/services/client-rpc-server.d.ts +3 -3
  85. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
  86. package/dist/types/src/packlets/services/feed-syncer.d.ts +2 -2
  87. package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -1
  88. package/dist/types/src/packlets/services/service-context.d.ts +2 -3
  89. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  90. package/dist/types/src/packlets/services/service-host.d.ts +2 -3
  91. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  92. package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
  93. package/dist/types/src/packlets/services/util.d.ts.map +1 -1
  94. package/dist/types/src/packlets/space-export/archive-format.d.ts +9 -0
  95. package/dist/types/src/packlets/space-export/archive-format.d.ts.map +1 -0
  96. package/dist/types/src/packlets/space-export/index.d.ts +4 -1
  97. package/dist/types/src/packlets/space-export/index.d.ts.map +1 -1
  98. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +23 -0
  99. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -0
  100. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +36 -0
  101. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -0
  102. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
  103. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
  104. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +7 -1
  105. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
  106. package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
  107. package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
  108. package/dist/types/src/packlets/spaces/automerge-space-state.d.ts.map +1 -1
  109. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +20 -14
  110. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  111. package/dist/types/src/packlets/spaces/data-space.d.ts +24 -7
  112. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  113. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  114. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
  115. package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
  116. package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
  117. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +1 -4
  118. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  119. package/dist/types/src/packlets/spaces/spaces-service.d.ts +10 -7
  120. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  121. package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
  122. package/dist/types/src/packlets/storage/profile-archive.d.ts.map +1 -1
  123. package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
  124. package/dist/types/src/packlets/storage/util.d.ts.map +1 -1
  125. package/dist/types/src/packlets/system/system-service.d.ts +1 -1
  126. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  127. package/dist/types/src/packlets/testing/credential-utils.d.ts.map +1 -1
  128. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  129. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  130. package/dist/types/src/packlets/worker/worker-runtime.d.ts +11 -1
  131. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  132. package/dist/types/src/packlets/worker/worker-session.d.ts +0 -2
  133. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
  134. package/dist/types/src/testing/setup.d.ts.map +1 -1
  135. package/dist/types/src/version.d.ts +1 -1
  136. package/dist/types/tsconfig.tsbuildinfo +1 -1
  137. package/package.json +43 -50
  138. package/src/index.ts +1 -0
  139. package/src/packlets/agents/edge-agent-manager.ts +8 -5
  140. package/src/packlets/agents/edge-agent-service.ts +4 -2
  141. package/src/packlets/devices/devices-service.test.ts +0 -1
  142. package/src/packlets/devtools/devtools.ts +0 -1
  143. package/src/packlets/diagnostics/diagnostics.ts +1 -2
  144. package/src/packlets/identity/contacts-service.ts +0 -1
  145. package/src/packlets/identity/identity-manager.test.ts +5 -5
  146. package/src/packlets/identity/identity-manager.ts +18 -17
  147. package/src/packlets/identity/identity-recovery-manager.ts +20 -16
  148. package/src/packlets/identity/identity-service.test.ts +6 -27
  149. package/src/packlets/identity/identity-service.ts +13 -81
  150. package/src/packlets/identity/identity.test.ts +2 -2
  151. package/src/packlets/identity/identity.ts +9 -32
  152. package/src/packlets/invitations/device-invitation-protocol.ts +3 -2
  153. package/src/packlets/invitations/edge-invitation-handler.ts +9 -5
  154. package/src/packlets/invitations/invitation-host-extension.ts +7 -10
  155. package/src/packlets/invitations/invitation-protocol.ts +5 -1
  156. package/src/packlets/invitations/invitation-state.ts +1 -15
  157. package/src/packlets/invitations/invitations-handler.test.ts +4 -5
  158. package/src/packlets/invitations/invitations-handler.ts +67 -15
  159. package/src/packlets/invitations/invitations-manager.ts +40 -15
  160. package/src/packlets/invitations/invitations-service.ts +9 -9
  161. package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
  162. package/src/packlets/invitations/space-invitation-protocol.ts +4 -3
  163. package/src/packlets/logging/logging-service.ts +15 -15
  164. package/src/packlets/network/network-service.test.ts +0 -1
  165. package/src/packlets/network/network-service.ts +10 -8
  166. package/src/packlets/services/client-rpc-server.ts +15 -12
  167. package/src/packlets/services/feed-syncer.test.ts +3 -3
  168. package/src/packlets/services/feed-syncer.ts +67 -20
  169. package/src/packlets/services/service-context.test.ts +3 -2
  170. package/src/packlets/services/service-context.ts +51 -43
  171. package/src/packlets/services/service-host.test.ts +8 -8
  172. package/src/packlets/services/service-host.ts +12 -24
  173. package/src/packlets/services/service-registry.test.ts +0 -1
  174. package/src/packlets/space-export/archive-format.ts +42 -0
  175. package/src/packlets/space-export/index.ts +4 -1
  176. package/src/packlets/space-export/serialized-space-reader.ts +111 -0
  177. package/src/packlets/space-export/serialized-space-writer.ts +252 -0
  178. package/src/packlets/space-export/space-archive-reader.ts +64 -3
  179. package/src/packlets/space-export/space-archive-writer.ts +38 -2
  180. package/src/packlets/space-export/space-archive.test.ts +461 -0
  181. package/src/packlets/spaces/data-space-manager.test.ts +79 -13
  182. package/src/packlets/spaces/data-space-manager.ts +80 -115
  183. package/src/packlets/spaces/data-space.ts +55 -31
  184. package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
  185. package/src/packlets/spaces/edge-feed-replicator.ts +9 -7
  186. package/src/packlets/spaces/epoch-migrations.ts +4 -3
  187. package/src/packlets/spaces/genesis.ts +6 -1
  188. package/src/packlets/spaces/notarization-plugin.ts +2 -1
  189. package/src/packlets/spaces/spaces-service.test.ts +18 -11
  190. package/src/packlets/spaces/spaces-service.ts +115 -17
  191. package/src/packlets/testing/invitation-utils.ts +3 -2
  192. package/src/packlets/worker/worker-runtime.ts +39 -6
  193. package/src/packlets/worker/worker-session.ts +4 -10
  194. package/src/version.ts +1 -1
  195. package/dist/lib/browser/chunk-FRMIC6UB.mjs.map +0 -7
  196. package/dist/lib/node-esm/chunk-6ONWVRY5.mjs.map +0 -7
  197. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
  198. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
  199. package/src/packlets/identity/default-space-state-machine.ts +0 -44
  200. /package/dist/lib/browser/{chunk-NQSC7HOE.mjs.map → chunk-XJRPB3GA.mjs.map} +0 -0
  201. /package/dist/lib/node-esm/{chunk-PKEGMOQ4.mjs.map → chunk-2DT3MZRL.mjs.map} +0 -0
@@ -3,7 +3,7 @@
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
8
  import { RpcPeer, type RpcPeerOptions, type ServiceBundle, parseMethodName } from '@dxos/rpc';
9
9
  import { MapCounter, trace } from '@dxos/tracing';
@@ -16,12 +16,14 @@ export type ClientRpcServerProps = {
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
 
@@ -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
  });
@@ -69,9 +69,9 @@ const createEdgeConnection = ({
69
69
  setIdentity: () => {},
70
70
  open: async () => {},
71
71
  close: async () => {},
72
- send: async (routerMessage: RouterMessage) => {
72
+ send: async (ctx, routerMessage: RouterMessage) => {
73
73
  const decoded = cborDecode(routerMessage.payload!.value) as ProtocolMessage;
74
- await syncServer.handleMessage(decoded).pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
74
+ await syncServer.handleMessage(ctx, decoded).pipe(RuntimeProvider.runPromise(serverRuntime.runtimeEffect));
75
75
  },
76
76
  onMessage: (listener: (message: RouterMessage) => void) => {
77
77
  messageListeners.add(listener);
@@ -105,7 +105,7 @@ const createFeedSyncHarness = async ({
105
105
  const syncServer = new SyncServer({
106
106
  peerId: 'server',
107
107
  feedStore: serverFeedStore,
108
- sendMessage: (message) =>
108
+ sendMessage: (_ctx, message) =>
109
109
  Effect.promise(async () => {
110
110
  const routerMessage = createBuf(MessageSchema, {
111
111
  source: {
@@ -8,12 +8,13 @@ import * as Effect from 'effect/Effect';
8
8
  import * as Schema from 'effect/Schema';
9
9
 
10
10
  import { AsyncTask, scheduleTask } from '@dxos/async';
11
- import { Resource } from '@dxos/context';
11
+ import { Context, Resource } from '@dxos/context';
12
12
  import { type EdgeConnection, MessageSchema } from '@dxos/edge-client';
13
13
  import { RuntimeProvider } from '@dxos/effect';
14
14
  import { type FeedStore, SyncClient } from '@dxos/feed';
15
15
  import { invariant } from '@dxos/invariant';
16
16
  import { SpaceId } from '@dxos/keys';
17
+ import { log } from '@dxos/log';
17
18
  import { FeedProtocol } from '@dxos/protocols';
18
19
  import { EdgeService } from '@dxos/protocols';
19
20
  import { createBuf } from '@dxos/protocols/buf';
@@ -113,6 +114,10 @@ export class FeedSyncer extends Resource {
113
114
  if (service !== EdgeService.QUEUE_REPLICATOR) {
114
115
  return;
115
116
  }
117
+ log('feed sync edge ingress', {
118
+ serviceId: msg.serviceId,
119
+ payloadByteLength: msg.payload?.value?.byteLength,
120
+ });
116
121
  const handleMessageEffect = Effect.gen(this, function* () {
117
122
  const decoded = yield* Effect.try({
118
123
  try: () => cborXdecode(msg.payload!.value),
@@ -120,7 +125,17 @@ export class FeedSyncer extends Resource {
120
125
  });
121
126
  const payload = yield* Schema.validate(FeedProtocol.ProtocolMessage)(decoded);
122
127
  yield* this.#syncClient.handleMessage(payload);
123
- });
128
+ }).pipe(
129
+ Effect.tapError((cause) =>
130
+ Effect.sync(() =>
131
+ log('feed sync edge message handling failed', {
132
+ serviceId: msg.serviceId,
133
+ payloadByteLength: msg.payload?.value?.byteLength,
134
+ cause: cause instanceof Error ? cause.message : String(cause),
135
+ }),
136
+ ),
137
+ ),
138
+ );
124
139
 
125
140
  void RuntimeProvider.runPromise(this.#runtime)(handleMessageEffect);
126
141
  }),
@@ -128,7 +143,12 @@ export class FeedSyncer extends Resource {
128
143
 
129
144
  this._ctx.onDispose(
130
145
  // NOTE: This will fire immediately if the connection is already open.
131
- this.#edgeClient.onReconnected(async () => {}),
146
+ this.#edgeClient.onReconnected(async () => {
147
+ log('feed sync edge reconnected', {
148
+ peerKey: this.#edgeClient.peerKey,
149
+ identityKey: this.#edgeClient.identityKey,
150
+ });
151
+ }),
132
152
  );
133
153
 
134
154
  this.#feedStore.onNewBlocks.on(this._ctx, () => {
@@ -176,17 +196,20 @@ export class FeedSyncer extends Resource {
176
196
  /**
177
197
  * Performs queue sync and blocks until there are no pending sync batches.
178
198
  */
179
- async syncBlocking({
180
- spaceId,
181
- subspaceTag,
182
- shouldPush = true,
183
- shouldPull = true,
184
- }: {
185
- spaceId: SpaceId;
186
- subspaceTag: string;
187
- shouldPush?: boolean;
188
- shouldPull?: boolean;
189
- }): Promise<void> {
199
+ async syncBlocking(
200
+ ctx: Context,
201
+ {
202
+ spaceId,
203
+ subspaceTag,
204
+ shouldPush = true,
205
+ shouldPull = true,
206
+ }: {
207
+ spaceId: SpaceId;
208
+ subspaceTag: string;
209
+ shouldPush?: boolean;
210
+ shouldPull?: boolean;
211
+ },
212
+ ): Promise<void> {
190
213
  invariant(SpaceId.isValid(spaceId));
191
214
  invariant(FeedProtocol.isWellKnownNamespace(subspaceTag));
192
215
  if (!shouldPush && !shouldPull) {
@@ -200,7 +223,7 @@ export class FeedSyncer extends Resource {
200
223
  while (!done) {
201
224
  done = true;
202
225
  if (shouldPull) {
203
- const pullResult = yield* this.#syncClient.pull({
226
+ const pullResult = yield* this.#syncClient.pull(ctx, {
204
227
  spaceId,
205
228
  feedNamespace: subspaceTag,
206
229
  limit: this.#messageBlocksLimit,
@@ -209,7 +232,7 @@ export class FeedSyncer extends Resource {
209
232
  }
210
233
 
211
234
  if (shouldPush) {
212
- const pushResult = yield* this.#syncClient.push({
235
+ const pushResult = yield* this.#syncClient.push(ctx, {
213
236
  spaceId,
214
237
  feedNamespace: subspaceTag,
215
238
  limit: this.#messageBlocksLimit,
@@ -233,20 +256,44 @@ export class FeedSyncer extends Resource {
233
256
  this.#lastFullPoll = Date.now();
234
257
  }
235
258
 
236
- #sendMessage(message: FeedProtocol.QueryRequest | FeedProtocol.AppendRequest): Effect.Effect<void, unknown, never> {
259
+ #sendMessage(
260
+ ctx: Context,
261
+ message: FeedProtocol.QueryRequest | FeedProtocol.AppendRequest,
262
+ ): Effect.Effect<void, unknown, never> {
237
263
  return Effect.gen(this, function* () {
238
264
  const encoded = encoder.encode(message);
265
+ const serviceId = this.#getTargetServiceId(message);
266
+ const rpcTag = 'blocks' in message ? 'AppendRequest' : 'QueryRequest';
267
+ log('feed sync edge rpc outgoing', {
268
+ tag: rpcTag,
269
+ serviceId,
270
+ payloadByteLength: encoded.byteLength,
271
+ spaceId: message.spaceId,
272
+ feedNamespace: message.feedNamespace,
273
+ requestId: message.requestId,
274
+ });
239
275
  yield* Effect.tryPromise(async () =>
240
276
  this.#edgeClient.send(
277
+ ctx,
241
278
  createBuf(MessageSchema, {
242
279
  source: {
243
280
  identityKey: this.#edgeClient.identityKey,
244
281
  peerKey: this.#edgeClient.peerKey,
245
282
  },
246
- serviceId: this.#getTargetServiceId(message),
283
+ serviceId,
247
284
  payload: { value: bufferToArray(encoded) },
248
285
  }),
249
286
  ),
287
+ ).pipe(
288
+ Effect.tapError((cause) =>
289
+ Effect.sync(() =>
290
+ log('feed sync edge send failed', {
291
+ serviceId,
292
+ tag: rpcTag,
293
+ cause: cause instanceof Error ? cause.message : String(cause),
294
+ }),
295
+ ),
296
+ ),
250
297
  );
251
298
  });
252
299
  }
@@ -266,7 +313,7 @@ export class FeedSyncer extends Resource {
266
313
  Effect.gen(this, function* () {
267
314
  let doneForAllNamespaces = true;
268
315
  for (const feedNamespace of this.#syncNamespaces) {
269
- const { done } = yield* this.#syncClient.pull({
316
+ const { done } = yield* this.#syncClient.pull(this._ctx, {
270
317
  spaceId,
271
318
  feedNamespace,
272
319
  limit: this.#messageBlocksLimit,
@@ -309,7 +356,7 @@ export class FeedSyncer extends Resource {
309
356
  Effect.gen(this, function* () {
310
357
  let doneForAllNamespaces = true;
311
358
  for (const feedNamespace of this.#syncNamespaces) {
312
- const { done } = yield* this.#syncClient.push({
359
+ const { done } = yield* this.#syncClient.push(this._ctx, {
313
360
  spaceId,
314
361
  feedNamespace,
315
362
  limit: this.#messageBlocksLimit,
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { describe, test } from 'vitest';
6
6
 
7
+ import { Context } from '@dxos/context';
7
8
  import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
8
9
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
9
10
  import { openAndClose } from '@dxos/test-utils';
@@ -19,7 +20,7 @@ describe('services/ServiceContext', () => {
19
20
  const device2 = await createOpenServiceContext(networkContext);
20
21
  await Promise.all(performInvitation({ host: device1, guest: device2, options: { kind: Invitation.Kind.DEVICE } }));
21
22
 
22
- const space1 = await device1.dataSpaceManager!.createSpace();
23
+ const space1 = await device1.dataSpaceManager!.createSpace(new Context());
23
24
  await device2.dataSpaceManager!.waitUntilSpaceReady(space1!.key);
24
25
  const space2 = await device2.dataSpaceManager!.spaces.get(space1.key);
25
26
  await space2!.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.timeframe);
@@ -35,7 +36,7 @@ describe('services/ServiceContext', () => {
35
36
 
36
37
  const identity2 = await createOpenServiceContext(networkContext);
37
38
  await identity2.createIdentity();
38
- const space1 = await identity2.dataSpaceManager!.createSpace();
39
+ const space1 = await identity2.dataSpaceManager!.createSpace(new Context());
39
40
  await Promise.all(
40
41
  performInvitation({
41
42
  host: identity2,
@@ -10,7 +10,9 @@ import { type CredentialProcessor, getCredentialAssertion } from '@dxos/credenti
10
10
  import { failUndefined, warnAfterTimeout } from '@dxos/debug';
11
11
  import {
12
12
  EchoEdgeReplicator,
13
+ EchoEdgeSubductionReplicator,
13
14
  EchoHost,
15
+ type EdgeAutomergeReplicator,
14
16
  MeshEchoReplicator,
15
17
  MetadataStore,
16
18
  SpaceManager,
@@ -22,12 +24,12 @@ import { type RuntimeProvider } from '@dxos/effect';
22
24
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
23
25
  import { invariant } from '@dxos/invariant';
24
26
  import { Keyring } from '@dxos/keyring';
25
- import { PublicKey, type SpaceId } from '@dxos/keys';
27
+ import { type SpaceId } from '@dxos/keys';
26
28
  import { type LevelDB } from '@dxos/kv-store';
27
29
  import { log } from '@dxos/log';
28
30
  import { type SignalManager } from '@dxos/messaging';
29
31
  import { type SwarmNetworkManager } from '@dxos/network-manager';
30
- import { InvalidStorageVersionError, STORAGE_VERSION, trace } from '@dxos/protocols';
32
+ import { InvalidStorageVersionError, STORAGE_VERSION } from '@dxos/protocols';
31
33
  import { FeedProtocol } from '@dxos/protocols';
32
34
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
33
35
  import { type Runtime } from '@dxos/protocols/proto/dxos/config';
@@ -42,6 +44,7 @@ import { safeInstanceof } from '@dxos/util';
42
44
  import { EdgeAgentManager } from '../agents';
43
45
  import {
44
46
  type CreateIdentityOptions,
47
+ type Identity,
45
48
  IdentityManager,
46
49
  type IdentityManagerProps,
47
50
  type JoinIdentityProps,
@@ -56,7 +59,6 @@ import {
56
59
  SpaceInvitationProtocol,
57
60
  } from '../invitations';
58
61
  import { DataSpaceManager, type DataSpaceManagerRuntimeProps, type SigningContext } from '../spaces';
59
-
60
62
  import { FeedSyncer } from './feed-syncer';
61
63
 
62
64
  export type ServiceContextRuntimeProps = Pick<
@@ -74,7 +76,7 @@ export type ServiceContextRuntimeProps = Pick<
74
76
  // TODO(burdon): Rename/break-up into smaller components. And/or make members private.
75
77
  // TODO(dmaretskyi): Gets duplicated in CJS build between normal and testing bundles.
76
78
  @safeInstanceof('dxos.client-services.ServiceContext')
77
- @Trace.resource()
79
+ @Trace.resource({ lifecycle: true })
78
80
  export class ServiceContext extends Resource {
79
81
  private readonly _edgeIdentityUpdateMutex = new Mutex();
80
82
 
@@ -90,7 +92,7 @@ export class ServiceContext extends Resource {
90
92
  public readonly invitationsManager: InvitationsManager;
91
93
  public readonly echoHost: EchoHost;
92
94
  private readonly _meshReplicator?: MeshEchoReplicator = undefined;
93
- private readonly _echoEdgeReplicator?: EchoEdgeReplicator = undefined;
95
+ private readonly _echoEdgeReplicator?: EdgeAutomergeReplicator = undefined;
94
96
  private readonly _feedSyncer?: FeedSyncer = undefined;
95
97
 
96
98
  // Initialized after identity is initialized.
@@ -104,8 +106,6 @@ export class ServiceContext extends Resource {
104
106
 
105
107
  private _deviceSpaceSync?: CredentialProcessor;
106
108
 
107
- private readonly _instanceId = PublicKey.random().toHex();
108
-
109
109
  constructor(
110
110
  public readonly storage: Storage,
111
111
  public readonly level: LevelDB,
@@ -169,8 +169,9 @@ export class ServiceContext extends Resource {
169
169
  peerIdProvider: () => this.identityManager.identity?.deviceKey?.toHex(),
170
170
  getSpaceKeyByRootDocumentId: (documentId) => this.spaceManager.findSpaceByRootDocumentId(documentId)?.key,
171
171
  runtime: this._runtime,
172
- syncQueue: async (request) => {
173
- return this._feedSyncer?.syncBlocking({
172
+ useSubduction: this._edgeFeatures?.subductionReplicator,
173
+ syncQueue: async (ctx, request) => {
174
+ return this._feedSyncer?.syncBlocking(ctx, {
174
175
  spaceId: request.spaceId as SpaceId,
175
176
  subspaceTag: request.subspaceTag,
176
177
  shouldPush: request.shouldPush,
@@ -205,11 +206,18 @@ export class ServiceContext extends Resource {
205
206
  if (!this._runtimeProps?.disableP2pReplication) {
206
207
  this._meshReplicator = new MeshEchoReplicator();
207
208
  }
208
- if (this._edgeConnection && this._edgeFeatures?.echoReplicator && this._edgeHttpClient) {
209
- this._echoEdgeReplicator = new EchoEdgeReplicator({
210
- edgeConnection: this._edgeConnection,
211
- edgeHttpClient: this._edgeHttpClient,
212
- });
209
+ if (this._edgeConnection && this._edgeHttpClient) {
210
+ if (this._edgeFeatures?.subductionReplicator) {
211
+ this._echoEdgeReplicator = new EchoEdgeSubductionReplicator({
212
+ edgeConnection: this._edgeConnection,
213
+ edgeHttpClient: this._edgeHttpClient,
214
+ });
215
+ } else if (this._edgeFeatures?.echoReplicator) {
216
+ this._echoEdgeReplicator = new EchoEdgeReplicator({
217
+ edgeConnection: this._edgeConnection,
218
+ edgeHttpClient: this._edgeHttpClient,
219
+ });
220
+ }
213
221
  }
214
222
 
215
223
  if (this.echoHost.feedStore && this._edgeConnection) {
@@ -224,27 +232,26 @@ export class ServiceContext extends Resource {
224
232
  }
225
233
  }
226
234
 
227
- @Trace.span()
235
+ @Trace.span({ op: 'lifecycle' })
228
236
  protected override async _open(ctx: Context): Promise<void> {
229
237
  await this._checkStorageVersion();
230
238
 
231
239
  log('opening...');
232
- log.trace('dxos.sdk.service-context.open', trace.begin({ id: this._instanceId }));
233
240
 
234
241
  log('opening identityManager...');
235
242
  await this.identityManager.open(ctx);
236
243
  log('identityManager opened', { hasIdentity: !!this.identityManager.identity });
237
244
 
238
245
  log('setting network identity...');
239
- await this._setNetworkIdentity();
246
+ await this._setNetworkIdentity({ identity: this.identityManager.identity });
240
247
  log('network identity set');
241
248
 
242
249
  log('opening edge connection...');
243
- await this._edgeConnection?.open();
250
+ await this._edgeConnection?.open(ctx);
244
251
  log('edge connection opened');
245
252
 
246
253
  log('opening signal manager...');
247
- await this.signalManager.open();
254
+ await this.signalManager.open(ctx);
248
255
  log('signal manager opened');
249
256
 
250
257
  log('opening network manager...');
@@ -257,12 +264,12 @@ export class ServiceContext extends Resource {
257
264
 
258
265
  if (this._meshReplicator) {
259
266
  log('adding mesh replicator...');
260
- await this.echoHost.addReplicator(this._meshReplicator);
267
+ await this.echoHost.addReplicator(ctx, this._meshReplicator);
261
268
  log('mesh replicator added');
262
269
  }
263
270
  if (this._echoEdgeReplicator) {
264
271
  log('adding edge replicator...');
265
- await this.echoHost.addReplicator(this._echoEdgeReplicator);
272
+ await this.echoHost.addReplicator(ctx, this._echoEdgeReplicator);
266
273
  log('edge replicator added');
267
274
  }
268
275
 
@@ -276,7 +283,7 @@ export class ServiceContext extends Resource {
276
283
 
277
284
  if (this.identityManager.identity) {
278
285
  log('joining network...');
279
- await this.identityManager.identity.joinNetwork();
286
+ await this.identityManager.identity.joinNetwork(ctx);
280
287
  log('network joined');
281
288
 
282
289
  log('initializing spaces...(calling _initialize)');
@@ -287,14 +294,13 @@ export class ServiceContext extends Resource {
287
294
  }
288
295
 
289
296
  log('opening feed syncer...');
290
- await this._feedSyncer?.open();
297
+ await this._feedSyncer?.open(ctx);
291
298
  log('feed syncer opened');
292
299
 
293
300
  log('loading persistent invitations...');
294
- const loadedInvitations = await this.invitationsManager.loadPersistentInvitations();
301
+ const loadedInvitations = await this.invitationsManager.loadPersistentInvitations(ctx);
295
302
  log('loaded persistent invitations', { count: loadedInvitations.invitations?.length });
296
303
 
297
- log.trace('dxos.sdk.service-context.open', trace.end({ id: this._instanceId }));
298
304
  log('opened');
299
305
  }
300
306
 
@@ -306,13 +312,13 @@ export class ServiceContext extends Resource {
306
312
  if (this._deviceSpaceSync && this.identityManager.identity) {
307
313
  await this.identityManager.identity.space.spaceState.removeCredentialProcessor(this._deviceSpaceSync);
308
314
  }
309
- await this.dataSpaceManager?.close();
315
+ await this.dataSpaceManager?.close(ctx);
310
316
  await this.edgeAgentManager?.close();
311
- await this.identityManager.close();
317
+ await this.identityManager.close(ctx);
312
318
  await this.spaceManager.close();
313
319
  await this.echoHost.close(ctx);
314
320
 
315
- await this.networkManager.close();
321
+ await this.networkManager.close(ctx);
316
322
  await this.signalManager.close();
317
323
  await this._edgeConnection?.close();
318
324
  await this.feedStore.close();
@@ -321,11 +327,12 @@ export class ServiceContext extends Resource {
321
327
  log('closed');
322
328
  }
323
329
 
324
- async createIdentity(params: CreateIdentityOptions = {}) {
325
- const identity = await this.identityManager.createIdentity(params);
326
- await this._setNetworkIdentity();
327
- await identity.joinNetwork();
328
- await this._initialize(new Context());
330
+ async createIdentity(params: CreateIdentityOptions = {}, ctx?: Context) {
331
+ ctx ??= this._ctx;
332
+ const identity = await this.identityManager.createIdentity(params, ctx);
333
+ await this._setNetworkIdentity({ identity });
334
+ await identity.joinNetwork(ctx);
335
+ await this._initialize(ctx);
329
336
  return identity;
330
337
  }
331
338
 
@@ -349,11 +356,11 @@ export class ServiceContext extends Resource {
349
356
  }
350
357
 
351
358
  private async _acceptIdentity(params: JoinIdentityProps) {
352
- const { identity, identityRecord } = await this.identityManager.prepareIdentity(params);
353
- await this._setNetworkIdentity({ deviceCredential: params.authorizedDeviceCredential! });
354
- await identity.joinNetwork();
359
+ const { identity, identityRecord } = await this.identityManager.prepareIdentity(params, this._ctx);
360
+ await this._setNetworkIdentity({ deviceCredential: params.authorizedDeviceCredential!, identity });
361
+ await identity.joinNetwork(this._ctx);
355
362
  await this.identityManager.acceptIdentity(identity, identityRecord, params.deviceProfile);
356
- await this._initialize(new Context());
363
+ await this._initialize(this._ctx);
357
364
  return identity;
358
365
  }
359
366
 
@@ -397,7 +404,7 @@ export class ServiceContext extends Resource {
397
404
  edgeFeatures: this._edgeFeatures,
398
405
  });
399
406
  log('_initialize: opening DataSpaceManager...');
400
- await this.dataSpaceManager.open();
407
+ await this.dataSpaceManager.open(ctx);
401
408
  log('_initialize: DataSpaceManager opened');
402
409
 
403
410
  this.edgeAgentManager = new EdgeAgentManager(
@@ -407,7 +414,7 @@ export class ServiceContext extends Resource {
407
414
  identity,
408
415
  );
409
416
  log('_initialize: opening EdgeAgentManager...');
410
- await this.edgeAgentManager.open();
417
+ await this.edgeAgentManager.open(ctx);
411
418
  log('_initialize: EdgeAgentManager opened');
412
419
 
413
420
  this._handlerFactories.set(Invitation.Kind.SPACE, (invitation) => {
@@ -438,9 +445,10 @@ export class ServiceContext extends Resource {
438
445
 
439
446
  try {
440
447
  log('accepting space recorded in halo', { details: assertion });
441
- await this.dataSpaceManager.acceptSpace({
448
+ await this.dataSpaceManager.acceptSpace(this._ctx, {
442
449
  spaceKey: assertion.spaceKey,
443
450
  genesisFeedKey: assertion.genesisFeedKey,
451
+ tags: assertion.tags,
444
452
  });
445
453
  } catch (err) {
446
454
  log.catch(err);
@@ -451,13 +459,13 @@ export class ServiceContext extends Resource {
451
459
  await identity.space.spaceState.addCredentialProcessor(this._deviceSpaceSync);
452
460
  }
453
461
 
454
- private async _setNetworkIdentity(params?: { deviceCredential: Credential }): Promise<void> {
462
+ private async _setNetworkIdentity(params?: { deviceCredential?: Credential; identity?: Identity }): Promise<void> {
455
463
  log('_setNetworkIdentity: acquiring mutex...');
456
464
  using _ = await this._edgeIdentityUpdateMutex.acquire();
457
465
  log('_setNetworkIdentity: mutex acquired');
458
466
 
459
467
  let edgeIdentity: EdgeIdentity;
460
- const identity = this.identityManager.identity;
468
+ const identity = params?.identity;
461
469
  if (identity) {
462
470
  log('_setNetworkIdentity: has identity', {
463
471
  identity: identity.identityKey.toHex(),
@@ -470,7 +478,7 @@ export class ServiceContext extends Resource {
470
478
  identity.signer,
471
479
  identity.identityKey,
472
480
  identity.deviceKey,
473
- params?.deviceCredential && { credential: params.deviceCredential },
481
+ { credential: params.deviceCredential },
474
482
  [], // TODO(dmaretskyi): Service access credentials.
475
483
  );
476
484
  log('_setNetworkIdentity: chain edge identity created');
@@ -3,7 +3,6 @@
3
3
  //
4
4
 
5
5
  import { rmSync } from 'node:fs';
6
-
7
6
  import { afterEach, describe, expect, onTestFinished, test } from 'vitest';
8
7
 
9
8
  import { Trigger, asyncTimeout, latch } from '@dxos/async';
@@ -13,6 +12,7 @@ import { verifyPresentation } from '@dxos/credentials';
13
12
  import { type PublicKey } from '@dxos/keys';
14
13
  import { MemorySignalManagerContext } from '@dxos/messaging';
15
14
  import { type Identity } from '@dxos/protocols/proto/dxos/client/services';
15
+ import { MembershipPolicy } from '@dxos/protocols/proto/dxos/halo/credentials';
16
16
  import { type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
17
17
  import { isNode } from '@dxos/util';
18
18
 
@@ -29,16 +29,16 @@ describe('ClientServicesHost', () => {
29
29
  test('open and close', async () => {
30
30
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
31
31
  await host.open(new Context());
32
- await host.close();
32
+ await host.close(Context.default());
33
33
  });
34
34
 
35
35
  test('queryCredentials', async () => {
36
36
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
37
37
  await host.open(new Context());
38
- onTestFinished(() => host.close());
38
+ onTestFinished(() => host.close(Context.default()));
39
39
 
40
40
  await host.services.IdentityService!.createIdentity({});
41
- const { spaceKey } = await host.services.SpacesService!.createSpace();
41
+ const { spaceKey } = await host.services.SpacesService!.createSpace({ membershipPolicy: MembershipPolicy.INVITE });
42
42
 
43
43
  const stream = host.services.SpacesService!.queryCredentials({ spaceKey });
44
44
  const [done, tick] = latch({ count: 3 });
@@ -54,7 +54,7 @@ describe('ClientServicesHost', () => {
54
54
  test('write and query credentials', async () => {
55
55
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
56
56
  await host.open(new Context());
57
- onTestFinished(() => host.close());
57
+ onTestFinished(() => host.close(Context.default()));
58
58
 
59
59
  await host.services.IdentityService!.createIdentity({});
60
60
 
@@ -91,7 +91,7 @@ describe('ClientServicesHost', () => {
91
91
  test('sign presentation', async () => {
92
92
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
93
93
  await host.open(new Context());
94
- onTestFinished(() => host.close());
94
+ onTestFinished(() => host.close(Context.default()));
95
95
 
96
96
  await host.services.IdentityService!.createIdentity({});
97
97
 
@@ -128,7 +128,7 @@ describe('ClientServicesHost', () => {
128
128
  expect(host.context.storage.size).to.exist;
129
129
 
130
130
  await asyncTimeout(host.reset(), 1000);
131
- await host.close();
131
+ await host.close(Context.default());
132
132
  }
133
133
 
134
134
  {
@@ -146,7 +146,7 @@ describe('ClientServicesHost', () => {
146
146
  });
147
147
  await expect(asyncTimeout(trigger.wait(), 200)).rejects.toBeInstanceOf(Error);
148
148
  await stream?.close();
149
- await host.close();
149
+ await host.close(Context.default());
150
150
  }
151
151
  });
152
152
  });