@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,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { type PushStream, scheduleTask, TimeoutError, type Trigger } from '@dxos/async';
5
+ import { type PushStream, TimeoutError, type Trigger, scheduleTask } from '@dxos/async';
6
6
  import { INVITATION_TIMEOUT, getExpirationTime } from '@dxos/client-protocol';
7
7
  import { type Context, ContextDisposedError } from '@dxos/context';
8
8
  import { createKeyPair, sign } from '@dxos/crypto';
@@ -10,19 +10,19 @@ import { type EdgeHttpClient } from '@dxos/edge-client';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { PublicKey } from '@dxos/keys';
12
12
  import { log } from '@dxos/log';
13
- import { createTeleportProtocolFactory, type SwarmNetworkManager, type SwarmConnection } from '@dxos/network-manager';
13
+ import { type SwarmConnection, type SwarmNetworkManager, createTeleportProtocolFactory } from '@dxos/network-manager';
14
14
  import { InvalidInvitationError, InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
15
15
  import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
16
16
  import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
17
17
  import { AuthenticationResponse, type IntroductionResponse } from '@dxos/protocols/proto/dxos/halo/invitations';
18
18
  import { InvitationOptions } from '@dxos/protocols/proto/dxos/halo/invitations';
19
- import { type ExtensionContext, type TeleportExtension, type TeleportParams } from '@dxos/teleport';
19
+ import { type ExtensionContext, type TeleportExtension, type TeleportProps } from '@dxos/teleport';
20
20
  import { trace as _trace } from '@dxos/tracing';
21
21
  import { ComplexSet } from '@dxos/util';
22
22
 
23
23
  import { type EdgeInvitationConfig, EdgeInvitationHandler } from './edge-invitation-handler';
24
24
  import { InvitationGuestExtension } from './invitation-guest-extenstion';
25
- import { InvitationHostExtension, isAuthenticationRequired, MAX_OTP_ATTEMPTS } from './invitation-host-extension';
25
+ import { InvitationHostExtension, MAX_OTP_ATTEMPTS, isAuthenticationRequired } from './invitation-host-extension';
26
26
  import { type InvitationProtocol } from './invitation-protocol';
27
27
  import { createGuardedInvitationState } from './invitation-state';
28
28
  import { InvitationTopology } from './invitation-topology';
@@ -31,8 +31,8 @@ const metrics = _trace.metrics;
31
31
 
32
32
  const MAX_DELEGATED_INVITATION_HOST_TRIES = 3;
33
33
 
34
- export type InvitationConnectionParams = {
35
- teleport: Partial<TeleportParams>;
34
+ export type InvitationConnectionProps = {
35
+ teleport: Partial<TeleportProps>;
36
36
  edgeInvitations?: EdgeInvitationConfig;
37
37
  };
38
38
 
@@ -64,6 +64,7 @@ export type InvitationConnectionParams = {
64
64
  * TODO: the flow logic should either be contained in invitations-handler or in extensions, not be split across
65
65
  * TODO: potentially re-evaluate host-side API to allow multiple concurrent connection, so that mutex can be removed
66
66
  */
67
+ @_trace.resource()
67
68
  export class InvitationsHandler {
68
69
  /**
69
70
  * @internal
@@ -71,7 +72,7 @@ export class InvitationsHandler {
71
72
  constructor(
72
73
  private readonly _networkManager: SwarmNetworkManager,
73
74
  private readonly _edgeClient?: EdgeHttpClient,
74
- private readonly _connectionParams?: InvitationConnectionParams,
75
+ private readonly _connectionProps?: InvitationConnectionProps,
75
76
  ) {}
76
77
 
77
78
  handleInvitationFlow(
@@ -87,6 +88,33 @@ export class InvitationsHandler {
87
88
  type: invitation.type,
88
89
  });
89
90
  metrics.increment('dxos.invitation.host');
91
+
92
+ const hostSpanId = `invitation-host-${invitation.invitationId}`;
93
+ // Reassign ctx to the child context so downstream `@trace.span` calls stay in the same trace.
94
+ // Link child -> parent disposal so `ctx.dispose()` inside this flow still completes the
95
+ // invitation stream (the caller's ctx owns `stream.complete()` via onDispose).
96
+ // Do NOT await `invitationCtx.dispose()` here: `derive()` registers a parent -> child
97
+ // dispose hook, so awaiting the parent dispose would re-enter the still-pending child
98
+ // dispose promise and deadlock.
99
+ const invitationCtx = ctx;
100
+ ctx =
101
+ _trace.spanStart({
102
+ id: hostSpanId,
103
+ instance: this,
104
+ methodName: 'handleInvitationFlow',
105
+ parentCtx: ctx,
106
+ op: 'invitation.host',
107
+ attributes: {
108
+ 'ctx.dxos.invitation.id': invitation.invitationId,
109
+ 'ctx.dxos.invitation.kind': Invitation.Kind[invitation.kind],
110
+ },
111
+ }) ?? ctx;
112
+ if (ctx !== invitationCtx) {
113
+ ctx.onDispose(() => {
114
+ void invitationCtx.dispose();
115
+ });
116
+ }
117
+ ctx.onDispose(() => _trace.spanEnd(hostSpanId));
90
118
  const guardedState = createGuardedInvitationState(ctx, invitation, stream);
91
119
  // Called for every connecting peer.
92
120
  const createExtension = (): InvitationHostExtension => {
@@ -200,7 +228,7 @@ export class InvitationsHandler {
200
228
  ctx,
201
229
  async () => {
202
230
  // ensure the swarm is closed before changing state and closing the stream.
203
- await swarmConnection.close();
231
+ await swarmConnection.close(ctx);
204
232
  guardedState.set(null, Invitation.State.EXPIRED);
205
233
  metrics.increment('dxos.invitation.expired');
206
234
  await ctx.dispose();
@@ -232,6 +260,34 @@ export class InvitationsHandler {
232
260
  });
233
261
  const { timeout = INVITATION_TIMEOUT } = invitation;
234
262
 
263
+ const guestSpanId = `invitation-guest-${invitation.invitationId}`;
264
+ // Reassign ctx to the child context returned by spanStart so downstream calls
265
+ // (`edgeInvitationHandler.handle`, `_joinSwarm`, etc.) inherit this span as their
266
+ // parent rather than starting a new root trace.
267
+ // Link child -> parent disposal so `ctx.dispose()` inside this flow still completes the
268
+ // invitation stream. See note in `handleInvitationFlow`: must not await the parent
269
+ // dispose here (`derive()` registers a parent -> child dispose hook, so awaiting would
270
+ // re-enter the still-pending child dispose promise and deadlock).
271
+ const invitationCtx = ctx;
272
+ ctx =
273
+ _trace.spanStart({
274
+ id: guestSpanId,
275
+ instance: this,
276
+ methodName: 'acceptInvitation',
277
+ parentCtx: ctx,
278
+ op: 'invitation.guest',
279
+ attributes: {
280
+ 'ctx.dxos.invitation.id': invitation.invitationId,
281
+ 'ctx.dxos.invitation.kind': Invitation.Kind[invitation.kind],
282
+ },
283
+ }) ?? ctx;
284
+ if (ctx !== invitationCtx) {
285
+ ctx.onDispose(() => {
286
+ void invitationCtx.dispose();
287
+ });
288
+ }
289
+ ctx.onDispose(() => _trace.spanEnd(guestSpanId));
290
+
235
291
  if (deviceProfile) {
236
292
  invariant(invitation.kind === Invitation.Kind.DEVICE, 'deviceProfile provided for non-device invitation');
237
293
  }
@@ -345,7 +401,7 @@ export class InvitationsHandler {
345
401
  admitted = true;
346
402
 
347
403
  // 4. Record credential in our HALO.
348
- const result = await protocol.accept(admissionResponse, admissionRequest);
404
+ const result = await protocol.accept(ctx, admissionResponse, admissionRequest);
349
405
 
350
406
  // 5. Success.
351
407
  log.verbose('dxos.sdk.invitations-handler.guest.admitted-by-host', {
@@ -388,9 +444,9 @@ export class InvitationsHandler {
388
444
  return extension;
389
445
  };
390
446
 
391
- const edgeInvitationHandler = new EdgeInvitationHandler(this._connectionParams?.edgeInvitations, this._edgeClient, {
392
- onInvitationSuccess: async (admissionResponse, admissionRequest) => {
393
- const result = await protocol.accept(admissionResponse, admissionRequest);
447
+ const edgeInvitationHandler = new EdgeInvitationHandler(this._connectionProps?.edgeInvitations, this._edgeClient, {
448
+ onInvitationSuccess: async (edgeCtx, admissionResponse, admissionRequest) => {
449
+ const result = await protocol.accept(edgeCtx, admissionResponse, admissionRequest);
394
450
  log.info('admitted by edge', { ...protocol.toJSON() });
395
451
  guardedState.complete({ ...guardedState.current, ...result, state: Invitation.State.SUCCESS });
396
452
  },
@@ -436,15 +492,15 @@ export class InvitationsHandler {
436
492
  } else {
437
493
  label = `invitation host for space ${invitation.spaceKey?.truncate()}`;
438
494
  }
439
- const swarmConnection = await this._networkManager.joinSwarm({
495
+ const swarmConnection = await this._networkManager.joinSwarm(ctx, {
440
496
  topic: invitation.swarmKey,
441
497
  protocolProvider: createTeleportProtocolFactory(async (teleport) => {
442
498
  teleport.addExtension('dxos.halo.invitations', extensionFactory());
443
- }, this._connectionParams?.teleport),
499
+ }, this._connectionProps?.teleport),
444
500
  topology: new InvitationTopology(role),
445
501
  label,
446
502
  });
447
- ctx.onDispose(() => swarmConnection.close());
503
+ ctx.onDispose(() => swarmConnection.close(ctx));
448
504
  return swarmConnection;
449
505
  }
450
506
 
@@ -503,7 +559,7 @@ export class InvitationsHandler {
503
559
  const checkInvitation = (protocol: InvitationProtocol, invitation: Partial<Invitation>) => {
504
560
  const expiresOn = getExpirationTime(invitation);
505
561
  if (expiresOn && expiresOn.getTime() < Date.now()) {
506
- return new InvalidInvitationError('Invitation already expired.');
562
+ return new InvalidInvitationError({ message: 'Invitation already expired.' });
507
563
  }
508
564
  return protocol.checkInvitation(invitation);
509
565
  };
@@ -4,14 +4,14 @@
4
4
 
5
5
  import { Event, PushStream, TimeoutError, Trigger } from '@dxos/async';
6
6
  import {
7
- AuthenticatingInvitation,
8
7
  AUTHENTICATION_CODE_LENGTH,
8
+ AuthenticatingInvitation,
9
9
  CancellableInvitation,
10
10
  INVITATION_TIMEOUT,
11
11
  } from '@dxos/client-protocol';
12
12
  import { Context } from '@dxos/context';
13
13
  import { generatePasscode } from '@dxos/credentials';
14
- import { hasInvitationExpired, type MetadataStore } from '@dxos/echo-pipeline';
14
+ import { type MetadataStore, hasInvitationExpired } from '@dxos/echo-pipeline';
15
15
  import { invariant } from '@dxos/invariant';
16
16
  import { PublicKey } from '@dxos/keys';
17
17
  import { log } from '@dxos/log';
@@ -21,14 +21,16 @@ import {
21
21
  Invitation,
22
22
  } from '@dxos/protocols/proto/dxos/client/services';
23
23
  import { SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
24
+ import { trace } from '@dxos/tracing';
24
25
 
25
26
  import type { InvitationProtocol } from './invitation-protocol';
26
- import { createAdmissionKeypair, type InvitationsHandler } from './invitations-handler';
27
+ import { type InvitationsHandler, createAdmissionKeypair } from './invitations-handler';
27
28
 
28
29
  /**
29
30
  * Entry point for creating and accepting invitations, keeps track of existing invitation set and
30
31
  * emits events when the set changes.
31
32
  */
33
+ @trace.resource()
32
34
  export class InvitationsManager {
33
35
  private readonly _createInvitations = new Map<string, CancellableInvitation>();
34
36
  private readonly _acceptInvitations = new Map<string, AuthenticatingInvitation>();
@@ -48,7 +50,11 @@ export class InvitationsManager {
48
50
  private readonly _metadataStore: MetadataStore,
49
51
  ) {}
50
52
 
51
- async createInvitation(options: Partial<Invitation> & Pick<Invitation, 'kind'>): Promise<CancellableInvitation> {
53
+ @trace.span({ showInBrowserTimeline: true, op: 'lifecycle' })
54
+ async createInvitation(
55
+ ctx: Context,
56
+ options: Partial<Invitation> & Pick<Invitation, 'kind'>,
57
+ ): Promise<CancellableInvitation> {
52
58
  if (options.invitationId) {
53
59
  const existingInvitation = this._createInvitations.get(options.invitationId);
54
60
  if (existingInvitation) {
@@ -63,7 +69,11 @@ export class InvitationsManager {
63
69
  }
64
70
  const invitation = this._createInvitation(handler, options);
65
71
 
66
- const { ctx, stream, observableInvitation } = this._createObservableInvitation(handler, invitation);
72
+ const {
73
+ ctx: invitationCtx,
74
+ stream,
75
+ observableInvitation,
76
+ } = this._createObservableInvitation(ctx, handler, invitation);
67
77
 
68
78
  this._createInvitations.set(invitation.invitationId, observableInvitation);
69
79
  this.invitationCreated.emit(invitation);
@@ -84,12 +94,12 @@ export class InvitationsManager {
84
94
  return observableInvitation;
85
95
  }
86
96
 
87
- this._invitationsHandler.handleInvitationFlow(ctx, stream, handler, observableInvitation.get());
97
+ this._invitationsHandler.handleInvitationFlow(invitationCtx, stream, handler, observableInvitation.get());
88
98
 
89
99
  return observableInvitation;
90
100
  }
91
101
 
92
- async loadPersistentInvitations(): Promise<{ invitations: Invitation[] }> {
102
+ async loadPersistentInvitations(ctx: Context): Promise<{ invitations: Invitation[] }> {
93
103
  if (this._persistentInvitationsLoaded) {
94
104
  const invitations = this.getCreatedInvitations().filter((i) => i.persistent);
95
105
  return { invitations };
@@ -101,7 +111,7 @@ export class InvitationsManager {
101
111
 
102
112
  const loadTasks = freshInvitations.map((persistentInvitation) => {
103
113
  invariant(!this._createInvitations.get(persistentInvitation.invitationId), 'invitation already exists');
104
- return this.createInvitation({ ...persistentInvitation, persistent: false });
114
+ return this.createInvitation(ctx, { ...persistentInvitation, persistent: false });
105
115
  });
106
116
  const cInvitations = await Promise.all(loadTasks);
107
117
 
@@ -115,7 +125,7 @@ export class InvitationsManager {
115
125
  }
116
126
  }
117
127
 
118
- acceptInvitation(request: AcceptInvitationRequest): AuthenticatingInvitation {
128
+ acceptInvitation(ctx: Context, request: AcceptInvitationRequest): AuthenticatingInvitation {
119
129
  const options = request.invitation;
120
130
  const existingInvitation = this._acceptInvitations.get(options.invitationId);
121
131
  if (existingInvitation) {
@@ -123,8 +133,20 @@ export class InvitationsManager {
123
133
  }
124
134
 
125
135
  const handler = this._getHandler(options);
126
- const { ctx, invitation, stream, otpEnteredTrigger } = this._createObservableAcceptingInvitation(handler, options);
127
- this._invitationsHandler.acceptInvitation(ctx, stream, handler, options, otpEnteredTrigger, request.deviceProfile);
136
+ const {
137
+ ctx: invitationCtx,
138
+ invitation,
139
+ stream,
140
+ otpEnteredTrigger,
141
+ } = this._createObservableAcceptingInvitation(ctx, handler, options);
142
+ this._invitationsHandler.acceptInvitation(
143
+ invitationCtx,
144
+ stream,
145
+ handler,
146
+ options,
147
+ otpEnteredTrigger,
148
+ request.deviceProfile,
149
+ );
128
150
  this._acceptInvitations.set(invitation.get().invitationId, invitation);
129
151
  this.invitationAccepted.emit(invitation.get());
130
152
 
@@ -198,7 +220,7 @@ export class InvitationsManager {
198
220
  state = Invitation.State.INIT,
199
221
  timeout = INVITATION_TIMEOUT,
200
222
  swarmKey = PublicKey.random(),
201
- persistent = _options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY, // default no not storing keypairs
223
+ persistent = _options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY,
202
224
  created = new Date(),
203
225
  guestKeypair = undefined,
204
226
  role = SpaceMember.Role.ADMIN,
@@ -232,17 +254,18 @@ export class InvitationsManager {
232
254
  }
233
255
 
234
256
  private _createObservableInvitation(
257
+ ctx: Context,
235
258
  handler: InvitationProtocol,
236
259
  invitation: Invitation,
237
260
  ): { ctx: Context; stream: PushStream<Invitation>; observableInvitation: CancellableInvitation } {
238
261
  const stream = new PushStream<Invitation>();
239
- const ctx = new Context({
262
+ const invitationCtx = ctx.derive({
240
263
  onError: (err) => {
241
264
  stream.error(err);
242
- void ctx.dispose();
265
+ void invitationCtx.dispose();
243
266
  },
244
267
  });
245
- ctx.onDispose(() => {
268
+ invitationCtx.onDispose(() => {
246
269
  log('complete', { ...handler.toJSON() });
247
270
  stream.complete();
248
271
  });
@@ -251,13 +274,14 @@ export class InvitationsManager {
251
274
  subscriber: stream.observable,
252
275
  onCancel: async () => {
253
276
  stream.next({ ...invitation, state: Invitation.State.CANCELLED });
254
- await ctx.dispose();
277
+ await invitationCtx.dispose();
255
278
  },
256
279
  });
257
- return { ctx, stream, observableInvitation };
280
+ return { ctx: invitationCtx, stream, observableInvitation };
258
281
  }
259
282
 
260
283
  private _createObservableAcceptingInvitation(
284
+ parentCtx: Context,
261
285
  handler: InvitationProtocol,
262
286
  initialState: Invitation,
263
287
  ): {
@@ -268,7 +292,8 @@ export class InvitationsManager {
268
292
  } {
269
293
  const otpEnteredTrigger = new Trigger<string>();
270
294
  const stream = new PushStream<Invitation>();
271
- const ctx = new Context({
295
+ // Derive from caller ctx so `TRACE_SPAN_ATTRIBUTE` propagates via the parent chain.
296
+ const ctx = parentCtx.derive({
272
297
  onError: (err) => {
273
298
  if (err instanceof TimeoutError) {
274
299
  log('timeout', { ...handler.toJSON() });
@@ -2,10 +2,10 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { Stream } from '@dxos/codec-protobuf/stream';
5
+ import { type RequestOptions, Stream } from '@dxos/codec-protobuf';
6
6
  import {
7
- type AuthenticationRequest,
8
7
  type AcceptInvitationRequest,
8
+ type AuthenticationRequest,
9
9
  type Invitation,
10
10
  type InvitationsService,
11
11
  QueryInvitationsResponse,
@@ -27,23 +27,23 @@ export class InvitationsServiceImpl implements InvitationsService {
27
27
  };
28
28
  }
29
29
 
30
- createInvitation(options: Invitation): Stream<Invitation> {
31
- return new Stream<Invitation>(({ next, close }) => {
30
+ createInvitation(request: Invitation, options?: RequestOptions): Stream<Invitation> {
31
+ return new Stream<Invitation>(({ ctx, next, close }) => {
32
32
  void this._invitationsManager
33
- .createInvitation(options)
33
+ .createInvitation(ctx, request)
34
34
  .then((invitation) => {
35
35
  trace.metrics.increment('dxos.invitation.created');
36
36
  invitation.subscribe(next, close, close);
37
37
  })
38
38
  .catch(close);
39
- });
39
+ }, options?.ctx);
40
40
  }
41
41
 
42
- acceptInvitation(request: AcceptInvitationRequest): Stream<Invitation> {
43
- const invitation = this._invitationsManager.acceptInvitation(request);
44
- return new Stream<Invitation>(({ next, close }) => {
42
+ acceptInvitation(request: AcceptInvitationRequest, options?: RequestOptions): Stream<Invitation> {
43
+ return new Stream<Invitation>(({ ctx, next, close }) => {
44
+ const invitation = this._invitationsManager.acceptInvitation(ctx, request);
45
45
  invitation.subscribe(next, close, close);
46
- });
46
+ }, options?.ctx);
47
47
  }
48
48
 
49
49
  async authenticate(request: AuthenticationRequest): Promise<void> {
@@ -2,9 +2,10 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { onTestFinished, describe, expect, test } from 'vitest';
5
+ import { describe, expect, onTestFinished, test } from 'vitest';
6
6
 
7
- import { asyncChain, Trigger } from '@dxos/async';
7
+ import { Trigger, chain } from '@dxos/async';
8
+ import { Context } from '@dxos/context';
8
9
  import { raise } from '@dxos/debug';
9
10
  import { AlreadyJoinedError } from '@dxos/protocols';
10
11
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
@@ -22,28 +23,28 @@ const closeAfterTest = async (peer: ServiceContext) => {
22
23
 
23
24
  describe('services/space-invitations-protocol', () => {
24
25
  test('genesis', async () => {
25
- const [peer] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(1));
26
+ const [peer] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(1));
26
27
 
27
- const space = await peer.dataSpaceManager!.createSpace();
28
+ const space = await peer.dataSpaceManager!.createSpace(new Context());
28
29
  expect(peer.dataSpaceManager!.spaces.has(space.key)).to.be.true;
29
30
 
30
- await space.close();
31
+ await space.close(new Context());
31
32
  });
32
33
 
33
34
  test('genesis & ready', async () => {
34
- const [peer] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(1));
35
+ const [peer] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(1));
35
36
 
36
- const space = await peer.dataSpaceManager!.createSpace();
37
+ const space = await peer.dataSpaceManager!.createSpace(new Context());
37
38
  expect(peer.dataSpaceManager!.spaces.has(space.key)).to.be.true;
38
39
 
39
40
  await peer.dataSpaceManager?.waitUntilSpaceReady(space.key);
40
- await space.close();
41
+ await space.close(new Context());
41
42
  });
42
43
 
43
44
  test('invitation with no auth', async () => {
44
- const [host, guest] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
45
+ const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
45
46
 
46
- const space1 = await host.dataSpaceManager!.createSpace();
47
+ const space1 = await host.dataSpaceManager!.createSpace(new Context());
47
48
  const spaceKey = space1.key;
48
49
 
49
50
  await Promise.all(performInvitation({ host, guest, options: { kind: Invitation.Kind.SPACE, spaceKey } }));
@@ -59,15 +60,15 @@ describe('services/space-invitations-protocol', () => {
59
60
 
60
61
  await space2.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.timeframe);
61
62
 
62
- await space1.close();
63
- await space2.close();
63
+ await space1.close(new Context());
64
+ await space2.close(new Context());
64
65
  }
65
66
  });
66
67
 
67
68
  test('invitation when already joined', async () => {
68
- const [host, guest] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
69
+ const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
69
70
 
70
- const space1 = await host.dataSpaceManager!.createSpace();
71
+ const space1 = await host.dataSpaceManager!.createSpace(new Context());
71
72
  const spaceKey = space1.key;
72
73
 
73
74
  await Promise.all(performInvitation({ host, guest, options: { kind: Invitation.Kind.SPACE, spaceKey } }));
@@ -92,11 +93,11 @@ describe('services/space-invitations-protocol', () => {
92
93
  });
93
94
 
94
95
  test('creates and accepts invitation with retry', async () => {
95
- const [host, guest] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
96
+ const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
96
97
 
97
98
  let attempt = 0;
98
99
 
99
- const space1 = await host.dataSpaceManager!.createSpace();
100
+ const space1 = await host.dataSpaceManager!.createSpace(new Context());
100
101
 
101
102
  const [{ invitation: invitation1, error: error1 }, { invitation: invitation2, error: error2 }] = await Promise.all(
102
103
  performInvitation({
@@ -143,8 +144,8 @@ describe('services/space-invitations-protocol', () => {
143
144
 
144
145
  await space2.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.timeframe);
145
146
 
146
- await space1.close();
147
- await space2.close();
147
+ await space1.close(new Context());
148
+ await space2.close(new Context());
148
149
  }
149
150
 
150
151
  expect(
@@ -153,15 +154,15 @@ describe('services/space-invitations-protocol', () => {
153
154
  });
154
155
 
155
156
  test('timeout', async () => {
156
- const [host, guest] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
157
- const space = await host.dataSpaceManager!.createSpace();
157
+ const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
158
+ const space = await host.dataSpaceManager!.createSpace(new Context());
158
159
  const hostInvitation = await createInvitation(host, {
159
160
  kind: Invitation.Kind.SPACE,
160
161
  spaceKey: space.key,
161
162
  timeout: 100,
162
163
  });
163
164
  const invitation = hostInvitation.get();
164
- await host.close();
165
+ await host.close(Context.default());
165
166
 
166
167
  const guestTimeout = new Trigger();
167
168
  const guestInvitation = await acceptInvitation(guest, invitation);
@@ -175,12 +176,12 @@ describe('services/space-invitations-protocol', () => {
175
176
  });
176
177
 
177
178
  test('cancels invitation', async () => {
178
- const [host, guest] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
179
+ const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
179
180
 
180
181
  const hostConnected = new Trigger<Invitation>();
181
182
  const guestConnected = new Trigger<Invitation>();
182
183
 
183
- const space1 = await host.dataSpaceManager!.createSpace();
184
+ const space1 = await host.dataSpaceManager!.createSpace(new Context());
184
185
 
185
186
  const invitationPromises = performInvitation({
186
187
  host,
@@ -213,7 +214,7 @@ describe('services/space-invitations-protocol', () => {
213
214
  expect(invitation1?.state).to.eq(Invitation.State.CANCELLED);
214
215
  expect(error).to.exist;
215
216
 
216
- await space1.close();
217
+ await space1.close(new Context());
217
218
  });
218
219
 
219
220
  // TODO(burdon): Flaky.
@@ -223,7 +224,7 @@ describe('services/space-invitations-protocol', () => {
223
224
  // createPeers(GUEST_COUNT + 1)
224
225
  // );
225
226
 
226
- // const hostSpace = await host.dataSpaceManager!.createSpace();
227
+ // const hostSpace = await host.dataSpaceManager!.createSpace(new Context());
227
228
  // const swarmKey = PublicKey.random();
228
229
  // const hostObservable = await host.spaceInvitations!.createInvitation(hostSpace, {
229
230
  // swarmKey,
@@ -2,6 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { type Context } from '@dxos/context';
5
6
  import {
6
7
  createCancelDelegatedSpaceInvitationCredential,
7
8
  createDelegatedSpaceInvitationCredential,
@@ -12,24 +13,18 @@ import { invariant } from '@dxos/invariant';
12
13
  import { type Keyring } from '@dxos/keyring';
13
14
  import { type PublicKey } from '@dxos/keys';
14
15
  import { log } from '@dxos/log';
15
- import {
16
- AlreadyJoinedError,
17
- type ApiError,
18
- AuthorizationError,
19
- InvalidInvitationError,
20
- SpaceNotFoundError,
21
- } from '@dxos/protocols';
16
+ import { AlreadyJoinedError, AuthorizationError, InvalidInvitationError, SpaceNotFoundError } from '@dxos/protocols';
22
17
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
23
- import { SpaceMember, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
18
+ import { type ProfileDocument, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
24
19
  import {
25
20
  type AdmissionRequest,
26
21
  type AdmissionResponse,
27
22
  type IntroductionRequest,
28
23
  } from '@dxos/protocols/proto/dxos/halo/invitations';
29
24
 
25
+ import { type DataSpaceManager, type SigningContext } from '../spaces';
30
26
  import { type InvitationProtocol } from './invitation-protocol';
31
27
  import { computeExpirationTime } from './utils';
32
- import { type DataSpaceManager, type SigningContext } from '../spaces';
33
28
 
34
29
  export class SpaceInvitationProtocol implements InvitationProtocol {
35
30
  constructor(
@@ -47,16 +42,16 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
47
42
  };
48
43
  }
49
44
 
50
- checkCanInviteNewMembers(): ApiError | undefined {
45
+ checkCanInviteNewMembers(): Error | undefined {
51
46
  if (this._spaceKey == null) {
52
- return new InvalidInvitationError('No spaceKey was provided for a space invitation.');
47
+ return new InvalidInvitationError({ message: 'No spaceKey was provided for a space invitation.' });
53
48
  }
54
49
  const space = this._spaceManager.spaces.get(this._spaceKey);
55
50
  if (space == null) {
56
51
  return new SpaceNotFoundError(this._spaceKey);
57
52
  }
58
53
  if (!space?.inner.spaceState.hasMembershipManagementPermission(this._signingContext.identityKey)) {
59
- return new AuthorizationError('No member management permission.');
54
+ return new AuthorizationError({ message: 'No member management permission.' });
60
55
  }
61
56
  return undefined;
62
57
  }
@@ -147,10 +142,10 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
147
142
 
148
143
  checkInvitation(invitation: Partial<Invitation>): InvalidInvitationError | AlreadyJoinedError | undefined {
149
144
  if (invitation.spaceKey == null) {
150
- return new InvalidInvitationError('No spaceKey was provided for a space invitation.');
145
+ return new InvalidInvitationError({ message: 'No spaceKey was provided for a space invitation.' });
151
146
  }
152
147
  if (this._spaceManager.spaces.has(invitation.spaceKey)) {
153
- return new AlreadyJoinedError('Already joined space.');
148
+ return new AlreadyJoinedError({ message: 'Already joined space.' });
154
149
  }
155
150
  }
156
151
 
@@ -175,7 +170,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
175
170
  };
176
171
  }
177
172
 
178
- async accept(response: AdmissionResponse): Promise<Partial<Invitation>> {
173
+ async accept(ctx: Context, response: AdmissionResponse): Promise<Partial<Invitation>> {
179
174
  invariant(response.space);
180
175
  const { credential, controlTimeframe, dataTimeframe } = response.space;
181
176
  const assertion = getCredentialAssertion(credential);
@@ -183,15 +178,16 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
183
178
  invariant(credential.subject.id.equals(this._signingContext.identityKey));
184
179
 
185
180
  if (this._spaceManager.spaces.has(assertion.spaceKey)) {
186
- throw new AlreadyJoinedError('Already joined space.');
181
+ throw new AlreadyJoinedError({ message: 'Already joined space.' });
187
182
  }
188
183
 
189
184
  // Create local space.
190
- await this._spaceManager.acceptSpace({
185
+ await this._spaceManager.acceptSpace(ctx, {
191
186
  spaceKey: assertion.spaceKey,
192
187
  genesisFeedKey: assertion.genesisFeedKey,
193
188
  controlTimeframe,
194
189
  dataTimeframe,
190
+ tags: assertion.tags,
195
191
  });
196
192
 
197
193
  await this._signingContext.recordCredential(credential);
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { type Mutex, type MutexGuard } from '@dxos/async';
6
- import { cancelWithContext, type Context, ContextDisposedError } from '@dxos/context';
6
+ import { type Context, ContextDisposedError, cancelWithContext } from '@dxos/context';
7
7
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
8
8
 
9
9
  export const stateToString = (state: Invitation.State): string => {
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { asyncTimeout, Trigger } from '@dxos/async';
5
+ import { Trigger, asyncTimeout } from '@dxos/async';
6
6
  import { RESOURCE_LOCK_TIMEOUT } from '@dxos/client-protocol';
7
7
  import { log, logInfo } from '@dxos/log';
8
8