@dxos/client-services 0.5.1-main.f02b2c7 → 0.5.1-main.f2d5836
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.
- package/dist/lib/browser/{chunk-T3ZIANWR.mjs → chunk-CZKKHM32.mjs} +1381 -1004
- package/dist/lib/browser/chunk-CZKKHM32.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +31 -2
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +29 -9
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-425TJE5X.cjs → chunk-T34IF5GF.cjs} +1576 -1207
- package/dist/lib/node/chunk-T34IF5GF.cjs.map +7 -0
- package/dist/lib/node/index.cjs +73 -44
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +35 -15
- package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
- package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +2 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts +39 -0
- package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/{invitation-extension.d.ts → invitation-host-extension.d.ts} +17 -31
- package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +6 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-topology.d.ts +37 -0
- package/dist/types/src/packlets/invitations/invitation-topology.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +19 -10
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.test.d.ts +2 -0
- package/dist/types/src/packlets/invitations/invitations-handler.test.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts +2 -1
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -0
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/utils.d.ts +6 -0
- package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -0
- package/dist/types/src/packlets/services/service-context.d.ts +8 -5
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/level.d.ts +1 -2
- package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +2 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +2 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/shell-runtime.d.ts +10 -2
- package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/package.json +36 -35
- package/src/packlets/diagnostics/diagnostics-collector.ts +14 -9
- package/src/packlets/diagnostics/diagnostics.ts +78 -68
- package/src/packlets/invitations/device-invitation-protocol.ts +5 -1
- package/src/packlets/invitations/invitation-guest-extenstion.ts +126 -0
- package/src/packlets/invitations/{invitation-extension.ts → invitation-host-extension.ts} +99 -105
- package/src/packlets/invitations/invitation-protocol.ts +7 -1
- package/src/packlets/invitations/invitation-topology.ts +87 -0
- package/src/packlets/invitations/invitations-handler.test.ts +361 -0
- package/src/packlets/invitations/invitations-handler.ts +246 -149
- package/src/packlets/invitations/invitations-manager.ts +45 -3
- package/src/packlets/invitations/space-invitation-protocol.ts +23 -3
- package/src/packlets/invitations/utils.ts +27 -0
- package/src/packlets/services/automerge-host.test.ts +3 -1
- package/src/packlets/services/service-context.ts +7 -6
- package/src/packlets/services/service-host.ts +5 -6
- package/src/packlets/spaces/data-space.ts +4 -2
- package/src/packlets/spaces/genesis.ts +1 -1
- package/src/packlets/spaces/spaces-service.ts +12 -6
- package/src/packlets/storage/level.ts +2 -2
- package/src/packlets/testing/invitation-utils.ts +23 -3
- package/src/packlets/testing/test-builder.ts +6 -3
- package/src/packlets/vault/shell-runtime.ts +40 -2
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-T3ZIANWR.mjs.map +0 -7
- package/dist/lib/node/chunk-425TJE5X.cjs.map +0 -7
- package/dist/types/src/packlets/invitations/invitation-extension.d.ts.map +0 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Event, PushStream } from '@dxos/async';
|
|
5
|
+
import { Event, PushStream, TimeoutError, Trigger } from '@dxos/async';
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
AuthenticatingInvitation,
|
|
8
8
|
AUTHENTICATION_CODE_LENGTH,
|
|
9
9
|
CancellableInvitation,
|
|
10
10
|
INVITATION_TIMEOUT,
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type AuthenticationRequest,
|
|
21
21
|
Invitation,
|
|
22
22
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
23
|
+
import { SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
23
24
|
|
|
24
25
|
import type { InvitationProtocol } from './invitation-protocol';
|
|
25
26
|
import { createAdmissionKeypair, type InvitationsHandler } from './invitations-handler';
|
|
@@ -117,7 +118,8 @@ export class InvitationsManager {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
const handler = this._getHandler(options);
|
|
120
|
-
const invitation = this.
|
|
121
|
+
const { ctx, invitation, stream, otpEnteredTrigger } = this._createObservableAcceptingInvitation(handler, options);
|
|
122
|
+
this._invitationsHandler.acceptInvitation(ctx, stream, handler, options, otpEnteredTrigger, request.deviceProfile);
|
|
121
123
|
this._acceptInvitations.set(invitation.get().invitationId, invitation);
|
|
122
124
|
this.invitationAccepted.emit(invitation.get());
|
|
123
125
|
|
|
@@ -149,6 +151,10 @@ export class InvitationsManager {
|
|
|
149
151
|
if (created.get().persistent) {
|
|
150
152
|
await this._metadataStore.removeInvitation(invitationId);
|
|
151
153
|
}
|
|
154
|
+
if (created.get().type === Invitation.Type.DELEGATED) {
|
|
155
|
+
const handler = this._getHandler(created.get());
|
|
156
|
+
await handler.cancelDelegation(created.get());
|
|
157
|
+
}
|
|
152
158
|
await created.cancel();
|
|
153
159
|
this._createInvitations.delete(invitationId);
|
|
154
160
|
this.removedCreated.emit(created.get());
|
|
@@ -190,6 +196,7 @@ export class InvitationsManager {
|
|
|
190
196
|
persistent = options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY, // default no not storing keypairs
|
|
191
197
|
created = new Date(),
|
|
192
198
|
guestKeypair = undefined,
|
|
199
|
+
role = SpaceMember.Role.ADMIN,
|
|
193
200
|
lifetime = 86400, // 1 day,
|
|
194
201
|
multiUse = false,
|
|
195
202
|
} = options ?? {};
|
|
@@ -210,6 +217,7 @@ export class InvitationsManager {
|
|
|
210
217
|
guestKeypair ?? (authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? createAdmissionKeypair() : undefined),
|
|
211
218
|
created,
|
|
212
219
|
lifetime,
|
|
220
|
+
role,
|
|
213
221
|
multiUse,
|
|
214
222
|
delegationCredentialId: options?.delegationCredentialId,
|
|
215
223
|
...protocol.getInvitationContext(),
|
|
@@ -239,6 +247,40 @@ export class InvitationsManager {
|
|
|
239
247
|
return { ctx, stream, observableInvitation };
|
|
240
248
|
}
|
|
241
249
|
|
|
250
|
+
private _createObservableAcceptingInvitation(handler: InvitationProtocol, initialState: Invitation) {
|
|
251
|
+
const otpEnteredTrigger = new Trigger<string>();
|
|
252
|
+
const stream = new PushStream<Invitation>();
|
|
253
|
+
const ctx = new Context({
|
|
254
|
+
onError: (err) => {
|
|
255
|
+
if (err instanceof TimeoutError) {
|
|
256
|
+
log('timeout', { ...handler.toJSON() });
|
|
257
|
+
stream.next({ ...initialState, state: Invitation.State.TIMEOUT });
|
|
258
|
+
} else {
|
|
259
|
+
log.warn('auth failed', err);
|
|
260
|
+
stream.next({ ...initialState, state: Invitation.State.ERROR });
|
|
261
|
+
}
|
|
262
|
+
void ctx.dispose();
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
ctx.onDispose(() => {
|
|
266
|
+
log('complete', { ...handler.toJSON() });
|
|
267
|
+
stream.complete();
|
|
268
|
+
});
|
|
269
|
+
const invitation = new AuthenticatingInvitation({
|
|
270
|
+
initialInvitation: initialState,
|
|
271
|
+
subscriber: stream.observable,
|
|
272
|
+
onCancel: async () => {
|
|
273
|
+
stream.next({ ...initialState, state: Invitation.State.CANCELLED });
|
|
274
|
+
await ctx.dispose();
|
|
275
|
+
},
|
|
276
|
+
onAuthenticate: async (code: string) => {
|
|
277
|
+
// TODO(burdon): Reset creates a race condition? Event?
|
|
278
|
+
otpEnteredTrigger.wake(code);
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
return { ctx, invitation, stream, otpEnteredTrigger };
|
|
282
|
+
}
|
|
283
|
+
|
|
242
284
|
private async _persistIfRequired(
|
|
243
285
|
handler: InvitationProtocol,
|
|
244
286
|
changeStream: PushStream<Invitation>,
|
|
@@ -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';
|
|
@@ -53,7 +54,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
53
54
|
guestProfile?: ProfileDocument | undefined,
|
|
54
55
|
): Promise<AdmissionResponse> {
|
|
55
56
|
invariant(this._spaceKey);
|
|
56
|
-
const space =
|
|
57
|
+
const space = this._spaceManager.spaces.get(this._spaceKey);
|
|
57
58
|
invariant(space);
|
|
58
59
|
|
|
59
60
|
invariant(request.space);
|
|
@@ -66,6 +67,8 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
66
67
|
identityKey,
|
|
67
68
|
space.key,
|
|
68
69
|
space.inner.genesisFeedKey,
|
|
70
|
+
invitation.role ?? SpaceMember.Role.ADMIN,
|
|
71
|
+
space.inner.spaceState.membershipChainHeads,
|
|
69
72
|
guestProfile,
|
|
70
73
|
invitation.delegationCredentialId,
|
|
71
74
|
);
|
|
@@ -87,7 +90,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
87
90
|
|
|
88
91
|
async delegate(invitation: Invitation): Promise<PublicKey> {
|
|
89
92
|
invariant(this._spaceKey);
|
|
90
|
-
const space =
|
|
93
|
+
const space = this._spaceManager.spaces.get(this._spaceKey);
|
|
91
94
|
invariant(space);
|
|
92
95
|
if (invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY) {
|
|
93
96
|
invariant(invitation.guestKeypair?.publicKey);
|
|
@@ -101,7 +104,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
101
104
|
invitationId: invitation.invitationId,
|
|
102
105
|
authMethod: invitation.authMethod,
|
|
103
106
|
swarmKey: invitation.swarmKey,
|
|
104
|
-
role: SpaceMember.Role.ADMIN,
|
|
107
|
+
role: invitation.role ?? SpaceMember.Role.ADMIN,
|
|
105
108
|
expiresOn: invitation.lifetime
|
|
106
109
|
? new Date((invitation.created?.getTime() ?? Date.now()) + invitation.lifetime)
|
|
107
110
|
: undefined,
|
|
@@ -118,6 +121,23 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
118
121
|
return credential.credential.credential.id!;
|
|
119
122
|
}
|
|
120
123
|
|
|
124
|
+
async cancelDelegation(invitation: Invitation): Promise<void> {
|
|
125
|
+
invariant(this._spaceKey);
|
|
126
|
+
invariant(invitation.type === Invitation.Type.DELEGATED && invitation.delegationCredentialId);
|
|
127
|
+
const space = this._spaceManager.spaces.get(this._spaceKey);
|
|
128
|
+
invariant(space);
|
|
129
|
+
|
|
130
|
+
log('cancelling delegated space invitation', { host: this._signingContext.deviceKey, id: invitation.invitationId });
|
|
131
|
+
const credential = await createCancelDelegatedSpaceInvitationCredential(
|
|
132
|
+
this._signingContext.credentialSigner,
|
|
133
|
+
space.key,
|
|
134
|
+
invitation.delegationCredentialId,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
invariant(credential.credential);
|
|
138
|
+
await writeMessages(space.inner.controlPipeline.writer, [credential]);
|
|
139
|
+
}
|
|
140
|
+
|
|
121
141
|
checkInvitation(invitation: Partial<Invitation>) {
|
|
122
142
|
if (invitation.spaceKey && this._spaceManager.spaces.has(invitation.spaceKey)) {
|
|
123
143
|
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 {
|
|
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 &
|
|
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:
|
|
83
|
+
public readonly level: LevelDB,
|
|
83
84
|
public readonly networkManager: NetworkManager,
|
|
84
85
|
public readonly signalManager: SignalManager,
|
|
85
|
-
public readonly _runtimeParams?:
|
|
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
|
|
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?:
|
|
84
|
+
private _level?: LevelDB;
|
|
86
85
|
private _callbacks?: ClientServicesHostCallbacks;
|
|
87
86
|
private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
|
|
88
87
|
|
|
@@ -340,10 +339,10 @@ export class ClientServicesHost {
|
|
|
340
339
|
const traceId = PublicKey.random().toHex();
|
|
341
340
|
log.trace('dxos.sdk.client-services-host.reset', trace.begin({ id: traceId }));
|
|
342
341
|
|
|
343
|
-
log('resetting...');
|
|
342
|
+
log.info('resetting...');
|
|
344
343
|
await this._serviceContext?.close();
|
|
345
344
|
await this._storage!.reset();
|
|
346
|
-
log('reset');
|
|
345
|
+
log.info('reset');
|
|
347
346
|
log.trace('dxos.sdk.client-services-host.reset', trace.end({ id: traceId }));
|
|
348
347
|
await this._callbacks?.onReset?.();
|
|
349
348
|
}
|
|
@@ -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
|
|
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';
|
|
@@ -19,6 +20,7 @@ import { CancelledError, SystemError } from '@dxos/protocols';
|
|
|
19
20
|
import { SpaceState, type Space as SpaceProto, CreateEpochRequest } from '@dxos/protocols/proto/dxos/client/services';
|
|
20
21
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
21
22
|
import { type SpaceCache } from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
23
|
+
import { SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
22
24
|
import {
|
|
23
25
|
AdmittedFeed,
|
|
24
26
|
type ProfileDocument,
|
|
@@ -122,7 +124,7 @@ export class DataSpace {
|
|
|
122
124
|
new ComplexSet(
|
|
123
125
|
PublicKey.hash,
|
|
124
126
|
Array.from(this._inner.spaceState.members.values())
|
|
125
|
-
.filter((member) =>
|
|
127
|
+
.filter((member) => member.role !== SpaceMember.Role.REMOVED)
|
|
126
128
|
.map((member) => member.key),
|
|
127
129
|
),
|
|
128
130
|
update: this._inner.stateUpdate,
|
|
@@ -36,7 +36,7 @@ export const spaceGenesis = async (
|
|
|
36
36
|
assertion: {
|
|
37
37
|
'@type': 'dxos.halo.credentials.SpaceMember',
|
|
38
38
|
spaceKey: space.key,
|
|
39
|
-
role: SpaceMember.Role.
|
|
39
|
+
role: SpaceMember.Role.OWNER,
|
|
40
40
|
profile: signingContext.getProfile(),
|
|
41
41
|
genesisFeedKey: space.controlFeedKey ?? failUndefined(),
|
|
42
42
|
},
|
|
@@ -22,8 +22,9 @@ import {
|
|
|
22
22
|
type SubscribeMessagesRequest,
|
|
23
23
|
type UpdateSpaceRequest,
|
|
24
24
|
type WriteCredentialsRequest,
|
|
25
|
+
type UpdateMemberRoleRequest,
|
|
25
26
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
26
|
-
import { type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
27
|
+
import { type Credential, SpaceMember as HaloSpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
27
28
|
import { type GossipMessage } from '@dxos/protocols/proto/dxos/mesh/teleport/gossip';
|
|
28
29
|
import { type Provider } from '@dxos/util';
|
|
29
30
|
|
|
@@ -67,6 +68,10 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
async updateMemberRole(_: UpdateMemberRoleRequest): Promise<void> {
|
|
72
|
+
throw new Error('not implemented');
|
|
73
|
+
}
|
|
74
|
+
|
|
70
75
|
querySpaces(): Stream<QuerySpacesResponse> {
|
|
71
76
|
return new Stream<QuerySpacesResponse>(({ next, ctx }) => {
|
|
72
77
|
const scheduler = new UpdateScheduler(
|
|
@@ -213,11 +218,12 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
213
218
|
identityKey: member.key,
|
|
214
219
|
profile: member.profile ?? {},
|
|
215
220
|
},
|
|
216
|
-
presence:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
+
presence:
|
|
222
|
+
member.role === HaloSpaceMember.Role.REMOVED
|
|
223
|
+
? SpaceMember.PresenceState.REMOVED
|
|
224
|
+
: isMe || peers.length > 0
|
|
225
|
+
? SpaceMember.PresenceState.ONLINE
|
|
226
|
+
: SpaceMember.PresenceState.OFFLINE,
|
|
221
227
|
peerStates: peers,
|
|
222
228
|
};
|
|
223
229
|
}),
|
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
|
|
220
|
-
|
|
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,
|
|
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) => {
|
|
@@ -6,7 +6,12 @@ import { Event } from '@dxos/async';
|
|
|
6
6
|
import { appServiceBundle, type AppServiceBundle, type ShellRuntime, shellServiceBundle } from '@dxos/client-protocol';
|
|
7
7
|
import { invariant } from '@dxos/invariant';
|
|
8
8
|
import { type PublicKey } from '@dxos/keys';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
type AppContextRequest,
|
|
11
|
+
type LayoutRequest,
|
|
12
|
+
ShellLayout,
|
|
13
|
+
type InvitationUrlRequest,
|
|
14
|
+
} from '@dxos/protocols/proto/dxos/iframe';
|
|
10
15
|
import { createProtoRpcPeer, type ProtoRpcPeer, type RpcPort } from '@dxos/rpc';
|
|
11
16
|
|
|
12
17
|
/**
|
|
@@ -14,11 +19,19 @@ import { createProtoRpcPeer, type ProtoRpcPeer, type RpcPort } from '@dxos/rpc';
|
|
|
14
19
|
*/
|
|
15
20
|
export class ShellRuntimeImpl implements ShellRuntime {
|
|
16
21
|
readonly layoutUpdate = new Event<LayoutRequest>();
|
|
22
|
+
readonly invitationUrlUpdate = new Event<InvitationUrlRequest>();
|
|
23
|
+
|
|
17
24
|
private _appRpc?: ProtoRpcPeer<AppServiceBundle>;
|
|
18
25
|
private _layout = ShellLayout.DEFAULT;
|
|
19
|
-
private _invitationCode?: string;
|
|
20
26
|
private _spaceKey?: PublicKey;
|
|
21
27
|
|
|
28
|
+
private _invitationCode?: string;
|
|
29
|
+
private _invitationUrl? = typeof window !== 'undefined' ? window.location.origin : undefined;
|
|
30
|
+
|
|
31
|
+
// TODO(burdon): Change to using underscores (coordinate with @dxos/web-auth).
|
|
32
|
+
private _deviceInvitationParam = 'deviceInvitationCode'; // TODO(burdon): device_invitation_code
|
|
33
|
+
private _spaceInvitationParam = 'spaceInvitationCode'; // TODO(burdon): space_invitation_code
|
|
34
|
+
|
|
22
35
|
constructor(private readonly _port: RpcPort) {}
|
|
23
36
|
|
|
24
37
|
get layout() {
|
|
@@ -33,6 +46,18 @@ export class ShellRuntimeImpl implements ShellRuntime {
|
|
|
33
46
|
return this._spaceKey;
|
|
34
47
|
}
|
|
35
48
|
|
|
49
|
+
get invitationUrl() {
|
|
50
|
+
return this._invitationUrl!;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get deviceInvitationParam() {
|
|
54
|
+
return this._deviceInvitationParam;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get spaceInvitationParam() {
|
|
58
|
+
return this._spaceInvitationParam;
|
|
59
|
+
}
|
|
60
|
+
|
|
36
61
|
setLayout({ layout, invitationCode, spaceKey }: LayoutRequest) {
|
|
37
62
|
this._layout = layout;
|
|
38
63
|
this._invitationCode = invitationCode;
|
|
@@ -40,6 +65,13 @@ export class ShellRuntimeImpl implements ShellRuntime {
|
|
|
40
65
|
this.layoutUpdate.emit({ layout, invitationCode, spaceKey });
|
|
41
66
|
}
|
|
42
67
|
|
|
68
|
+
setInvitationUrl({ invitationUrl, deviceInvitationParam, spaceInvitationParam }: InvitationUrlRequest) {
|
|
69
|
+
this._invitationUrl = invitationUrl;
|
|
70
|
+
this._deviceInvitationParam = deviceInvitationParam;
|
|
71
|
+
this._spaceInvitationParam = spaceInvitationParam;
|
|
72
|
+
this.invitationUrlUpdate.emit({ invitationUrl, deviceInvitationParam, spaceInvitationParam });
|
|
73
|
+
}
|
|
74
|
+
|
|
43
75
|
async setAppContext(context: AppContextRequest) {
|
|
44
76
|
invariant(this._appRpc, 'runtime not open');
|
|
45
77
|
|
|
@@ -58,6 +90,12 @@ export class ShellRuntimeImpl implements ShellRuntime {
|
|
|
58
90
|
this._spaceKey = request.spaceKey;
|
|
59
91
|
this.layoutUpdate.emit(request);
|
|
60
92
|
},
|
|
93
|
+
setInvitationUrl: async (request) => {
|
|
94
|
+
this._invitationUrl = request.invitationUrl;
|
|
95
|
+
this._deviceInvitationParam = request.deviceInvitationParam;
|
|
96
|
+
this._spaceInvitationParam = request.spaceInvitationParam;
|
|
97
|
+
this.invitationUrlUpdate.emit(request);
|
|
98
|
+
},
|
|
61
99
|
},
|
|
62
100
|
},
|
|
63
101
|
port: this._port,
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const DXOS_VERSION = "0.5.1-main.
|
|
1
|
+
export const DXOS_VERSION = "0.5.1-main.f2d5836";
|