@dxos/client-services 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5
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-ERQJUBAW.mjs → chunk-HYGNOM23.mjs} +4279 -3342
- package/dist/lib/browser/chunk-HYGNOM23.mjs.map +7 -0
- package/dist/lib/browser/chunk-NQSC7HOE.mjs +22 -0
- package/dist/lib/browser/chunk-NQSC7HOE.mjs.map +7 -0
- package/dist/lib/browser/chunk-QCWEHHJW.mjs +24 -0
- package/dist/lib/browser/chunk-QCWEHHJW.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +539 -98
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/browser.mjs +126 -0
- package/dist/lib/browser/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/node.mjs +66 -0
- package/dist/lib/browser/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +45 -26
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs +24 -0
- package/dist/lib/node-esm/chunk-2SZHAWBN.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-TMEG7JOG.mjs → chunk-GFT7MAQE.mjs} +3764 -2695
- package/dist/lib/node-esm/chunk-GFT7MAQE.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs +22 -0
- package/dist/lib/node-esm/chunk-PKEGMOQ4.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +539 -98
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +93 -0
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +11 -0
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs +126 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs +66 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +45 -26
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +3 -2
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts +3 -2
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +20 -20
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts +1 -1
- package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +2 -3
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/index.d.ts +1 -1
- package/dist/types/src/packlets/diagnostics/index.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +2 -2
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +7 -7
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +7 -6
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +6 -10
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +9 -12
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +6 -5
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +2 -2
- package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/index.d.ts +1 -1
- package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +8 -5
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-state.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -4
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts +3 -3
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +4 -4
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +5 -4
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/index.d.ts +2 -2
- package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +5 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +7 -6
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +5 -5
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
- package/dist/types/src/packlets/services/feed-syncer.d.ts +59 -0
- package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/platform.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +14 -9
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +21 -8
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/archive-format.d.ts +9 -0
- package/dist/types/src/packlets/space-export/archive-format.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/index.d.ts +4 -1
- package/dist/types/src/packlets/space-export/index.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +23 -0
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +36 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +8 -2
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/automerge-space-state.d.ts +1 -1
- package/dist/types/src/packlets/spaces/automerge-space-state.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +29 -17
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +30 -13
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +2 -2
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +6 -6
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +18 -8
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/profile-archive.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +6 -3
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +8 -7
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts +41 -4
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-session.d.ts +2 -4
- package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +72 -48
- package/src/index.ts +1 -0
- package/src/packlets/agents/edge-agent-manager.ts +10 -7
- package/src/packlets/agents/edge-agent-service.ts +17 -5
- package/src/packlets/devices/devices-service.test.ts +3 -3
- package/src/packlets/devices/devices-service.ts +2 -2
- package/src/packlets/devtools/devtools.ts +29 -29
- package/src/packlets/devtools/feeds.ts +2 -2
- package/src/packlets/devtools/network.ts +1 -1
- package/src/packlets/diagnostics/browser-diagnostics-broadcast.ts +1 -1
- package/src/packlets/diagnostics/diagnostics-broadcast.ts +1 -1
- package/src/packlets/diagnostics/diagnostics-collector.ts +1 -1
- package/src/packlets/diagnostics/diagnostics.ts +2 -3
- package/src/packlets/diagnostics/index.ts +1 -1
- package/src/packlets/identity/authenticator.node.test.ts +1 -1
- package/src/packlets/identity/authenticator.ts +3 -3
- package/src/packlets/identity/contacts-service.ts +2 -2
- package/src/packlets/identity/identity-manager.test.ts +8 -8
- package/src/packlets/identity/identity-manager.ts +23 -20
- package/src/packlets/identity/identity-recovery-manager.ts +22 -18
- package/src/packlets/identity/identity-service.test.ts +8 -28
- package/src/packlets/identity/identity-service.ts +13 -80
- package/src/packlets/identity/identity.test.ts +11 -11
- package/src/packlets/identity/identity.ts +17 -39
- package/src/packlets/invitations/device-invitation-protocol.test.ts +4 -4
- package/src/packlets/invitations/device-invitation-protocol.ts +8 -6
- package/src/packlets/invitations/edge-invitation-handler.ts +10 -6
- package/src/packlets/invitations/index.ts +1 -1
- package/src/packlets/invitations/invitation-guest-extenstion.ts +7 -5
- package/src/packlets/invitations/invitation-host-extension.ts +8 -6
- package/src/packlets/invitations/invitation-protocol.ts +8 -5
- package/src/packlets/invitations/invitation-state.ts +0 -10
- package/src/packlets/invitations/invitations-handler.test.ts +301 -292
- package/src/packlets/invitations/invitations-handler.ts +72 -16
- package/src/packlets/invitations/invitations-manager.ts +43 -18
- package/src/packlets/invitations/invitations-service.ts +10 -10
- package/src/packlets/invitations/space-invitation-protocol.test.ts +26 -25
- package/src/packlets/invitations/space-invitation-protocol.ts +13 -17
- package/src/packlets/invitations/utils.ts +1 -1
- package/src/packlets/locks/browser.ts +1 -1
- package/src/packlets/locks/index.ts +2 -2
- package/src/packlets/logging/logging-service.ts +8 -3
- package/src/packlets/logging/logging.test.ts +1 -1
- package/src/packlets/network/network-service.test.ts +3 -3
- package/src/packlets/network/network-service.ts +12 -10
- package/src/packlets/services/client-rpc-server.ts +20 -17
- package/src/packlets/services/feed-syncer.test.ts +340 -0
- package/src/packlets/services/feed-syncer.ts +337 -0
- package/src/packlets/services/platform.ts +7 -1
- package/src/packlets/services/service-context.test.ts +4 -3
- package/src/packlets/services/service-context.ts +145 -59
- package/src/packlets/services/service-host.test.ts +10 -9
- package/src/packlets/services/service-host.ts +85 -38
- package/src/packlets/services/service-registry.test.ts +1 -1
- package/src/packlets/space-export/archive-format.ts +42 -0
- package/src/packlets/space-export/index.ts +4 -1
- package/src/packlets/space-export/serialized-space-reader.ts +111 -0
- package/src/packlets/space-export/serialized-space-writer.ts +246 -0
- package/src/packlets/space-export/space-archive-reader.ts +65 -4
- package/src/packlets/space-export/space-archive-writer.ts +44 -6
- package/src/packlets/space-export/space-archive.test.ts +461 -0
- package/src/packlets/space-export/tar.test.ts +1 -1
- package/src/packlets/spaces/automerge-space-state.ts +1 -1
- package/src/packlets/spaces/data-space-manager.test.ts +79 -13
- package/src/packlets/spaces/data-space-manager.ts +131 -118
- package/src/packlets/spaces/data-space.ts +65 -39
- package/src/packlets/spaces/edge-feed-replicator.test.ts +4 -4
- package/src/packlets/spaces/edge-feed-replicator.ts +13 -11
- package/src/packlets/spaces/epoch-migrations.ts +5 -5
- package/src/packlets/spaces/genesis.ts +6 -1
- package/src/packlets/spaces/notarization-plugin.test.ts +3 -3
- package/src/packlets/spaces/notarization-plugin.ts +13 -12
- package/src/packlets/spaces/spaces-service.test.ts +20 -12
- package/src/packlets/spaces/spaces-service.ts +138 -38
- package/src/packlets/storage/profile-archive.ts +1 -1
- package/src/packlets/storage/storage.ts +7 -8
- package/src/packlets/system/system-service.test.ts +1 -1
- package/src/packlets/system/system-service.ts +4 -4
- package/src/packlets/testing/invitation-utils.ts +11 -7
- package/src/packlets/testing/test-builder.ts +39 -13
- package/src/packlets/worker/worker-runtime.ts +180 -17
- package/src/packlets/worker/worker-session.ts +15 -21
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-ERQJUBAW.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-TMEG7JOG.mjs.map +0 -7
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
- package/src/packlets/identity/default-space-state-machine.ts +0 -44
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type PushStream,
|
|
5
|
+
import { type PushStream, TimeoutError, type Trigger, scheduleTask } from '@dxos/async';
|
|
6
6
|
import { INVITATION_TIMEOUT, getExpirationTime } from '@dxos/client-protocol';
|
|
7
7
|
import { type Context, ContextDisposedError } from '@dxos/context';
|
|
8
8
|
import { createKeyPair, sign } from '@dxos/crypto';
|
|
@@ -10,19 +10,19 @@ import { type EdgeHttpClient } from '@dxos/edge-client';
|
|
|
10
10
|
import { invariant } from '@dxos/invariant';
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
|
-
import {
|
|
13
|
+
import { type SwarmConnection, type SwarmNetworkManager, createTeleportProtocolFactory } from '@dxos/network-manager';
|
|
14
14
|
import { InvalidInvitationError, InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
|
|
15
15
|
import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
16
16
|
import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
17
17
|
import { AuthenticationResponse, type IntroductionResponse } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
18
18
|
import { InvitationOptions } from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
19
|
-
import { type ExtensionContext, type TeleportExtension, type
|
|
19
|
+
import { type ExtensionContext, type TeleportExtension, type TeleportProps } from '@dxos/teleport';
|
|
20
20
|
import { trace as _trace } from '@dxos/tracing';
|
|
21
21
|
import { ComplexSet } from '@dxos/util';
|
|
22
22
|
|
|
23
23
|
import { type EdgeInvitationConfig, EdgeInvitationHandler } from './edge-invitation-handler';
|
|
24
24
|
import { InvitationGuestExtension } from './invitation-guest-extenstion';
|
|
25
|
-
import { InvitationHostExtension,
|
|
25
|
+
import { InvitationHostExtension, MAX_OTP_ATTEMPTS, isAuthenticationRequired } from './invitation-host-extension';
|
|
26
26
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
27
27
|
import { createGuardedInvitationState } from './invitation-state';
|
|
28
28
|
import { InvitationTopology } from './invitation-topology';
|
|
@@ -31,8 +31,8 @@ const metrics = _trace.metrics;
|
|
|
31
31
|
|
|
32
32
|
const MAX_DELEGATED_INVITATION_HOST_TRIES = 3;
|
|
33
33
|
|
|
34
|
-
export type
|
|
35
|
-
teleport: Partial<
|
|
34
|
+
export type InvitationConnectionProps = {
|
|
35
|
+
teleport: Partial<TeleportProps>;
|
|
36
36
|
edgeInvitations?: EdgeInvitationConfig;
|
|
37
37
|
};
|
|
38
38
|
|
|
@@ -64,6 +64,7 @@ export type InvitationConnectionParams = {
|
|
|
64
64
|
* TODO: the flow logic should either be contained in invitations-handler or in extensions, not be split across
|
|
65
65
|
* TODO: potentially re-evaluate host-side API to allow multiple concurrent connection, so that mutex can be removed
|
|
66
66
|
*/
|
|
67
|
+
@_trace.resource()
|
|
67
68
|
export class InvitationsHandler {
|
|
68
69
|
/**
|
|
69
70
|
* @internal
|
|
@@ -71,7 +72,7 @@ export class InvitationsHandler {
|
|
|
71
72
|
constructor(
|
|
72
73
|
private readonly _networkManager: SwarmNetworkManager,
|
|
73
74
|
private readonly _edgeClient?: EdgeHttpClient,
|
|
74
|
-
private readonly
|
|
75
|
+
private readonly _connectionProps?: InvitationConnectionProps,
|
|
75
76
|
) {}
|
|
76
77
|
|
|
77
78
|
handleInvitationFlow(
|
|
@@ -87,6 +88,33 @@ export class InvitationsHandler {
|
|
|
87
88
|
type: invitation.type,
|
|
88
89
|
});
|
|
89
90
|
metrics.increment('dxos.invitation.host');
|
|
91
|
+
|
|
92
|
+
const hostSpanId = `invitation-host-${invitation.invitationId}`;
|
|
93
|
+
// Reassign ctx to the child context so downstream `@trace.span` calls stay in the same trace.
|
|
94
|
+
// Link child -> parent disposal so `ctx.dispose()` inside this flow still completes the
|
|
95
|
+
// invitation stream (the caller's ctx owns `stream.complete()` via onDispose).
|
|
96
|
+
// Do NOT await `invitationCtx.dispose()` here: `derive()` registers a parent -> child
|
|
97
|
+
// dispose hook, so awaiting the parent dispose would re-enter the still-pending child
|
|
98
|
+
// dispose promise and deadlock.
|
|
99
|
+
const invitationCtx = ctx;
|
|
100
|
+
ctx =
|
|
101
|
+
_trace.spanStart({
|
|
102
|
+
id: hostSpanId,
|
|
103
|
+
instance: this,
|
|
104
|
+
methodName: 'handleInvitationFlow',
|
|
105
|
+
parentCtx: ctx,
|
|
106
|
+
op: 'invitation.host',
|
|
107
|
+
attributes: {
|
|
108
|
+
'ctx.dxos.invitation.id': invitation.invitationId,
|
|
109
|
+
'ctx.dxos.invitation.kind': Invitation.Kind[invitation.kind],
|
|
110
|
+
},
|
|
111
|
+
}) ?? ctx;
|
|
112
|
+
if (ctx !== invitationCtx) {
|
|
113
|
+
ctx.onDispose(() => {
|
|
114
|
+
void invitationCtx.dispose();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
ctx.onDispose(() => _trace.spanEnd(hostSpanId));
|
|
90
118
|
const guardedState = createGuardedInvitationState(ctx, invitation, stream);
|
|
91
119
|
// Called for every connecting peer.
|
|
92
120
|
const createExtension = (): InvitationHostExtension => {
|
|
@@ -200,7 +228,7 @@ export class InvitationsHandler {
|
|
|
200
228
|
ctx,
|
|
201
229
|
async () => {
|
|
202
230
|
// ensure the swarm is closed before changing state and closing the stream.
|
|
203
|
-
await swarmConnection.close();
|
|
231
|
+
await swarmConnection.close(ctx);
|
|
204
232
|
guardedState.set(null, Invitation.State.EXPIRED);
|
|
205
233
|
metrics.increment('dxos.invitation.expired');
|
|
206
234
|
await ctx.dispose();
|
|
@@ -232,6 +260,34 @@ export class InvitationsHandler {
|
|
|
232
260
|
});
|
|
233
261
|
const { timeout = INVITATION_TIMEOUT } = invitation;
|
|
234
262
|
|
|
263
|
+
const guestSpanId = `invitation-guest-${invitation.invitationId}`;
|
|
264
|
+
// Reassign ctx to the child context returned by spanStart so downstream calls
|
|
265
|
+
// (`edgeInvitationHandler.handle`, `_joinSwarm`, etc.) inherit this span as their
|
|
266
|
+
// parent rather than starting a new root trace.
|
|
267
|
+
// Link child -> parent disposal so `ctx.dispose()` inside this flow still completes the
|
|
268
|
+
// invitation stream. See note in `handleInvitationFlow`: must not await the parent
|
|
269
|
+
// dispose here (`derive()` registers a parent -> child dispose hook, so awaiting would
|
|
270
|
+
// re-enter the still-pending child dispose promise and deadlock).
|
|
271
|
+
const invitationCtx = ctx;
|
|
272
|
+
ctx =
|
|
273
|
+
_trace.spanStart({
|
|
274
|
+
id: guestSpanId,
|
|
275
|
+
instance: this,
|
|
276
|
+
methodName: 'acceptInvitation',
|
|
277
|
+
parentCtx: ctx,
|
|
278
|
+
op: 'invitation.guest',
|
|
279
|
+
attributes: {
|
|
280
|
+
'ctx.dxos.invitation.id': invitation.invitationId,
|
|
281
|
+
'ctx.dxos.invitation.kind': Invitation.Kind[invitation.kind],
|
|
282
|
+
},
|
|
283
|
+
}) ?? ctx;
|
|
284
|
+
if (ctx !== invitationCtx) {
|
|
285
|
+
ctx.onDispose(() => {
|
|
286
|
+
void invitationCtx.dispose();
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
ctx.onDispose(() => _trace.spanEnd(guestSpanId));
|
|
290
|
+
|
|
235
291
|
if (deviceProfile) {
|
|
236
292
|
invariant(invitation.kind === Invitation.Kind.DEVICE, 'deviceProfile provided for non-device invitation');
|
|
237
293
|
}
|
|
@@ -345,7 +401,7 @@ export class InvitationsHandler {
|
|
|
345
401
|
admitted = true;
|
|
346
402
|
|
|
347
403
|
// 4. Record credential in our HALO.
|
|
348
|
-
const result = await protocol.accept(admissionResponse, admissionRequest);
|
|
404
|
+
const result = await protocol.accept(ctx, admissionResponse, admissionRequest);
|
|
349
405
|
|
|
350
406
|
// 5. Success.
|
|
351
407
|
log.verbose('dxos.sdk.invitations-handler.guest.admitted-by-host', {
|
|
@@ -388,9 +444,9 @@ export class InvitationsHandler {
|
|
|
388
444
|
return extension;
|
|
389
445
|
};
|
|
390
446
|
|
|
391
|
-
const edgeInvitationHandler = new EdgeInvitationHandler(this.
|
|
392
|
-
onInvitationSuccess: async (admissionResponse, admissionRequest) => {
|
|
393
|
-
const result = await protocol.accept(admissionResponse, admissionRequest);
|
|
447
|
+
const edgeInvitationHandler = new EdgeInvitationHandler(this._connectionProps?.edgeInvitations, this._edgeClient, {
|
|
448
|
+
onInvitationSuccess: async (edgeCtx, admissionResponse, admissionRequest) => {
|
|
449
|
+
const result = await protocol.accept(edgeCtx, admissionResponse, admissionRequest);
|
|
394
450
|
log.info('admitted by edge', { ...protocol.toJSON() });
|
|
395
451
|
guardedState.complete({ ...guardedState.current, ...result, state: Invitation.State.SUCCESS });
|
|
396
452
|
},
|
|
@@ -436,15 +492,15 @@ export class InvitationsHandler {
|
|
|
436
492
|
} else {
|
|
437
493
|
label = `invitation host for space ${invitation.spaceKey?.truncate()}`;
|
|
438
494
|
}
|
|
439
|
-
const swarmConnection = await this._networkManager.joinSwarm({
|
|
495
|
+
const swarmConnection = await this._networkManager.joinSwarm(ctx, {
|
|
440
496
|
topic: invitation.swarmKey,
|
|
441
497
|
protocolProvider: createTeleportProtocolFactory(async (teleport) => {
|
|
442
498
|
teleport.addExtension('dxos.halo.invitations', extensionFactory());
|
|
443
|
-
}, this.
|
|
499
|
+
}, this._connectionProps?.teleport),
|
|
444
500
|
topology: new InvitationTopology(role),
|
|
445
501
|
label,
|
|
446
502
|
});
|
|
447
|
-
ctx.onDispose(() => swarmConnection.close());
|
|
503
|
+
ctx.onDispose(() => swarmConnection.close(ctx));
|
|
448
504
|
return swarmConnection;
|
|
449
505
|
}
|
|
450
506
|
|
|
@@ -503,7 +559,7 @@ export class InvitationsHandler {
|
|
|
503
559
|
const checkInvitation = (protocol: InvitationProtocol, invitation: Partial<Invitation>) => {
|
|
504
560
|
const expiresOn = getExpirationTime(invitation);
|
|
505
561
|
if (expiresOn && expiresOn.getTime() < Date.now()) {
|
|
506
|
-
return new InvalidInvitationError('Invitation already expired.');
|
|
562
|
+
return new InvalidInvitationError({ message: 'Invitation already expired.' });
|
|
507
563
|
}
|
|
508
564
|
return protocol.checkInvitation(invitation);
|
|
509
565
|
};
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
import { Event, PushStream, TimeoutError, Trigger } from '@dxos/async';
|
|
6
6
|
import {
|
|
7
|
-
AuthenticatingInvitation,
|
|
8
7
|
AUTHENTICATION_CODE_LENGTH,
|
|
8
|
+
AuthenticatingInvitation,
|
|
9
9
|
CancellableInvitation,
|
|
10
10
|
INVITATION_TIMEOUT,
|
|
11
11
|
} from '@dxos/client-protocol';
|
|
12
12
|
import { Context } from '@dxos/context';
|
|
13
13
|
import { generatePasscode } from '@dxos/credentials';
|
|
14
|
-
import {
|
|
14
|
+
import { type MetadataStore, hasInvitationExpired } from '@dxos/echo-pipeline';
|
|
15
15
|
import { invariant } from '@dxos/invariant';
|
|
16
16
|
import { PublicKey } from '@dxos/keys';
|
|
17
17
|
import { log } from '@dxos/log';
|
|
@@ -21,14 +21,16 @@ import {
|
|
|
21
21
|
Invitation,
|
|
22
22
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
23
23
|
import { SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
24
|
+
import { trace } from '@dxos/tracing';
|
|
24
25
|
|
|
25
26
|
import type { InvitationProtocol } from './invitation-protocol';
|
|
26
|
-
import {
|
|
27
|
+
import { type InvitationsHandler, createAdmissionKeypair } from './invitations-handler';
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Entry point for creating and accepting invitations, keeps track of existing invitation set and
|
|
30
31
|
* emits events when the set changes.
|
|
31
32
|
*/
|
|
33
|
+
@trace.resource()
|
|
32
34
|
export class InvitationsManager {
|
|
33
35
|
private readonly _createInvitations = new Map<string, CancellableInvitation>();
|
|
34
36
|
private readonly _acceptInvitations = new Map<string, AuthenticatingInvitation>();
|
|
@@ -48,7 +50,11 @@ export class InvitationsManager {
|
|
|
48
50
|
private readonly _metadataStore: MetadataStore,
|
|
49
51
|
) {}
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
@trace.span({ showInBrowserTimeline: true, op: 'lifecycle' })
|
|
54
|
+
async createInvitation(
|
|
55
|
+
ctx: Context,
|
|
56
|
+
options: Partial<Invitation> & Pick<Invitation, 'kind'>,
|
|
57
|
+
): Promise<CancellableInvitation> {
|
|
52
58
|
if (options.invitationId) {
|
|
53
59
|
const existingInvitation = this._createInvitations.get(options.invitationId);
|
|
54
60
|
if (existingInvitation) {
|
|
@@ -63,7 +69,11 @@ export class InvitationsManager {
|
|
|
63
69
|
}
|
|
64
70
|
const invitation = this._createInvitation(handler, options);
|
|
65
71
|
|
|
66
|
-
const {
|
|
72
|
+
const {
|
|
73
|
+
ctx: invitationCtx,
|
|
74
|
+
stream,
|
|
75
|
+
observableInvitation,
|
|
76
|
+
} = this._createObservableInvitation(ctx, handler, invitation);
|
|
67
77
|
|
|
68
78
|
this._createInvitations.set(invitation.invitationId, observableInvitation);
|
|
69
79
|
this.invitationCreated.emit(invitation);
|
|
@@ -84,12 +94,12 @@ export class InvitationsManager {
|
|
|
84
94
|
return observableInvitation;
|
|
85
95
|
}
|
|
86
96
|
|
|
87
|
-
this._invitationsHandler.handleInvitationFlow(
|
|
97
|
+
this._invitationsHandler.handleInvitationFlow(invitationCtx, stream, handler, observableInvitation.get());
|
|
88
98
|
|
|
89
99
|
return observableInvitation;
|
|
90
100
|
}
|
|
91
101
|
|
|
92
|
-
async loadPersistentInvitations(): Promise<{ invitations: Invitation[] }> {
|
|
102
|
+
async loadPersistentInvitations(ctx: Context): Promise<{ invitations: Invitation[] }> {
|
|
93
103
|
if (this._persistentInvitationsLoaded) {
|
|
94
104
|
const invitations = this.getCreatedInvitations().filter((i) => i.persistent);
|
|
95
105
|
return { invitations };
|
|
@@ -101,7 +111,7 @@ export class InvitationsManager {
|
|
|
101
111
|
|
|
102
112
|
const loadTasks = freshInvitations.map((persistentInvitation) => {
|
|
103
113
|
invariant(!this._createInvitations.get(persistentInvitation.invitationId), 'invitation already exists');
|
|
104
|
-
return this.createInvitation({ ...persistentInvitation, persistent: false });
|
|
114
|
+
return this.createInvitation(ctx, { ...persistentInvitation, persistent: false });
|
|
105
115
|
});
|
|
106
116
|
const cInvitations = await Promise.all(loadTasks);
|
|
107
117
|
|
|
@@ -115,7 +125,7 @@ export class InvitationsManager {
|
|
|
115
125
|
}
|
|
116
126
|
}
|
|
117
127
|
|
|
118
|
-
acceptInvitation(request: AcceptInvitationRequest): AuthenticatingInvitation {
|
|
128
|
+
acceptInvitation(ctx: Context, request: AcceptInvitationRequest): AuthenticatingInvitation {
|
|
119
129
|
const options = request.invitation;
|
|
120
130
|
const existingInvitation = this._acceptInvitations.get(options.invitationId);
|
|
121
131
|
if (existingInvitation) {
|
|
@@ -123,8 +133,20 @@ export class InvitationsManager {
|
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
const handler = this._getHandler(options);
|
|
126
|
-
const {
|
|
127
|
-
|
|
136
|
+
const {
|
|
137
|
+
ctx: invitationCtx,
|
|
138
|
+
invitation,
|
|
139
|
+
stream,
|
|
140
|
+
otpEnteredTrigger,
|
|
141
|
+
} = this._createObservableAcceptingInvitation(ctx, handler, options);
|
|
142
|
+
this._invitationsHandler.acceptInvitation(
|
|
143
|
+
invitationCtx,
|
|
144
|
+
stream,
|
|
145
|
+
handler,
|
|
146
|
+
options,
|
|
147
|
+
otpEnteredTrigger,
|
|
148
|
+
request.deviceProfile,
|
|
149
|
+
);
|
|
128
150
|
this._acceptInvitations.set(invitation.get().invitationId, invitation);
|
|
129
151
|
this.invitationAccepted.emit(invitation.get());
|
|
130
152
|
|
|
@@ -198,7 +220,7 @@ export class InvitationsManager {
|
|
|
198
220
|
state = Invitation.State.INIT,
|
|
199
221
|
timeout = INVITATION_TIMEOUT,
|
|
200
222
|
swarmKey = PublicKey.random(),
|
|
201
|
-
persistent = _options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY,
|
|
223
|
+
persistent = _options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY,
|
|
202
224
|
created = new Date(),
|
|
203
225
|
guestKeypair = undefined,
|
|
204
226
|
role = SpaceMember.Role.ADMIN,
|
|
@@ -232,17 +254,18 @@ export class InvitationsManager {
|
|
|
232
254
|
}
|
|
233
255
|
|
|
234
256
|
private _createObservableInvitation(
|
|
257
|
+
ctx: Context,
|
|
235
258
|
handler: InvitationProtocol,
|
|
236
259
|
invitation: Invitation,
|
|
237
260
|
): { ctx: Context; stream: PushStream<Invitation>; observableInvitation: CancellableInvitation } {
|
|
238
261
|
const stream = new PushStream<Invitation>();
|
|
239
|
-
const
|
|
262
|
+
const invitationCtx = ctx.derive({
|
|
240
263
|
onError: (err) => {
|
|
241
264
|
stream.error(err);
|
|
242
|
-
void
|
|
265
|
+
void invitationCtx.dispose();
|
|
243
266
|
},
|
|
244
267
|
});
|
|
245
|
-
|
|
268
|
+
invitationCtx.onDispose(() => {
|
|
246
269
|
log('complete', { ...handler.toJSON() });
|
|
247
270
|
stream.complete();
|
|
248
271
|
});
|
|
@@ -251,13 +274,14 @@ export class InvitationsManager {
|
|
|
251
274
|
subscriber: stream.observable,
|
|
252
275
|
onCancel: async () => {
|
|
253
276
|
stream.next({ ...invitation, state: Invitation.State.CANCELLED });
|
|
254
|
-
await
|
|
277
|
+
await invitationCtx.dispose();
|
|
255
278
|
},
|
|
256
279
|
});
|
|
257
|
-
return { ctx, stream, observableInvitation };
|
|
280
|
+
return { ctx: invitationCtx, stream, observableInvitation };
|
|
258
281
|
}
|
|
259
282
|
|
|
260
283
|
private _createObservableAcceptingInvitation(
|
|
284
|
+
parentCtx: Context,
|
|
261
285
|
handler: InvitationProtocol,
|
|
262
286
|
initialState: Invitation,
|
|
263
287
|
): {
|
|
@@ -268,7 +292,8 @@ export class InvitationsManager {
|
|
|
268
292
|
} {
|
|
269
293
|
const otpEnteredTrigger = new Trigger<string>();
|
|
270
294
|
const stream = new PushStream<Invitation>();
|
|
271
|
-
|
|
295
|
+
// Derive from caller ctx so `TRACE_SPAN_ATTRIBUTE` propagates via the parent chain.
|
|
296
|
+
const ctx = parentCtx.derive({
|
|
272
297
|
onError: (err) => {
|
|
273
298
|
if (err instanceof TimeoutError) {
|
|
274
299
|
log('timeout', { ...handler.toJSON() });
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Stream } from '@dxos/codec-protobuf
|
|
5
|
+
import { type RequestOptions, Stream } from '@dxos/codec-protobuf';
|
|
6
6
|
import {
|
|
7
|
-
type AuthenticationRequest,
|
|
8
7
|
type AcceptInvitationRequest,
|
|
8
|
+
type AuthenticationRequest,
|
|
9
9
|
type Invitation,
|
|
10
10
|
type InvitationsService,
|
|
11
11
|
QueryInvitationsResponse,
|
|
@@ -27,23 +27,23 @@ export class InvitationsServiceImpl implements InvitationsService {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
createInvitation(
|
|
31
|
-
return new Stream<Invitation>(({ next, close }) => {
|
|
30
|
+
createInvitation(request: Invitation, options?: RequestOptions): Stream<Invitation> {
|
|
31
|
+
return new Stream<Invitation>(({ ctx, next, close }) => {
|
|
32
32
|
void this._invitationsManager
|
|
33
|
-
.createInvitation(
|
|
33
|
+
.createInvitation(ctx, request)
|
|
34
34
|
.then((invitation) => {
|
|
35
35
|
trace.metrics.increment('dxos.invitation.created');
|
|
36
36
|
invitation.subscribe(next, close, close);
|
|
37
37
|
})
|
|
38
38
|
.catch(close);
|
|
39
|
-
});
|
|
39
|
+
}, options?.ctx);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
acceptInvitation(request: AcceptInvitationRequest): Stream<Invitation> {
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
acceptInvitation(request: AcceptInvitationRequest, options?: RequestOptions): Stream<Invitation> {
|
|
43
|
+
return new Stream<Invitation>(({ ctx, next, close }) => {
|
|
44
|
+
const invitation = this._invitationsManager.acceptInvitation(ctx, request);
|
|
45
45
|
invitation.subscribe(next, close, close);
|
|
46
|
-
});
|
|
46
|
+
}, options?.ctx);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
async authenticate(request: AuthenticationRequest): Promise<void> {
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { Trigger, chain } from '@dxos/async';
|
|
8
|
+
import { Context } from '@dxos/context';
|
|
8
9
|
import { raise } from '@dxos/debug';
|
|
9
10
|
import { AlreadyJoinedError } from '@dxos/protocols';
|
|
10
11
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
@@ -22,28 +23,28 @@ const closeAfterTest = async (peer: ServiceContext) => {
|
|
|
22
23
|
|
|
23
24
|
describe('services/space-invitations-protocol', () => {
|
|
24
25
|
test('genesis', async () => {
|
|
25
|
-
const [peer] = await
|
|
26
|
+
const [peer] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(1));
|
|
26
27
|
|
|
27
|
-
const space = await peer.dataSpaceManager!.createSpace();
|
|
28
|
+
const space = await peer.dataSpaceManager!.createSpace(new Context());
|
|
28
29
|
expect(peer.dataSpaceManager!.spaces.has(space.key)).to.be.true;
|
|
29
30
|
|
|
30
|
-
await space.close();
|
|
31
|
+
await space.close(new Context());
|
|
31
32
|
});
|
|
32
33
|
|
|
33
34
|
test('genesis & ready', async () => {
|
|
34
|
-
const [peer] = await
|
|
35
|
+
const [peer] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(1));
|
|
35
36
|
|
|
36
|
-
const space = await peer.dataSpaceManager!.createSpace();
|
|
37
|
+
const space = await peer.dataSpaceManager!.createSpace(new Context());
|
|
37
38
|
expect(peer.dataSpaceManager!.spaces.has(space.key)).to.be.true;
|
|
38
39
|
|
|
39
40
|
await peer.dataSpaceManager?.waitUntilSpaceReady(space.key);
|
|
40
|
-
await space.close();
|
|
41
|
+
await space.close(new Context());
|
|
41
42
|
});
|
|
42
43
|
|
|
43
44
|
test('invitation with no auth', async () => {
|
|
44
|
-
const [host, guest] = await
|
|
45
|
+
const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
|
|
45
46
|
|
|
46
|
-
const space1 = await host.dataSpaceManager!.createSpace();
|
|
47
|
+
const space1 = await host.dataSpaceManager!.createSpace(new Context());
|
|
47
48
|
const spaceKey = space1.key;
|
|
48
49
|
|
|
49
50
|
await Promise.all(performInvitation({ host, guest, options: { kind: Invitation.Kind.SPACE, spaceKey } }));
|
|
@@ -59,15 +60,15 @@ describe('services/space-invitations-protocol', () => {
|
|
|
59
60
|
|
|
60
61
|
await space2.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.timeframe);
|
|
61
62
|
|
|
62
|
-
await space1.close();
|
|
63
|
-
await space2.close();
|
|
63
|
+
await space1.close(new Context());
|
|
64
|
+
await space2.close(new Context());
|
|
64
65
|
}
|
|
65
66
|
});
|
|
66
67
|
|
|
67
68
|
test('invitation when already joined', async () => {
|
|
68
|
-
const [host, guest] = await
|
|
69
|
+
const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
|
|
69
70
|
|
|
70
|
-
const space1 = await host.dataSpaceManager!.createSpace();
|
|
71
|
+
const space1 = await host.dataSpaceManager!.createSpace(new Context());
|
|
71
72
|
const spaceKey = space1.key;
|
|
72
73
|
|
|
73
74
|
await Promise.all(performInvitation({ host, guest, options: { kind: Invitation.Kind.SPACE, spaceKey } }));
|
|
@@ -92,11 +93,11 @@ describe('services/space-invitations-protocol', () => {
|
|
|
92
93
|
});
|
|
93
94
|
|
|
94
95
|
test('creates and accepts invitation with retry', async () => {
|
|
95
|
-
const [host, guest] = await
|
|
96
|
+
const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
|
|
96
97
|
|
|
97
98
|
let attempt = 0;
|
|
98
99
|
|
|
99
|
-
const space1 = await host.dataSpaceManager!.createSpace();
|
|
100
|
+
const space1 = await host.dataSpaceManager!.createSpace(new Context());
|
|
100
101
|
|
|
101
102
|
const [{ invitation: invitation1, error: error1 }, { invitation: invitation2, error: error2 }] = await Promise.all(
|
|
102
103
|
performInvitation({
|
|
@@ -143,8 +144,8 @@ describe('services/space-invitations-protocol', () => {
|
|
|
143
144
|
|
|
144
145
|
await space2.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.timeframe);
|
|
145
146
|
|
|
146
|
-
await space1.close();
|
|
147
|
-
await space2.close();
|
|
147
|
+
await space1.close(new Context());
|
|
148
|
+
await space2.close(new Context());
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
expect(
|
|
@@ -153,15 +154,15 @@ describe('services/space-invitations-protocol', () => {
|
|
|
153
154
|
});
|
|
154
155
|
|
|
155
156
|
test('timeout', async () => {
|
|
156
|
-
const [host, guest] = await
|
|
157
|
-
const space = await host.dataSpaceManager!.createSpace();
|
|
157
|
+
const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
|
|
158
|
+
const space = await host.dataSpaceManager!.createSpace(new Context());
|
|
158
159
|
const hostInvitation = await createInvitation(host, {
|
|
159
160
|
kind: Invitation.Kind.SPACE,
|
|
160
161
|
spaceKey: space.key,
|
|
161
162
|
timeout: 100,
|
|
162
163
|
});
|
|
163
164
|
const invitation = hostInvitation.get();
|
|
164
|
-
await host.close();
|
|
165
|
+
await host.close(Context.default());
|
|
165
166
|
|
|
166
167
|
const guestTimeout = new Trigger();
|
|
167
168
|
const guestInvitation = await acceptInvitation(guest, invitation);
|
|
@@ -175,12 +176,12 @@ describe('services/space-invitations-protocol', () => {
|
|
|
175
176
|
});
|
|
176
177
|
|
|
177
178
|
test('cancels invitation', async () => {
|
|
178
|
-
const [host, guest] = await
|
|
179
|
+
const [host, guest] = await chain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
|
|
179
180
|
|
|
180
181
|
const hostConnected = new Trigger<Invitation>();
|
|
181
182
|
const guestConnected = new Trigger<Invitation>();
|
|
182
183
|
|
|
183
|
-
const space1 = await host.dataSpaceManager!.createSpace();
|
|
184
|
+
const space1 = await host.dataSpaceManager!.createSpace(new Context());
|
|
184
185
|
|
|
185
186
|
const invitationPromises = performInvitation({
|
|
186
187
|
host,
|
|
@@ -213,7 +214,7 @@ describe('services/space-invitations-protocol', () => {
|
|
|
213
214
|
expect(invitation1?.state).to.eq(Invitation.State.CANCELLED);
|
|
214
215
|
expect(error).to.exist;
|
|
215
216
|
|
|
216
|
-
await space1.close();
|
|
217
|
+
await space1.close(new Context());
|
|
217
218
|
});
|
|
218
219
|
|
|
219
220
|
// TODO(burdon): Flaky.
|
|
@@ -223,7 +224,7 @@ describe('services/space-invitations-protocol', () => {
|
|
|
223
224
|
// createPeers(GUEST_COUNT + 1)
|
|
224
225
|
// );
|
|
225
226
|
|
|
226
|
-
// const hostSpace = await host.dataSpaceManager!.createSpace();
|
|
227
|
+
// const hostSpace = await host.dataSpaceManager!.createSpace(new Context());
|
|
227
228
|
// const swarmKey = PublicKey.random();
|
|
228
229
|
// const hostObservable = await host.spaceInvitations!.createInvitation(hostSpace, {
|
|
229
230
|
// swarmKey,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Context } from '@dxos/context';
|
|
5
6
|
import {
|
|
6
7
|
createCancelDelegatedSpaceInvitationCredential,
|
|
7
8
|
createDelegatedSpaceInvitationCredential,
|
|
@@ -12,24 +13,18 @@ import { invariant } from '@dxos/invariant';
|
|
|
12
13
|
import { type Keyring } from '@dxos/keyring';
|
|
13
14
|
import { type PublicKey } from '@dxos/keys';
|
|
14
15
|
import { log } from '@dxos/log';
|
|
15
|
-
import {
|
|
16
|
-
AlreadyJoinedError,
|
|
17
|
-
type ApiError,
|
|
18
|
-
AuthorizationError,
|
|
19
|
-
InvalidInvitationError,
|
|
20
|
-
SpaceNotFoundError,
|
|
21
|
-
} from '@dxos/protocols';
|
|
16
|
+
import { AlreadyJoinedError, AuthorizationError, InvalidInvitationError, SpaceNotFoundError } from '@dxos/protocols';
|
|
22
17
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
23
|
-
import {
|
|
18
|
+
import { type ProfileDocument, SpaceMember } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
24
19
|
import {
|
|
25
20
|
type AdmissionRequest,
|
|
26
21
|
type AdmissionResponse,
|
|
27
22
|
type IntroductionRequest,
|
|
28
23
|
} from '@dxos/protocols/proto/dxos/halo/invitations';
|
|
29
24
|
|
|
25
|
+
import { type DataSpaceManager, type SigningContext } from '../spaces';
|
|
30
26
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
31
27
|
import { computeExpirationTime } from './utils';
|
|
32
|
-
import { type DataSpaceManager, type SigningContext } from '../spaces';
|
|
33
28
|
|
|
34
29
|
export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
35
30
|
constructor(
|
|
@@ -47,16 +42,16 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
47
42
|
};
|
|
48
43
|
}
|
|
49
44
|
|
|
50
|
-
checkCanInviteNewMembers():
|
|
45
|
+
checkCanInviteNewMembers(): Error | undefined {
|
|
51
46
|
if (this._spaceKey == null) {
|
|
52
|
-
return new InvalidInvitationError('No spaceKey was provided for a space invitation.');
|
|
47
|
+
return new InvalidInvitationError({ message: 'No spaceKey was provided for a space invitation.' });
|
|
53
48
|
}
|
|
54
49
|
const space = this._spaceManager.spaces.get(this._spaceKey);
|
|
55
50
|
if (space == null) {
|
|
56
51
|
return new SpaceNotFoundError(this._spaceKey);
|
|
57
52
|
}
|
|
58
53
|
if (!space?.inner.spaceState.hasMembershipManagementPermission(this._signingContext.identityKey)) {
|
|
59
|
-
return new AuthorizationError('No member management permission.');
|
|
54
|
+
return new AuthorizationError({ message: 'No member management permission.' });
|
|
60
55
|
}
|
|
61
56
|
return undefined;
|
|
62
57
|
}
|
|
@@ -147,10 +142,10 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
147
142
|
|
|
148
143
|
checkInvitation(invitation: Partial<Invitation>): InvalidInvitationError | AlreadyJoinedError | undefined {
|
|
149
144
|
if (invitation.spaceKey == null) {
|
|
150
|
-
return new InvalidInvitationError('No spaceKey was provided for a space invitation.');
|
|
145
|
+
return new InvalidInvitationError({ message: 'No spaceKey was provided for a space invitation.' });
|
|
151
146
|
}
|
|
152
147
|
if (this._spaceManager.spaces.has(invitation.spaceKey)) {
|
|
153
|
-
return new AlreadyJoinedError('Already joined space.');
|
|
148
|
+
return new AlreadyJoinedError({ message: 'Already joined space.' });
|
|
154
149
|
}
|
|
155
150
|
}
|
|
156
151
|
|
|
@@ -175,7 +170,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
175
170
|
};
|
|
176
171
|
}
|
|
177
172
|
|
|
178
|
-
async accept(response: AdmissionResponse): Promise<Partial<Invitation>> {
|
|
173
|
+
async accept(ctx: Context, response: AdmissionResponse): Promise<Partial<Invitation>> {
|
|
179
174
|
invariant(response.space);
|
|
180
175
|
const { credential, controlTimeframe, dataTimeframe } = response.space;
|
|
181
176
|
const assertion = getCredentialAssertion(credential);
|
|
@@ -183,15 +178,16 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
|
|
|
183
178
|
invariant(credential.subject.id.equals(this._signingContext.identityKey));
|
|
184
179
|
|
|
185
180
|
if (this._spaceManager.spaces.has(assertion.spaceKey)) {
|
|
186
|
-
throw new AlreadyJoinedError('Already joined space.');
|
|
181
|
+
throw new AlreadyJoinedError({ message: 'Already joined space.' });
|
|
187
182
|
}
|
|
188
183
|
|
|
189
184
|
// Create local space.
|
|
190
|
-
await this._spaceManager.acceptSpace({
|
|
185
|
+
await this._spaceManager.acceptSpace(ctx, {
|
|
191
186
|
spaceKey: assertion.spaceKey,
|
|
192
187
|
genesisFeedKey: assertion.genesisFeedKey,
|
|
193
188
|
controlTimeframe,
|
|
194
189
|
dataTimeframe,
|
|
190
|
+
tags: assertion.tags,
|
|
195
191
|
});
|
|
196
192
|
|
|
197
193
|
await this._signingContext.recordCredential(credential);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Mutex, type MutexGuard } from '@dxos/async';
|
|
6
|
-
import {
|
|
6
|
+
import { type Context, ContextDisposedError, cancelWithContext } from '@dxos/context';
|
|
7
7
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
8
8
|
|
|
9
9
|
export const stateToString = (state: Invitation.State): string => {
|