@dxos/client-services 0.8.3 → 0.8.4-main.28f8d3d
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-LBG3C332.mjs → chunk-KVJOLMLK.mjs} +2620 -2412
- package/dist/lib/browser/chunk-KVJOLMLK.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +42 -23
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +17 -16
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/{chunk-SKGQLRKS.mjs → chunk-67QB26KM.mjs} +2617 -2408
- package/dist/lib/node-esm/chunk-67QB26KM.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +42 -23
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +17 -16
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts +1 -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 +18 -18
- 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 +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
- 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/default-space-state-machine.d.ts +1 -1
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +1 -1
- 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/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 +1 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -1
- 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 +1 -1
- package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +2 -2
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +3 -3
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +1 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
- 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 +2 -2
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +4 -4
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -2
- 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.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +2 -2
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- 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 +41 -39
- package/src/packlets/agents/edge-agent-service.ts +2 -2
- package/src/packlets/devices/devices-service.test.ts +4 -3
- package/src/packlets/devices/devices-service.ts +1 -1
- package/src/packlets/devtools/devtools.ts +28 -27
- 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 +1 -1
- package/src/packlets/identity/authenticator.node.test.ts +1 -1
- package/src/packlets/identity/authenticator.ts +1 -1
- package/src/packlets/identity/contacts-service.ts +3 -2
- package/src/packlets/identity/default-space-state-machine.ts +1 -1
- package/src/packlets/identity/identity-manager.test.ts +3 -3
- package/src/packlets/identity/identity-manager.ts +3 -3
- package/src/packlets/identity/identity-service.test.ts +3 -2
- package/src/packlets/identity/identity-service.ts +2 -1
- package/src/packlets/identity/identity.test.ts +5 -5
- package/src/packlets/identity/identity.ts +7 -6
- package/src/packlets/invitations/device-invitation-protocol.test.ts +4 -4
- package/src/packlets/invitations/device-invitation-protocol.ts +2 -1
- package/src/packlets/invitations/edge-invitation-handler.ts +1 -1
- package/src/packlets/invitations/index.ts +1 -1
- package/src/packlets/invitations/invitation-guest-extenstion.ts +1 -1
- package/src/packlets/invitations/invitation-host-extension.ts +2 -2
- package/src/packlets/invitations/invitation-protocol.ts +1 -1
- package/src/packlets/invitations/invitations-handler.test.ts +302 -292
- package/src/packlets/invitations/invitations-handler.ts +3 -3
- package/src/packlets/invitations/invitations-manager.ts +3 -3
- package/src/packlets/invitations/invitations-service.ts +1 -1
- package/src/packlets/invitations/space-invitation-protocol.test.ts +9 -9
- package/src/packlets/invitations/space-invitation-protocol.ts +3 -2
- package/src/packlets/invitations/utils.ts +1 -1
- package/src/packlets/locks/browser.ts +1 -1
- package/src/packlets/locks/index.ts +1 -1
- package/src/packlets/logging/logging-service.ts +3 -2
- package/src/packlets/logging/logging.test.ts +1 -1
- package/src/packlets/network/network-service.test.ts +4 -3
- package/src/packlets/network/network-service.ts +2 -2
- package/src/packlets/services/client-rpc-server.ts +1 -1
- package/src/packlets/services/service-context.test.ts +1 -1
- package/src/packlets/services/service-context.ts +4 -4
- package/src/packlets/services/service-host.test.ts +3 -2
- package/src/packlets/services/service-host.ts +15 -13
- package/src/packlets/services/service-registry.test.ts +2 -1
- package/src/packlets/space-export/space-archive-writer.ts +2 -2
- 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.ts +16 -15
- package/src/packlets/spaces/data-space.ts +9 -8
- package/src/packlets/spaces/edge-feed-replicator.test.ts +2 -2
- package/src/packlets/spaces/edge-feed-replicator.ts +1 -1
- package/src/packlets/spaces/notarization-plugin.test.ts +1 -1
- package/src/packlets/spaces/notarization-plugin.ts +3 -3
- package/src/packlets/spaces/spaces-service.test.ts +3 -2
- package/src/packlets/spaces/spaces-service.ts +16 -15
- package/src/packlets/storage/profile-archive.ts +1 -1
- package/src/packlets/storage/storage.ts +3 -4
- 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 +1 -1
- package/src/packlets/testing/test-builder.ts +3 -3
- package/src/packlets/worker/worker-runtime.ts +2 -1
- package/src/packlets/worker/worker-session.ts +4 -4
- package/src/version.ts +1 -5
- package/README.yml +0 -5
- package/dist/lib/browser/chunk-LBG3C332.mjs.map +0 -7
- package/dist/lib/node/chunk-LMGLGOUU.cjs +0 -9311
- package/dist/lib/node/chunk-LMGLGOUU.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -437
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/testing/index.cjs +0 -452
- package/dist/lib/node/testing/index.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-SKGQLRKS.mjs.map +0 -7
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { beforeEach,
|
|
5
|
+
import { beforeEach, describe, expect, onTestFinished, test } from 'vitest';
|
|
6
6
|
|
|
7
|
-
import { type PushStream,
|
|
7
|
+
import { type PushStream, Trigger, sleep, waitForCondition } from '@dxos/async';
|
|
8
8
|
import { Context } from '@dxos/context';
|
|
9
9
|
import { PublicKey } from '@dxos/keys';
|
|
10
10
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
11
11
|
import { openAndClose } from '@dxos/test-utils';
|
|
12
12
|
import { range } from '@dxos/util';
|
|
13
13
|
|
|
14
|
+
import { TestBuilder, type TestPeer } from '../testing';
|
|
15
|
+
|
|
14
16
|
import { type InvitationProtocol } from './invitation-protocol';
|
|
15
17
|
import { InvitationsHandler } from './invitations-handler';
|
|
16
18
|
import { SpaceInvitationProtocol } from './space-invitation-protocol';
|
|
17
|
-
import { TestBuilder, type TestPeer } from '../testing';
|
|
18
19
|
|
|
19
20
|
interface PeerSetup {
|
|
20
21
|
ctx: Context;
|
|
@@ -32,335 +33,344 @@ type StateUpdateSink = PushStream<Invitation> & {
|
|
|
32
33
|
waitFor(state: Invitation.State): Promise<void>;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
// TODO(burdon): Flaky.
|
|
37
|
+
describe.skipIf(process.env.CI && !process.env.RUN_FLAKY_TESTS)(
|
|
38
|
+
'InvitationHandler',
|
|
39
|
+
{ retry: 3, timeout: 30_000 },
|
|
40
|
+
() => {
|
|
41
|
+
let testBuilder: TestBuilder;
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
testBuilder = new TestBuilder();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('delegated invitations', () => {
|
|
48
|
+
for (const multiUse of [false, true]) {
|
|
49
|
+
test(`base case success multiUse=${multiUse}`, async () => {
|
|
50
|
+
const host = await createPeer();
|
|
51
|
+
const invitation = await createInvitation(host, { multiUse });
|
|
52
|
+
await hostInvitation(host, invitation);
|
|
53
|
+
|
|
54
|
+
const guest = await createPeer(host.spaceKey);
|
|
55
|
+
await performAuth(guest, invitation);
|
|
37
56
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
57
|
+
await sleep(15);
|
|
58
|
+
expect(guest.ctx.disposed).to.be.true;
|
|
59
|
+
if (multiUse) {
|
|
60
|
+
expect(host.ctx.disposed).to.be.false;
|
|
61
|
+
} else {
|
|
62
|
+
expect(host.ctx.disposed).to.be.true;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
41
66
|
|
|
42
|
-
|
|
43
|
-
for (const multiUse of [false, true]) {
|
|
44
|
-
test(`base case success multiUse=${multiUse}`, async () => {
|
|
67
|
+
test('invitation timeout', async () => {
|
|
45
68
|
const host = await createPeer();
|
|
46
|
-
const invitation = await createInvitation(host, {
|
|
69
|
+
const invitation = await createInvitation(host, {
|
|
70
|
+
timeout: 100,
|
|
71
|
+
});
|
|
47
72
|
await hostInvitation(host, invitation);
|
|
48
73
|
|
|
49
74
|
const guest = await createPeer(host.spaceKey);
|
|
50
|
-
await
|
|
75
|
+
await acceptInvitation(guest, invitation);
|
|
51
76
|
|
|
52
|
-
await
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} else {
|
|
57
|
-
expect(host.ctx.disposed).to.be.true;
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
77
|
+
await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
78
|
+
await sleep(200);
|
|
79
|
+
await host.sink.waitFor(Invitation.State.CONNECTING);
|
|
80
|
+
await guest.sink.waitFor(Invitation.State.TIMEOUT);
|
|
61
81
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
timeout: 100,
|
|
82
|
+
await sleep(10);
|
|
83
|
+
expect(host.ctx.disposed).to.be.false;
|
|
84
|
+
expect(guest.ctx.disposed).to.be.false;
|
|
66
85
|
});
|
|
67
|
-
await hostInvitation(host, invitation);
|
|
68
86
|
|
|
69
|
-
|
|
70
|
-
|
|
87
|
+
test('host ctx active after guest disconnects', async () => {
|
|
88
|
+
const host = await createPeer();
|
|
89
|
+
const invitation = await createInvitation(host, {
|
|
90
|
+
timeout: 100,
|
|
91
|
+
});
|
|
92
|
+
await hostInvitation(host, invitation);
|
|
71
93
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
await host.sink.waitFor(Invitation.State.CONNECTING);
|
|
75
|
-
await guest.sink.waitFor(Invitation.State.TIMEOUT);
|
|
94
|
+
const guest = await createPeer(host.spaceKey);
|
|
95
|
+
await acceptInvitation(guest, invitation);
|
|
76
96
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
97
|
+
await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
98
|
+
await guest.peer.networkManager.close();
|
|
99
|
+
await host.sink.waitFor(Invitation.State.CONNECTING);
|
|
81
100
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const invitation = await createInvitation(host, {
|
|
85
|
-
timeout: 100,
|
|
101
|
+
await sleep(10);
|
|
102
|
+
expect(host.ctx.disposed).to.be.false;
|
|
86
103
|
});
|
|
87
|
-
await hostInvitation(host, invitation);
|
|
88
|
-
|
|
89
|
-
const guest = await createPeer(host.spaceKey);
|
|
90
|
-
await acceptInvitation(guest, invitation);
|
|
91
104
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
test('invitation success after first guest error', async () => {
|
|
106
|
+
const host = await createPeer();
|
|
107
|
+
const invitation = await createInvitation(host);
|
|
108
|
+
await hostInvitation(host, invitation);
|
|
95
109
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
110
|
+
const badGuest = await createPeer(host.spaceKey);
|
|
111
|
+
await failAuth(badGuest, invitation);
|
|
112
|
+
await badGuest.sink.waitFor(Invitation.State.ERROR);
|
|
99
113
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
await hostInvitation(host, invitation);
|
|
114
|
+
const goodGuest = await createPeer(host.spaceKey);
|
|
115
|
+
await performAuth(goodGuest, invitation);
|
|
116
|
+
await host.sink.waitFor(Invitation.State.SUCCESS);
|
|
104
117
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
118
|
+
await sleep(10);
|
|
119
|
+
expect(goodGuest.ctx.disposed).to.be.true;
|
|
120
|
+
expect(host.ctx.disposed).to.be.true;
|
|
121
|
+
});
|
|
108
122
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
123
|
+
test('multiUse invitation with multiple guests', async () => {
|
|
124
|
+
const host = await createPeer();
|
|
125
|
+
const invitation = await createInvitation(host, { multiUse: true });
|
|
126
|
+
await hostInvitation(host, invitation);
|
|
112
127
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
128
|
+
const guest1 = await createPeer(host.spaceKey);
|
|
129
|
+
await performAuth(guest1, invitation);
|
|
130
|
+
const guest2 = await createPeer(host.spaceKey);
|
|
131
|
+
await performAuth(guest2, invitation);
|
|
117
132
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
133
|
+
await sleep(5);
|
|
134
|
+
[guest1, guest2].forEach((g) => expect(g.ctx.disposed).to.be.true);
|
|
135
|
+
expect(host.ctx.disposed).to.be.false;
|
|
136
|
+
});
|
|
122
137
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
138
|
+
test('invitation success after host error with another host', async () => {
|
|
139
|
+
const host = await createPeer();
|
|
140
|
+
const invitation = await createInvitation(host, { multiUse: true });
|
|
141
|
+
await hostInvitation(host, invitation);
|
|
142
|
+
await createNewHost(invitation);
|
|
127
143
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
144
|
+
const guest = await createPeer(host.spaceKey);
|
|
145
|
+
const codeInput = await failAuth(guest, invitation);
|
|
146
|
+
while (!guest.ctx.disposed) {
|
|
147
|
+
codeInput.wake(invitation.authCode!);
|
|
148
|
+
await sleep(10);
|
|
149
|
+
}
|
|
150
|
+
await guest.sink.waitFor(Invitation.State.SUCCESS);
|
|
151
|
+
});
|
|
132
152
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
test('single guest - many hosts', async () => {
|
|
154
|
+
const hosts: PeerSetup[] = [await createPeer()];
|
|
155
|
+
const [host] = hosts;
|
|
156
|
+
const invitation = await createInvitation(host, { multiUse: true });
|
|
157
|
+
await hostInvitation(host, invitation);
|
|
158
|
+
for (let i = 0; i < 4; i++) {
|
|
159
|
+
hosts.push(await createNewHost(invitation));
|
|
160
|
+
}
|
|
138
161
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
codeInput.wake(invitation.authCode!);
|
|
162
|
+
const guest = await createPeer(host.spaceKey);
|
|
163
|
+
await performAuth(guest, invitation);
|
|
164
|
+
await guest.sink.waitFor(Invitation.State.SUCCESS);
|
|
143
165
|
await sleep(10);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
166
|
+
expect(guest.ctx.disposed).to.be.true;
|
|
167
|
+
});
|
|
147
168
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
169
|
+
test('guest gives up after trying with three hosts', { timeout: 20_000 }, async () => {
|
|
170
|
+
const hosts: PeerSetup[] = [await createPeer()];
|
|
171
|
+
const [host] = hosts;
|
|
172
|
+
const invitation = await createInvitation(host, { multiUse: true });
|
|
173
|
+
await hostInvitation(host, invitation);
|
|
174
|
+
for (let i = 0; i < 2; i++) {
|
|
175
|
+
hosts.push(await createNewHost(invitation));
|
|
176
|
+
}
|
|
156
177
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
178
|
+
const guest = await createPeer(host.spaceKey);
|
|
179
|
+
const codeInput = await acceptInvitation(guest, invitation);
|
|
180
|
+
while (!guest.ctx.disposed) {
|
|
181
|
+
await failCodeInput(guest, codeInput, invitation);
|
|
182
|
+
await sleep(10);
|
|
183
|
+
}
|
|
163
184
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
hosts
|
|
171
|
-
|
|
185
|
+
await sleep(10);
|
|
186
|
+
expect(guest.sink.lastState).to.eq(Invitation.State.ERROR);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('single host - many guests', async () => {
|
|
190
|
+
const hosts: PeerSetup[] = [await createPeer()];
|
|
191
|
+
const [host] = hosts;
|
|
192
|
+
const invitation = await createInvitation(host, { multiUse: true });
|
|
193
|
+
await hostInvitation(host, invitation);
|
|
194
|
+
const guests = await Promise.all(
|
|
195
|
+
range(5).map(async () => {
|
|
196
|
+
const guest = await createPeer(host.spaceKey);
|
|
197
|
+
await performAuth(guest, invitation);
|
|
198
|
+
return guest;
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
172
201
|
|
|
173
|
-
const guest = await createPeer(host.spaceKey);
|
|
174
|
-
const codeInput = await acceptInvitation(guest, invitation);
|
|
175
|
-
while (!guest.ctx.disposed) {
|
|
176
|
-
await failCodeInput(guest, codeInput, invitation);
|
|
177
202
|
await sleep(10);
|
|
178
|
-
|
|
203
|
+
guests.forEach((g) => {
|
|
204
|
+
expect(g.ctx.disposed).to.be.true;
|
|
205
|
+
expect(g.sink.lastState).to.eq(Invitation.State.SUCCESS);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
179
208
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
209
|
+
test('many guests - many hosts', async () => {
|
|
210
|
+
const hosts: PeerSetup[] = [await createPeer()];
|
|
211
|
+
const [host] = hosts;
|
|
212
|
+
const invitation = await createInvitation(host, { multiUse: true });
|
|
213
|
+
await hostInvitation(host, invitation);
|
|
214
|
+
for (let i = 0; i < 4; i++) {
|
|
215
|
+
hosts.push(await createNewHost(invitation));
|
|
216
|
+
}
|
|
217
|
+
const guests = await Promise.all(
|
|
218
|
+
range(5).map(async () => {
|
|
219
|
+
const guest = await createPeer(host.spaceKey);
|
|
220
|
+
await performAuth(guest, invitation);
|
|
221
|
+
return guest;
|
|
222
|
+
}),
|
|
223
|
+
);
|
|
224
|
+
await sleep(10);
|
|
225
|
+
guests.forEach((g) => {
|
|
226
|
+
expect(g.ctx.disposed).to.be.true;
|
|
227
|
+
expect(g.sink.lastState).to.eq(Invitation.State.SUCCESS);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
183
230
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
231
|
+
test('single use invitation - many guests - only one admitted', async () => {
|
|
232
|
+
const host = await createPeer();
|
|
233
|
+
const invitation = await createInvitation(host);
|
|
234
|
+
await hostInvitation(host, invitation);
|
|
235
|
+
const guests = await Promise.all(
|
|
236
|
+
range(5).map(async () => {
|
|
237
|
+
const guest = await createPeer(invitation.spaceKey);
|
|
238
|
+
const authCodeInput2 = await acceptInvitation(guest, invitation);
|
|
239
|
+
authCodeInput2.wake(invitation.authCode!);
|
|
240
|
+
return guest;
|
|
241
|
+
}),
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
await waitForCondition({
|
|
245
|
+
condition: () => guests.find((g) => g.sink.lastState === Invitation.State.SUCCESS) != null,
|
|
246
|
+
});
|
|
247
|
+
await sleep(40);
|
|
248
|
+
const success = guests.filter((g) => g.sink.lastState === Invitation.State.SUCCESS);
|
|
249
|
+
expect(success.length).to.eq(1);
|
|
201
250
|
});
|
|
202
251
|
});
|
|
203
252
|
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
await
|
|
209
|
-
|
|
210
|
-
|
|
253
|
+
const createPeer = async (spaceKey: PublicKey | null = null): Promise<PeerSetup> => {
|
|
254
|
+
const peer = testBuilder.createPeer();
|
|
255
|
+
await peer.createIdentity();
|
|
256
|
+
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
257
|
+
await peer.echoHost.addReplicator(peer.meshEchoReplicator);
|
|
258
|
+
if (spaceKey == null) {
|
|
259
|
+
const space = await peer.dataSpaceManager.createSpace();
|
|
260
|
+
spaceKey = space.key;
|
|
211
261
|
}
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
const guest = await createPeer(host.spaceKey);
|
|
215
|
-
await performAuth(guest, invitation);
|
|
216
|
-
return guest;
|
|
217
|
-
}),
|
|
218
|
-
);
|
|
219
|
-
await sleep(10);
|
|
220
|
-
guests.forEach((g) => {
|
|
221
|
-
expect(g.ctx.disposed).to.be.true;
|
|
222
|
-
expect(g.sink.lastState).to.eq(Invitation.State.SUCCESS);
|
|
262
|
+
const invitationHandler = new InvitationsHandler(peer.networkManager, undefined, {
|
|
263
|
+
teleport: { controlHeartbeatInterval: 250 }, // faster peer failure detection
|
|
223
264
|
});
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const invitation = await createInvitation(host);
|
|
229
|
-
await hostInvitation(host, invitation);
|
|
230
|
-
const guests = await Promise.all(
|
|
231
|
-
range(5).map(async () => {
|
|
232
|
-
const guest = await createPeer(invitation.spaceKey);
|
|
233
|
-
const authCodeInput2 = await acceptInvitation(guest, invitation);
|
|
234
|
-
authCodeInput2.wake(invitation.authCode!);
|
|
235
|
-
return guest;
|
|
236
|
-
}),
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
await waitForCondition({
|
|
240
|
-
condition: () => guests.find((g) => g.sink.lastState === Invitation.State.SUCCESS) != null,
|
|
265
|
+
const protocol = new SpaceInvitationProtocol(peer.dataSpaceManager, peer.identity, peer.keyring, spaceKey);
|
|
266
|
+
const ctx = new Context();
|
|
267
|
+
onTestFinished(async () => {
|
|
268
|
+
await ctx.dispose();
|
|
241
269
|
});
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const createPeer = async (spaceKey: PublicKey | null = null): Promise<PeerSetup> => {
|
|
249
|
-
const peer = testBuilder.createPeer();
|
|
250
|
-
await peer.createIdentity();
|
|
251
|
-
await openAndClose(peer.echoHost, peer.dataSpaceManager);
|
|
252
|
-
await peer.echoHost.addReplicator(peer.meshEchoReplicator);
|
|
253
|
-
if (spaceKey == null) {
|
|
254
|
-
const space = await peer.dataSpaceManager.createSpace();
|
|
255
|
-
spaceKey = space.key;
|
|
256
|
-
}
|
|
257
|
-
const invitationHandler = new InvitationsHandler(peer.networkManager, undefined, {
|
|
258
|
-
teleport: { controlHeartbeatInterval: 250 }, // faster peer failure detection
|
|
259
|
-
});
|
|
260
|
-
const protocol = new SpaceInvitationProtocol(peer.dataSpaceManager, peer.identity, peer.keyring, spaceKey);
|
|
261
|
-
const ctx = new Context();
|
|
262
|
-
onTestFinished(async () => {
|
|
263
|
-
await ctx.dispose();
|
|
264
|
-
});
|
|
265
|
-
const sink = newStateUpdateSink();
|
|
266
|
-
return { ctx, sink, peer, protocol, handler: invitationHandler, spaceKey };
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const hostInvitation = async (setup: PeerSetup, invitation: Invitation) => {
|
|
270
|
-
await setup.ctx.dispose();
|
|
271
|
-
setup.ctx = new Context();
|
|
272
|
-
onTestFinished(async () => {
|
|
270
|
+
const sink = newStateUpdateSink();
|
|
271
|
+
return { ctx, sink, peer, protocol, handler: invitationHandler, spaceKey };
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const hostInvitation = async (setup: PeerSetup, invitation: Invitation) => {
|
|
273
275
|
await setup.ctx.dispose();
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
setup.ctx = new Context();
|
|
277
|
+
onTestFinished(async () => {
|
|
278
|
+
await setup.ctx.dispose();
|
|
279
|
+
});
|
|
280
|
+
setup.handler.handleInvitationFlow(setup.ctx, setup.sink, setup.protocol, invitation);
|
|
281
|
+
};
|
|
277
282
|
|
|
278
|
-
|
|
279
|
-
await setup.ctx.dispose();
|
|
280
|
-
setup.ctx = new Context();
|
|
281
|
-
onTestFinished(async () => {
|
|
283
|
+
const acceptInvitation = async (setup: PeerSetup, invitation: Invitation): Promise<Trigger<string>> => {
|
|
282
284
|
await setup.ctx.dispose();
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const wrongAuthCodeInput = await acceptInvitation(setup, invitation);
|
|
291
|
-
await setup.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
292
|
-
await failCodeInput(setup, wrongAuthCodeInput, invitation);
|
|
293
|
-
return wrongAuthCodeInput;
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
const failCodeInput = async (setup: PeerSetup, codeInput: Trigger<string>, invitation: Invitation): Promise<void> => {
|
|
297
|
-
const checkFrom = setup.sink.sink.length;
|
|
298
|
-
while (
|
|
299
|
-
!setup.ctx.disposed &&
|
|
300
|
-
!setup.sink.hasState(checkFrom, Invitation.State.ERROR) &&
|
|
301
|
-
!setup.sink.hasState(checkFrom, Invitation.State.CONNECTED)
|
|
302
|
-
) {
|
|
303
|
-
codeInput.wake(invitation.authCode + '1');
|
|
304
|
-
await sleep(20);
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
const createNewHost = async (invitation: Invitation): Promise<PeerSetup> => {
|
|
309
|
-
const newHost = await createPeer(invitation.spaceKey!);
|
|
310
|
-
await performAuth(newHost, invitation);
|
|
311
|
-
await sleep(30);
|
|
312
|
-
await hostInvitation(newHost, invitation);
|
|
313
|
-
return newHost;
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
const performAuth = async (setup: PeerSetup, invitation: Invitation) => {
|
|
317
|
-
const authCodeInput2 = await acceptInvitation(setup, invitation);
|
|
318
|
-
await setup.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
319
|
-
authCodeInput2.wake(invitation.authCode!);
|
|
320
|
-
await setup.sink.waitFor(Invitation.State.SUCCESS);
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const newStateUpdateSink = (): StateUpdateSink => {
|
|
324
|
-
const sink: Invitation[] = [];
|
|
325
|
-
const hasState = (startingIndex: number, state: Invitation.State): boolean => {
|
|
326
|
-
return sink
|
|
327
|
-
.slice(startingIndex)
|
|
328
|
-
.map((i) => i.state)
|
|
329
|
-
.includes(state);
|
|
285
|
+
setup.ctx = new Context();
|
|
286
|
+
onTestFinished(async () => {
|
|
287
|
+
await setup.ctx.dispose();
|
|
288
|
+
});
|
|
289
|
+
const authCodeInput = new Trigger<string>();
|
|
290
|
+
setup.handler.acceptInvitation(setup.ctx, setup.sink, setup.protocol, invitation, authCodeInput);
|
|
291
|
+
return authCodeInput;
|
|
330
292
|
};
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
293
|
+
|
|
294
|
+
const failAuth = async (setup: PeerSetup, invitation: Invitation) => {
|
|
295
|
+
const wrongAuthCodeInput = await acceptInvitation(setup, invitation);
|
|
296
|
+
await setup.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
297
|
+
await failCodeInput(setup, wrongAuthCodeInput, invitation);
|
|
298
|
+
return wrongAuthCodeInput;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const failCodeInput = async (
|
|
302
|
+
setup: PeerSetup,
|
|
303
|
+
codeInput: Trigger<string>,
|
|
304
|
+
invitation: Invitation,
|
|
305
|
+
): Promise<void> => {
|
|
306
|
+
const checkFrom = setup.sink.sink.length;
|
|
307
|
+
while (
|
|
308
|
+
!setup.ctx.disposed &&
|
|
309
|
+
!setup.sink.hasState(checkFrom, Invitation.State.ERROR) &&
|
|
310
|
+
!setup.sink.hasState(checkFrom, Invitation.State.CONNECTED)
|
|
311
|
+
) {
|
|
312
|
+
codeInput.wake(invitation.authCode + '1');
|
|
313
|
+
await sleep(20);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const createNewHost = async (invitation: Invitation): Promise<PeerSetup> => {
|
|
318
|
+
const newHost = await createPeer(invitation.spaceKey!);
|
|
319
|
+
await performAuth(newHost, invitation);
|
|
320
|
+
await sleep(30);
|
|
321
|
+
await hostInvitation(newHost, invitation);
|
|
322
|
+
return newHost;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const performAuth = async (setup: PeerSetup, invitation: Invitation) => {
|
|
326
|
+
const authCodeInput2 = await acceptInvitation(setup, invitation);
|
|
327
|
+
await setup.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
|
|
328
|
+
authCodeInput2.wake(invitation.authCode!);
|
|
329
|
+
await setup.sink.waitFor(Invitation.State.SUCCESS);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const newStateUpdateSink = (): StateUpdateSink => {
|
|
333
|
+
const sink: Invitation[] = [];
|
|
334
|
+
const hasState = (startingIndex: number, state: Invitation.State): boolean => {
|
|
335
|
+
return sink
|
|
336
|
+
.slice(startingIndex)
|
|
337
|
+
.map((i) => i.state)
|
|
338
|
+
.includes(state);
|
|
339
|
+
};
|
|
340
|
+
return {
|
|
341
|
+
sink,
|
|
342
|
+
next: sink.push.bind(sink),
|
|
343
|
+
error: () => {},
|
|
344
|
+
complete: () => {},
|
|
345
|
+
hasState,
|
|
346
|
+
get lastState() {
|
|
347
|
+
return sink[sink.length - 1]?.state;
|
|
348
|
+
},
|
|
349
|
+
waitFor: async (state: Invitation.State): Promise<void> => {
|
|
350
|
+
if (sink[sink.length - 1]?.state === state) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const sliceStart = sink.length;
|
|
354
|
+
await waitForCondition({
|
|
355
|
+
condition: () => hasState(sliceStart, state),
|
|
356
|
+
});
|
|
357
|
+
},
|
|
358
|
+
} as any;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
const createInvitation = async (setup: PeerSetup, options?: Partial<Invitation>): Promise<Invitation> => {
|
|
362
|
+
const observable = await setup.peer.invitationsManager.createInvitation({
|
|
363
|
+
type: Invitation.Type.DELEGATED,
|
|
364
|
+
kind: Invitation.Kind.SPACE,
|
|
365
|
+
authMethod: Invitation.AuthMethod.SHARED_SECRET,
|
|
366
|
+
spaceKey: setup.spaceKey,
|
|
367
|
+
multiUse: false,
|
|
368
|
+
...options,
|
|
369
|
+
});
|
|
370
|
+
// cancel to avoid interfering with invitations-handler direct invocations
|
|
371
|
+
const invitation = observable.get();
|
|
372
|
+
await setup.peer.invitationsManager.cancelInvitation(invitation);
|
|
373
|
+
return { ...invitation, swarmKey: PublicKey.random() };
|
|
374
|
+
};
|
|
375
|
+
},
|
|
376
|
+
);
|