@dxos/client-services 0.8.4-main.c85a9c8dae → 0.8.4-main.d05539e30a

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-MQ6PWJ76.mjs → chunk-NGONP3EI.mjs} +1640 -3097
  4. package/dist/lib/browser/chunk-NGONP3EI.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-GUAL4U7S.mjs → chunk-OAECSUV2.mjs} +1640 -3097
  20. package/dist/lib/node-esm/chunk-OAECSUV2.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 +106 -46
  171. package/src/packlets/services/service-host.test.ts +8 -8
  172. package/src/packlets/services/service-host.ts +17 -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-MQ6PWJ76.mjs.map +0 -7
  196. package/dist/lib/node-esm/chunk-GUAL4U7S.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,44 +232,75 @@ 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
 
241
+ log('opening identityManager...');
234
242
  await this.identityManager.open(ctx);
243
+ log('identityManager opened', { hasIdentity: !!this.identityManager.identity });
235
244
 
236
- await this._setNetworkIdentity();
245
+ log('setting network identity...');
246
+ await this._setNetworkIdentity({ identity: this.identityManager.identity });
247
+ log('network identity set');
237
248
 
238
- await this._edgeConnection?.open();
239
- await this.signalManager.open();
249
+ log('opening edge connection...');
250
+ await this._edgeConnection?.open(ctx);
251
+ log('edge connection opened');
252
+
253
+ log('opening signal manager...');
254
+ await this.signalManager.open(ctx);
255
+ log('signal manager opened');
256
+
257
+ log('opening network manager...');
240
258
  await this.networkManager.open();
259
+ log('network manager opened');
241
260
 
261
+ log('opening echo host...');
242
262
  await this.echoHost.open(ctx);
263
+ log('echo host opened');
243
264
 
244
265
  if (this._meshReplicator) {
245
- await this.echoHost.addReplicator(this._meshReplicator);
266
+ log('adding mesh replicator...');
267
+ await this.echoHost.addReplicator(ctx, this._meshReplicator);
268
+ log('mesh replicator added');
246
269
  }
247
270
  if (this._echoEdgeReplicator) {
248
- await this.echoHost.addReplicator(this._echoEdgeReplicator);
271
+ log('adding edge replicator...');
272
+ await this.echoHost.addReplicator(ctx, this._echoEdgeReplicator);
273
+ log('edge replicator added');
249
274
  }
250
275
 
276
+ log('loading metadata store...');
251
277
  await this.metadataStore.load();
278
+ log('metadata store loaded');
279
+
280
+ log('opening space manager...');
252
281
  await this.spaceManager.open();
282
+ log('space manager opened');
253
283
 
254
284
  if (this.identityManager.identity) {
255
- await this.identityManager.identity.joinNetwork();
285
+ log('joining network...');
286
+ await this.identityManager.identity.joinNetwork(ctx);
287
+ log('network joined');
288
+
289
+ log('initializing spaces...(calling _initialize)');
256
290
  await this._initialize(ctx);
291
+ log('spaces initialized');
292
+ } else {
293
+ log('no identity, skipping network join and space initialization');
257
294
  }
258
295
 
259
- await this._feedSyncer?.open();
296
+ log('opening feed syncer...');
297
+ await this._feedSyncer?.open(ctx);
298
+ log('feed syncer opened');
260
299
 
261
- const loadedInvitations = await this.invitationsManager.loadPersistentInvitations();
300
+ log('loading persistent invitations...');
301
+ const loadedInvitations = await this.invitationsManager.loadPersistentInvitations(ctx);
262
302
  log('loaded persistent invitations', { count: loadedInvitations.invitations?.length });
263
303
 
264
- log.trace('dxos.sdk.service-context.open', trace.end({ id: this._instanceId }));
265
304
  log('opened');
266
305
  }
267
306
 
@@ -273,13 +312,13 @@ export class ServiceContext extends Resource {
273
312
  if (this._deviceSpaceSync && this.identityManager.identity) {
274
313
  await this.identityManager.identity.space.spaceState.removeCredentialProcessor(this._deviceSpaceSync);
275
314
  }
276
- await this.dataSpaceManager?.close();
315
+ await this.dataSpaceManager?.close(ctx);
277
316
  await this.edgeAgentManager?.close();
278
- await this.identityManager.close();
317
+ await this.identityManager.close(ctx);
279
318
  await this.spaceManager.close();
280
319
  await this.echoHost.close(ctx);
281
320
 
282
- await this.networkManager.close();
321
+ await this.networkManager.close(ctx);
283
322
  await this.signalManager.close();
284
323
  await this._edgeConnection?.close();
285
324
  await this.feedStore.close();
@@ -288,11 +327,12 @@ export class ServiceContext extends Resource {
288
327
  log('closed');
289
328
  }
290
329
 
291
- async createIdentity(params: CreateIdentityOptions = {}) {
292
- const identity = await this.identityManager.createIdentity(params);
293
- await this._setNetworkIdentity();
294
- await identity.joinNetwork();
295
- 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);
296
336
  return identity;
297
337
  }
298
338
 
@@ -316,11 +356,11 @@ export class ServiceContext extends Resource {
316
356
  }
317
357
 
318
358
  private async _acceptIdentity(params: JoinIdentityProps) {
319
- const { identity, identityRecord } = await this.identityManager.prepareIdentity(params);
320
- await this._setNetworkIdentity({ deviceCredential: params.authorizedDeviceCredential! });
321
- 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);
322
362
  await this.identityManager.acceptIdentity(identity, identityRecord, params.deviceProfile);
323
- await this._initialize(new Context());
363
+ await this._initialize(this._ctx);
324
364
  return identity;
325
365
  }
326
366
 
@@ -335,7 +375,7 @@ export class ServiceContext extends Resource {
335
375
  // Called when identity is created.
336
376
  @Trace.span()
337
377
  private async _initialize(ctx: Context): Promise<void> {
338
- log('initializing spaces...');
378
+ log('_initialize: start');
339
379
  const identity = this.identityManager.identity ?? failUndefined();
340
380
  const signingContext: SigningContext = {
341
381
  credentialSigner: identity.getIdentityCredentialSigner(),
@@ -347,6 +387,7 @@ export class ServiceContext extends Resource {
347
387
  },
348
388
  };
349
389
 
390
+ log('_initialize: creating DataSpaceManager');
350
391
  this.dataSpaceManager = new DataSpaceManager({
351
392
  spaceManager: this.spaceManager,
352
393
  metadataStore: this.metadataStore,
@@ -362,7 +403,9 @@ export class ServiceContext extends Resource {
362
403
  runtimeProps: this._runtimeProps as DataSpaceManagerRuntimeProps,
363
404
  edgeFeatures: this._edgeFeatures,
364
405
  });
365
- await this.dataSpaceManager.open();
406
+ log('_initialize: opening DataSpaceManager...');
407
+ await this.dataSpaceManager.open(ctx);
408
+ log('_initialize: DataSpaceManager opened');
366
409
 
367
410
  this.edgeAgentManager = new EdgeAgentManager(
368
411
  this._edgeFeatures,
@@ -370,13 +413,16 @@ export class ServiceContext extends Resource {
370
413
  this.dataSpaceManager,
371
414
  identity,
372
415
  );
373
- await this.edgeAgentManager.open();
416
+ log('_initialize: opening EdgeAgentManager...');
417
+ await this.edgeAgentManager.open(ctx);
418
+ log('_initialize: EdgeAgentManager opened');
374
419
 
375
420
  this._handlerFactories.set(Invitation.Kind.SPACE, (invitation) => {
376
421
  invariant(this.dataSpaceManager, 'dataSpaceManager not initialized yet');
377
422
  return new SpaceInvitationProtocol(this.dataSpaceManager, signingContext, this.keyring, invitation.spaceKey);
378
423
  });
379
424
  this.initialized.wake();
425
+ log('_initialize: initialized.wake() called');
380
426
 
381
427
  this._deviceSpaceSync = {
382
428
  processCredential: async (credential: Credential) => {
@@ -399,9 +445,10 @@ export class ServiceContext extends Resource {
399
445
 
400
446
  try {
401
447
  log('accepting space recorded in halo', { details: assertion });
402
- await this.dataSpaceManager.acceptSpace({
448
+ await this.dataSpaceManager.acceptSpace(this._ctx, {
403
449
  spaceKey: assertion.spaceKey,
404
450
  genesisFeedKey: assertion.genesisFeedKey,
451
+ tags: assertion.tags,
405
452
  });
406
453
  } catch (err) {
407
454
  log.catch(err);
@@ -412,33 +459,42 @@ export class ServiceContext extends Resource {
412
459
  await identity.space.spaceState.addCredentialProcessor(this._deviceSpaceSync);
413
460
  }
414
461
 
415
- private async _setNetworkIdentity(params?: { deviceCredential: Credential }): Promise<void> {
462
+ private async _setNetworkIdentity(params?: { deviceCredential?: Credential; identity?: Identity }): Promise<void> {
463
+ log('_setNetworkIdentity: acquiring mutex...');
416
464
  using _ = await this._edgeIdentityUpdateMutex.acquire();
465
+ log('_setNetworkIdentity: mutex acquired');
417
466
 
418
467
  let edgeIdentity: EdgeIdentity;
419
- const identity = this.identityManager.identity;
468
+ const identity = params?.identity;
420
469
  if (identity) {
421
- log('setting identity on edge connection', {
470
+ log('_setNetworkIdentity: has identity', {
422
471
  identity: identity.identityKey.toHex(),
423
- swarms: this.networkManager.topics,
472
+ hasDeviceCredential: !!params?.deviceCredential,
424
473
  });
425
474
 
426
475
  if (params?.deviceCredential) {
476
+ log('_setNetworkIdentity: creating chain edge identity with device credential...');
427
477
  edgeIdentity = await createChainEdgeIdentity(
428
478
  identity.signer,
429
479
  identity.identityKey,
430
480
  identity.deviceKey,
431
- params?.deviceCredential && { credential: params.deviceCredential },
481
+ { credential: params.deviceCredential },
432
482
  [], // TODO(dmaretskyi): Service access credentials.
433
483
  );
484
+ log('_setNetworkIdentity: chain edge identity created');
434
485
  } else {
486
+ log('_setNetworkIdentity: waiting for identity.ready()...');
435
487
  // TODO: throw here or from identity if device chain can't be loaded, to avoid indefinite hangup
436
488
  await warnAfterTimeout(10_000, 'Waiting for identity to be ready for edge connection', async () => {
437
489
  await identity.ready();
438
490
  });
491
+ log('_setNetworkIdentity: identity.ready() resolved', {
492
+ hasDeviceCredentialChain: !!identity.deviceCredentialChain,
493
+ });
439
494
 
440
495
  invariant(identity.deviceCredentialChain);
441
496
 
497
+ log('_setNetworkIdentity: creating chain edge identity...');
442
498
  edgeIdentity = await createChainEdgeIdentity(
443
499
  identity.signer,
444
500
  identity.identityKey,
@@ -446,9 +502,12 @@ export class ServiceContext extends Resource {
446
502
  identity.deviceCredentialChain,
447
503
  [], // TODO(dmaretskyi): Service access credentials.
448
504
  );
505
+ log('_setNetworkIdentity: chain edge identity created');
449
506
  }
450
507
  } else {
508
+ log('_setNetworkIdentity: no identity, creating ephemeral edge identity...');
451
509
  edgeIdentity = await createEphemeralEdgeIdentity();
510
+ log('_setNetworkIdentity: ephemeral edge identity created');
452
511
  }
453
512
 
454
513
  this._edgeConnection?.setIdentity(edgeIdentity);
@@ -457,5 +516,6 @@ export class ServiceContext extends Resource {
457
516
  identityKey: edgeIdentity.identityKey,
458
517
  peerKey: edgeIdentity.peerKey,
459
518
  });
519
+ log('_setNetworkIdentity: done');
460
520
  }
461
521
  }