@dxos/client-services 0.5.1-main.ef0d69d → 0.5.1-main.f81ddc4

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 (66) hide show
  1. package/dist/lib/browser/{chunk-KGHYHY4Q.mjs → chunk-OE6XNPWD.mjs} +1296 -940
  2. package/dist/lib/browser/chunk-OE6XNPWD.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -1
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +29 -9
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/{chunk-4WE4TH57.cjs → chunk-PQ6V45LX.cjs} +1459 -1111
  8. package/dist/lib/node/chunk-PQ6V45LX.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +43 -43
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/packlets/testing/index.cjs +35 -15
  12. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  13. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +2 -1
  14. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  15. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts +39 -0
  16. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -0
  17. package/dist/types/src/packlets/invitations/{invitation-extension.d.ts → invitation-host-extension.d.ts} +17 -31
  18. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -0
  19. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +6 -1
  20. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
  21. package/dist/types/src/packlets/invitations/invitation-topology.d.ts +37 -0
  22. package/dist/types/src/packlets/invitations/invitation-topology.d.ts.map +1 -0
  23. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +19 -10
  24. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  25. package/dist/types/src/packlets/invitations/invitations-handler.test.d.ts +2 -0
  26. package/dist/types/src/packlets/invitations/invitations-handler.test.d.ts.map +1 -0
  27. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +2 -1
  28. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  29. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -0
  30. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  31. package/dist/types/src/packlets/invitations/utils.d.ts +6 -0
  32. package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -0
  33. package/dist/types/src/packlets/services/service-context.d.ts +8 -5
  34. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  35. package/dist/types/src/packlets/services/service-host.d.ts +1 -1
  36. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  37. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  38. package/dist/types/src/packlets/storage/level.d.ts +1 -2
  39. package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
  40. package/dist/types/src/packlets/testing/invitation-utils.d.ts +2 -1
  41. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  42. package/dist/types/src/packlets/testing/test-builder.d.ts +2 -1
  43. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  44. package/dist/types/src/version.d.ts +1 -1
  45. package/package.json +36 -35
  46. package/src/packlets/invitations/device-invitation-protocol.ts +5 -1
  47. package/src/packlets/invitations/invitation-guest-extenstion.ts +126 -0
  48. package/src/packlets/invitations/{invitation-extension.ts → invitation-host-extension.ts} +99 -105
  49. package/src/packlets/invitations/invitation-protocol.ts +7 -1
  50. package/src/packlets/invitations/invitation-topology.ts +87 -0
  51. package/src/packlets/invitations/invitations-handler.test.ts +361 -0
  52. package/src/packlets/invitations/invitations-handler.ts +246 -149
  53. package/src/packlets/invitations/invitations-manager.ts +42 -3
  54. package/src/packlets/invitations/space-invitation-protocol.ts +19 -1
  55. package/src/packlets/invitations/utils.ts +27 -0
  56. package/src/packlets/services/automerge-host.test.ts +3 -1
  57. package/src/packlets/services/service-context.ts +7 -6
  58. package/src/packlets/services/service-host.ts +3 -4
  59. package/src/packlets/spaces/data-space.ts +2 -1
  60. package/src/packlets/storage/level.ts +2 -2
  61. package/src/packlets/testing/invitation-utils.ts +23 -3
  62. package/src/packlets/testing/test-builder.ts +6 -3
  63. package/src/version.ts +1 -1
  64. package/dist/lib/browser/chunk-KGHYHY4Q.mjs.map +0 -7
  65. package/dist/lib/node/chunk-4WE4TH57.cjs.map +0 -7
  66. package/dist/types/src/packlets/invitations/invitation-extension.d.ts.map +0 -1
@@ -4,6 +4,7 @@
4
4
 
5
5
  import {
6
6
  createAdmissionCredentials,
7
+ createCancelDelegatedSpaceInvitationCredential,
7
8
  createDelegatedSpaceInvitationCredential,
8
9
  getCredentialAssertion,
9
10
  } from '@dxos/credentials';
@@ -87,7 +88,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
87
88
 
88
89
  async delegate(invitation: Invitation): Promise<PublicKey> {
89
90
  invariant(this._spaceKey);
90
- const space = await this._spaceManager.spaces.get(this._spaceKey);
91
+ const space = this._spaceManager.spaces.get(this._spaceKey);
91
92
  invariant(space);
92
93
  if (invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY) {
93
94
  invariant(invitation.guestKeypair?.publicKey);
@@ -118,6 +119,23 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
118
119
  return credential.credential.credential.id!;
119
120
  }
120
121
 
122
+ async cancelDelegation(invitation: Invitation): Promise<void> {
123
+ invariant(this._spaceKey);
124
+ invariant(invitation.type === Invitation.Type.DELEGATED && invitation.delegationCredentialId);
125
+ const space = this._spaceManager.spaces.get(this._spaceKey);
126
+ invariant(space);
127
+
128
+ log('cancelling delegated space invitation', { host: this._signingContext.deviceKey, id: invitation.invitationId });
129
+ const credential = await createCancelDelegatedSpaceInvitationCredential(
130
+ this._signingContext.credentialSigner,
131
+ space.key,
132
+ invitation.delegationCredentialId,
133
+ );
134
+
135
+ invariant(credential.credential);
136
+ await writeMessages(space.inner.controlPipeline.writer, [credential]);
137
+ }
138
+
121
139
  checkInvitation(invitation: Partial<Invitation>) {
122
140
  if (invitation.spaceKey && this._spaceManager.spaces.has(invitation.spaceKey)) {
123
141
  return new AlreadyJoinedError('Already joined space.');
@@ -0,0 +1,27 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Mutex, type MutexGuard } from '@dxos/async';
6
+ import { cancelWithContext, type Context, ContextDisposedError } from '@dxos/context';
7
+ import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
8
+
9
+ export const stateToString = (state: Invitation.State): string => {
10
+ return Object.entries(Invitation.State).find(([key, val]) => val === state)?.[0] ?? 'unknown';
11
+ };
12
+
13
+ export const tryAcquireBeforeContextDisposed = async (ctx: Context, mutex: Mutex): Promise<MutexGuard> => {
14
+ let guard: MutexGuard | undefined;
15
+ return cancelWithContext(
16
+ ctx,
17
+ (async () => {
18
+ guard = await mutex.acquire();
19
+ if (ctx.disposed) {
20
+ guard.release();
21
+ guard = undefined;
22
+ throw new ContextDisposedError();
23
+ }
24
+ return guard;
25
+ })(),
26
+ );
27
+ };
@@ -8,7 +8,8 @@ import { asyncTimeout } from '@dxos/async';
8
8
  import { getHeads } from '@dxos/automerge/automerge';
9
9
  import { AutomergeContext } from '@dxos/echo-db';
10
10
  import { AutomergeHost, DataServiceImpl } from '@dxos/echo-pipeline';
11
- import { createTestLevel } from '@dxos/echo-pipeline/testing';
11
+ import { IndexMetadataStore } from '@dxos/indexing';
12
+ import { createTestLevel } from '@dxos/kv-store/testing';
12
13
  import { afterTest, describe, test } from '@dxos/test';
13
14
 
14
15
  describe('AutomergeHost', () => {
@@ -26,6 +27,7 @@ describe('AutomergeHost', () => {
26
27
 
27
28
  const host = new AutomergeHost({
28
29
  db: level.sublevel('automerge'),
30
+ indexMetadataStore: new IndexMetadataStore({ db: level.sublevel('index-metadata') }),
29
31
  });
30
32
  await host.open();
31
33
  afterTest(() => host.close());
@@ -2,8 +2,6 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { type Level } from 'level';
6
-
7
5
  import { Trigger } from '@dxos/async';
8
6
  import { Context, Resource } from '@dxos/context';
9
7
  import { getCredentialAssertion, type CredentialProcessor } from '@dxos/credentials';
@@ -14,6 +12,7 @@ import { FeedFactory, FeedStore } from '@dxos/feed-store';
14
12
  import { invariant } from '@dxos/invariant';
15
13
  import { Keyring } from '@dxos/keyring';
16
14
  import { PublicKey } from '@dxos/keys';
15
+ import { type LevelDB } from '@dxos/kv-store';
17
16
  import { log } from '@dxos/log';
18
17
  import { type SignalManager } from '@dxos/messaging';
19
18
  import { type NetworkManager } from '@dxos/network-manager';
@@ -22,6 +21,7 @@ import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
22
21
  import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
23
22
  import { type Credential, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
24
23
  import { type Storage } from '@dxos/random-access-storage';
24
+ import type { TeleportParams } from '@dxos/teleport';
25
25
  import { BlobStore } from '@dxos/teleport-extension-object-sync';
26
26
  import { trace as Trace } from '@dxos/tracing';
27
27
  import { safeInstanceof } from '@dxos/util';
@@ -41,7 +41,8 @@ import {
41
41
  import { InvitationsManager } from '../invitations/invitations-manager';
42
42
  import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
43
43
 
44
- export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams;
44
+ export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams &
45
+ DataSpaceManagerRuntimeParams & { invitationConnectionDefaultParams?: Partial<TeleportParams> };
45
46
  /**
46
47
  * Shared backend for all client services.
47
48
  */
@@ -79,10 +80,10 @@ export class ServiceContext extends Resource {
79
80
 
80
81
  constructor(
81
82
  public readonly storage: Storage,
82
- public readonly level: Level<string, string>,
83
+ public readonly level: LevelDB,
83
84
  public readonly networkManager: NetworkManager,
84
85
  public readonly signalManager: SignalManager,
85
- public readonly _runtimeParams?: IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams,
86
+ public readonly _runtimeParams?: ServiceContextRuntimeParams,
86
87
  ) {
87
88
  super();
88
89
 
@@ -124,7 +125,7 @@ export class ServiceContext extends Resource {
124
125
  storage: this.storage,
125
126
  });
126
127
 
127
- this.invitations = new InvitationsHandler(this.networkManager);
128
+ this.invitations = new InvitationsHandler(this.networkManager, _runtimeParams?.invitationConnectionDefaultParams);
128
129
  this.invitationsManager = new InvitationsManager(
129
130
  this.invitations,
130
131
  (invitation) => this.getInvitationHandler(invitation),
@@ -2,16 +2,15 @@
2
2
  // Copyright 2021 DXOS.org
3
3
  //
4
4
 
5
- import { type Level } from 'level';
6
-
7
5
  import { Event, synchronized } from '@dxos/async';
8
6
  import { clientServiceBundle, defaultKey, type ClientServices, Properties } from '@dxos/client-protocol';
9
7
  import { type Config } from '@dxos/config';
10
8
  import { Context } from '@dxos/context';
11
- import { type ObjectStructure, encodeReference, type SpaceDoc, type LevelDB } from '@dxos/echo-pipeline';
9
+ import { type ObjectStructure, encodeReference, type SpaceDoc } from '@dxos/echo-protocol';
12
10
  import { getTypeReference } from '@dxos/echo-schema';
13
11
  import { invariant } from '@dxos/invariant';
14
12
  import { PublicKey } from '@dxos/keys';
13
+ import { type LevelDB } from '@dxos/kv-store';
15
14
  import { log } from '@dxos/log';
16
15
  import { WebsocketSignalManager, type SignalManager } from '@dxos/messaging';
17
16
  import { NetworkManager, createSimplePeerTransportFactory, type TransportFactory } from '@dxos/network-manager';
@@ -82,7 +81,7 @@ export class ClientServicesHost {
82
81
  private _signalManager?: SignalManager;
83
82
  private _networkManager?: NetworkManager;
84
83
  private _storage?: Storage;
85
- private _level?: Level<string, string>;
84
+ private _level?: LevelDB;
86
85
  private _callbacks?: ClientServicesHostCallbacks;
87
86
  private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
88
87
 
@@ -7,8 +7,9 @@ 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
9
  import { type EchoHost } from '@dxos/echo-db';
10
- import { type MetadataStore, type Space, createMappedFeedWriter, type SpaceDoc } from '@dxos/echo-pipeline';
10
+ import { type MetadataStore, type Space, createMappedFeedWriter } from '@dxos/echo-pipeline';
11
11
  import { AutomergeDocumentLoaderImpl } from '@dxos/echo-pipeline';
12
+ import { type SpaceDoc } from '@dxos/echo-protocol';
12
13
  import { TYPE_PROPERTIES } from '@dxos/echo-schema';
13
14
  import { type FeedStore } from '@dxos/feed-store';
14
15
  import { failedInvariant, invariant } from '@dxos/invariant';
@@ -2,10 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Level } from 'level';
6
5
  import path from 'node:path';
7
6
 
8
7
  import { PublicKey } from '@dxos/keys';
8
+ import { createLevel as createKV } from '@dxos/kv-store';
9
9
  import { type Runtime } from '@dxos/protocols/proto/dxos/config';
10
10
 
11
11
  import { getRootPath, isPersistent } from './util';
@@ -13,7 +13,7 @@ import { getRootPath, isPersistent } from './util';
13
13
  export const createLevel = async (config: Runtime.Client.Storage) => {
14
14
  const persistent = isPersistent(config);
15
15
  const storagePath = persistent ? path.join(getRootPath(config), 'level') : `/tmp/dxos-${PublicKey.random().toHex()}`;
16
- const level = new Level<string, string>(storagePath);
16
+ const level = createKV(storagePath);
17
17
  // TODO(dmaretskyi): This function shouldn't call open - .
18
18
  await level.open();
19
19
  return level;
@@ -45,6 +45,7 @@ export type PerformInvitationParams = {
45
45
  guest?: PerformInvitationCallbacks<AuthenticatingInvitation>;
46
46
  };
47
47
  guestDeviceProfile?: DeviceProfileDocument;
48
+ codeInputDelay?: number;
48
49
  };
49
50
 
50
51
  export type Result = { invitation?: Invitation; error?: Error };
@@ -55,7 +56,10 @@ export const performInvitation = ({
55
56
  options,
56
57
  hooks,
57
58
  guestDeviceProfile,
59
+ codeInputDelay,
58
60
  }: PerformInvitationParams): [Promise<Result>, Promise<Result>] => {
61
+ let guestError = false;
62
+ let guestConnected = false;
59
63
  const hostComplete = new Trigger<Result>();
60
64
  const guestComplete = new Trigger<Result>();
61
65
  const authCode = new Trigger<string>();
@@ -65,6 +69,10 @@ export const performInvitation = ({
65
69
  async (hostInvitation: Invitation) => {
66
70
  switch (hostInvitation.state) {
67
71
  case Invitation.State.CONNECTING: {
72
+ if (guestConnected) {
73
+ break;
74
+ }
75
+ guestConnected = true;
68
76
  if (hooks?.host?.onConnecting?.(hostObservable)) {
69
77
  break;
70
78
  }
@@ -89,7 +97,16 @@ export const performInvitation = ({
89
97
  if (hooks?.guest?.onReady?.(guestObservable)) {
90
98
  break;
91
99
  }
92
- await guestObservable.authenticate(await authCode.wait());
100
+ const code = await authCode.wait();
101
+ if (codeInputDelay == null) {
102
+ await guestObservable.authenticate(code);
103
+ } else {
104
+ setTimeout(async () => {
105
+ if (!guestError) {
106
+ await guestObservable.authenticate(code);
107
+ }
108
+ }, codeInputDelay);
109
+ }
93
110
  break;
94
111
  }
95
112
 
@@ -123,6 +140,7 @@ export const performInvitation = ({
123
140
  }
124
141
  },
125
142
  (error: Error) => {
143
+ guestError = true;
126
144
  if (hooks?.guest?.onError?.(guestObservable)) {
127
145
  return;
128
146
  }
@@ -216,8 +234,10 @@ const acceptInvitation = (
216
234
  invitation = sanitizeInvitation(invitation);
217
235
 
218
236
  if (guest instanceof ServiceContext) {
219
- const guestHandler = guest.getInvitationHandler({ kind: invitation.kind });
220
- return guest.invitations.acceptInvitation(guestHandler, invitation, guestDeviceProfile);
237
+ return guest.invitationsManager.acceptInvitation({
238
+ invitation,
239
+ deviceProfile: guestDeviceProfile,
240
+ });
221
241
  }
222
242
 
223
243
  return guest.join(invitation, guestDeviceProfile);
@@ -7,10 +7,11 @@ import { Context } from '@dxos/context';
7
7
  import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
8
8
  import { failUndefined } from '@dxos/debug';
9
9
  import { EchoHost } from '@dxos/echo-db';
10
- import { MetadataStore, type LevelDB, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
11
- import { createTestLevel } from '@dxos/echo-pipeline/testing';
10
+ import { MetadataStore, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
12
11
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
13
12
  import { Keyring } from '@dxos/keyring';
13
+ import { type LevelDB } from '@dxos/kv-store';
14
+ import { createTestLevel } from '@dxos/kv-store/testing';
14
15
  import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
15
16
  import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
16
17
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
@@ -48,7 +49,9 @@ export const createServiceContext = async ({
48
49
  const level = createTestLevel();
49
50
  await level.open();
50
51
 
51
- return new ServiceContext(storage, level, networkManager, signalManager);
52
+ return new ServiceContext(storage, level, networkManager, signalManager, {
53
+ invitationConnectionDefaultParams: { controlHeartbeatInterval: 200 },
54
+ });
52
55
  };
53
56
 
54
57
  export const createPeers = async (numPeers: number) => {
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.5.1-main.ef0d69d";
1
+ export const DXOS_VERSION = "0.5.1-main.f81ddc4";