@dxos/client-services 0.8.4-main.a4bbb77 → 0.8.4-main.abd8ff62ef
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-FZDVFED2.mjs → chunk-KW4WMU5R.mjs} +2698 -4599
- package/dist/lib/browser/chunk-KW4WMU5R.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/chunk-XJRPB3GA.mjs +22 -0
- package/dist/lib/browser/chunk-XJRPB3GA.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +490 -228
- 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 +88 -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 +86 -0
- package/dist/lib/browser/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/browser/packlets/locks/node.mjs +48 -0
- package/dist/lib/browser/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +60 -90
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-2DT3MZRL.mjs +22 -0
- package/dist/lib/node-esm/chunk-2DT3MZRL.mjs.map +7 -0
- 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-JDTIU3EP.mjs → chunk-NDMKP2CH.mjs} +2621 -4391
- package/dist/lib/node-esm/chunk-NDMKP2CH.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +490 -228
- 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 +88 -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 +86 -0
- package/dist/lib/node-esm/packlets/locks/browser.mjs.map +7 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs +48 -0
- package/dist/lib/node-esm/packlets/locks/node.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +60 -90
- 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 +2 -1
- 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 +2 -2
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/metadata.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts.map +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.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-collector.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.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +6 -6
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +8 -7
- 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 +8 -11
- 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 +1 -1
- package/dist/types/src/packlets/invitations/edge-invitation-handler.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 +7 -4
- 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/invitation-topology.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 +3 -3
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +4 -3
- 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/browser.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/index.d.ts +1 -1
- package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/node.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +4 -0
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +5 -4
- 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 +13 -9
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +20 -7
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/packlets/services/util.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 +7 -1
- 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.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +28 -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 +26 -9
- 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/epoch-migrations.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 -9
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +10 -7
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/level.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/storage/util.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/credential-utils.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 +6 -5
- 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/testing/setup.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 +70 -55
- package/src/index.ts +1 -0
- package/src/packlets/agents/edge-agent-manager.ts +8 -5
- package/src/packlets/agents/edge-agent-service.ts +15 -3
- package/src/packlets/devices/devices-service.test.ts +0 -1
- package/src/packlets/devices/devices-service.ts +1 -1
- package/src/packlets/devtools/devtools.ts +2 -3
- package/src/packlets/diagnostics/diagnostics.ts +1 -2
- package/src/packlets/diagnostics/index.ts +1 -1
- package/src/packlets/identity/authenticator.ts +2 -2
- package/src/packlets/identity/contacts-service.ts +0 -1
- package/src/packlets/identity/identity-manager.test.ts +5 -5
- package/src/packlets/identity/identity-manager.ts +23 -22
- package/src/packlets/identity/identity-recovery-manager.ts +22 -18
- package/src/packlets/identity/identity-service.test.ts +6 -27
- package/src/packlets/identity/identity-service.ts +13 -81
- package/src/packlets/identity/identity.test.ts +6 -6
- package/src/packlets/identity/identity.ts +11 -34
- package/src/packlets/invitations/device-invitation-protocol.ts +8 -7
- package/src/packlets/invitations/edge-invitation-handler.ts +9 -5
- package/src/packlets/invitations/invitation-guest-extenstion.ts +6 -4
- package/src/packlets/invitations/invitation-host-extension.ts +13 -14
- package/src/packlets/invitations/invitation-protocol.ts +7 -4
- package/src/packlets/invitations/invitation-state.ts +1 -15
- package/src/packlets/invitations/invitations-handler.test.ts +4 -5
- package/src/packlets/invitations/invitations-handler.ts +74 -22
- package/src/packlets/invitations/invitations-manager.ts +40 -15
- package/src/packlets/invitations/invitations-service.ts +9 -9
- package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
- package/src/packlets/invitations/space-invitation-protocol.ts +11 -16
- package/src/packlets/locks/index.ts +1 -1
- package/src/packlets/logging/logging-service.ts +20 -16
- package/src/packlets/network/network-service.test.ts +0 -1
- package/src/packlets/network/network-service.ts +10 -8
- package/src/packlets/services/client-rpc-server.ts +19 -16
- 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 +3 -2
- package/src/packlets/services/service-context.ts +138 -56
- package/src/packlets/services/service-host.test.ts +8 -8
- package/src/packlets/services/service-host.ts +70 -40
- package/src/packlets/services/service-registry.test.ts +0 -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 +253 -0
- package/src/packlets/space-export/space-archive-reader.ts +64 -3
- package/src/packlets/space-export/space-archive-writer.ts +41 -3
- package/src/packlets/space-export/space-archive.test.ts +461 -0
- package/src/packlets/spaces/data-space-manager.test.ts +79 -13
- package/src/packlets/spaces/data-space-manager.ts +115 -115
- package/src/packlets/spaces/data-space.ts +58 -33
- package/src/packlets/spaces/edge-feed-replicator.test.ts +2 -2
- package/src/packlets/spaces/edge-feed-replicator.ts +12 -10
- 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 +2 -2
- package/src/packlets/spaces/notarization-plugin.ts +10 -9
- package/src/packlets/spaces/spaces-service.test.ts +18 -11
- package/src/packlets/spaces/spaces-service.ts +123 -24
- package/src/packlets/storage/storage.ts +4 -4
- package/src/packlets/testing/invitation-utils.ts +10 -6
- package/src/packlets/testing/test-builder.ts +36 -10
- package/src/packlets/worker/worker-runtime.ts +188 -17
- package/src/packlets/worker/worker-session.ts +12 -18
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-FZDVFED2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JDTIU3EP.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
|
@@ -8,7 +8,7 @@ import { randomBytes, verify } from '@dxos/crypto';
|
|
|
8
8
|
import { InvariantViolation, invariant } from '@dxos/invariant';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
|
-
import { InvalidInvitationExtensionRoleError
|
|
11
|
+
import { InvalidInvitationExtensionRoleError } from '@dxos/protocols';
|
|
12
12
|
import { schema } from '@dxos/protocols/proto';
|
|
13
13
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
14
14
|
import { type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
@@ -110,8 +110,7 @@ export class InvitationHostExtension
|
|
|
110
110
|
|
|
111
111
|
introduce: async (request) => {
|
|
112
112
|
const { profile, invitationId } = request;
|
|
113
|
-
|
|
114
|
-
log.trace('dxos.sdk.invitation-handler.host.introduce', trace.begin({ id: traceId }));
|
|
113
|
+
log('introducing host invitation');
|
|
115
114
|
|
|
116
115
|
const invitation = this._requireActiveInvitation();
|
|
117
116
|
this._assertInvitationState(Invitation.State.CONNECTED);
|
|
@@ -131,7 +130,7 @@ export class InvitationHostExtension
|
|
|
131
130
|
this._challenge =
|
|
132
131
|
invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? randomBytes(32) : undefined;
|
|
133
132
|
|
|
134
|
-
log
|
|
133
|
+
log('introduced host invitation');
|
|
135
134
|
return {
|
|
136
135
|
authMethod: invitation.authMethod,
|
|
137
136
|
challenge: this._challenge,
|
|
@@ -139,8 +138,7 @@ export class InvitationHostExtension
|
|
|
139
138
|
},
|
|
140
139
|
|
|
141
140
|
authenticate: async ({ authCode: code, signedChallenge }) => {
|
|
142
|
-
|
|
143
|
-
log.trace('dxos.sdk.invitation-handler.host.authenticate', trace.begin({ id: traceId }));
|
|
141
|
+
log('authenticating host invitation');
|
|
144
142
|
|
|
145
143
|
const invitation = this._requireActiveInvitation();
|
|
146
144
|
log.verbose('received authentication request', { authCode: code });
|
|
@@ -201,13 +199,12 @@ export class InvitationHostExtension
|
|
|
201
199
|
return { status };
|
|
202
200
|
}
|
|
203
201
|
|
|
204
|
-
log
|
|
202
|
+
log('authenticated host invitation', { status });
|
|
205
203
|
return { status };
|
|
206
204
|
},
|
|
207
205
|
|
|
208
206
|
admit: async (request) => {
|
|
209
|
-
|
|
210
|
-
log.trace('dxos.sdk.invitation-handler.host.admit', trace.begin({ id: traceId }));
|
|
207
|
+
log('admitting guest');
|
|
211
208
|
const invitation = this._requireActiveInvitation();
|
|
212
209
|
|
|
213
210
|
try {
|
|
@@ -221,7 +218,7 @@ export class InvitationHostExtension
|
|
|
221
218
|
|
|
222
219
|
const response = await this._callbacks.admit(request);
|
|
223
220
|
|
|
224
|
-
log
|
|
221
|
+
log('admitted guest');
|
|
225
222
|
return response;
|
|
226
223
|
} catch (err: any) {
|
|
227
224
|
this._callbacks.onError(err);
|
|
@@ -245,10 +242,12 @@ export class InvitationHostExtension
|
|
|
245
242
|
await cancelWithContext(this._ctx, this._remoteOptionsTrigger.wait({ timeout: OPTIONS_TIMEOUT }));
|
|
246
243
|
log.verbose('options received');
|
|
247
244
|
if (this._remoteOptions?.role !== InvitationOptions.Role.GUEST) {
|
|
248
|
-
throw new InvalidInvitationExtensionRoleError(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
245
|
+
throw new InvalidInvitationExtensionRoleError({
|
|
246
|
+
context: {
|
|
247
|
+
expected: InvitationOptions.Role.GUEST,
|
|
248
|
+
remoteOptions: this._remoteOptions,
|
|
249
|
+
remotePeerId: context.remotePeerId,
|
|
250
|
+
},
|
|
252
251
|
});
|
|
253
252
|
}
|
|
254
253
|
this._callbacks.onStateUpdate(Invitation.State.CONNECTED);
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Context } from '@dxos/context';
|
|
5
6
|
import { type PublicKey } from '@dxos/keys';
|
|
6
|
-
import type { ApiError } from '@dxos/protocols';
|
|
7
7
|
import type { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
8
8
|
import type { DeviceProfileDocument, ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
9
9
|
import type {
|
|
@@ -26,7 +26,7 @@ export interface InvitationProtocol {
|
|
|
26
26
|
// Host
|
|
27
27
|
//
|
|
28
28
|
|
|
29
|
-
checkCanInviteNewMembers():
|
|
29
|
+
checkCanInviteNewMembers(): Error | undefined;
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Protocol-specific information to include in the invitation.
|
|
@@ -58,7 +58,7 @@ export interface InvitationProtocol {
|
|
|
58
58
|
*
|
|
59
59
|
* For example, the guest may already be a member of the space.
|
|
60
60
|
*/
|
|
61
|
-
checkInvitation(invitation: Partial<Invitation>):
|
|
61
|
+
checkInvitation(invitation: Partial<Invitation>): Error | undefined;
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Get profile information to send to the host to identify the guest.
|
|
@@ -72,6 +72,9 @@ export interface InvitationProtocol {
|
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* Redeem the admission credential.
|
|
75
|
+
* @param ctx - Caller context used for tracing and cancellation. Forwarded to downstream
|
|
76
|
+
* internal methods (e.g. `DataSpaceManager.acceptSpace`) so their spans become children of
|
|
77
|
+
* the invitation flow span.
|
|
75
78
|
*/
|
|
76
|
-
accept(response: AdmissionResponse, request: AdmissionRequest): Promise<Partial<Invitation>>;
|
|
79
|
+
accept(ctx: Context, response: AdmissionResponse, request: AdmissionRequest): Promise<Partial<Invitation>>;
|
|
77
80
|
}
|
|
@@ -31,12 +31,6 @@ export const createGuardedInvitationState = (
|
|
|
31
31
|
invitation: Invitation,
|
|
32
32
|
stream: PushStream<Invitation>,
|
|
33
33
|
): GuardedInvitationState => {
|
|
34
|
-
// the mutex guards invitation flow on host and guest side, making sure only one flow is currently active
|
|
35
|
-
// deadlocks seem very unlikely because hosts don't initiate multiple connections
|
|
36
|
-
// even if this somehow happens that there are 2 guests (A, B) and 2 hosts (1, 2) and:
|
|
37
|
-
// A has lock for flow with 1, B has lock for flow with 2
|
|
38
|
-
// 1 has lock for flow with B, 2 has lock for flow with A
|
|
39
|
-
// there'll be a 10-second introduction timeout after which connection will be closed and deadlock broken
|
|
40
34
|
const mutex = new Mutex();
|
|
41
35
|
let lastActiveLockHolder: FlowLockHolder | null = null;
|
|
42
36
|
let currentInvitation = { ...invitation };
|
|
@@ -44,9 +38,6 @@ export const createGuardedInvitationState = (
|
|
|
44
38
|
if (ctx.disposed || (lockHolder !== null && mutex.isLocked() && !lockHolder.hasFlowLock())) {
|
|
45
39
|
return false;
|
|
46
40
|
}
|
|
47
|
-
// don't allow transitions from a terminal state unless a new extension acquired mutex
|
|
48
|
-
// handles a case when error occurs (e.g. connection is closed) after we completed the flow
|
|
49
|
-
// successfully or already reported another error
|
|
50
41
|
return lockHolder == null || lastActiveLockHolder !== lockHolder || isNonTerminalState(currentInvitation.state);
|
|
51
42
|
};
|
|
52
43
|
return {
|
|
@@ -54,7 +45,6 @@ export const createGuardedInvitationState = (
|
|
|
54
45
|
get current() {
|
|
55
46
|
return currentInvitation;
|
|
56
47
|
},
|
|
57
|
-
// disposing context prevents any further state updates
|
|
58
48
|
complete: (newState: Partial<Invitation>) => {
|
|
59
49
|
logStateUpdate(currentInvitation, undefined, invitation.state);
|
|
60
50
|
currentInvitation = { ...currentInvitation, ...newState };
|
|
@@ -94,11 +84,7 @@ const logStateUpdate = (invitation: Invitation, actor: any, newState: Invitation
|
|
|
94
84
|
error: error?.message,
|
|
95
85
|
errorStack: error?.stack,
|
|
96
86
|
};
|
|
97
|
-
|
|
98
|
-
log.verbose('dxos.sdk.invitations-handler.state.update', logContext);
|
|
99
|
-
} else {
|
|
100
|
-
log.info('dxos.sdk.invitations-handler.state.update', logContext);
|
|
101
|
-
}
|
|
87
|
+
log.verbose('dxos.sdk.invitations-handler.state.update', logContext);
|
|
102
88
|
};
|
|
103
89
|
|
|
104
90
|
const isNonTerminalState = (currentState: Invitation.State): boolean => {
|
|
@@ -12,7 +12,6 @@ import { openAndClose } from '@dxos/test-utils';
|
|
|
12
12
|
import { range } from '@dxos/util';
|
|
13
13
|
|
|
14
14
|
import { TestBuilder, type TestPeer } from '../testing';
|
|
15
|
-
|
|
16
15
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
17
16
|
import { InvitationsHandler } from './invitations-handler';
|
|
18
17
|
import { SpaceInvitationProtocol } from './space-invitation-protocol';
|
|
@@ -95,7 +94,7 @@ describe.skipIf(process.env.CI && !process.env.RUN_FLAKY_TESTS)(
|
|
|
95
94
|
await acceptInvitation(guest, invitation);
|
|
96
95
|
|
|
97
96
|
await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
98
|
-
await guest.peer.networkManager.close();
|
|
97
|
+
await guest.peer.networkManager.close(Context.default());
|
|
99
98
|
await host.sink.waitFor(Invitation.State.CONNECTING);
|
|
100
99
|
|
|
101
100
|
await sleep(10);
|
|
@@ -254,9 +253,9 @@ describe.skipIf(process.env.CI && !process.env.RUN_FLAKY_TESTS)(
|
|
|
254
253
|
const peer = testBuilder.createPeer();
|
|
255
254
|
await peer.createIdentity();
|
|
256
255
|
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
257
|
-
await peer.echoHost.addReplicator(peer.meshEchoReplicator);
|
|
256
|
+
await peer.echoHost.addReplicator(Context.default(), peer.meshEchoReplicator);
|
|
258
257
|
if (spaceKey == null) {
|
|
259
|
-
const space = await peer.dataSpaceManager.createSpace();
|
|
258
|
+
const space = await peer.dataSpaceManager.createSpace(new Context());
|
|
260
259
|
spaceKey = space.key;
|
|
261
260
|
}
|
|
262
261
|
const invitationHandler = new InvitationsHandler(peer.networkManager, undefined, {
|
|
@@ -359,7 +358,7 @@ describe.skipIf(process.env.CI && !process.env.RUN_FLAKY_TESTS)(
|
|
|
359
358
|
};
|
|
360
359
|
|
|
361
360
|
const createInvitation = async (setup: PeerSetup, options?: Partial<Invitation>): Promise<Invitation> => {
|
|
362
|
-
const observable = await setup.peer.invitationsManager.createInvitation({
|
|
361
|
+
const observable = await setup.peer.invitationsManager.createInvitation(setup.ctx, {
|
|
363
362
|
type: Invitation.Type.DELEGATED,
|
|
364
363
|
kind: Invitation.Kind.SPACE,
|
|
365
364
|
authMethod: Invitation.AuthMethod.SHARED_SECRET,
|
|
@@ -11,12 +11,12 @@ import { invariant } from '@dxos/invariant';
|
|
|
11
11
|
import { PublicKey } from '@dxos/keys';
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
13
|
import { type SwarmConnection, type SwarmNetworkManager, createTeleportProtocolFactory } from '@dxos/network-manager';
|
|
14
|
-
import { InvalidInvitationError, InvalidInvitationExtensionRoleError
|
|
14
|
+
import { InvalidInvitationError, InvalidInvitationExtensionRoleError } 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
|
|
|
@@ -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 => {
|
|
@@ -132,15 +160,14 @@ export class InvitationsHandler {
|
|
|
132
160
|
});
|
|
133
161
|
|
|
134
162
|
scheduleTask(connectionCtx, async () => {
|
|
135
|
-
const traceId = PublicKey.random().toHex();
|
|
136
163
|
try {
|
|
137
|
-
log
|
|
164
|
+
log('opening host invitation handler');
|
|
138
165
|
log.verbose('connected', { ...protocol.toJSON() });
|
|
139
166
|
const deviceKey = await extension.completedTrigger.wait({ timeout: invitation.timeout });
|
|
140
167
|
log.verbose('admitted guest', { guest: deviceKey, ...protocol.toJSON() });
|
|
141
168
|
guardedState.set(extension, Invitation.State.SUCCESS);
|
|
142
169
|
metrics.increment('dxos.invitation.success');
|
|
143
|
-
log
|
|
170
|
+
log('host invitation handler opened');
|
|
144
171
|
admitted = true;
|
|
145
172
|
|
|
146
173
|
if (!invitation.multiUse) {
|
|
@@ -159,7 +186,6 @@ export class InvitationsHandler {
|
|
|
159
186
|
log.error('failed', err);
|
|
160
187
|
}
|
|
161
188
|
}
|
|
162
|
-
log.trace('dxos.sdk.invitations-handler.host.onOpen', trace.error({ id: traceId, error: err }));
|
|
163
189
|
// Close connection
|
|
164
190
|
extensionsCtx.close(err);
|
|
165
191
|
}
|
|
@@ -200,7 +226,7 @@ export class InvitationsHandler {
|
|
|
200
226
|
ctx,
|
|
201
227
|
async () => {
|
|
202
228
|
// ensure the swarm is closed before changing state and closing the stream.
|
|
203
|
-
await swarmConnection.close();
|
|
229
|
+
await swarmConnection.close(ctx);
|
|
204
230
|
guardedState.set(null, Invitation.State.EXPIRED);
|
|
205
231
|
metrics.increment('dxos.invitation.expired');
|
|
206
232
|
await ctx.dispose();
|
|
@@ -232,6 +258,34 @@ export class InvitationsHandler {
|
|
|
232
258
|
});
|
|
233
259
|
const { timeout = INVITATION_TIMEOUT } = invitation;
|
|
234
260
|
|
|
261
|
+
const guestSpanId = `invitation-guest-${invitation.invitationId}`;
|
|
262
|
+
// Reassign ctx to the child context returned by spanStart so downstream calls
|
|
263
|
+
// (`edgeInvitationHandler.handle`, `_joinSwarm`, etc.) inherit this span as their
|
|
264
|
+
// parent rather than starting a new root trace.
|
|
265
|
+
// Link child -> parent disposal so `ctx.dispose()` inside this flow still completes the
|
|
266
|
+
// invitation stream. See note in `handleInvitationFlow`: must not await the parent
|
|
267
|
+
// dispose here (`derive()` registers a parent -> child dispose hook, so awaiting would
|
|
268
|
+
// re-enter the still-pending child dispose promise and deadlock).
|
|
269
|
+
const invitationCtx = ctx;
|
|
270
|
+
ctx =
|
|
271
|
+
_trace.spanStart({
|
|
272
|
+
id: guestSpanId,
|
|
273
|
+
instance: this,
|
|
274
|
+
methodName: 'acceptInvitation',
|
|
275
|
+
parentCtx: ctx,
|
|
276
|
+
op: 'invitation.guest',
|
|
277
|
+
attributes: {
|
|
278
|
+
'ctx.dxos.invitation.id': invitation.invitationId,
|
|
279
|
+
'ctx.dxos.invitation.kind': Invitation.Kind[invitation.kind],
|
|
280
|
+
},
|
|
281
|
+
}) ?? ctx;
|
|
282
|
+
if (ctx !== invitationCtx) {
|
|
283
|
+
ctx.onDispose(() => {
|
|
284
|
+
void invitationCtx.dispose();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
ctx.onDispose(() => _trace.spanEnd(guestSpanId));
|
|
288
|
+
|
|
235
289
|
if (deviceProfile) {
|
|
236
290
|
invariant(invitation.kind === Invitation.Kind.DEVICE, 'deviceProfile provided for non-device invitation');
|
|
237
291
|
}
|
|
@@ -279,9 +333,8 @@ export class InvitationsHandler {
|
|
|
279
333
|
});
|
|
280
334
|
|
|
281
335
|
scheduleTask(connectionCtx, async () => {
|
|
282
|
-
const traceId = PublicKey.random().toHex();
|
|
283
336
|
try {
|
|
284
|
-
log
|
|
337
|
+
log('opening guest invitation handler');
|
|
285
338
|
|
|
286
339
|
scheduleTask(
|
|
287
340
|
connectionCtx,
|
|
@@ -345,7 +398,7 @@ export class InvitationsHandler {
|
|
|
345
398
|
admitted = true;
|
|
346
399
|
|
|
347
400
|
// 4. Record credential in our HALO.
|
|
348
|
-
const result = await protocol.accept(admissionResponse, admissionRequest);
|
|
401
|
+
const result = await protocol.accept(ctx, admissionResponse, admissionRequest);
|
|
349
402
|
|
|
350
403
|
// 5. Success.
|
|
351
404
|
log.verbose('dxos.sdk.invitations-handler.guest.admitted-by-host', {
|
|
@@ -357,7 +410,7 @@ export class InvitationsHandler {
|
|
|
357
410
|
...result,
|
|
358
411
|
state: Invitation.State.SUCCESS,
|
|
359
412
|
});
|
|
360
|
-
log
|
|
413
|
+
log('guest invitation handler opened');
|
|
361
414
|
} catch (err: any) {
|
|
362
415
|
if (err instanceof TimeoutError) {
|
|
363
416
|
log.verbose('timeout', { ...protocol.toJSON() });
|
|
@@ -367,7 +420,6 @@ export class InvitationsHandler {
|
|
|
367
420
|
guardedState.error(extension, err);
|
|
368
421
|
}
|
|
369
422
|
extensionCtx.close(err);
|
|
370
|
-
log.trace('dxos.sdk.invitations-handler.guest.onOpen', trace.error({ id: traceId, error: err }));
|
|
371
423
|
}
|
|
372
424
|
});
|
|
373
425
|
},
|
|
@@ -388,9 +440,9 @@ export class InvitationsHandler {
|
|
|
388
440
|
return extension;
|
|
389
441
|
};
|
|
390
442
|
|
|
391
|
-
const edgeInvitationHandler = new EdgeInvitationHandler(this.
|
|
392
|
-
onInvitationSuccess: async (admissionResponse, admissionRequest) => {
|
|
393
|
-
const result = await protocol.accept(admissionResponse, admissionRequest);
|
|
443
|
+
const edgeInvitationHandler = new EdgeInvitationHandler(this._connectionProps?.edgeInvitations, this._edgeClient, {
|
|
444
|
+
onInvitationSuccess: async (edgeCtx, admissionResponse, admissionRequest) => {
|
|
445
|
+
const result = await protocol.accept(edgeCtx, admissionResponse, admissionRequest);
|
|
394
446
|
log.info('admitted by edge', { ...protocol.toJSON() });
|
|
395
447
|
guardedState.complete({ ...guardedState.current, ...result, state: Invitation.State.SUCCESS });
|
|
396
448
|
},
|
|
@@ -436,15 +488,15 @@ export class InvitationsHandler {
|
|
|
436
488
|
} else {
|
|
437
489
|
label = `invitation host for space ${invitation.spaceKey?.truncate()}`;
|
|
438
490
|
}
|
|
439
|
-
const swarmConnection = await this._networkManager.joinSwarm({
|
|
491
|
+
const swarmConnection = await this._networkManager.joinSwarm(ctx, {
|
|
440
492
|
topic: invitation.swarmKey,
|
|
441
493
|
protocolProvider: createTeleportProtocolFactory(async (teleport) => {
|
|
442
494
|
teleport.addExtension('dxos.halo.invitations', extensionFactory());
|
|
443
|
-
}, this.
|
|
495
|
+
}, this._connectionProps?.teleport),
|
|
444
496
|
topology: new InvitationTopology(role),
|
|
445
497
|
label,
|
|
446
498
|
});
|
|
447
|
-
ctx.onDispose(() => swarmConnection.close());
|
|
499
|
+
ctx.onDispose(() => swarmConnection.close(ctx));
|
|
448
500
|
return swarmConnection;
|
|
449
501
|
}
|
|
450
502
|
|
|
@@ -503,7 +555,7 @@ export class InvitationsHandler {
|
|
|
503
555
|
const checkInvitation = (protocol: InvitationProtocol, invitation: Partial<Invitation>) => {
|
|
504
556
|
const expiresOn = getExpirationTime(invitation);
|
|
505
557
|
if (expiresOn && expiresOn.getTime() < Date.now()) {
|
|
506
|
-
return new InvalidInvitationError('Invitation already expired.');
|
|
558
|
+
return new InvalidInvitationError({ message: 'Invitation already expired.' });
|
|
507
559
|
}
|
|
508
560
|
return protocol.checkInvitation(invitation);
|
|
509
561
|
};
|
|
@@ -21,6 +21,7 @@ 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
27
|
import { type InvitationsHandler, createAdmissionKeypair } from './invitations-handler';
|
|
@@ -29,6 +30,7 @@ import { type InvitationsHandler, createAdmissionKeypair } from './invitations-h
|
|
|
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,7 +2,7 @@
|
|
|
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
7
|
type AcceptInvitationRequest,
|
|
8
8
|
type AuthenticationRequest,
|
|
@@ -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> {
|