@dxos/client-services 0.4.10-main.fe71b4c → 0.4.10-next.71cec10

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 (39) hide show
  1. package/dist/lib/browser/{chunk-7S34JE6M.mjs → chunk-5U7G5S73.mjs} +379 -330
  2. package/dist/lib/browser/chunk-5U7G5S73.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +3 -1
  4. package/dist/lib/browser/index.mjs.map +1 -1
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/packlets/testing/index.mjs +1 -1
  7. package/dist/lib/node/{chunk-DQMGKBOV.cjs → chunk-Y3ADPF24.cjs} +377 -329
  8. package/dist/lib/node/chunk-Y3ADPF24.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +44 -42
  10. package/dist/lib/node/index.cjs.map +1 -1
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/packlets/testing/index.cjs +6 -6
  13. package/dist/types/src/packlets/indexing/util.d.ts.map +1 -1
  14. package/dist/types/src/packlets/invitations/index.d.ts +1 -0
  15. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  16. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  17. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +42 -0
  18. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -0
  19. package/dist/types/src/packlets/invitations/invitations-service.d.ts +7 -23
  20. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  21. package/dist/types/src/packlets/services/service-context.d.ts +2 -0
  22. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  23. package/dist/types/src/packlets/services/service-host.d.ts +1 -0
  24. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  25. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  26. package/dist/types/src/version.d.ts +1 -1
  27. package/package.json +34 -34
  28. package/src/packlets/indexing/util.ts +13 -6
  29. package/src/packlets/invitations/index.ts +1 -0
  30. package/src/packlets/invitations/invitations-handler.ts +1 -2
  31. package/src/packlets/invitations/invitations-manager.ts +197 -0
  32. package/src/packlets/invitations/invitations-service.ts +21 -168
  33. package/src/packlets/services/automerge-host.test.ts +1 -1
  34. package/src/packlets/services/service-context.ts +11 -0
  35. package/src/packlets/services/service-host.ts +11 -15
  36. package/src/packlets/spaces/data-space.ts +1 -1
  37. package/src/version.ts +1 -1
  38. package/dist/lib/browser/chunk-7S34JE6M.mjs.map +0 -7
  39. package/dist/lib/node/chunk-DQMGKBOV.cjs.map +0 -7
@@ -2,43 +2,22 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { Event, scheduleTask } from '@dxos/async';
6
- import { type AuthenticatingInvitation, type CancellableInvitation } from '@dxos/client-protocol';
7
5
  import { Stream } from '@dxos/codec-protobuf';
8
- import { Context } from '@dxos/context';
9
- import { hasInvitationExpired, type MetadataStore } from '@dxos/echo-pipeline';
10
- import { invariant } from '@dxos/invariant';
11
- import { log } from '@dxos/log';
12
6
  import {
13
7
  type AuthenticationRequest,
14
8
  type AcceptInvitationRequest,
15
- Invitation,
9
+ type Invitation,
16
10
  type InvitationsService,
17
11
  QueryInvitationsResponse,
18
12
  } from '@dxos/protocols/proto/dxos/client/services';
19
13
 
20
- import { type InvitationProtocol } from './invitation-protocol';
21
- import { type InvitationsHandler } from './invitations-handler';
14
+ import { type InvitationsManager } from './invitations-manager';
22
15
 
23
16
  /**
24
17
  * Adapts invitation service observable to client/service stream.
25
18
  */
26
19
  export class InvitationsServiceImpl implements InvitationsService {
27
- private readonly _createInvitations = new Map<string, CancellableInvitation>();
28
- private readonly _acceptInvitations = new Map<string, AuthenticatingInvitation>();
29
- private readonly _invitationCreated = new Event<Invitation>();
30
- private readonly _invitationAccepted = new Event<Invitation>();
31
- private readonly _removedCreated = new Event<Invitation>();
32
- private readonly _removedAccepted = new Event<Invitation>();
33
- private readonly _saved = new Event<Invitation>();
34
- private readonly _persistentInvitationsLoadedEvent = new Event();
35
- private _persistentInvitationsLoaded = false;
36
-
37
- constructor(
38
- private readonly _invitationsHandler: InvitationsHandler,
39
- private readonly _getHandler: (invitation: Invitation) => InvitationProtocol,
40
- private readonly _metadataStore: MetadataStore,
41
- ) {}
20
+ constructor(private readonly _invitationsManager: InvitationsManager) {}
42
21
 
43
22
  // TODO(burdon): Guest/host label.
44
23
  getLoggingContext() {
@@ -48,148 +27,31 @@ export class InvitationsServiceImpl implements InvitationsService {
48
27
  }
49
28
 
50
29
  createInvitation(options: Invitation): Stream<Invitation> {
51
- let invitation: CancellableInvitation;
52
-
53
- const savePersistentInvitationCtx = new Context();
54
- const existingInvitation = this._createInvitations.get(options.invitationId);
55
- if (existingInvitation) {
56
- invitation = existingInvitation;
57
- } else {
58
- const handler = this._getHandler(options);
59
- invitation = this._invitationsHandler.createInvitation(handler, options);
60
- this._createInvitations.set(invitation.get().invitationId, invitation);
61
- this._invitationCreated.emit(invitation.get());
62
- }
63
-
30
+ const invitation = this._invitationsManager.createInvitation(options);
64
31
  return new Stream<Invitation>(({ next, close }) => {
65
- if (invitation.get().persistent) {
66
- scheduleTask(savePersistentInvitationCtx, async () => {
67
- try {
68
- await this._metadataStore.addInvitation(invitation.get());
69
- this._saved.emit(invitation.get());
70
- } catch (err: any) {
71
- close(err);
72
- }
73
- });
74
- }
75
- invitation.subscribe(
76
- (invitation) => {
77
- next(invitation);
78
- },
79
- async (err: Error) => {
80
- await savePersistentInvitationCtx.dispose();
81
-
82
- // TODO(nf): also remove from storage?
83
- close(err);
84
- },
85
- async () => {
86
- close();
87
- if (invitation.get().persistent) {
88
- await savePersistentInvitationCtx.dispose();
89
- // TODO(nf): remove on all complete conditions?
90
- await this._metadataStore.removeInvitation(invitation.get().invitationId);
91
- }
92
-
93
- this._createInvitations.delete(invitation.get().invitationId);
94
- if (!invitation.get().multiUse) {
95
- this._removedCreated.emit(invitation.get());
96
- }
97
- },
98
- );
99
- });
100
- }
101
-
102
- async loadPersistentInvitations() {
103
- const persistentInvitations = this._metadataStore.getInvitations();
104
-
105
- // get saved persistent invitations, filter and remove from storage those that have expired.
106
- const freshInvitations = persistentInvitations.filter(async (invitation) => !hasInvitationExpired(invitation));
107
-
108
- const cInvitations = freshInvitations.map((persistentInvitation) => {
109
- invariant(!this._createInvitations.get(persistentInvitation.invitationId), 'invitation already exists');
110
-
111
- const handler = this._getHandler(persistentInvitation);
112
- const invitation = this._invitationsHandler.createInvitation(handler, persistentInvitation);
113
- this._createInvitations.set(invitation.get().invitationId, invitation);
114
- this._invitationCreated.emit(invitation.get());
115
- return persistentInvitation;
32
+ invitation.subscribe(next, close, close);
116
33
  });
117
- this._persistentInvitationsLoadedEvent.emit();
118
- this._persistentInvitationsLoaded = true;
119
- return { invitations: cInvitations };
120
34
  }
121
35
 
122
- acceptInvitation({ invitation: options, deviceProfile }: AcceptInvitationRequest): Stream<Invitation> {
123
- let invitation: AuthenticatingInvitation;
124
-
125
- // TODO(nf): duplicate check in InvitationHandler
126
- if (deviceProfile) {
127
- invariant(options.kind === Invitation.Kind.DEVICE, 'deviceProfile provided for non-device invitation');
128
- }
129
-
130
- const existingInvitation = this._acceptInvitations.get(options.invitationId);
131
- if (existingInvitation) {
132
- invitation = existingInvitation;
133
- } else {
134
- const handler = this._getHandler(options);
135
- invitation = this._invitationsHandler.acceptInvitation(handler, options, deviceProfile);
136
- this._acceptInvitations.set(invitation.get().invitationId, invitation);
137
- this._invitationAccepted.emit(invitation.get());
138
- }
139
-
36
+ acceptInvitation(request: AcceptInvitationRequest): Stream<Invitation> {
37
+ const invitation = this._invitationsManager.acceptInvitation(request);
140
38
  return new Stream<Invitation>(({ next, close }) => {
141
- invitation.subscribe(
142
- (invitation) => {
143
- next(invitation);
144
- },
145
- (err: Error) => {
146
- close(err);
147
- },
148
- () => {
149
- close();
150
- this._acceptInvitations.delete(invitation.get().invitationId);
151
- if (!invitation.get().multiUse) {
152
- this._removedAccepted.emit(invitation.get());
153
- }
154
- },
155
- );
39
+ invitation.subscribe(next, close, close);
156
40
  });
157
41
  }
158
42
 
159
- async authenticate({ invitationId, authCode }: AuthenticationRequest): Promise<void> {
160
- log('authenticating...');
161
- invariant(invitationId);
162
- const observable = this._acceptInvitations.get(invitationId);
163
- if (!observable) {
164
- log.warn('invalid invitation', { invitationId });
165
- } else {
166
- await observable.authenticate(authCode);
167
- }
43
+ async authenticate(request: AuthenticationRequest): Promise<void> {
44
+ return this._invitationsManager.authenticate(request);
168
45
  }
169
46
 
170
- async cancelInvitation({ invitationId }: { invitationId: string }): Promise<void> {
171
- log('cancelInvitation...', { invitationId });
172
- invariant(invitationId);
173
- const created = this._createInvitations.get(invitationId);
174
- const accepted = this._acceptInvitations.get(invitationId);
175
- if (created) {
176
- await created.cancel();
177
- this._createInvitations.delete(invitationId);
178
- this._removedCreated.emit(created.get());
179
- if (created.get().persistent) {
180
- await this._metadataStore.removeInvitation(created.get().invitationId);
181
- }
182
- } else if (accepted) {
183
- await accepted.cancel();
184
- this._acceptInvitations.delete(invitationId);
185
- this._removedAccepted.emit(accepted.get());
186
- }
47
+ async cancelInvitation(request: { invitationId: string }): Promise<void> {
48
+ return this._invitationsManager.cancelInvitation(request);
187
49
  }
188
50
 
189
51
  queryInvitations(): Stream<QueryInvitationsResponse> {
190
52
  return new Stream<QueryInvitationsResponse>(({ next, ctx }) => {
191
53
  // Push added invitations to the stream.
192
- this._invitationCreated.on(ctx, (invitation) => {
54
+ this._invitationsManager.invitationCreated.on(ctx, (invitation) => {
193
55
  next({
194
56
  action: QueryInvitationsResponse.Action.ADDED,
195
57
  type: QueryInvitationsResponse.Type.CREATED,
@@ -197,7 +59,7 @@ export class InvitationsServiceImpl implements InvitationsService {
197
59
  });
198
60
  });
199
61
 
200
- this._invitationAccepted.on(ctx, (invitation) => {
62
+ this._invitationsManager.invitationAccepted.on(ctx, (invitation) => {
201
63
  next({
202
64
  action: QueryInvitationsResponse.Action.ADDED,
203
65
  type: QueryInvitationsResponse.Type.ACCEPTED,
@@ -206,7 +68,7 @@ export class InvitationsServiceImpl implements InvitationsService {
206
68
  });
207
69
 
208
70
  // Push removed invitations to the stream.
209
- this._removedCreated.on(ctx, (invitation) => {
71
+ this._invitationsManager.removedCreated.on(ctx, (invitation) => {
210
72
  next({
211
73
  action: QueryInvitationsResponse.Action.REMOVED,
212
74
  type: QueryInvitationsResponse.Type.CREATED,
@@ -214,7 +76,7 @@ export class InvitationsServiceImpl implements InvitationsService {
214
76
  });
215
77
  });
216
78
 
217
- this._removedAccepted.on(ctx, (invitation) => {
79
+ this._invitationsManager.removedAccepted.on(ctx, (invitation) => {
218
80
  next({
219
81
  action: QueryInvitationsResponse.Action.REMOVED,
220
82
  type: QueryInvitationsResponse.Type.ACCEPTED,
@@ -223,7 +85,7 @@ export class InvitationsServiceImpl implements InvitationsService {
223
85
  });
224
86
 
225
87
  // used only for testing
226
- this._saved.on(ctx, (invitation) => {
88
+ this._invitationsManager.saved.on(ctx, (invitation) => {
227
89
  next({
228
90
  action: QueryInvitationsResponse.Action.SAVED,
229
91
  type: QueryInvitationsResponse.Type.CREATED,
@@ -235,33 +97,24 @@ export class InvitationsServiceImpl implements InvitationsService {
235
97
  next({
236
98
  action: QueryInvitationsResponse.Action.ADDED,
237
99
  type: QueryInvitationsResponse.Type.CREATED,
238
- invitations: Array.from(this._createInvitations.values()).map((invitation) => invitation.get()),
100
+ invitations: this._invitationsManager.getCreatedInvitations(),
239
101
  existing: true,
240
102
  });
241
103
 
242
104
  next({
243
105
  action: QueryInvitationsResponse.Action.ADDED,
244
106
  type: QueryInvitationsResponse.Type.ACCEPTED,
245
- invitations: Array.from(this._acceptInvitations.values()).map((invitation) => invitation.get()),
107
+ invitations: this._invitationsManager.getAcceptedInvitations(),
246
108
  existing: true,
247
109
  });
248
110
 
249
- if (this._persistentInvitationsLoaded) {
111
+ this._invitationsManager.onPersistentInvitationsLoaded(ctx, () => {
250
112
  next({
251
113
  action: QueryInvitationsResponse.Action.LOAD_COMPLETE,
252
114
  type: QueryInvitationsResponse.Type.CREATED,
253
115
  // TODO(nf): populate with invitations
254
116
  });
255
- } else {
256
- this._persistentInvitationsLoadedEvent.on(ctx, () => {
257
- next({
258
- action: QueryInvitationsResponse.Action.LOAD_COMPLETE,
259
- type: QueryInvitationsResponse.Type.CREATED,
260
- // TODO(nf): populate with invitations
261
- });
262
- });
263
- }
264
-
117
+ });
265
118
  // TODO(nf): expired invitations?
266
119
  });
267
120
  }
@@ -5,9 +5,9 @@
5
5
  import { expect } from 'chai';
6
6
 
7
7
  import { asyncTimeout, sleep } from '@dxos/async';
8
+ import { AutomergeContext } from '@dxos/echo-db';
8
9
  import { AutomergeHost, DataServiceImpl } from '@dxos/echo-pipeline';
9
10
  import { createTestLevel } from '@dxos/echo-pipeline/testing';
10
- import { AutomergeContext } from '@dxos/echo-schema';
11
11
  import { afterTest, describe, test } from '@dxos/test';
12
12
 
13
13
  describe('AutomergeHost', () => {
@@ -39,6 +39,7 @@ import {
39
39
  SpaceInvitationProtocol,
40
40
  type InvitationProtocol,
41
41
  } from '../invitations';
42
+ import { InvitationsManager } from '../invitations/invitations-manager';
42
43
  import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
43
44
 
44
45
  export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams;
@@ -62,6 +63,7 @@ export class ServiceContext extends Resource {
62
63
  public readonly spaceManager: SpaceManager;
63
64
  public readonly identityManager: IdentityManager;
64
65
  public readonly invitations: InvitationsHandler;
66
+ public readonly invitationsManager: InvitationsManager;
65
67
  public readonly automergeHost: AutomergeHost;
66
68
  public readonly indexMetadata: IndexMetadataStore;
67
69
  public readonly indexer: Indexer;
@@ -136,6 +138,11 @@ export class ServiceContext extends Resource {
136
138
  });
137
139
 
138
140
  this.invitations = new InvitationsHandler(this.networkManager);
141
+ this.invitationsManager = new InvitationsManager(
142
+ this.invitations,
143
+ (invitation) => this.getInvitationHandler(invitation),
144
+ this.metadataStore,
145
+ );
139
146
 
140
147
  // TODO(burdon): _initialize called in multiple places.
141
148
  // TODO(burdon): Call _initialize on success.
@@ -166,6 +173,10 @@ export class ServiceContext extends Resource {
166
173
  if (this.identityManager.identity) {
167
174
  await this._initialize(ctx);
168
175
  }
176
+
177
+ const loadedInvitations = await this.invitationsManager.loadPersistentInvitations();
178
+ log('loaded persistent invitations', { count: loadedInvitations.invitations?.length });
179
+
169
180
  log.trace('dxos.sdk.service-context.open', trace.end({ id: this._instanceId }));
170
181
  log('opened');
171
182
  }
@@ -16,7 +16,7 @@ import {
16
16
  type LevelDB,
17
17
  } from '@dxos/echo-pipeline';
18
18
  import { getTypeReference } from '@dxos/echo-schema';
19
- import { IndexServiceImpl } from '@dxos/indexing';
19
+ import { QueryServiceImpl } from '@dxos/indexing';
20
20
  import { invariant } from '@dxos/invariant';
21
21
  import { PublicKey } from '@dxos/keys';
22
22
  import { log } from '@dxos/log';
@@ -83,6 +83,7 @@ export class ClientServicesHost {
83
83
  private readonly _systemService: SystemServiceImpl;
84
84
  private readonly _loggingService: LoggingServiceImpl;
85
85
  private readonly _tracingService = TRACE_PROCESSOR.createTraceSender();
86
+ private _queryService!: QueryServiceImpl;
86
87
 
87
88
  private _config?: Config;
88
89
  private readonly _statusUpdate = new Event<void>();
@@ -262,6 +263,12 @@ export class ClientServicesHost {
262
263
  this._runtimeParams,
263
264
  );
264
265
 
266
+ this._queryService = new QueryServiceImpl({
267
+ indexer: this._serviceContext.indexer,
268
+ automergeHost: this._serviceContext.automergeHost,
269
+ });
270
+ await this._queryService.open(ctx);
271
+
265
272
  this._serviceRegistry.setServices({
266
273
  SystemService: this._systemService,
267
274
 
@@ -272,11 +279,7 @@ export class ClientServicesHost {
272
279
  (profile) => this._serviceContext.broadcastProfileUpdate(profile),
273
280
  ),
274
281
 
275
- InvitationsService: new InvitationsServiceImpl(
276
- this._serviceContext.invitations,
277
- (invitation) => this._serviceContext.getInvitationHandler(invitation),
278
- this._serviceContext.metadataStore,
279
- ),
282
+ InvitationsService: new InvitationsServiceImpl(this._serviceContext.invitationsManager),
280
283
 
281
284
  DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
282
285
 
@@ -291,10 +294,7 @@ export class ClientServicesHost {
291
294
 
292
295
  DataService: new DataServiceImpl(this._serviceContext.automergeHost),
293
296
 
294
- IndexService: new IndexServiceImpl({
295
- indexer: this._serviceContext.indexer,
296
- automergeHost: this._serviceContext.automergeHost,
297
- }),
297
+ QueryService: this._queryService,
298
298
 
299
299
  NetworkService: new NetworkServiceImpl(this._serviceContext.networkManager, this._serviceContext.signalManager),
300
300
 
@@ -310,11 +310,6 @@ export class ClientServicesHost {
310
310
  });
311
311
 
312
312
  await this._serviceContext.open(ctx);
313
- // TODO(nf): move to InvitationManager in ServiceContext?
314
- invariant(this.serviceRegistry.services.InvitationsService);
315
- const loadedInvitations = await this.serviceRegistry.services.InvitationsService.loadPersistentInvitations();
316
-
317
- log('loaded persistent invitations', { count: loadedInvitations.invitations?.length });
318
313
 
319
314
  const devtoolsProxy = this._config?.get('runtime.client.devtoolsProxy');
320
315
  if (devtoolsProxy) {
@@ -349,6 +344,7 @@ export class ClientServicesHost {
349
344
  await this._devtoolsProxy?.close();
350
345
  this._serviceRegistry.setServices({ SystemService: this._systemService });
351
346
  await this._loggingService.close();
347
+ await this._queryService.close();
352
348
  await this._serviceContext.close();
353
349
  await this._level?.close();
354
350
  this._open = false;
@@ -6,7 +6,6 @@ import { Event, asyncTimeout, scheduleTask, sleep, synchronized, trackLeaks } fr
6
6
  import { AUTH_TIMEOUT } from '@dxos/client-protocol';
7
7
  import { cancelWithContext, Context, ContextDisposedError } from '@dxos/context';
8
8
  import { timed, warnAfterTimeout } from '@dxos/debug';
9
- import { TYPE_PROPERTIES } from '@dxos/echo-db';
10
9
  import {
11
10
  type MetadataStore,
12
11
  type Space,
@@ -15,6 +14,7 @@ import {
15
14
  type SpaceDoc,
16
15
  } from '@dxos/echo-pipeline';
17
16
  import { AutomergeDocumentLoaderImpl } from '@dxos/echo-pipeline';
17
+ import { TYPE_PROPERTIES } from '@dxos/echo-schema';
18
18
  import { type FeedStore } from '@dxos/feed-store';
19
19
  import { failedInvariant, invariant } from '@dxos/invariant';
20
20
  import { type Keyring } from '@dxos/keyring';
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.4.10-main.fe71b4c";
1
+ export const DXOS_VERSION = "0.4.10-next.71cec10";