@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.
Files changed (168) hide show
  1. package/dist/lib/browser/{chunk-LBG3C332.mjs → chunk-KVJOLMLK.mjs} +2620 -2412
  2. package/dist/lib/browser/chunk-KVJOLMLK.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +42 -23
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +17 -16
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/{chunk-SKGQLRKS.mjs → chunk-67QB26KM.mjs} +2617 -2408
  9. package/dist/lib/node-esm/chunk-67QB26KM.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +42 -23
  11. package/dist/lib/node-esm/index.mjs.map +3 -3
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +17 -16
  14. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  15. package/dist/types/src/packlets/agents/edge-agent-service.d.ts +1 -1
  16. package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
  17. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  18. package/dist/types/src/packlets/devtools/devtools.d.ts +18 -18
  19. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  20. package/dist/types/src/packlets/devtools/feeds.d.ts +1 -1
  21. package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
  22. package/dist/types/src/packlets/devtools/network.d.ts +1 -1
  23. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  24. package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts +1 -1
  25. package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts.map +1 -1
  26. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts +1 -1
  27. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
  28. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +1 -1
  29. package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
  30. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  31. package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
  32. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  33. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +1 -1
  34. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +1 -1
  35. package/dist/types/src/packlets/identity/identity-manager.d.ts +1 -1
  36. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  37. package/dist/types/src/packlets/identity/identity-service.d.ts +1 -1
  38. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  39. package/dist/types/src/packlets/identity/identity.d.ts +1 -1
  40. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  41. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +1 -1
  42. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  43. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +1 -1
  44. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
  45. package/dist/types/src/packlets/invitations/index.d.ts +1 -1
  46. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  47. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
  48. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  49. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +1 -1
  50. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
  51. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  52. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  53. package/dist/types/src/packlets/invitations/invitations-service.d.ts +1 -1
  54. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  55. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -1
  56. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  57. package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -1
  58. package/dist/types/src/packlets/locks/index.d.ts +1 -1
  59. package/dist/types/src/packlets/locks/index.d.ts.map +1 -1
  60. package/dist/types/src/packlets/logging/logging-service.d.ts +1 -1
  61. package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
  62. package/dist/types/src/packlets/network/network-service.d.ts +2 -2
  63. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  64. package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
  65. package/dist/types/src/packlets/services/service-context.d.ts +3 -3
  66. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  67. package/dist/types/src/packlets/services/service-host.d.ts +1 -1
  68. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  69. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +1 -1
  70. package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
  71. package/dist/types/src/packlets/spaces/automerge-space-state.d.ts +1 -1
  72. package/dist/types/src/packlets/spaces/automerge-space-state.d.ts.map +1 -1
  73. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +2 -2
  74. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  75. package/dist/types/src/packlets/spaces/data-space.d.ts +4 -4
  76. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  77. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  78. package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -2
  79. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  80. package/dist/types/src/packlets/storage/profile-archive.d.ts.map +1 -1
  81. package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
  82. package/dist/types/src/packlets/system/system-service.d.ts +1 -1
  83. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
  84. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  85. package/dist/types/src/packlets/testing/test-builder.d.ts +2 -2
  86. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  87. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  88. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
  89. package/dist/types/src/version.d.ts +1 -1
  90. package/dist/types/src/version.d.ts.map +1 -1
  91. package/dist/types/tsconfig.tsbuildinfo +1 -1
  92. package/package.json +41 -39
  93. package/src/packlets/agents/edge-agent-service.ts +2 -2
  94. package/src/packlets/devices/devices-service.test.ts +4 -3
  95. package/src/packlets/devices/devices-service.ts +1 -1
  96. package/src/packlets/devtools/devtools.ts +28 -27
  97. package/src/packlets/devtools/feeds.ts +2 -2
  98. package/src/packlets/devtools/network.ts +1 -1
  99. package/src/packlets/diagnostics/browser-diagnostics-broadcast.ts +1 -1
  100. package/src/packlets/diagnostics/diagnostics-broadcast.ts +1 -1
  101. package/src/packlets/diagnostics/diagnostics-collector.ts +1 -1
  102. package/src/packlets/diagnostics/diagnostics.ts +1 -1
  103. package/src/packlets/identity/authenticator.node.test.ts +1 -1
  104. package/src/packlets/identity/authenticator.ts +1 -1
  105. package/src/packlets/identity/contacts-service.ts +3 -2
  106. package/src/packlets/identity/default-space-state-machine.ts +1 -1
  107. package/src/packlets/identity/identity-manager.test.ts +3 -3
  108. package/src/packlets/identity/identity-manager.ts +3 -3
  109. package/src/packlets/identity/identity-service.test.ts +3 -2
  110. package/src/packlets/identity/identity-service.ts +2 -1
  111. package/src/packlets/identity/identity.test.ts +5 -5
  112. package/src/packlets/identity/identity.ts +7 -6
  113. package/src/packlets/invitations/device-invitation-protocol.test.ts +4 -4
  114. package/src/packlets/invitations/device-invitation-protocol.ts +2 -1
  115. package/src/packlets/invitations/edge-invitation-handler.ts +1 -1
  116. package/src/packlets/invitations/index.ts +1 -1
  117. package/src/packlets/invitations/invitation-guest-extenstion.ts +1 -1
  118. package/src/packlets/invitations/invitation-host-extension.ts +2 -2
  119. package/src/packlets/invitations/invitation-protocol.ts +1 -1
  120. package/src/packlets/invitations/invitations-handler.test.ts +302 -292
  121. package/src/packlets/invitations/invitations-handler.ts +3 -3
  122. package/src/packlets/invitations/invitations-manager.ts +3 -3
  123. package/src/packlets/invitations/invitations-service.ts +1 -1
  124. package/src/packlets/invitations/space-invitation-protocol.test.ts +9 -9
  125. package/src/packlets/invitations/space-invitation-protocol.ts +3 -2
  126. package/src/packlets/invitations/utils.ts +1 -1
  127. package/src/packlets/locks/browser.ts +1 -1
  128. package/src/packlets/locks/index.ts +1 -1
  129. package/src/packlets/logging/logging-service.ts +3 -2
  130. package/src/packlets/logging/logging.test.ts +1 -1
  131. package/src/packlets/network/network-service.test.ts +4 -3
  132. package/src/packlets/network/network-service.ts +2 -2
  133. package/src/packlets/services/client-rpc-server.ts +1 -1
  134. package/src/packlets/services/service-context.test.ts +1 -1
  135. package/src/packlets/services/service-context.ts +4 -4
  136. package/src/packlets/services/service-host.test.ts +3 -2
  137. package/src/packlets/services/service-host.ts +15 -13
  138. package/src/packlets/services/service-registry.test.ts +2 -1
  139. package/src/packlets/space-export/space-archive-writer.ts +2 -2
  140. package/src/packlets/space-export/tar.test.ts +1 -1
  141. package/src/packlets/spaces/automerge-space-state.ts +1 -1
  142. package/src/packlets/spaces/data-space-manager.ts +16 -15
  143. package/src/packlets/spaces/data-space.ts +9 -8
  144. package/src/packlets/spaces/edge-feed-replicator.test.ts +2 -2
  145. package/src/packlets/spaces/edge-feed-replicator.ts +1 -1
  146. package/src/packlets/spaces/notarization-plugin.test.ts +1 -1
  147. package/src/packlets/spaces/notarization-plugin.ts +3 -3
  148. package/src/packlets/spaces/spaces-service.test.ts +3 -2
  149. package/src/packlets/spaces/spaces-service.ts +16 -15
  150. package/src/packlets/storage/profile-archive.ts +1 -1
  151. package/src/packlets/storage/storage.ts +3 -4
  152. package/src/packlets/system/system-service.test.ts +1 -1
  153. package/src/packlets/system/system-service.ts +4 -4
  154. package/src/packlets/testing/invitation-utils.ts +1 -1
  155. package/src/packlets/testing/test-builder.ts +3 -3
  156. package/src/packlets/worker/worker-runtime.ts +2 -1
  157. package/src/packlets/worker/worker-session.ts +4 -4
  158. package/src/version.ts +1 -5
  159. package/README.yml +0 -5
  160. package/dist/lib/browser/chunk-LBG3C332.mjs.map +0 -7
  161. package/dist/lib/node/chunk-LMGLGOUU.cjs +0 -9311
  162. package/dist/lib/node/chunk-LMGLGOUU.cjs.map +0 -7
  163. package/dist/lib/node/index.cjs +0 -437
  164. package/dist/lib/node/index.cjs.map +0 -7
  165. package/dist/lib/node/meta.json +0 -1
  166. package/dist/lib/node/testing/index.cjs +0 -452
  167. package/dist/lib/node/testing/index.cjs.map +0 -7
  168. 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, onTestFinished, describe, expect, test } from 'vitest';
5
+ import { beforeEach, describe, expect, onTestFinished, test } from 'vitest';
6
6
 
7
- import { type PushStream, sleep, Trigger, waitForCondition } from '@dxos/async';
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
- describe('InvitationHandler', () => {
36
- let testBuilder: TestBuilder;
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
- beforeEach(() => {
39
- testBuilder = new TestBuilder();
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
- describe('delegated invitations', () => {
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, { multiUse });
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 performAuth(guest, invitation);
75
+ await acceptInvitation(guest, invitation);
51
76
 
52
- await sleep(15);
53
- expect(guest.ctx.disposed).to.be.true;
54
- if (multiUse) {
55
- expect(host.ctx.disposed).to.be.false;
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
- test('invitation timeout', async () => {
63
- const host = await createPeer();
64
- const invitation = await createInvitation(host, {
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
- const guest = await createPeer(host.spaceKey);
70
- await acceptInvitation(guest, invitation);
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
- await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
73
- await sleep(200);
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
- await sleep(10);
78
- expect(host.ctx.disposed).to.be.false;
79
- expect(guest.ctx.disposed).to.be.false;
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
- test('host ctx active after guest disconnects', async () => {
83
- const host = await createPeer();
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
- await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
93
- await guest.peer.networkManager.close();
94
- await host.sink.waitFor(Invitation.State.CONNECTING);
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
- await sleep(10);
97
- expect(host.ctx.disposed).to.be.false;
98
- });
110
+ const badGuest = await createPeer(host.spaceKey);
111
+ await failAuth(badGuest, invitation);
112
+ await badGuest.sink.waitFor(Invitation.State.ERROR);
99
113
 
100
- test('invitation success after first guest error', async () => {
101
- const host = await createPeer();
102
- const invitation = await createInvitation(host);
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
- const badGuest = await createPeer(host.spaceKey);
106
- await failAuth(badGuest, invitation);
107
- await badGuest.sink.waitFor(Invitation.State.ERROR);
118
+ await sleep(10);
119
+ expect(goodGuest.ctx.disposed).to.be.true;
120
+ expect(host.ctx.disposed).to.be.true;
121
+ });
108
122
 
109
- const goodGuest = await createPeer(host.spaceKey);
110
- await performAuth(goodGuest, invitation);
111
- await host.sink.waitFor(Invitation.State.SUCCESS);
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
- await sleep(10);
114
- expect(goodGuest.ctx.disposed).to.be.true;
115
- expect(host.ctx.disposed).to.be.true;
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
- test('multiUse invitation with multiple guests', async () => {
119
- const host = await createPeer();
120
- const invitation = await createInvitation(host, { multiUse: true });
121
- await hostInvitation(host, invitation);
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
- const guest1 = await createPeer(host.spaceKey);
124
- await performAuth(guest1, invitation);
125
- const guest2 = await createPeer(host.spaceKey);
126
- await performAuth(guest2, invitation);
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
- await sleep(5);
129
- [guest1, guest2].forEach((g) => expect(g.ctx.disposed).to.be.true);
130
- expect(host.ctx.disposed).to.be.false;
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
- test('invitation success after host error with another host', async () => {
134
- const host = await createPeer();
135
- const invitation = await createInvitation(host, { multiUse: true });
136
- await hostInvitation(host, invitation);
137
- await createNewHost(invitation);
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
- const guest = await createPeer(host.spaceKey);
140
- const codeInput = await failAuth(guest, invitation);
141
- while (!guest.ctx.disposed) {
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
- await guest.sink.waitFor(Invitation.State.SUCCESS);
146
- });
166
+ expect(guest.ctx.disposed).to.be.true;
167
+ });
147
168
 
148
- test('single guest - many hosts', async () => {
149
- const hosts: PeerSetup[] = [await createPeer()];
150
- const [host] = hosts;
151
- const invitation = await createInvitation(host, { multiUse: true });
152
- await hostInvitation(host, invitation);
153
- for (let i = 0; i < 4; i++) {
154
- hosts.push(await createNewHost(invitation));
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
- const guest = await createPeer(host.spaceKey);
158
- await performAuth(guest, invitation);
159
- await guest.sink.waitFor(Invitation.State.SUCCESS);
160
- await sleep(10);
161
- expect(guest.ctx.disposed).to.be.true;
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
- test('guest gives up after trying with three hosts', { timeout: 20_000 }, async () => {
165
- const hosts: PeerSetup[] = [await createPeer()];
166
- const [host] = hosts;
167
- const invitation = await createInvitation(host, { multiUse: true });
168
- await hostInvitation(host, invitation);
169
- for (let i = 0; i < 2; i++) {
170
- hosts.push(await createNewHost(invitation));
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
- await sleep(10);
181
- expect(guest.sink.lastState).to.eq(Invitation.State.ERROR);
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
- test('single host - many guests', async () => {
185
- const hosts: PeerSetup[] = [await createPeer()];
186
- const [host] = hosts;
187
- const invitation = await createInvitation(host, { multiUse: true });
188
- await hostInvitation(host, invitation);
189
- const guests = await Promise.all(
190
- range(5).map(async () => {
191
- const guest = await createPeer(host.spaceKey);
192
- await performAuth(guest, invitation);
193
- return guest;
194
- }),
195
- );
196
-
197
- await sleep(10);
198
- guests.forEach((g) => {
199
- expect(g.ctx.disposed).to.be.true;
200
- expect(g.sink.lastState).to.eq(Invitation.State.SUCCESS);
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
- test('many guests - many hosts', async () => {
205
- const hosts: PeerSetup[] = [await createPeer()];
206
- const [host] = hosts;
207
- const invitation = await createInvitation(host, { multiUse: true });
208
- await hostInvitation(host, invitation);
209
- for (let i = 0; i < 4; i++) {
210
- hosts.push(await createNewHost(invitation));
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 guests = await Promise.all(
213
- range(5).map(async () => {
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
- test('single use invitation - many guests - only one admitted', async () => {
227
- const host = await createPeer();
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
- await sleep(40);
243
- const success = guests.filter((g) => g.sink.lastState === Invitation.State.SUCCESS);
244
- expect(success.length).to.eq(1);
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
- setup.handler.handleInvitationFlow(setup.ctx, setup.sink, setup.protocol, invitation);
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
- const acceptInvitation = async (setup: PeerSetup, invitation: Invitation): Promise<Trigger<string>> => {
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
- const authCodeInput = new Trigger<string>();
285
- setup.handler.acceptInvitation(setup.ctx, setup.sink, setup.protocol, invitation, authCodeInput);
286
- return authCodeInput;
287
- };
288
-
289
- const failAuth = async (setup: PeerSetup, invitation: Invitation) => {
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
- return {
332
- sink,
333
- next: sink.push.bind(sink),
334
- error: () => {},
335
- complete: () => {},
336
- hasState,
337
- get lastState() {
338
- return sink[sink.length - 1]?.state;
339
- },
340
- waitFor: async (state: Invitation.State): Promise<void> => {
341
- if (sink[sink.length - 1]?.state === state) {
342
- return;
343
- }
344
- const sliceStart = sink.length;
345
- await waitForCondition({
346
- condition: () => hasState(sliceStart, state),
347
- });
348
- },
349
- } as any;
350
- };
351
-
352
- const createInvitation = async (setup: PeerSetup, options?: Partial<Invitation>): Promise<Invitation> => {
353
- const observable = await setup.peer.invitationsManager.createInvitation({
354
- type: Invitation.Type.DELEGATED,
355
- kind: Invitation.Kind.SPACE,
356
- authMethod: Invitation.AuthMethod.SHARED_SECRET,
357
- spaceKey: setup.spaceKey,
358
- multiUse: false,
359
- ...options,
360
- });
361
- // cancel to avoid interfering with invitations-handler direct invocations
362
- const invitation = observable.get();
363
- await setup.peer.invitationsManager.cancelInvitation(invitation);
364
- return { ...invitation, swarmKey: PublicKey.random() };
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
+ );