@dxos/client-services 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0

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 (181) hide show
  1. package/dist/lib/browser/{chunk-HJH6BNTN.mjs → chunk-3LSLNVKQ.mjs} +2102 -1870
  2. package/dist/lib/browser/chunk-3LSLNVKQ.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 +451 -67
  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 +36 -17
  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-ONQM6RQH.mjs → chunk-5S7PIHLS.mjs} +1942 -1579
  23. package/dist/lib/node-esm/chunk-5S7PIHLS.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 +451 -67
  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 +36 -17
  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.map +1 -1
  44. package/dist/types/src/packlets/devtools/devtools.d.ts +2 -2
  45. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  46. package/dist/types/src/packlets/diagnostics/index.d.ts +1 -1
  47. package/dist/types/src/packlets/diagnostics/index.d.ts.map +1 -1
  48. package/dist/types/src/packlets/identity/authenticator.d.ts +2 -2
  49. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  50. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  51. package/dist/types/src/packlets/identity/identity-manager.d.ts +6 -6
  52. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  53. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +7 -6
  54. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
  55. package/dist/types/src/packlets/identity/identity-service.d.ts +1 -6
  56. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  57. package/dist/types/src/packlets/identity/identity.d.ts +8 -11
  58. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  59. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +4 -4
  60. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  61. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
  62. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
  63. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  64. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +2 -3
  65. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
  66. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -4
  67. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  68. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +3 -3
  69. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  70. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +2 -2
  71. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  72. package/dist/types/src/packlets/locks/index.d.ts +1 -1
  73. package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
  74. package/dist/types/src/packlets/logging/logging-service.d.ts +4 -0
  75. package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
  76. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  77. package/dist/types/src/packlets/services/client-rpc-server.d.ts +2 -2
  78. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
  79. package/dist/types/src/packlets/services/feed-syncer.d.ts +59 -0
  80. package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -0
  81. package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
  82. package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
  83. package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
  84. package/dist/types/src/packlets/services/service-context.d.ts +13 -8
  85. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  86. package/dist/types/src/packlets/services/service-host.d.ts +20 -6
  87. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  88. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
  89. package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
  90. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +6 -0
  91. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
  92. package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
  93. package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
  94. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +27 -15
  95. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  96. package/dist/types/src/packlets/spaces/data-space.d.ts +24 -8
  97. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  98. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +2 -2
  99. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  100. package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
  101. package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
  102. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +6 -6
  103. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  104. package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -2
  105. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  106. package/dist/types/src/packlets/testing/invitation-utils.d.ts +6 -3
  107. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  108. package/dist/types/src/packlets/testing/test-builder.d.ts +6 -5
  109. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  110. package/dist/types/src/packlets/worker/worker-runtime.d.ts +31 -4
  111. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  112. package/dist/types/src/packlets/worker/worker-session.d.ts +2 -2
  113. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
  114. package/dist/types/src/version.d.ts +1 -1
  115. package/dist/types/src/version.d.ts.map +1 -1
  116. package/dist/types/tsconfig.tsbuildinfo +1 -1
  117. package/package.json +70 -48
  118. package/src/index.ts +1 -0
  119. package/src/packlets/agents/edge-agent-manager.ts +8 -5
  120. package/src/packlets/agents/edge-agent-service.ts +2 -1
  121. package/src/packlets/devices/devices-service.test.ts +0 -1
  122. package/src/packlets/devtools/devtools.ts +2 -3
  123. package/src/packlets/diagnostics/index.ts +1 -1
  124. package/src/packlets/identity/authenticator.ts +2 -2
  125. package/src/packlets/identity/contacts-service.ts +0 -1
  126. package/src/packlets/identity/identity-manager.test.ts +5 -5
  127. package/src/packlets/identity/identity-manager.ts +21 -18
  128. package/src/packlets/identity/identity-recovery-manager.ts +22 -18
  129. package/src/packlets/identity/identity-service.test.ts +6 -27
  130. package/src/packlets/identity/identity-service.ts +5 -76
  131. package/src/packlets/identity/identity.test.ts +2 -2
  132. package/src/packlets/identity/identity.ts +9 -32
  133. package/src/packlets/invitations/device-invitation-protocol.ts +5 -6
  134. package/src/packlets/invitations/edge-invitation-handler.ts +4 -3
  135. package/src/packlets/invitations/invitation-guest-extenstion.ts +6 -4
  136. package/src/packlets/invitations/invitation-host-extension.ts +6 -4
  137. package/src/packlets/invitations/invitation-protocol.ts +2 -3
  138. package/src/packlets/invitations/invitations-handler.test.ts +4 -5
  139. package/src/packlets/invitations/invitations-handler.ts +10 -10
  140. package/src/packlets/invitations/invitations-manager.ts +37 -14
  141. package/src/packlets/invitations/invitations-service.ts +4 -4
  142. package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
  143. package/src/packlets/invitations/space-invitation-protocol.ts +10 -15
  144. package/src/packlets/locks/index.ts +1 -1
  145. package/src/packlets/logging/logging-service.ts +4 -0
  146. package/src/packlets/network/network-service.test.ts +0 -1
  147. package/src/packlets/network/network-service.ts +5 -4
  148. package/src/packlets/services/client-rpc-server.ts +4 -4
  149. package/src/packlets/services/feed-syncer.test.ts +340 -0
  150. package/src/packlets/services/feed-syncer.ts +337 -0
  151. package/src/packlets/services/platform.ts +7 -1
  152. package/src/packlets/services/service-context.test.ts +3 -2
  153. package/src/packlets/services/service-context.ts +129 -44
  154. package/src/packlets/services/service-host.test.ts +8 -8
  155. package/src/packlets/services/service-host.ts +63 -22
  156. package/src/packlets/services/service-registry.test.ts +0 -1
  157. package/src/packlets/space-export/space-archive-reader.ts +64 -3
  158. package/src/packlets/space-export/space-archive-writer.ts +39 -2
  159. package/src/packlets/space-export/space-archive.test.ts +287 -0
  160. package/src/packlets/spaces/data-space-manager.test.ts +79 -13
  161. package/src/packlets/spaces/data-space-manager.ts +97 -107
  162. package/src/packlets/spaces/data-space.ts +52 -29
  163. package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
  164. package/src/packlets/spaces/edge-feed-replicator.ts +10 -9
  165. package/src/packlets/spaces/epoch-migrations.ts +5 -5
  166. package/src/packlets/spaces/genesis.ts +6 -1
  167. package/src/packlets/spaces/notarization-plugin.test.ts +2 -2
  168. package/src/packlets/spaces/notarization-plugin.ts +10 -9
  169. package/src/packlets/spaces/spaces-service.test.ts +9 -7
  170. package/src/packlets/spaces/spaces-service.ts +40 -16
  171. package/src/packlets/storage/storage.ts +4 -4
  172. package/src/packlets/testing/invitation-utils.ts +10 -6
  173. package/src/packlets/testing/test-builder.ts +36 -10
  174. package/src/packlets/worker/worker-runtime.ts +150 -13
  175. package/src/packlets/worker/worker-session.ts +8 -8
  176. package/src/version.ts +1 -1
  177. package/dist/lib/browser/chunk-HJH6BNTN.mjs.map +0 -7
  178. package/dist/lib/node-esm/chunk-ONQM6RQH.mjs.map +0 -7
  179. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
  180. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
  181. package/src/packlets/identity/default-space-state-machine.ts +0 -44
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { save } from '@automerge/automerge';
6
- import { type DocHandle } from '@automerge/automerge-repo';
6
+ import { type AutomergeUrl, type DocHandle } from '@automerge/automerge-repo';
7
7
 
8
8
  import { Event, Mutex, scheduleTask, sleep, synchronized, trackLeaks } from '@dxos/async';
9
9
  import { AUTH_TIMEOUT } from '@dxos/client-protocol';
@@ -13,7 +13,6 @@ import { timed, warnAfterTimeout } from '@dxos/debug';
13
13
  import {
14
14
  type DatabaseRoot,
15
15
  type EchoHost,
16
- FIND_PARAMS,
17
16
  type MetadataStore,
18
17
  type Space,
19
18
  createMappedFeedWriter,
@@ -25,7 +24,7 @@ import { failedInvariant, invariant } from '@dxos/invariant';
25
24
  import { type Keyring } from '@dxos/keyring';
26
25
  import { PublicKey } from '@dxos/keys';
27
26
  import { log } from '@dxos/log';
28
- import { CancelledError, SystemError } from '@dxos/protocols';
27
+ import { CancelledError, type FeedProtocol, SystemError } from '@dxos/protocols';
29
28
  import {
30
29
  type CreateEpochRequest,
31
30
  type Space as SpaceProto,
@@ -38,6 +37,7 @@ import {
38
37
  AdmittedFeed,
39
38
  type Credential,
40
39
  type Epoch,
40
+ MembershipPolicy,
41
41
  type ProfileDocument,
42
42
  SpaceMember,
43
43
  } from '@dxos/protocols/proto/dxos/halo/credentials';
@@ -48,7 +48,6 @@ import { trace } from '@dxos/tracing';
48
48
  import { type AsyncCallback, CallbackCollection, ComplexSet } from '@dxos/util';
49
49
 
50
50
  import { TrustedKeySetAuthVerifier } from '../identity';
51
-
52
51
  import { AutomergeSpaceState } from './automerge-space-state';
53
52
  import { type SigningContext } from './data-space-manager';
54
53
  import { EdgeFeedReplicator } from './edge-feed-replicator';
@@ -72,7 +71,7 @@ export type DataSpaceCallbacks = {
72
71
  beforeClose?: () => Promise<void>;
73
72
  };
74
73
 
75
- export type DataSpaceParams = {
74
+ export type DataSpaceProps = {
76
75
  initialState: SpaceState;
77
76
  inner: Space;
78
77
  metadataStore: MetadataStore;
@@ -84,6 +83,7 @@ export type DataSpaceParams = {
84
83
  signingContext: SigningContext;
85
84
  callbacks?: DataSpaceCallbacks;
86
85
  cache?: SpaceCache;
86
+ tags?: string[];
87
87
  edgeConnection?: EdgeConnection;
88
88
  edgeHttpClient?: EdgeHttpClient;
89
89
  edgeFeatures?: Runtime.Client.EdgeFeatures;
@@ -121,6 +121,9 @@ export class DataSpace {
121
121
 
122
122
  private _state = SpaceState.SPACE_CLOSED;
123
123
 
124
+ /** Immutable tags from space metadata, available immediately. */
125
+ readonly tags: string[];
126
+
124
127
  private _databaseRoot: DatabaseRoot | null = null;
125
128
 
126
129
  /**
@@ -136,7 +139,7 @@ export class DataSpace {
136
139
 
137
140
  public metrics: SpaceProto.Metrics = {};
138
141
 
139
- constructor(params: DataSpaceParams) {
142
+ constructor(params: DataSpaceProps) {
140
143
  this._inner = params.inner;
141
144
  this._inner.stateUpdate.on(this._ctx, () => this.stateUpdate.emit());
142
145
 
@@ -168,6 +171,7 @@ export class DataSpace {
168
171
  });
169
172
 
170
173
  this._cache = params.cache;
174
+ this.tags = params.tags ?? [];
171
175
 
172
176
  if (params.edgeConnection && params.edgeFeatures?.feedReplicator) {
173
177
  this._edgeFeedReplicator = new EdgeFeedReplicator({ messenger: params.edgeConnection, spaceId: this.id });
@@ -213,6 +217,11 @@ export class DataSpace {
213
217
  return this._cache;
214
218
  }
215
219
 
220
+ /** Membership policy from the genesis credential, defaults to INVITE. */
221
+ get membershipPolicy(): MembershipPolicy {
222
+ return this._inner.spaceState.genesisCredential ? this._inner.spaceState.membershipPolicy : MembershipPolicy.INVITE;
223
+ }
224
+
216
225
  get automergeSpaceState() {
217
226
  return this._automergeSpaceState;
218
227
  }
@@ -230,13 +239,14 @@ export class DataSpace {
230
239
  }
231
240
 
232
241
  @synchronized
233
- async open(): Promise<void> {
242
+ @trace.span({ showInBrowserTimeline: true })
243
+ async open(ctx: Context): Promise<void> {
234
244
  if (this._state === SpaceState.SPACE_CLOSED) {
235
- await this._open();
245
+ await this._open(ctx);
236
246
  }
237
247
  }
238
248
 
239
- private async _open(): Promise<void> {
249
+ private async _open(ctx: Context): Promise<void> {
240
250
  await this._presence.open();
241
251
  await this._gossip.open();
242
252
  await this._notarizationPlugin.open();
@@ -248,8 +258,8 @@ export class DataSpace {
248
258
  this.inner.protocol.feedAdded.append(this._onFeedAdded);
249
259
  }
250
260
 
251
- await this._inner.open(new Context());
252
- await this._inner.startProtocol();
261
+ await this._inner.open(ctx);
262
+ await this._inner.startProtocol(ctx);
253
263
 
254
264
  await this._edgeFeedReplicator?.open();
255
265
 
@@ -263,11 +273,12 @@ export class DataSpace {
263
273
  }
264
274
 
265
275
  @synchronized
266
- async close(): Promise<void> {
267
- await this._close();
276
+ @trace.span({ showInBrowserTimeline: true })
277
+ async close(ctx: Context): Promise<void> {
278
+ await this._close(ctx);
268
279
  }
269
280
 
270
- private async _close(): Promise<void> {
281
+ private async _close(ctx: Context): Promise<void> {
271
282
  await this._callbacks.beforeClose?.();
272
283
 
273
284
  await this.preClose.callSerial();
@@ -285,7 +296,7 @@ export class DataSpace {
285
296
 
286
297
  await this.authVerifier.close();
287
298
 
288
- await this._inner.close();
299
+ await this._inner.close(ctx);
289
300
  await this._inner.spaceState.removeCredentialProcessor(this._automergeSpaceState);
290
301
  await this._automergeSpaceState.close();
291
302
  await this._inner.spaceState.removeCredentialProcessor(this._notarizationPlugin);
@@ -310,7 +321,7 @@ export class DataSpace {
310
321
  scheduleTask(this._ctx, async () => {
311
322
  try {
312
323
  this.metrics.pipelineInitBegin = new Date();
313
- await this.initializeDataPipeline();
324
+ await this.initializeDataPipeline(this._ctx);
314
325
  } catch (err) {
315
326
  if (err instanceof CancelledError || err instanceof ContextDisposedError) {
316
327
  log('data pipeline initialization cancelled', err);
@@ -329,16 +340,16 @@ export class DataSpace {
329
340
  }
330
341
 
331
342
  @trace.span({ showInBrowserTimeline: true })
332
- async initializeDataPipeline(): Promise<void> {
343
+ async initializeDataPipeline(ctx: Context): Promise<void> {
333
344
  if (this._state !== SpaceState.SPACE_CONTROL_ONLY) {
334
- throw new SystemError('Invalid operation');
345
+ throw new SystemError({ message: 'Invalid operation' });
335
346
  }
336
347
 
337
348
  this._state = SpaceState.SPACE_INITIALIZING;
338
349
  log('new state', { state: SpaceState[this._state] });
339
350
 
340
351
  log('initializing control pipeline');
341
- await this._initializeAndReadControlPipeline();
352
+ await this._initializeAndReadControlPipeline(ctx);
342
353
 
343
354
  // Allow other tasks to run before loading the data pipeline.
344
355
  await sleep(1);
@@ -361,11 +372,19 @@ export class DataSpace {
361
372
  yield [this._databaseRoot.documentId, root];
362
373
 
363
374
  for (const documentUrl of this._databaseRoot.getAllLinkedDocuments()) {
364
- const data = await this._echoHost.exportDoc(Context.default(), documentUrl);
375
+ const data = await this._echoHost.exportDoc(documentUrl);
365
376
  yield [documentUrl.replace(/^automerge:/, ''), data];
366
377
  }
367
378
  }
368
379
 
380
+ /**
381
+ * Get all feeds and their blocks for this space.
382
+ * Used for space archive export.
383
+ */
384
+ async getAllFeeds(): Promise<Array<{ feedId: string; feedNamespace: string; blocks: FeedProtocol.Block[] }>> {
385
+ return this._echoHost.getAllFeedsForSpace(this.id);
386
+ }
387
+
369
388
  private async _enterReadyState(): Promise<void> {
370
389
  await this._callbacks.beforeReady?.();
371
390
 
@@ -377,9 +396,9 @@ export class DataSpace {
377
396
  }
378
397
 
379
398
  @trace.span({ showInBrowserTimeline: true })
380
- private async _initializeAndReadControlPipeline(): Promise<void> {
399
+ private async _initializeAndReadControlPipeline(ctx: Context): Promise<void> {
381
400
  await this._inner.controlPipeline.state.waitUntilReachedTargetTimeframe({
382
- ctx: this._ctx,
401
+ ctx,
383
402
  timeout: 10_000,
384
403
  breakOnStall: false,
385
404
  });
@@ -451,6 +470,9 @@ export class DataSpace {
451
470
 
452
471
  log('credentials notarized');
453
472
  } catch (err) {
473
+ if (err instanceof ContextDisposedError) {
474
+ return;
475
+ }
454
476
  log.error('error notarizing credentials for feed admission', err);
455
477
  throw err;
456
478
  }
@@ -471,7 +493,9 @@ export class DataSpace {
471
493
  await warnAfterTimeout(5_000, 'Automerge root doc load timeout (DataSpace)', async () => {
472
494
  handle = await cancelWithContext(
473
495
  this._ctx,
474
- this._echoHost.automergeRepo.find<DatabaseDirectory>(rootUrl as any, FIND_PARAMS),
496
+ this._echoHost.loadDoc<DatabaseDirectory>(this._ctx, rootUrl as AutomergeUrl, {
497
+ fetchFromNetwork: true,
498
+ }),
475
499
  );
476
500
  await cancelWithContext(this._ctx, handle.whenReady());
477
501
  });
@@ -492,7 +516,7 @@ export class DataSpace {
492
516
 
493
517
  // TODO(dmaretskyi): Close roots.
494
518
  // TODO(dmaretskyi): How do we handle changing to the next EPOCH?
495
- const root = await this._echoHost.openSpaceRoot(this.id, handle.url);
519
+ const root = await this._echoHost.openSpaceRoot(this._ctx, this.id, handle.url);
496
520
 
497
521
  // NOTE: Make sure this assignment happens synchronously together with the state change.
498
522
  this._databaseRoot = root;
@@ -569,25 +593,24 @@ export class DataSpace {
569
593
  }
570
594
 
571
595
  @synchronized
572
- async activate(): Promise<void> {
596
+ async activate(ctx: Context): Promise<void> {
573
597
  if (![SpaceState.SPACE_CLOSED, SpaceState.SPACE_INACTIVE].includes(this._state)) {
574
598
  return;
575
599
  }
576
600
 
577
601
  await this._metadataStore.setSpaceState(this.key, SpaceState.SPACE_ACTIVE);
578
- await this._open();
602
+ await this._open(ctx);
579
603
  this.initializeDataPipelineAsync();
580
604
  }
581
605
 
582
606
  @synchronized
583
- async deactivate(): Promise<void> {
607
+ async deactivate(ctx: Context): Promise<void> {
584
608
  if (this._state === SpaceState.SPACE_INACTIVE) {
585
609
  return;
586
610
  }
587
- // Unregister from data service.
588
611
  await this._metadataStore.setSpaceState(this.key, SpaceState.SPACE_INACTIVE);
589
612
  if (this._state !== SpaceState.SPACE_CLOSED) {
590
- await this._close();
613
+ await this._close(ctx);
591
614
  }
592
615
  this._state = SpaceState.SPACE_INACTIVE;
593
616
  log('new state', { state: SpaceState[this._state] });
@@ -107,7 +107,7 @@ describe('EdgeFeedReplicator', () => {
107
107
  const { feed } = await attachReplicator(messenger);
108
108
  await appendMessage(feed);
109
109
 
110
- sendSpy.mockImplementationOnce(async (request: any) => {
110
+ sendSpy.mockImplementationOnce(async (_ctx: any, request: any) => {
111
111
  sendResponseMessage(request, encodeCbor({ type: 'metadata', feedKey: feed.key.toHex(), length: 0 }));
112
112
  return Promise.resolve();
113
113
  });
@@ -22,7 +22,7 @@ import type { FeedBlock, ProtocolMessage } from '@dxos/protocols/feed-replicatio
22
22
  import { EdgeStatus } from '@dxos/protocols/proto/dxos/client/services';
23
23
  import { ComplexMap, arrayToBuffer, bufferToArray, defaultMap, rangeFromTo } from '@dxos/util';
24
24
 
25
- export type EdgeFeedReplicatorParams = {
25
+ export type EdgeFeedReplicatorProps = {
26
26
  messenger: EdgeConnection;
27
27
  spaceId: SpaceId;
28
28
  };
@@ -47,7 +47,7 @@ export class EdgeFeedReplicator extends Resource {
47
47
  */
48
48
  private _pushMutex = new ComplexMap<PublicKey, Mutex>(PublicKey.hash);
49
49
 
50
- constructor({ messenger, spaceId }: EdgeFeedReplicatorParams) {
50
+ constructor({ messenger, spaceId }: EdgeFeedReplicatorProps) {
51
51
  super();
52
52
  this._messenger = messenger;
53
53
  this._spaceId = spaceId;
@@ -132,7 +132,7 @@ export class EdgeFeedReplicator extends Resource {
132
132
 
133
133
  private async _replicateFeed(ctx: Context, feed: FeedWrapper<any>): Promise<void> {
134
134
  log('replicateFeed', { key: feed.key });
135
- await this._sendMessage({
135
+ await this._sendMessage(ctx, {
136
136
  type: 'get-metadata',
137
137
  feedKey: feed.key.toHex(),
138
138
  });
@@ -142,7 +142,7 @@ export class EdgeFeedReplicator extends Resource {
142
142
  });
143
143
  }
144
144
 
145
- private async _sendMessage(message: ProtocolMessage): Promise<void> {
145
+ private async _sendMessage(ctx: Context, message: ProtocolMessage): Promise<void> {
146
146
  if (!this._connectionCtx) {
147
147
  log('message dropped because connection was disposed');
148
148
  return;
@@ -160,6 +160,7 @@ export class EdgeFeedReplicator extends Resource {
160
160
 
161
161
  log('send', { type: message.type });
162
162
  await this._messenger.send(
163
+ ctx,
163
164
  buf.create(RouterMessageSchema, {
164
165
  source: {
165
166
  identityKey: this._messenger.identityKey,
@@ -194,7 +195,7 @@ export class EdgeFeedReplicator extends Resource {
194
195
  if (message.length > feed.length) {
195
196
  log('requesting missing blocks', logMeta);
196
197
 
197
- await this._sendMessage({
198
+ await this._sendMessage(this._connectionCtx!, {
198
199
  type: 'request',
199
200
  feedKey: feedKey.toHex(),
200
201
  range: { from: feed.length, to: message.length },
@@ -202,7 +203,7 @@ export class EdgeFeedReplicator extends Resource {
202
203
  } else if (message.length < feed.length) {
203
204
  log('pushing blocks to remote', logMeta);
204
205
 
205
- await this._pushBlocks(feed, message.length, feed.length);
206
+ await this._pushBlocks(this._connectionCtx!, feed, message.length, feed.length);
206
207
  }
207
208
 
208
209
  break;
@@ -229,7 +230,7 @@ export class EdgeFeedReplicator extends Resource {
229
230
  });
230
231
  }
231
232
 
232
- private async _pushBlocks(feed: FeedWrapper<any>, from: number, to: number): Promise<void> {
233
+ private async _pushBlocks(ctx: Context, feed: FeedWrapper<any>, from: number, to: number): Promise<void> {
233
234
  log('pushing blocks', { feed: feed.key.toHex(), from, to });
234
235
 
235
236
  const blocks: FeedBlock[] = await Promise.all(
@@ -247,7 +248,7 @@ export class EdgeFeedReplicator extends Resource {
247
248
  }),
248
249
  );
249
250
 
250
- await this._sendMessage({
251
+ await this._sendMessage(ctx, {
251
252
  type: 'data',
252
253
  feedKey: feed.key.toHex(),
253
254
  blocks,
@@ -283,7 +284,7 @@ export class EdgeFeedReplicator extends Resource {
283
284
 
284
285
  const remoteLength = this._remoteLength.get(feed.key)!;
285
286
  if (remoteLength < feed.length) {
286
- await this._pushBlocks(feed, remoteLength, feed.length);
287
+ await this._pushBlocks(this._connectionCtx!, feed, remoteLength, feed.length);
287
288
  }
288
289
  }
289
290
 
@@ -36,8 +36,8 @@ const LOAD_DOC_TIMEOUT = 10_000;
36
36
  export const runEpochMigration = async (ctx: Context, context: MigrationContext): Promise<MigrationResult> => {
37
37
  switch (context.migration) {
38
38
  case CreateEpochRequest.Migration.INIT_AUTOMERGE: {
39
- const document = context.echoHost.createDoc();
40
- await context.echoHost.flush();
39
+ const document = await context.echoHost.createDoc();
40
+ await context.echoHost.flush(ctx);
41
41
  return { newRoot: document.url };
42
42
  }
43
43
  case CreateEpochRequest.Migration.PRUNE_AUTOMERGE_ROOT_HISTORY: {
@@ -48,8 +48,8 @@ export const runEpochMigration = async (ctx: Context, context: MigrationContext)
48
48
  timeout: LOAD_DOC_TIMEOUT,
49
49
  });
50
50
 
51
- const newRoot = context.echoHost.createDoc(rootHandle.doc());
52
- await context.echoHost.flush();
51
+ const newRoot = await context.echoHost.createDoc(rootHandle.doc());
52
+ await context.echoHost.flush(ctx);
53
53
  return { newRoot: newRoot.url };
54
54
  }
55
55
  case CreateEpochRequest.Migration.FRAGMENT_AUTOMERGE_ROOT: {
@@ -63,7 +63,7 @@ export const runEpochMigration = async (ctx: Context, context: MigrationContext)
63
63
  invariant(context.newAutomergeRoot);
64
64
 
65
65
  // Defensive programming - it should be the responsibility of the caller to flush the new root.
66
- await context.echoHost.flush();
66
+ await context.echoHost.flush(ctx);
67
67
  return {
68
68
  newRoot: context.newAutomergeRoot,
69
69
  };
@@ -6,7 +6,7 @@ import { createCredential } from '@dxos/credentials';
6
6
  import { failUndefined } from '@dxos/debug';
7
7
  import { type Space } from '@dxos/echo-pipeline';
8
8
  import { type Keyring } from '@dxos/keyring';
9
- import { AdmittedFeed, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
9
+ import { AdmittedFeed, MembershipPolicy, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
10
10
  import { Timeframe } from '@dxos/timeframe';
11
11
 
12
12
  import { type SigningContext } from './data-space-manager';
@@ -16,6 +16,8 @@ export const spaceGenesis = async (
16
16
  signingContext: SigningContext,
17
17
  space: Space,
18
18
  automergeRoot?: string,
19
+ tags?: string[],
20
+ membershipPolicy?: MembershipPolicy,
19
21
  ) => {
20
22
  // TODO(dmaretskyi): Find a way to reconcile with credential generator.
21
23
  const credentials = [
@@ -26,6 +28,8 @@ export const spaceGenesis = async (
26
28
  assertion: {
27
29
  '@type': 'dxos.halo.credentials.SpaceGenesis',
28
30
  spaceKey: space.key,
31
+ tags: tags ?? [],
32
+ membershipPolicy: membershipPolicy ?? MembershipPolicy.INVITE,
29
33
  },
30
34
  }),
31
35
 
@@ -39,6 +43,7 @@ export const spaceGenesis = async (
39
43
  role: SpaceMember.Role.OWNER,
40
44
  profile: signingContext.getProfile(),
41
45
  genesisFeedKey: space.controlFeedKey ?? failUndefined(),
46
+ tags: tags ?? [],
42
47
  },
43
48
  }),
44
49
 
@@ -13,7 +13,7 @@ import { log } from '@dxos/log';
13
13
  import { AdmittedFeed, type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
14
14
  import { TestBuilder, type TestConnection, TestPeer } from '@dxos/teleport/testing';
15
15
 
16
- import { NotarizationPlugin, type NotarizationPluginParams } from './notarization-plugin';
16
+ import { NotarizationPlugin, type NotarizationPluginProps } from './notarization-plugin';
17
17
 
18
18
  class TestAgent extends TestPeer {
19
19
  private readonly _ctx = new Context();
@@ -21,7 +21,7 @@ class TestAgent extends TestPeer {
21
21
  feed = new MockFeedWriter<Credential>();
22
22
  notarizationPlugin: NotarizationPlugin;
23
23
 
24
- constructor(params: NotarizationPluginParams) {
24
+ constructor(params: NotarizationPluginProps) {
25
25
  super();
26
26
  this.notarizationPlugin = new NotarizationPlugin(params);
27
27
  this.feed.written.on(this._ctx, async ([credential]) => {
@@ -33,14 +33,14 @@ const WRITER_NOT_SET_ERROR_CODE = 'WRITER_NOT_SET';
33
33
 
34
34
  const credentialCodec = schema.getCodecForType('dxos.halo.credentials.Credential');
35
35
 
36
- export type NotarizationPluginParams = {
36
+ export type NotarizationPluginProps = {
37
37
  spaceId: SpaceId;
38
38
  edgeClient?: EdgeHttpClient;
39
39
  edgeFeatures?: Runtime.Client.EdgeFeatures;
40
40
  activeEdgePollingInterval?: number;
41
41
  };
42
42
 
43
- export type NotarizeParams = {
43
+ export type NotarizeProps = {
44
44
  /**
45
45
  * For cancellation.
46
46
  */
@@ -97,7 +97,7 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
97
97
 
98
98
  private readonly _edgeClient: EdgeHttpClient | undefined;
99
99
 
100
- constructor(params: NotarizationPluginParams) {
100
+ constructor(params: NotarizationPluginProps) {
101
101
  super();
102
102
  this._spaceId = params.spaceId;
103
103
  this._activeEdgePollingInterval = params.activeEdgePollingInterval ?? DEFAULT_ACTIVE_EDGE_POLLING_INTERVAL;
@@ -149,7 +149,7 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
149
149
  retryTimeout = DEFAULT_RETRY_TIMEOUT,
150
150
  successDelay = DEFAULT_SUCCESS_DELAY,
151
151
  edgeRetryJitter,
152
- }: NotarizeParams): Promise<void> {
152
+ }: NotarizeProps): Promise<void> {
153
153
  log('notarize', { credentials });
154
154
  invariant(
155
155
  credentials.every((credential) => credential.id),
@@ -246,6 +246,7 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
246
246
  scheduleTask(ctx, async () => {
247
247
  try {
248
248
  await client.notarizeCredentials(
249
+ ctx,
249
250
  this._spaceId,
250
251
  { credentials: encodedCredentials },
251
252
  { retry: { count: MAX_EDGE_RETRIES, timeout: timeouts.retryTimeout, jitter: timeouts.jitter } },
@@ -302,7 +303,7 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
302
303
  private _notarizePendingEdgeCredentials(client: EdgeHttpClient, writer: FeedWriter<Credential>): void {
303
304
  scheduleMicroTask(this._ctx, async () => {
304
305
  try {
305
- const response = await client.getCredentialsForNotarization(this._spaceId, {
306
+ const response = await client.getCredentialsForNotarization(this._ctx, this._spaceId, {
306
307
  retry: { count: MAX_EDGE_RETRIES },
307
308
  });
308
309
 
@@ -392,21 +393,21 @@ export class NotarizationPlugin extends Resource implements CredentialProcessor
392
393
  }
393
394
 
394
395
  const handleEdgeError = (error: any) => {
395
- if (!(error instanceof EdgeCallFailedError) || error.errorData) {
396
+ if (!(error instanceof EdgeCallFailedError) || error.data) {
396
397
  log.catch(error);
397
398
  } else {
398
- log.info('Edge notarization failure', { reason: error.reason });
399
+ log.info('Edge notarization failure', { message: error.message });
399
400
  }
400
401
  };
401
402
 
402
- export type NotarizationTeleportExtensionParams = {
403
+ export type NotarizationTeleportExtensionProps = {
403
404
  onOpen: () => Promise<void>;
404
405
  onClose: () => Promise<void>;
405
406
  onNotarize: (request: NotarizeRequest) => Promise<void>;
406
407
  };
407
408
 
408
409
  export class NotarizationTeleportExtension extends RpcExtension<Services, Services> {
409
- constructor(private readonly _params: NotarizationTeleportExtensionParams) {
410
+ constructor(private readonly _params: NotarizationTeleportExtensionProps) {
410
411
  super({
411
412
  requested: {
412
413
  NotarizationService: schema.getService('dxos.mesh.teleport.notarization.NotarizationService'),
@@ -8,10 +8,10 @@ import { Trigger } from '@dxos/async';
8
8
  import { Context } from '@dxos/context';
9
9
  import { PublicKey } from '@dxos/keys';
10
10
  import { type Space, type SpacesService } from '@dxos/protocols/proto/dxos/client/services';
11
+ import { MembershipPolicy } from '@dxos/protocols/proto/dxos/halo/credentials';
11
12
 
12
13
  import { type ServiceContext } from '../services';
13
14
  import { createServiceContext } from '../testing';
14
-
15
15
  import { SpacesServiceImpl } from './spaces-service';
16
16
 
17
17
  describe('SpacesService', () => {
@@ -33,12 +33,14 @@ describe('SpacesService', () => {
33
33
 
34
34
  describe('createSpace', () => {
35
35
  test('fails if no identity is available', async () => {
36
- await expect(spacesService.createSpace()).rejects.toBeInstanceOf(Error);
36
+ await expect(spacesService.createSpace({ membershipPolicy: MembershipPolicy.INVITE })).rejects.toBeInstanceOf(
37
+ Error,
38
+ );
37
39
  });
38
40
 
39
41
  test('creates a new space', async () => {
40
42
  await serviceContext.createIdentity();
41
- const space = await spacesService.createSpace();
43
+ const space = await spacesService.createSpace({ membershipPolicy: MembershipPolicy.INVITE });
42
44
  expect(space).to.exist;
43
45
  expect(space.spaceKey).to.be.instanceof(PublicKey);
44
46
  });
@@ -60,9 +62,9 @@ describe('SpacesService', () => {
60
62
  test('returns list of existing spaces', async () => {
61
63
  await serviceContext.createIdentity();
62
64
  const existingSpaces = [
63
- await spacesService.createSpace(),
64
- await spacesService.createSpace(),
65
- await spacesService.createSpace(),
65
+ await spacesService.createSpace({ membershipPolicy: MembershipPolicy.INVITE }),
66
+ await spacesService.createSpace({ membershipPolicy: MembershipPolicy.INVITE }),
67
+ await spacesService.createSpace({ membershipPolicy: MembershipPolicy.INVITE }),
66
68
  ];
67
69
 
68
70
  const query = spacesService.querySpaces();
@@ -88,7 +90,7 @@ describe('SpacesService', () => {
88
90
  expect(await result.wait()).to.be.length(0);
89
91
 
90
92
  result.reset();
91
- const space = await spacesService.createSpace();
93
+ const space = await spacesService.createSpace({ membershipPolicy: MembershipPolicy.INVITE });
92
94
  const spaces = await result.wait();
93
95
  expect(spaces).to.be.length(1);
94
96
  expect(spaces?.[0].spaceKey.equals(space.spaceKey)).to.be.true;