@dxos/client-services 0.8.4-main.ef1bc66f44 → 0.8.4-main.f466a3d56e

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 (203) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/browser/{chunk-NTZOEM4P.mjs → chunk-SNHT4M6V.mjs} +1731 -3089
  4. package/dist/lib/browser/chunk-SNHT4M6V.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-DQWA5ILA.mjs → chunk-2TVKX6UU.mjs} +1731 -3089
  20. package/dist/lib/node-esm/chunk-2TVKX6UU.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 +22 -4
  87. package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -1
  88. package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
  89. package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
  90. package/dist/types/src/packlets/services/service-context.d.ts +2 -4
  91. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  92. package/dist/types/src/packlets/services/service-host.d.ts +2 -3
  93. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  94. package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
  95. package/dist/types/src/packlets/services/util.d.ts.map +1 -1
  96. package/dist/types/src/packlets/space-export/archive-format.d.ts +9 -0
  97. package/dist/types/src/packlets/space-export/archive-format.d.ts.map +1 -0
  98. package/dist/types/src/packlets/space-export/index.d.ts +4 -1
  99. package/dist/types/src/packlets/space-export/index.d.ts.map +1 -1
  100. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +23 -0
  101. package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -0
  102. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +36 -0
  103. package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -0
  104. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
  105. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
  106. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +7 -1
  107. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
  108. package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
  109. package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
  110. package/dist/types/src/packlets/spaces/automerge-space-state.d.ts.map +1 -1
  111. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +20 -14
  112. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  113. package/dist/types/src/packlets/spaces/data-space.d.ts +24 -7
  114. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  115. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  116. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
  117. package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
  118. package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
  119. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +1 -4
  120. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  121. package/dist/types/src/packlets/spaces/spaces-service.d.ts +10 -7
  122. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  123. package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
  124. package/dist/types/src/packlets/storage/profile-archive.d.ts.map +1 -1
  125. package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
  126. package/dist/types/src/packlets/storage/util.d.ts.map +1 -1
  127. package/dist/types/src/packlets/system/system-service.d.ts +1 -1
  128. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  129. package/dist/types/src/packlets/testing/credential-utils.d.ts.map +1 -1
  130. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  131. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  132. package/dist/types/src/packlets/worker/worker-runtime.d.ts +11 -1
  133. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  134. package/dist/types/src/packlets/worker/worker-session.d.ts +0 -2
  135. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
  136. package/dist/types/src/testing/setup.d.ts.map +1 -1
  137. package/dist/types/src/version.d.ts +1 -1
  138. package/dist/types/tsconfig.tsbuildinfo +1 -1
  139. package/package.json +43 -50
  140. package/src/index.ts +1 -0
  141. package/src/packlets/agents/edge-agent-manager.ts +8 -5
  142. package/src/packlets/agents/edge-agent-service.ts +4 -2
  143. package/src/packlets/devices/devices-service.test.ts +0 -1
  144. package/src/packlets/devtools/devtools.ts +0 -1
  145. package/src/packlets/diagnostics/diagnostics.ts +1 -2
  146. package/src/packlets/identity/contacts-service.ts +0 -1
  147. package/src/packlets/identity/identity-manager.test.ts +5 -5
  148. package/src/packlets/identity/identity-manager.ts +18 -17
  149. package/src/packlets/identity/identity-recovery-manager.ts +20 -16
  150. package/src/packlets/identity/identity-service.test.ts +6 -27
  151. package/src/packlets/identity/identity-service.ts +13 -81
  152. package/src/packlets/identity/identity.test.ts +2 -2
  153. package/src/packlets/identity/identity.ts +9 -32
  154. package/src/packlets/invitations/device-invitation-protocol.ts +3 -2
  155. package/src/packlets/invitations/edge-invitation-handler.ts +9 -5
  156. package/src/packlets/invitations/invitation-host-extension.ts +7 -10
  157. package/src/packlets/invitations/invitation-protocol.ts +5 -1
  158. package/src/packlets/invitations/invitation-state.ts +1 -15
  159. package/src/packlets/invitations/invitations-handler.test.ts +4 -5
  160. package/src/packlets/invitations/invitations-handler.ts +67 -15
  161. package/src/packlets/invitations/invitations-manager.ts +40 -15
  162. package/src/packlets/invitations/invitations-service.ts +9 -9
  163. package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
  164. package/src/packlets/invitations/space-invitation-protocol.ts +4 -3
  165. package/src/packlets/logging/logging-service.ts +15 -15
  166. package/src/packlets/network/network-service.test.ts +0 -1
  167. package/src/packlets/network/network-service.ts +10 -8
  168. package/src/packlets/services/client-rpc-server.ts +15 -12
  169. package/src/packlets/services/feed-syncer.test.ts +340 -0
  170. package/src/packlets/services/feed-syncer.ts +175 -25
  171. package/src/packlets/services/service-context.test.ts +3 -2
  172. package/src/packlets/services/service-context.ts +113 -47
  173. package/src/packlets/services/service-host.test.ts +8 -8
  174. package/src/packlets/services/service-host.ts +17 -27
  175. package/src/packlets/services/service-registry.test.ts +0 -1
  176. package/src/packlets/space-export/archive-format.ts +42 -0
  177. package/src/packlets/space-export/index.ts +4 -1
  178. package/src/packlets/space-export/serialized-space-reader.ts +111 -0
  179. package/src/packlets/space-export/serialized-space-writer.ts +252 -0
  180. package/src/packlets/space-export/space-archive-reader.ts +64 -3
  181. package/src/packlets/space-export/space-archive-writer.ts +38 -2
  182. package/src/packlets/space-export/space-archive.test.ts +461 -0
  183. package/src/packlets/spaces/data-space-manager.test.ts +79 -13
  184. package/src/packlets/spaces/data-space-manager.ts +80 -115
  185. package/src/packlets/spaces/data-space.ts +55 -31
  186. package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
  187. package/src/packlets/spaces/edge-feed-replicator.ts +9 -7
  188. package/src/packlets/spaces/epoch-migrations.ts +4 -3
  189. package/src/packlets/spaces/genesis.ts +6 -1
  190. package/src/packlets/spaces/notarization-plugin.ts +2 -1
  191. package/src/packlets/spaces/spaces-service.test.ts +18 -11
  192. package/src/packlets/spaces/spaces-service.ts +115 -17
  193. package/src/packlets/testing/invitation-utils.ts +3 -2
  194. package/src/packlets/worker/worker-runtime.ts +39 -6
  195. package/src/packlets/worker/worker-session.ts +8 -14
  196. package/src/version.ts +1 -1
  197. package/dist/lib/browser/chunk-NTZOEM4P.mjs.map +0 -7
  198. package/dist/lib/node-esm/chunk-DQWA5ILA.mjs.map +0 -7
  199. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
  200. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
  201. package/src/packlets/identity/default-space-state-machine.ts +0 -44
  202. /package/dist/lib/browser/{chunk-NQSC7HOE.mjs.map → chunk-XJRPB3GA.mjs.map} +0 -0
  203. /package/dist/lib/node-esm/{chunk-PKEGMOQ4.mjs.map → chunk-2DT3MZRL.mjs.map} +0 -0
@@ -5,7 +5,9 @@
5
5
  import type { AutomergeUrl } from '@automerge/automerge-repo';
6
6
 
7
7
  import { SubscriptionList, UpdateScheduler, scheduleTask } from '@dxos/async';
8
+ import { type RequestOptions } from '@dxos/codec-protobuf';
8
9
  import { Stream } from '@dxos/codec-protobuf/stream';
10
+ import { Context } from '@dxos/context';
9
11
  import {
10
12
  type CredentialProcessor,
11
13
  createAdmissionCredentials,
@@ -13,7 +15,8 @@ import {
13
15
  getCredentialAssertion,
14
16
  } from '@dxos/credentials';
15
17
  import { raise } from '@dxos/debug';
16
- import { type SpaceManager } from '@dxos/echo-pipeline';
18
+ import { type EchoHost, type SpaceManager } from '@dxos/echo-pipeline';
19
+ import { type DatabaseDirectory } from '@dxos/echo-protocol';
17
20
  import { writeMessages } from '@dxos/feed-store';
18
21
  import { assertArgument, assertState, invariant } from '@dxos/invariant';
19
22
  import { SpaceId } from '@dxos/keys';
@@ -21,6 +24,7 @@ import { log } from '@dxos/log';
21
24
  import {
22
25
  ApiError,
23
26
  AuthorizationError,
27
+ FeedProtocol,
24
28
  IdentityNotInitializedError,
25
29
  SpaceNotFoundError,
26
30
  encodeError,
@@ -40,11 +44,13 @@ import {
40
44
  type QueryCredentialsRequest,
41
45
  type QuerySpacesResponse,
42
46
  type Space,
47
+ SpaceArchive,
43
48
  SpaceMember,
44
49
  SpaceState,
45
50
  type SpacesService,
46
51
  type SubscribeMessagesRequest,
47
52
  type UpdateMemberRoleRequest,
53
+ type CreateSpaceRequest,
48
54
  type UpdateSpaceRequest,
49
55
  type WriteCredentialsRequest,
50
56
  } from '@dxos/protocols/proto/dxos/client/services';
@@ -54,8 +60,14 @@ import { trace } from '@dxos/tracing';
54
60
  import { type Provider } from '@dxos/util';
55
61
 
56
62
  import { type IdentityManager } from '../identity';
57
- import { SpaceArchiveWriter, extractSpaceArchive } from '../space-export';
58
-
63
+ import {
64
+ SpaceArchiveWriter,
65
+ detectSpaceArchiveFormat,
66
+ extractSpaceArchive,
67
+ readSerializedSpaceArchive,
68
+ writeSerializedSpaceArchive,
69
+ objJsonToObjectStructure,
70
+ } from '../space-export';
59
71
  import { type DataSpace } from './data-space';
60
72
  import { type DataSpaceManager } from './data-space-manager';
61
73
 
@@ -63,29 +75,35 @@ export class SpacesServiceImpl implements SpacesService {
63
75
  constructor(
64
76
  private readonly _identityManager: IdentityManager,
65
77
  private readonly _spaceManager: SpaceManager,
78
+ private readonly _echoHost: EchoHost,
66
79
  private readonly _getDataSpaceManager: Provider<Promise<DataSpaceManager>>,
67
80
  ) {}
68
81
 
69
- async createSpace(): Promise<Space> {
82
+ async createSpace(request: CreateSpaceRequest, options?: RequestOptions): Promise<Space> {
70
83
  this._requireIdentity();
84
+ const ctx = options?.ctx ?? new Context();
71
85
  const dataSpaceManager = await this._getDataSpaceManager();
72
- const space = await dataSpaceManager.createSpace();
86
+ const space = await dataSpaceManager.createSpace(ctx, {
87
+ tags: request?.tags,
88
+ membershipPolicy: request?.membershipPolicy,
89
+ });
73
90
  await this._updateMetrics();
74
91
  return this._serializeSpace(space);
75
92
  }
76
93
 
77
- async updateSpace({ spaceKey, state, edgeReplication }: UpdateSpaceRequest): Promise<void> {
94
+ async updateSpace({ spaceKey, state, edgeReplication }: UpdateSpaceRequest, options?: RequestOptions): Promise<void> {
95
+ const ctx = options?.ctx ?? Context.default();
78
96
  const dataSpaceManager = await this._getDataSpaceManager();
79
97
  const space = dataSpaceManager.spaces.get(spaceKey) ?? raise(new SpaceNotFoundError(spaceKey));
80
98
 
81
99
  if (state) {
82
100
  switch (state) {
83
101
  case SpaceState.SPACE_ACTIVE:
84
- await space.activate();
102
+ await space.activate(ctx);
85
103
  break;
86
104
 
87
105
  case SpaceState.SPACE_INACTIVE:
88
- await space.deactivate();
106
+ await space.deactivate(ctx);
89
107
  break;
90
108
  default:
91
109
  throw new ApiError({ message: 'Invalid space state' });
@@ -93,7 +111,7 @@ export class SpacesServiceImpl implements SpacesService {
93
111
  }
94
112
 
95
113
  if (edgeReplication !== undefined) {
96
- await dataSpaceManager.setSpaceEdgeReplicationSetting(spaceKey, edgeReplication);
114
+ await dataSpaceManager.setSpaceEdgeReplicationSetting(ctx, spaceKey, edgeReplication);
97
115
  }
98
116
  }
99
117
 
@@ -262,18 +280,26 @@ export class SpacesServiceImpl implements SpacesService {
262
280
  });
263
281
  }
264
282
 
265
- async joinBySpaceKey({ spaceKey }: JoinBySpaceKeyRequest): Promise<JoinSpaceResponse> {
283
+ async joinBySpaceKey({ spaceKey }: JoinBySpaceKeyRequest, options?: RequestOptions): Promise<JoinSpaceResponse> {
284
+ const ctx = options?.ctx ?? Context.default();
266
285
  const dataSpaceManager = await this._getDataSpaceManager();
267
- const credential = await dataSpaceManager.requestSpaceAdmissionCredential(spaceKey);
268
- return this._joinByAdmission({ credential });
286
+ const credential = await dataSpaceManager.requestSpaceAdmissionCredential(ctx, spaceKey);
287
+ return this._joinByAdmission(ctx, { credential });
269
288
  }
270
289
 
271
290
  async exportSpace(request: ExportSpaceRequest): Promise<ExportSpaceResponse> {
272
- await using writer = await new SpaceArchiveWriter().open();
273
291
  assertArgument(SpaceId.isValid(request.spaceId), 'spaceId', 'Invalid space ID');
274
292
 
275
293
  const dataSpaceManager = await this._getDataSpaceManager();
276
294
  const space = dataSpaceManager.getSpaceById(request.spaceId) ?? raise(new Error('Space not found'));
295
+
296
+ const format = request.format ?? SpaceArchive.Format.BINARY;
297
+ if (format === SpaceArchive.Format.JSON) {
298
+ const archive = await writeSerializedSpaceArchive({ space, echoHost: this._echoHost });
299
+ return { archive };
300
+ }
301
+
302
+ await using writer = await new SpaceArchiveWriter().open();
277
303
  await writer.begin({ spaceId: space.id });
278
304
  const rootUrl = space.automergeSpaceState.lastEpoch?.subject.assertion.automergeRoot;
279
305
  assertState(rootUrl, 'Space does not have a root URL');
@@ -283,23 +309,92 @@ export class SpacesServiceImpl implements SpacesService {
283
309
  await writer.writeDocument(documentId, data);
284
310
  }
285
311
 
312
+ const feeds = await space.getAllFeeds();
313
+ for (const feed of feeds) {
314
+ const archiveBlocks = feed.blocks.map((block) => ({
315
+ actorId: block.actorId,
316
+ sequence: block.sequence,
317
+ prevActorId: block.prevActorId,
318
+ prevSequence: block.prevSequence,
319
+ position: block.position,
320
+ timestamp: block.timestamp,
321
+ data: Buffer.from(block.data).toString('base64'),
322
+ }));
323
+ await writer.writeFeed(feed.feedId, feed.feedNamespace, archiveBlocks);
324
+ }
325
+
286
326
  const archive = await writer.finish();
287
327
  return { archive };
288
328
  }
289
329
 
290
- async importSpace(request: ImportSpaceRequest): Promise<ImportSpaceResponse> {
330
+ async importSpace(request: ImportSpaceRequest, options?: RequestOptions): Promise<ImportSpaceResponse> {
331
+ const ctx = options?.ctx ?? Context.default();
291
332
  const dataSpaceManager = await this._getDataSpaceManager();
333
+
334
+ const format = request.archive.format ?? detectSpaceArchiveFormat(request.archive);
335
+ if (format === SpaceArchive.Format.JSON) {
336
+ const serialized = readSerializedSpaceArchive(request.archive);
337
+ const space = await dataSpaceManager.createSpace(ctx, { tags: request.tags });
338
+ await this._hydrateSpaceFromSerialized(space, serialized);
339
+ await this._updateMetrics();
340
+ return { newSpaceId: space.id };
341
+ }
342
+
292
343
  const extracted = await extractSpaceArchive(request.archive);
293
344
  invariant(extracted.metadata.echo?.currentRootUrl, 'Space archive does not contain a root URL');
294
- const space = await dataSpaceManager.createSpace({
345
+ const space = await dataSpaceManager.createSpace(ctx, {
295
346
  documents: extracted.documents,
296
347
  rootUrl: extracted.metadata.echo?.currentRootUrl as AutomergeUrl,
348
+ tags: request.tags,
297
349
  });
298
350
  await this._updateMetrics();
299
351
  return { newSpaceId: space.id };
300
352
  }
301
353
 
302
- private async _joinByAdmission({ credential }: ContactAdmission): Promise<JoinSpaceResponse> {
354
+ /**
355
+ * Populate a freshly-created space with the objects and feed messages described in a {@link SerializedSpace}.
356
+ *
357
+ * Objects are written directly into the space's automerge root document as inline
358
+ * {@link ObjectStructure} entries; feed messages are appended to the appropriate queue
359
+ * via {@link EchoHost.queuesService}.
360
+ */
361
+ private async _hydrateSpaceFromSerialized(
362
+ space: DataSpace,
363
+ serialized: ReturnType<typeof readSerializedSpaceArchive>,
364
+ ): Promise<void> {
365
+ const databaseRoot = space.databaseRoot;
366
+ assertState(databaseRoot, 'Space database root is not ready');
367
+
368
+ databaseRoot.handle.change((doc: DatabaseDirectory) => {
369
+ if (!doc.objects) {
370
+ doc.objects = {};
371
+ }
372
+ for (const obj of serialized.objects) {
373
+ doc.objects[obj.id] = objJsonToObjectStructure(obj);
374
+ }
375
+ });
376
+
377
+ for (const feed of serialized.feeds ?? []) {
378
+ if (feed.messages.length === 0) {
379
+ continue;
380
+ }
381
+
382
+ const namespace =
383
+ feed.namespace === 'trace' ? FeedProtocol.WellKnownNamespaces.trace : FeedProtocol.WellKnownNamespaces.data;
384
+ try {
385
+ await this._echoHost.queuesService.insertIntoQueue({
386
+ spaceId: space.id,
387
+ queueId: feed.feedObjectId,
388
+ subspaceTag: namespace,
389
+ objects: feed.messages.map((message) => JSON.stringify(message)),
390
+ });
391
+ } catch (err) {
392
+ log.warn('failed to import feed data', { feedObjectId: feed.feedObjectId, error: err });
393
+ }
394
+ }
395
+ }
396
+
397
+ private async _joinByAdmission(ctx: Context, { credential }: ContactAdmission): Promise<JoinSpaceResponse> {
303
398
  const assertion = getCredentialAssertion(credential);
304
399
  invariant(assertion['@type'] === 'dxos.halo.credentials.SpaceMember', 'Invalid credential');
305
400
  const myIdentity = this._identityManager.identity;
@@ -308,9 +403,10 @@ export class SpacesServiceImpl implements SpacesService {
308
403
  const dataSpaceManager = await this._getDataSpaceManager();
309
404
  let dataSpace = dataSpaceManager.spaces.get(assertion.spaceKey);
310
405
  if (!dataSpace) {
311
- dataSpace = await dataSpaceManager.acceptSpace({
406
+ dataSpace = await dataSpaceManager.acceptSpace(ctx, {
312
407
  spaceKey: assertion.spaceKey,
313
408
  genesisFeedKey: assertion.genesisFeedKey,
409
+ tags: assertion.tags,
314
410
  });
315
411
  await myIdentity.controlPipeline.writer.write({ credential: { credential } });
316
412
  }
@@ -363,6 +459,8 @@ export class SpacesServiceImpl implements SpacesService {
363
459
  }),
364
460
  ),
365
461
  creator: space.inner.spaceState.creator?.key,
462
+ tags: space.tags,
463
+ membershipPolicy: space.membershipPolicy,
366
464
  cache: space.cache,
367
465
  metrics: space.metrics,
368
466
  edgeReplication: space.getEdgeReplicationSetting(),
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { Trigger } from '@dxos/async';
6
6
  import { type AuthenticatingInvitation, type CancellableInvitation, InvitationEncoder } from '@dxos/client-protocol';
7
+ import { Context } from '@dxos/context';
7
8
  import { invariant } from '@dxos/invariant';
8
9
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
9
10
  import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
@@ -229,7 +230,7 @@ export const createInvitation = async (
229
230
  };
230
231
 
231
232
  if (host instanceof ServiceContext) {
232
- return host.invitationsManager.createInvitation({
233
+ return host.invitationsManager.createInvitation(new Context(), {
233
234
  kind: Invitation.Kind.SPACE,
234
235
  ...options,
235
236
  });
@@ -246,7 +247,7 @@ export const acceptInvitation = (
246
247
  invitation = sanitizeInvitation(invitation);
247
248
 
248
249
  if (guest instanceof ServiceContext) {
249
- return guest.invitationsManager.acceptInvitation({
250
+ return guest.invitationsManager.acceptInvitation(new Context(), {
250
251
  invitation,
251
252
  deviceProfile: guestDeviceProfile,
252
253
  });
@@ -29,7 +29,6 @@ import * as SqlTransaction from '@dxos/sql-sqlite/SqlTransaction';
29
29
  import { type MaybePromise } from '@dxos/util';
30
30
 
31
31
  import { ClientServicesHost } from '../services';
32
-
33
32
  import { WorkerSession } from './worker-session';
34
33
 
35
34
  // NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
@@ -131,20 +130,32 @@ export class WorkerRuntime {
131
130
  async start(): Promise<void> {
132
131
  log('starting...');
133
132
  try {
133
+ log('worker-runtime: acquiring liveness lock (background)');
134
134
  void this._livenessLock.acquire();
135
135
 
136
136
  // Steal the lock from the other worker.
137
+ log('worker-runtime: broadcasting stop to displace previous worker');
137
138
  this._broadcastChannel = new BroadcastChannel(this._channel);
138
139
  this._broadcastChannel.postMessage({ action: 'stop' });
139
140
  this._broadcastChannel.onmessage = async (event) => {
140
141
  if (event.data?.action === 'stop') {
142
+ log('worker-runtime: received stop broadcast');
141
143
  await this.stop();
142
144
  }
143
145
  };
144
146
 
147
+ log('worker-runtime: acquiring storage lock');
145
148
  await this._acquireLock();
149
+ log('worker-runtime: storage lock acquired, resolving config');
146
150
  this._config = await this._configProvider();
151
+ log('worker-runtime: config resolved');
152
+ this._signalTelemetryEnabled = this._config.get('runtime.client.signalTelemetryEnabled') ?? false;
153
+ const observabilityGroup = this._config.get('runtime.client.observabilityGroup');
154
+ if (observabilityGroup) {
155
+ this._signalMetadataTags.group = observabilityGroup;
156
+ }
147
157
  const signals = this._config.get('runtime.services.signaling');
158
+ log('worker-runtime: initializing client services host');
148
159
  this._clientServices.initialize({
149
160
  config: this._config,
150
161
  signalManager: this._config.get('runtime.client.edgeFeatures')?.signaling
@@ -154,8 +165,10 @@ export class WorkerRuntime {
154
165
  : new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.
155
166
  transportFactory: this._transportFactory,
156
167
  });
168
+ log('worker-runtime: client services host initialized, opening');
157
169
 
158
170
  await this._clientServices.open(new Context());
171
+ log('worker-runtime: client services host opened, signalling ready');
159
172
  this._ready.wake(undefined);
160
173
  log('started');
161
174
  setIdentityTags({
@@ -176,12 +189,36 @@ export class WorkerRuntime {
176
189
  this._releaseLock();
177
190
  this._broadcastChannel?.close();
178
191
  this._broadcastChannel = undefined;
179
- await this._clientServices.close();
192
+ await this._clientServices.close(Context.default());
180
193
  await this._runtime.dispose();
181
194
  await this._onStop?.();
182
195
  await this._livenessLock.release();
183
196
  }
184
197
 
198
+ /**
199
+ * Update signaling telemetry tags from a client-supplied config overlay.
200
+ *
201
+ * The worker services outlive individual client connections, so the first client seeds the
202
+ * worker's core config (storage, signaling, edge features). For fields that can legitimately
203
+ * differ per tab — `observabilityGroup` and `signalTelemetryEnabled` — this method lets later
204
+ * connections refresh the signal metadata the worker attaches to its signaling requests
205
+ * (last-writer-wins, matching the pre-DX-930 per-session RPC behaviour).
206
+ */
207
+ updateSignalMetadata(config: Config): void {
208
+ const observabilityGroup = config.get('runtime.client.observabilityGroup');
209
+ if (observabilityGroup) {
210
+ this._signalMetadataTags.group = observabilityGroup;
211
+ } else {
212
+ // Clear stale group so a later config that removes observabilityGroup stops attributing
213
+ // telemetry to the previous client's group (last-writer-wins).
214
+ delete this._signalMetadataTags.group;
215
+ }
216
+ const signalTelemetryEnabled = config.get('runtime.client.signalTelemetryEnabled');
217
+ if (signalTelemetryEnabled !== undefined) {
218
+ this._signalTelemetryEnabled = signalTelemetryEnabled;
219
+ }
220
+ }
221
+
185
222
  /**
186
223
  * Create a new session.
187
224
  */
@@ -214,10 +251,6 @@ export class WorkerRuntime {
214
251
  !this._signalMetadataTags.origin || this._signalMetadataTags.origin === session.origin,
215
252
  `worker origin changed from ${this._signalMetadataTags.origin} to ${session.origin}?`,
216
253
  );
217
- if (session.observabilityGroup) {
218
- this._signalMetadataTags.group = session.observabilityGroup;
219
- }
220
- this._signalTelemetryEnabled = session.signalTelemetryEnabled ?? false;
221
254
  this._signalMetadataTags.origin = session.origin;
222
255
  this._sessions.add(session);
223
256
 
@@ -41,10 +41,6 @@ export class WorkerSession {
41
41
  @logInfo
42
42
  public origin?: string;
43
43
 
44
- // TODO(nf): factor out?
45
- public observabilityGroup?: string;
46
- public signalTelemetryEnabled?: boolean;
47
-
48
44
  @logInfo
49
45
  public lockKey?: string;
50
46
 
@@ -55,21 +51,21 @@ export class WorkerSession {
55
51
  this._serviceHost = serviceHost;
56
52
 
57
53
  const middleware: Pick<ClientRpcServerProps, 'handleCall' | 'handleStream'> = {
58
- handleCall: async (method, params, handler) => {
54
+ handleCall: async (method, params, handler, options) => {
59
55
  const error = await readySignal.wait({ timeout: PROXY_CONNECTION_TIMEOUT });
60
56
  if (error) {
61
57
  throw error;
62
58
  }
63
59
 
64
- return handler(method, params);
60
+ return handler(method, params, options);
65
61
  },
66
- handleStream: async (method, params, handler) => {
62
+ handleStream: async (method, params, handler, options) => {
67
63
  const error = await readySignal.wait({ timeout: PROXY_CONNECTION_TIMEOUT });
68
64
  if (error) {
69
65
  throw error;
70
66
  }
71
67
 
72
- return handler(method, params);
68
+ return handler(method, params, options);
73
69
  },
74
70
  };
75
71
 
@@ -95,8 +91,6 @@ export class WorkerSession {
95
91
  start: async (request) => {
96
92
  this.origin = request.origin;
97
93
  this.lockKey = request.lockKey;
98
- this.observabilityGroup = request.observabilityGroup;
99
- this.signalTelemetryEnabled = request.signalTelemetryEnabled;
100
94
  this._startTrigger.wake();
101
95
  },
102
96
 
@@ -119,7 +113,7 @@ export class WorkerSession {
119
113
  }
120
114
 
121
115
  async open(): Promise<void> {
122
- log.info('opening...');
116
+ log('opening...');
123
117
  await Promise.all([this._clientRpc.open(), this._iframeRpc.open(), this._maybeOpenShell()]);
124
118
 
125
119
  // Wait until the worker's RPC service has started.
@@ -130,11 +124,11 @@ export class WorkerSession {
130
124
  void this._afterLockReleases(this.lockKey, () => this.close());
131
125
  }
132
126
 
133
- log.info('opened');
127
+ log('opened');
134
128
  }
135
129
 
136
130
  async close(): Promise<void> {
137
- log.info('closing...');
131
+ log.debug('closing...');
138
132
  try {
139
133
  await this.onClose.callIfSet();
140
134
  } catch (err: any) {
@@ -142,7 +136,7 @@ export class WorkerSession {
142
136
  }
143
137
 
144
138
  await Promise.all([this._clientRpc.close(), this._iframeRpc.close()]);
145
- log.info('closed');
139
+ log.debug('closed');
146
140
  }
147
141
 
148
142
  private async _maybeOpenShell(): Promise<void> {
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.8.4-main.ef1bc66f44";
1
+ export const DXOS_VERSION = "0.8.4-main.f466a3d56e";