@dxos/client-services 0.1.23 → 0.1.24

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 (115) hide show
  1. package/dist/lib/browser/chunk-R2FEBB66.mjs +3865 -0
  2. package/dist/lib/browser/chunk-R2FEBB66.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +56 -3066
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/packlets/testing/index.mjs +198 -0
  7. package/dist/lib/browser/packlets/testing/index.mjs.map +7 -0
  8. package/dist/lib/node/index.cjs +1401 -645
  9. package/dist/lib/node/index.cjs.map +4 -4
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/packlets/testing/index.cjs +3688 -0
  12. package/dist/lib/node/packlets/testing/index.cjs.map +7 -0
  13. package/dist/types/src/packlets/deprecated/profile.d.ts +3 -1
  14. package/dist/types/src/packlets/deprecated/profile.d.ts.map +1 -1
  15. package/dist/types/src/packlets/deprecated/space.d.ts.map +1 -1
  16. package/dist/types/src/packlets/deprecated/system.d.ts +15 -9
  17. package/dist/types/src/packlets/deprecated/system.d.ts.map +1 -1
  18. package/dist/types/src/packlets/devtools/devtools.d.ts +2 -2
  19. package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
  20. package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
  21. package/dist/types/src/packlets/devtools/network.d.ts +3 -3
  22. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  23. package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
  24. package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
  25. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  26. package/dist/types/src/packlets/identity/identity-manager.d.ts +7 -1
  27. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  28. package/dist/types/src/packlets/identity/identity.d.ts +1 -0
  29. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  30. package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts +11 -3
  31. package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts.map +1 -1
  32. package/dist/types/src/packlets/invitations/invitations.d.ts +1 -1
  33. package/dist/types/src/packlets/invitations/invitations.d.ts.map +1 -1
  34. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
  35. package/dist/types/src/packlets/services/service-context.d.ts +2 -0
  36. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  37. package/dist/types/src/packlets/services/service-context.test.d.ts +2 -0
  38. package/dist/types/src/packlets/services/service-context.test.d.ts.map +1 -0
  39. package/dist/types/src/packlets/services/service-definitions.d.ts +1 -1
  40. package/dist/types/src/packlets/services/service-definitions.d.ts.map +1 -1
  41. package/dist/types/src/packlets/services/service-host.d.ts +9 -6
  42. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  43. package/dist/types/src/packlets/services/service-registry.d.ts +4 -3
  44. package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
  45. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +9 -2
  46. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  47. package/dist/types/src/packlets/spaces/data-space.d.ts +18 -4
  48. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  49. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +50 -0
  50. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -0
  51. package/dist/types/src/packlets/spaces/notarization-plugin.test.d.ts +2 -0
  52. package/dist/types/src/packlets/spaces/notarization-plugin.test.d.ts.map +1 -0
  53. package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -1
  54. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  55. package/dist/types/src/packlets/testing/credential-utils.d.ts +8 -0
  56. package/dist/types/src/packlets/testing/credential-utils.d.ts.map +1 -0
  57. package/dist/types/src/packlets/testing/index.d.ts +2 -0
  58. package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
  59. package/dist/types/src/packlets/testing/invitation-utils.d.ts +3 -0
  60. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -0
  61. package/dist/types/src/packlets/testing/test-builder.d.ts +2 -2
  62. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  63. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +28 -0
  64. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -0
  65. package/dist/types/src/packlets/vault/{iframe-runtime.d.ts → iframe-proxy-runtime.d.ts} +4 -4
  66. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -0
  67. package/dist/types/src/packlets/vault/index.d.ts +4 -1
  68. package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
  69. package/dist/types/src/packlets/vault/vault-resource-lock.d.ts +19 -0
  70. package/dist/types/src/packlets/vault/vault-resource-lock.d.ts.map +1 -0
  71. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
  72. package/dist/types/src/packlets/vault/worker-session.d.ts +4 -4
  73. package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
  74. package/package.json +29 -29
  75. package/src/packlets/deprecated/profile.ts +20 -2
  76. package/src/packlets/deprecated/space.ts +41 -37
  77. package/src/packlets/deprecated/system.ts +26 -13
  78. package/src/packlets/devtools/devtools.ts +4 -4
  79. package/src/packlets/devtools/feeds.ts +11 -6
  80. package/src/packlets/devtools/network.ts +20 -9
  81. package/src/packlets/devtools/spaces.ts +7 -6
  82. package/src/packlets/identity/authenticator.ts +11 -6
  83. package/src/packlets/identity/identity-manager.test.ts +24 -15
  84. package/src/packlets/identity/identity-manager.ts +22 -8
  85. package/src/packlets/identity/identity.test.ts +21 -22
  86. package/src/packlets/identity/identity.ts +10 -5
  87. package/src/packlets/invitations/halo-invitations-handler.test.ts +4 -45
  88. package/src/packlets/invitations/halo-invitations-handler.ts +33 -17
  89. package/src/packlets/invitations/invitations.ts +2 -1
  90. package/src/packlets/invitations/space-invitations-handler.test.ts +43 -26
  91. package/src/packlets/invitations/space-invitations-handler.ts +8 -11
  92. package/src/packlets/services/service-context.test.ts +56 -0
  93. package/src/packlets/services/service-context.ts +60 -4
  94. package/src/packlets/services/service-definitions.ts +1 -1
  95. package/src/packlets/services/service-host.test.ts +74 -5
  96. package/src/packlets/services/service-host.ts +85 -23
  97. package/src/packlets/services/service-registry.test.ts +2 -1
  98. package/src/packlets/services/service-registry.ts +5 -1
  99. package/src/packlets/spaces/data-space-manager.test.ts +71 -14
  100. package/src/packlets/spaces/data-space-manager.ts +49 -8
  101. package/src/packlets/spaces/data-space.ts +113 -14
  102. package/src/packlets/spaces/notarization-plugin.test.ts +81 -0
  103. package/src/packlets/spaces/notarization-plugin.ts +211 -0
  104. package/src/packlets/spaces/spaces-service.ts +9 -1
  105. package/src/packlets/testing/credential-utils.ts +28 -0
  106. package/src/packlets/testing/index.ts +2 -0
  107. package/src/packlets/testing/invitation-utils.ts +44 -0
  108. package/src/packlets/testing/test-builder.ts +14 -18
  109. package/src/packlets/vault/iframe-host-runtime.ts +112 -0
  110. package/src/packlets/vault/{iframe-runtime.ts → iframe-proxy-runtime.ts} +3 -3
  111. package/src/packlets/vault/index.ts +4 -1
  112. package/src/packlets/vault/vault-resource-lock.ts +76 -0
  113. package/src/packlets/vault/worker-runtime.ts +13 -3
  114. package/src/packlets/vault/worker-session.ts +17 -17
  115. package/dist/types/src/packlets/vault/iframe-runtime.d.ts.map +0 -1
@@ -0,0 +1,3865 @@
1
+ import "@dxos/node-std/globals"
2
+
3
+ // packages/sdk/client-services/src/packlets/deprecated/space.ts
4
+ import assert from "@dxos/node-std/assert";
5
+ import { Stream } from "@dxos/codec-protobuf";
6
+ import { todo } from "@dxos/debug";
7
+ import { log } from "@dxos/log";
8
+ import { SpaceMember } from "@dxos/protocols/proto/dxos/client";
9
+ import { humanize } from "@dxos/util";
10
+ var SpaceServiceImpl = class {
11
+ constructor(serviceContext) {
12
+ this.serviceContext = serviceContext;
13
+ this.inviteeInvitations = /* @__PURE__ */ new Map();
14
+ }
15
+ subscribeToSpace(request) {
16
+ return new Stream(({ next }) => {
17
+ next({
18
+ space: {
19
+ publicKey: request.spaceKey,
20
+ isOpen: true,
21
+ isActive: true,
22
+ members: []
23
+ }
24
+ });
25
+ });
26
+ }
27
+ subscribeSpaces() {
28
+ return new Stream(({ next, ctx }) => {
29
+ const onUpdate = () => {
30
+ const spaces = Array.from(this.serviceContext.dataSpaceManager.spaces.values()).filter((space) => this.serviceContext.dataServiceSubscriptions.getDataService(space.key)).map((space) => ({
31
+ publicKey: space.key,
32
+ isOpen: true,
33
+ isActive: true,
34
+ members: Array.from(space.inner.spaceState.members.values()).map((member) => {
35
+ var _a, _b, _c;
36
+ return {
37
+ identityKey: member.key,
38
+ profile: {
39
+ identityKey: member.key,
40
+ displayName: (_b = (_a = member.assertion.profile) == null ? void 0 : _a.displayName) != null ? _b : humanize(member.key)
41
+ },
42
+ presence: ((_c = this.serviceContext.identityManager.identity) == null ? void 0 : _c.identityKey.equals(member.key)) || space.presence.getPeersOnline().filter(({ identityKey }) => identityKey.equals(member.key)).length > 0 ? SpaceMember.PresenceState.ONLINE : SpaceMember.PresenceState.OFFLINE
43
+ };
44
+ })
45
+ }));
46
+ log("update", {
47
+ spaces
48
+ }, {
49
+ file: "space.ts",
50
+ line: 119,
51
+ scope: this,
52
+ callSite: (f, a) => f(...a)
53
+ });
54
+ next({
55
+ spaces
56
+ });
57
+ };
58
+ setTimeout(async () => {
59
+ if (!this.serviceContext.dataSpaceManager) {
60
+ next({
61
+ spaces: []
62
+ });
63
+ }
64
+ await this.serviceContext.initialized.wait();
65
+ const subscribeSpaces = () => {
66
+ for (const space of this.serviceContext.dataSpaceManager.spaces.values()) {
67
+ if (!this.serviceContext.dataServiceSubscriptions.getDataService(space.key)) {
68
+ continue;
69
+ }
70
+ space.stateUpdate.on(ctx, onUpdate);
71
+ space.presence.updated.on(ctx, onUpdate);
72
+ }
73
+ };
74
+ this.serviceContext.dataSpaceManager.updated.on(ctx, () => {
75
+ subscribeSpaces();
76
+ onUpdate();
77
+ });
78
+ subscribeSpaces();
79
+ onUpdate();
80
+ });
81
+ });
82
+ }
83
+ async getSpaceDetails(request) {
84
+ return todo();
85
+ }
86
+ async createSpace() {
87
+ if (!this.serviceContext.identityManager.identity) {
88
+ throw new Error("This device has no HALO identity available. See https://docs.dxos.org/guide/halo");
89
+ }
90
+ await this.serviceContext.initialized.wait();
91
+ const space = await this.serviceContext.dataSpaceManager.createSpace();
92
+ return {
93
+ publicKey: space.key,
94
+ isOpen: true,
95
+ isActive: true
96
+ };
97
+ }
98
+ async cloneSpace(snapshot) {
99
+ return todo();
100
+ }
101
+ async setSpaceState(request) {
102
+ return todo();
103
+ }
104
+ async authenticateInvitation(request) {
105
+ var _a;
106
+ assert(request.processId, "Process ID is missing.");
107
+ const invitation = this.inviteeInvitations.get(request.processId);
108
+ assert(invitation, "Invitation not found.");
109
+ assert(request.secret, "Secret not provided.");
110
+ invitation.secret = request.secret;
111
+ (_a = invitation.secretTrigger) == null ? void 0 : _a.call(invitation);
112
+ }
113
+ subscribeMembers(request) {
114
+ return todo();
115
+ }
116
+ async createSnapshot(request) {
117
+ return todo();
118
+ }
119
+ };
120
+
121
+ // packages/sdk/client-services/src/packlets/deprecated/profile.ts
122
+ import assert2 from "@dxos/node-std/assert";
123
+ import { Stream as Stream2 } from "@dxos/codec-protobuf";
124
+ import { signPresentation } from "@dxos/credentials";
125
+ import { todo as todo2 } from "@dxos/debug";
126
+ var ProfileServiceImpl = class {
127
+ constructor(context) {
128
+ this.context = context;
129
+ this.inviteeInvitations = /* @__PURE__ */ new Map();
130
+ }
131
+ subscribeProfile() {
132
+ return new Stream2(({ next }) => {
133
+ const emitNext = () => {
134
+ var _a;
135
+ return next({
136
+ profile: this.context.identityManager.identity ? {
137
+ identityKey: this.context.identityManager.identity.identityKey,
138
+ deviceKey: this.context.identityManager.identity.deviceKey,
139
+ displayName: (_a = this.context.identityManager.identity.profileDocument) == null ? void 0 : _a.displayName,
140
+ haloSpace: this.context.identityManager.identity.space.key
141
+ } : void 0
142
+ });
143
+ };
144
+ emitNext();
145
+ return this.context.identityManager.stateUpdate.on(emitNext);
146
+ });
147
+ }
148
+ async createProfile(request) {
149
+ var _a;
150
+ await this.context.createIdentity({
151
+ displayName: request.displayName
152
+ });
153
+ return {
154
+ identityKey: this.context.identityManager.identity.identityKey,
155
+ deviceKey: this.context.identityManager.identity.deviceKey,
156
+ displayName: (_a = this.context.identityManager.identity.profileDocument) == null ? void 0 : _a.displayName,
157
+ haloSpace: this.context.identityManager.identity.space.key
158
+ };
159
+ }
160
+ async recoverProfile(request) {
161
+ return todo2();
162
+ if (!request.seedPhrase) {
163
+ throw new Error("Recovery SeedPhrase not provided.");
164
+ }
165
+ }
166
+ async signPresentation({ presentation, nonce }) {
167
+ assert2(this.context.identityManager.identity, "Identity not initialized.");
168
+ return await signPresentation({
169
+ presentation,
170
+ signer: this.context.keyring,
171
+ signerKey: this.context.identityManager.identity.deviceKey,
172
+ chain: this.context.identityManager.identity.deviceCredentialChain,
173
+ nonce
174
+ });
175
+ }
176
+ };
177
+
178
+ // packages/sdk/client-services/src/packlets/deprecated/system.ts
179
+ var SystemServiceImpl = class {
180
+ constructor({ config, onInit, onStatus, onReset }) {
181
+ this._config = config;
182
+ this._onInit = onInit;
183
+ this._onStatus = onStatus;
184
+ this._onReset = onReset;
185
+ }
186
+ async getConfig() {
187
+ return this._config.values;
188
+ }
189
+ // TODO(burdon): Connect to iframe RPC heartbeat for network status?
190
+ async getStatus() {
191
+ return this._onStatus();
192
+ }
193
+ async initSession() {
194
+ await this._onInit();
195
+ }
196
+ async reset() {
197
+ await this._onReset();
198
+ }
199
+ };
200
+
201
+ // packages/sdk/client-services/src/packlets/deprecated/tracing.ts
202
+ var TracingServiceImpl = class {
203
+ constructor(_config) {
204
+ this._config = _config;
205
+ }
206
+ async setTracingOptions() {
207
+ throw new Error("Tracing not available.");
208
+ }
209
+ subscribeToRpcTrace() {
210
+ throw new Error("Tracing not available.");
211
+ }
212
+ };
213
+
214
+ // packages/sdk/client-services/src/packlets/devtools/feeds.ts
215
+ import { EventSubscriptions } from "@dxos/async";
216
+ import { Stream as Stream3 } from "@dxos/codec-protobuf";
217
+ import { FeedIterator } from "@dxos/feed-store";
218
+ import { PublicKey } from "@dxos/keys";
219
+ import { ComplexMap } from "@dxos/util";
220
+ var subscribeToFeeds = ({ feedStore }, { feedKeys }) => {
221
+ return new Stream3(({ next }) => {
222
+ if ((feedKeys == null ? void 0 : feedKeys.length) === 0) {
223
+ return;
224
+ }
225
+ const subscriptions = new EventSubscriptions();
226
+ const feedMap = new ComplexMap(PublicKey.hash);
227
+ const update = () => {
228
+ const { feeds } = feedStore;
229
+ feeds.filter((feed) => !(feedKeys == null ? void 0 : feedKeys.length) || feedKeys.some((feedKey) => feedKey.equals(feed.key))).forEach((feed) => {
230
+ if (!feedMap.has(feed.key)) {
231
+ feedMap.set(feed.key, feed);
232
+ feed.on("close", update);
233
+ subscriptions.add(feed.off("close", update));
234
+ }
235
+ });
236
+ next({
237
+ feeds: Array.from(feedMap.values()).map((feed) => ({
238
+ feedKey: feed.key,
239
+ length: feed.properties.length
240
+ }))
241
+ });
242
+ };
243
+ subscriptions.add(feedStore.feedOpened.on(update));
244
+ update();
245
+ return () => {
246
+ subscriptions.clear();
247
+ };
248
+ });
249
+ };
250
+ var subscribeToFeedBlocks = ({ feedStore }, { feedKey, maxBlocks = 10 }) => {
251
+ return new Stream3(({ next }) => {
252
+ if (!feedKey) {
253
+ return;
254
+ }
255
+ const subscriptions = new EventSubscriptions();
256
+ const timeout = setTimeout(async () => {
257
+ const feed = feedStore.getFeed(feedKey);
258
+ if (!feed) {
259
+ return;
260
+ }
261
+ const update = async () => {
262
+ const iterator = new FeedIterator(feed);
263
+ await iterator.open();
264
+ const blocks = [];
265
+ for await (const block of iterator) {
266
+ blocks.push(block);
267
+ if (blocks.length >= feed.properties.length) {
268
+ break;
269
+ }
270
+ }
271
+ next({
272
+ blocks: blocks.slice(-maxBlocks)
273
+ });
274
+ await iterator.close();
275
+ };
276
+ feed.on("append", update);
277
+ subscriptions.add(() => feed.off("append", update));
278
+ feed.on("truncate", update);
279
+ subscriptions.add(() => feed.off("truncate", update));
280
+ await update();
281
+ });
282
+ return () => {
283
+ subscriptions.clear();
284
+ clearTimeout(timeout);
285
+ };
286
+ });
287
+ };
288
+
289
+ // packages/sdk/client-services/src/packlets/devtools/network.ts
290
+ import { Stream as Stream4 } from "@dxos/codec-protobuf";
291
+ import { Context } from "@dxos/context";
292
+ import { PublicKey as PublicKey2 } from "@dxos/keys";
293
+ var subscribeToNetworkStatus = ({ networkManager }) => new Stream4(({ next, close }) => {
294
+ const update = () => {
295
+ try {
296
+ const status = networkManager.signalManager.getStatus();
297
+ next({
298
+ servers: status
299
+ });
300
+ } catch (err) {
301
+ close(err);
302
+ }
303
+ };
304
+ networkManager.signalManager.statusChanged.on(update);
305
+ update();
306
+ });
307
+ var subscribeToSignal = ({ networkManager }) => new Stream4(({ next }) => {
308
+ const ctx = new Context();
309
+ networkManager.signalManager.onMessage.on(ctx, (message) => {
310
+ next({
311
+ message: {
312
+ author: message.author.asUint8Array(),
313
+ recipient: message.recipient.asUint8Array(),
314
+ payload: message.payload
315
+ },
316
+ receivedAt: new Date()
317
+ });
318
+ });
319
+ networkManager.signalManager.swarmEvent.on(ctx, (swarmEvent) => {
320
+ next({
321
+ swarmEvent: swarmEvent.swarmEvent,
322
+ receivedAt: new Date()
323
+ });
324
+ });
325
+ return () => {
326
+ return ctx.dispose();
327
+ };
328
+ });
329
+ var subscribeToNetworkTopics = ({ networkManager }) => new Stream4(({ next, close }) => {
330
+ const update = () => {
331
+ try {
332
+ const topics = networkManager.topics;
333
+ const labeledTopics = topics.map((topic) => {
334
+ var _a, _b;
335
+ return {
336
+ topic,
337
+ label: (_b = (_a = networkManager.getSwarm(topic)) == null ? void 0 : _a.label) != null ? _b : topic.toHex()
338
+ };
339
+ });
340
+ next({
341
+ topics: labeledTopics
342
+ });
343
+ } catch (err) {
344
+ close(err);
345
+ }
346
+ };
347
+ networkManager.topicsUpdated.on(update);
348
+ update();
349
+ });
350
+ var subscribeToSwarmInfo = ({ networkManager }) => new Stream4(({ next }) => {
351
+ var _a;
352
+ const update = () => {
353
+ var _a2;
354
+ const info = (_a2 = networkManager.connectionLog) == null ? void 0 : _a2.swarms;
355
+ if (info) {
356
+ next({
357
+ data: info
358
+ });
359
+ }
360
+ };
361
+ (_a = networkManager.connectionLog) == null ? void 0 : _a.update.on(update);
362
+ update();
363
+ });
364
+ var getNetworkPeers = ({ networkManager }, request) => {
365
+ if (!request.topic) {
366
+ throw new Error("Expected a network topic");
367
+ }
368
+ const map = networkManager.getSwarmMap(PublicKey2.from(request.topic));
369
+ return {
370
+ peers: map == null ? void 0 : map.peers.map((peer) => ({
371
+ ...peer,
372
+ connections: peer.connections.map((connection) => connection.asUint8Array())
373
+ }))
374
+ };
375
+ };
376
+
377
+ // packages/sdk/client-services/src/packlets/devtools/spaces.ts
378
+ import { Stream as Stream5 } from "@dxos/codec-protobuf";
379
+ var subscribeToSpaces = (context, { spaceKeys = [] }) => {
380
+ return new Stream5(({ next }) => {
381
+ let unsubscribe;
382
+ const update = async () => {
383
+ const spaces = [
384
+ ...context.spaceManager.spaces.values()
385
+ ];
386
+ const filteredSpaces = spaces.filter((space) => !(spaceKeys == null ? void 0 : spaceKeys.length) || spaceKeys.some((spaceKey) => spaceKey.equals(space.key)));
387
+ next({
388
+ spaces: filteredSpaces.map((space) => {
389
+ const spaceMetadata = context.metadataStore.spaces.find((spaceMetadata2) => spaceMetadata2.key.equals(space.key));
390
+ return {
391
+ key: space.key,
392
+ isOpen: space.isOpen,
393
+ timeframe: spaceMetadata == null ? void 0 : spaceMetadata.dataTimeframe,
394
+ genesisFeed: space.genesisFeedKey,
395
+ controlFeed: space.controlFeedKey,
396
+ dataFeed: space.dataFeedKey
397
+ };
398
+ })
399
+ });
400
+ };
401
+ const timeout = setTimeout(async () => {
402
+ await context.initialized.wait();
403
+ unsubscribe = context.dataSpaceManager.updated.on(() => update());
404
+ await update();
405
+ });
406
+ return () => {
407
+ unsubscribe == null ? void 0 : unsubscribe();
408
+ clearTimeout(timeout);
409
+ };
410
+ });
411
+ };
412
+
413
+ // packages/sdk/client-services/src/packlets/devtools/devtools.ts
414
+ import { Event as AsyncEvent } from "@dxos/async";
415
+ import { Stream as Stream7 } from "@dxos/codec-protobuf";
416
+
417
+ // packages/sdk/client-services/src/packlets/devtools/keys.ts
418
+ import { Stream as Stream6 } from "@dxos/codec-protobuf";
419
+ var subscribeToKeyringKeys = ({ keyring }) => new Stream6(({ next }) => {
420
+ const update = () => {
421
+ next({
422
+ keys: keyring.list()
423
+ });
424
+ };
425
+ const unsubscribe = keyring.keysUpdate.on(update);
426
+ update();
427
+ return unsubscribe;
428
+ });
429
+
430
+ // packages/sdk/client-services/src/packlets/devtools/devtools.ts
431
+ var DevtoolsHostEvents = class {
432
+ constructor() {
433
+ this.ready = new AsyncEvent();
434
+ }
435
+ };
436
+ var DevtoolsServiceImpl = class {
437
+ constructor(params) {
438
+ this.params = params;
439
+ }
440
+ events(request) {
441
+ return new Stream7(({ next }) => {
442
+ this.params.events.ready.on(() => {
443
+ next({
444
+ ready: {}
445
+ });
446
+ });
447
+ });
448
+ }
449
+ getConfig(request) {
450
+ throw new Error();
451
+ }
452
+ resetStorage(request) {
453
+ throw new Error();
454
+ }
455
+ enableDebugLogging(request) {
456
+ throw new Error();
457
+ }
458
+ disableDebugLogging(request) {
459
+ throw new Error();
460
+ }
461
+ subscribeToKeyringKeys(request) {
462
+ return subscribeToKeyringKeys({
463
+ keyring: this.params.context.keyring
464
+ });
465
+ }
466
+ subscribeToCredentialMessages(request) {
467
+ throw new Error();
468
+ }
469
+ subscribeToSpaces(request) {
470
+ return subscribeToSpaces(this.params.context, request);
471
+ }
472
+ subscribeToItems(request) {
473
+ throw new Error();
474
+ }
475
+ subscribeToFeeds(request) {
476
+ return subscribeToFeeds({
477
+ feedStore: this.params.context.feedStore
478
+ }, request);
479
+ }
480
+ subscribeToFeedBlocks(request) {
481
+ return subscribeToFeedBlocks({
482
+ feedStore: this.params.context.feedStore
483
+ }, request);
484
+ }
485
+ getSpaceSnapshot(request) {
486
+ throw new Error();
487
+ }
488
+ saveSpaceSnapshot(request) {
489
+ throw new Error();
490
+ }
491
+ clearSnapshots(request) {
492
+ throw new Error();
493
+ }
494
+ getNetworkPeers(request) {
495
+ throw new Error();
496
+ }
497
+ subscribeToNetworkTopics(request) {
498
+ throw new Error();
499
+ }
500
+ subscribeToSignalStatus(request) {
501
+ return subscribeToNetworkStatus({
502
+ networkManager: this.params.context.networkManager
503
+ });
504
+ }
505
+ subscribeToSignal() {
506
+ return subscribeToSignal({
507
+ networkManager: this.params.context.networkManager
508
+ });
509
+ }
510
+ subscribeToSwarmInfo() {
511
+ return subscribeToSwarmInfo({
512
+ networkManager: this.params.context.networkManager
513
+ });
514
+ }
515
+ };
516
+
517
+ // packages/sdk/client-services/src/packlets/identity/authenticator.ts
518
+ import { Trigger } from "@dxos/async";
519
+ import { Context as Context2 } from "@dxos/context";
520
+ import { verifyCredential } from "@dxos/credentials";
521
+ import { log as log2 } from "@dxos/log";
522
+ import { schema } from "@dxos/protocols";
523
+ var createAuthProvider = (signer) => async (nonce) => {
524
+ const credential = await signer.createCredential({
525
+ assertion: {
526
+ "@type": "dxos.halo.credentials.Auth"
527
+ },
528
+ subject: signer.getIssuer(),
529
+ nonce
530
+ });
531
+ return schema.getCodecForType("dxos.halo.credentials.Credential").encode(credential);
532
+ };
533
+ var TrustedKeySetAuthVerifier = class {
534
+ // prettier-ignore
535
+ constructor(_params) {
536
+ this._params = _params;
537
+ this._ctx = new Context2();
538
+ }
539
+ async close() {
540
+ await this._ctx.dispose();
541
+ }
542
+ get verifier() {
543
+ return async (nonce, auth) => {
544
+ const credential = schema.getCodecForType("dxos.halo.credentials.Credential").decode(auth);
545
+ log2("authenticating...", {
546
+ credential
547
+ }, {
548
+ file: "authenticator.ts",
549
+ line: 57,
550
+ scope: this,
551
+ callSite: (f, a) => f(...a)
552
+ });
553
+ const result = await verifyCredential(credential);
554
+ if (result.kind === "fail") {
555
+ log2("Invalid credential", {
556
+ result
557
+ }, {
558
+ file: "authenticator.ts",
559
+ line: 61,
560
+ scope: this,
561
+ callSite: (f, a) => f(...a)
562
+ });
563
+ return false;
564
+ }
565
+ if (!credential.proof.nonce || !Buffer.from(nonce).equals(credential.proof.nonce)) {
566
+ log2("Invalid nonce", {
567
+ nonce,
568
+ credential
569
+ }, {
570
+ file: "authenticator.ts",
571
+ line: 66,
572
+ scope: this,
573
+ callSite: (f, a) => f(...a)
574
+ });
575
+ return false;
576
+ }
577
+ if (this._isTrustedKey(credential.issuer)) {
578
+ log2("key is not currently in trusted set, waiting...", {
579
+ key: credential.issuer
580
+ }, {
581
+ file: "authenticator.ts",
582
+ line: 71,
583
+ scope: this,
584
+ callSite: (f, a) => f(...a)
585
+ });
586
+ return true;
587
+ }
588
+ const trigger = new Trigger();
589
+ this._ctx.onDispose(() => {
590
+ trigger.wake(false);
591
+ });
592
+ const clear = this._params.update.on(this._ctx, () => {
593
+ if (this._isTrustedKey(credential.issuer)) {
594
+ log2("auth success", {
595
+ key: credential.issuer
596
+ }, {
597
+ file: "authenticator.ts",
598
+ line: 82,
599
+ scope: this,
600
+ callSite: (f, a) => f(...a)
601
+ });
602
+ trigger.wake(true);
603
+ } else {
604
+ log2("key is not currently in trusted set, waiting...", {
605
+ key: credential.issuer
606
+ }, {
607
+ file: "authenticator.ts",
608
+ line: 85,
609
+ scope: this,
610
+ callSite: (f, a) => f(...a)
611
+ });
612
+ }
613
+ });
614
+ try {
615
+ return await trigger.wait({
616
+ timeout: this._params.authTimeout
617
+ });
618
+ } catch (e) {
619
+ return false;
620
+ } finally {
621
+ clear();
622
+ }
623
+ };
624
+ }
625
+ _isTrustedKey(deviceKey) {
626
+ const deviceSet = this._params.trustedKeysProvider();
627
+ return deviceSet.has(deviceKey);
628
+ }
629
+ };
630
+
631
+ // packages/sdk/client-services/src/packlets/identity/identity.ts
632
+ import assert3 from "@dxos/node-std/assert";
633
+ import { Event } from "@dxos/async";
634
+ import { DeviceStateMachine, createCredentialSignerWithKey, createCredentialSignerWithChain, ProfileStateMachine } from "@dxos/credentials";
635
+ import { failUndefined } from "@dxos/debug";
636
+ import { writeMessages } from "@dxos/feed-store";
637
+ import { log as log3 } from "@dxos/log";
638
+ import { AdmittedFeed } from "@dxos/protocols/proto/dxos/halo/credentials";
639
+ var AUTH_TIMEOUT = 3e4;
640
+ var Identity = class {
641
+ constructor({ space, signer, identityKey, deviceKey }) {
642
+ this.stateUpdate = new Event();
643
+ this.space = space;
644
+ this._signer = signer;
645
+ this.identityKey = identityKey;
646
+ this.deviceKey = deviceKey;
647
+ this._deviceStateMachine = this.space.spaceState.registerProcessor(new DeviceStateMachine({
648
+ identityKey: this.identityKey,
649
+ deviceKey: this.deviceKey,
650
+ onUpdate: () => this.stateUpdate.emit()
651
+ }));
652
+ this._profileStateMachine = this.space.spaceState.registerProcessor(new ProfileStateMachine({
653
+ identityKey: this.identityKey,
654
+ onUpdate: () => this.stateUpdate.emit()
655
+ }));
656
+ this.authVerifier = new TrustedKeySetAuthVerifier({
657
+ trustedKeysProvider: () => this.authorizedDeviceKeys,
658
+ update: this.stateUpdate,
659
+ authTimeout: AUTH_TIMEOUT
660
+ });
661
+ }
662
+ // TODO(burdon): Expose state object?
663
+ get authorizedDeviceKeys() {
664
+ return this._deviceStateMachine.processor.authorizedDeviceKeys;
665
+ }
666
+ async open() {
667
+ await this._deviceStateMachine.open();
668
+ await this._profileStateMachine.open();
669
+ await this.space.open();
670
+ }
671
+ async close() {
672
+ await this.authVerifier.close();
673
+ await this._deviceStateMachine.close();
674
+ await this._profileStateMachine.close();
675
+ await this.space.close();
676
+ }
677
+ async ready() {
678
+ await this._deviceStateMachine.processor.deviceChainReady.wait();
679
+ await this.controlPipeline.state.waitUntilReachedTargetTimeframe({
680
+ timeout: 3e3
681
+ });
682
+ }
683
+ get profileDocument() {
684
+ return this._profileStateMachine.processor.profile;
685
+ }
686
+ /**
687
+ * @test-only
688
+ */
689
+ get controlPipeline() {
690
+ return this.space.controlPipeline;
691
+ }
692
+ get haloSpaceKey() {
693
+ return this.space.key;
694
+ }
695
+ get haloGenesisFeedKey() {
696
+ return this.space.genesisFeedKey;
697
+ }
698
+ get deviceCredentialChain() {
699
+ return this._deviceStateMachine.processor.deviceCredentialChain;
700
+ }
701
+ getAdmissionCredentials() {
702
+ var _a, _b;
703
+ return {
704
+ deviceKey: this.deviceKey,
705
+ controlFeedKey: (_a = this.space.controlFeedKey) != null ? _a : failUndefined(),
706
+ dataFeedKey: (_b = this.space.dataFeedKey) != null ? _b : failUndefined()
707
+ };
708
+ }
709
+ /**
710
+ * Issues credentials as identity.
711
+ * Requires identity to be ready.
712
+ */
713
+ getIdentityCredentialSigner() {
714
+ assert3(this._deviceStateMachine.processor.deviceCredentialChain, "Device credential chain is not ready.");
715
+ return createCredentialSignerWithChain(this._signer, this._deviceStateMachine.processor.deviceCredentialChain, this.deviceKey);
716
+ }
717
+ /**
718
+ * Issues credentials as device.
719
+ */
720
+ getDeviceCredentialSigner() {
721
+ return createCredentialSignerWithKey(this._signer, this.deviceKey);
722
+ }
723
+ async admitDevice({ deviceKey, controlFeedKey, dataFeedKey }) {
724
+ log3("Admitting device:", {
725
+ identityKey: this.identityKey,
726
+ hostDevice: this.deviceKey,
727
+ deviceKey,
728
+ controlFeedKey,
729
+ dataFeedKey
730
+ }, {
731
+ file: "identity.ts",
732
+ line: 160,
733
+ scope: this,
734
+ callSite: (f, a) => f(...a)
735
+ });
736
+ const signer = this.getIdentityCredentialSigner();
737
+ await writeMessages(this.controlPipeline.writer, [
738
+ await signer.createCredential({
739
+ subject: deviceKey,
740
+ assertion: {
741
+ "@type": "dxos.halo.credentials.AuthorizedDevice",
742
+ identityKey: this.identityKey,
743
+ deviceKey
744
+ }
745
+ }),
746
+ await signer.createCredential({
747
+ subject: controlFeedKey,
748
+ assertion: {
749
+ "@type": "dxos.halo.credentials.AdmittedFeed",
750
+ spaceKey: this.haloSpaceKey,
751
+ deviceKey,
752
+ identityKey: this.identityKey,
753
+ designation: AdmittedFeed.Designation.CONTROL
754
+ }
755
+ }),
756
+ await signer.createCredential({
757
+ subject: dataFeedKey,
758
+ assertion: {
759
+ "@type": "dxos.halo.credentials.AdmittedFeed",
760
+ spaceKey: this.haloSpaceKey,
761
+ deviceKey,
762
+ identityKey: this.identityKey,
763
+ designation: AdmittedFeed.Designation.DATA
764
+ }
765
+ })
766
+ ].map((credential) => ({
767
+ credential: {
768
+ credential
769
+ }
770
+ })));
771
+ }
772
+ };
773
+
774
+ // packages/sdk/client-services/src/packlets/identity/identity-manager.ts
775
+ import assert4 from "@dxos/node-std/assert";
776
+ import { Event as Event2 } from "@dxos/async";
777
+ import { createCredentialSignerWithKey as createCredentialSignerWithKey2, CredentialGenerator } from "@dxos/credentials";
778
+ import { log as log4 } from "@dxos/log";
779
+ import { AdmittedFeed as AdmittedFeed2 } from "@dxos/protocols/proto/dxos/halo/credentials";
780
+ import { deferFunction } from "@dxos/util";
781
+ var IdentityManager = class {
782
+ // TODO(burdon): IdentityManagerParams.
783
+ // TODO(dmaretskyi): Perhaps this should take/generate the peerKey outside of an initialized identity.
784
+ constructor(_metadataStore, _keyring, _feedStore, _spaceManager) {
785
+ this._metadataStore = _metadataStore;
786
+ this._keyring = _keyring;
787
+ this._feedStore = _feedStore;
788
+ this._spaceManager = _spaceManager;
789
+ this.stateUpdate = new Event2();
790
+ }
791
+ get identity() {
792
+ return this._identity;
793
+ }
794
+ async open() {
795
+ await this._metadataStore.load();
796
+ const identityRecord = this._metadataStore.getIdentityRecord();
797
+ log4("identity record", {
798
+ identityRecord
799
+ }, {
800
+ file: "identity-manager.ts",
801
+ line: 63,
802
+ scope: this,
803
+ callSite: (f, a) => f(...a)
804
+ });
805
+ if (identityRecord) {
806
+ this._identity = await this._constructIdentity(identityRecord);
807
+ await this._identity.open();
808
+ await this._identity.ready();
809
+ this.stateUpdate.emit();
810
+ }
811
+ }
812
+ async close() {
813
+ var _a;
814
+ await ((_a = this._identity) == null ? void 0 : _a.close());
815
+ }
816
+ async createIdentity({ displayName } = {}) {
817
+ assert4(!this._identity, "Identity already exists.");
818
+ log4("creating identity...", {}, {
819
+ file: "identity-manager.ts",
820
+ line: 78,
821
+ scope: this,
822
+ callSite: (f, a) => f(...a)
823
+ });
824
+ const controlFeedKey = await this._keyring.createKey();
825
+ const identityRecord = {
826
+ identityKey: await this._keyring.createKey(),
827
+ deviceKey: await this._keyring.createKey(),
828
+ haloSpace: {
829
+ spaceKey: await this._keyring.createKey(),
830
+ genesisFeedKey: controlFeedKey,
831
+ writeControlFeedKey: controlFeedKey,
832
+ writeDataFeedKey: await this._keyring.createKey()
833
+ }
834
+ };
835
+ const identity = await this._constructIdentity(identityRecord);
836
+ await identity.open();
837
+ {
838
+ const generator = new CredentialGenerator(this._keyring, identityRecord.identityKey, identityRecord.deviceKey);
839
+ const credentials = [
840
+ // Space genesis.
841
+ ...await generator.createSpaceGenesis(identityRecord.haloSpace.spaceKey, identityRecord.haloSpace.genesisFeedKey),
842
+ // Feed admission.
843
+ await generator.createFeedAdmission(identityRecord.haloSpace.spaceKey, identityRecord.haloSpace.writeDataFeedKey, AdmittedFeed2.Designation.DATA)
844
+ ];
845
+ if (displayName) {
846
+ credentials.push(await generator.createProfileCredential({
847
+ displayName
848
+ }));
849
+ }
850
+ credentials.push(await generator.createDeviceAuthorization(identityRecord.deviceKey));
851
+ for (const credential of credentials) {
852
+ await identity.controlPipeline.writer.write({
853
+ credential: {
854
+ credential
855
+ }
856
+ });
857
+ }
858
+ }
859
+ await this._metadataStore.setIdentityRecord(identityRecord);
860
+ this._identity = identity;
861
+ await this._identity.ready();
862
+ this.stateUpdate.emit();
863
+ log4("created identity", {
864
+ identityKey: identity.identityKey,
865
+ deviceKey: identity.deviceKey
866
+ }, {
867
+ file: "identity-manager.ts",
868
+ line: 136,
869
+ scope: this,
870
+ callSite: (f, a) => f(...a)
871
+ });
872
+ return identity;
873
+ }
874
+ /**
875
+ * Accept an existing identity. Expects it's device key to be authorized (now or later).
876
+ */
877
+ async acceptIdentity(params) {
878
+ log4("accepting identity", {
879
+ params
880
+ }, {
881
+ file: "identity-manager.ts",
882
+ line: 144,
883
+ scope: this,
884
+ callSite: (f, a) => f(...a)
885
+ });
886
+ assert4(!this._identity, "Identity already exists.");
887
+ const identityRecord = {
888
+ identityKey: params.identityKey,
889
+ deviceKey: params.deviceKey,
890
+ haloSpace: {
891
+ spaceKey: params.haloSpaceKey,
892
+ genesisFeedKey: params.haloGenesisFeedKey,
893
+ writeControlFeedKey: params.controlFeedKey,
894
+ writeDataFeedKey: params.dataFeedKey
895
+ }
896
+ };
897
+ const identity = await this._constructIdentity(identityRecord);
898
+ await identity.open();
899
+ this._identity = identity;
900
+ await this._metadataStore.setIdentityRecord(identityRecord);
901
+ await this._identity.ready();
902
+ this.stateUpdate.emit();
903
+ log4("accepted identity", {
904
+ identityKey: identity.identityKey,
905
+ deviceKey: identity.deviceKey
906
+ }, {
907
+ file: "identity-manager.ts",
908
+ line: 164,
909
+ scope: this,
910
+ callSite: (f, a) => f(...a)
911
+ });
912
+ return identity;
913
+ }
914
+ async _constructIdentity(identityRecord) {
915
+ assert4(!this._identity);
916
+ log4("constructing identity", {
917
+ identityRecord
918
+ }, {
919
+ file: "identity-manager.ts",
920
+ line: 170,
921
+ scope: this,
922
+ callSite: (f, a) => f(...a)
923
+ });
924
+ const controlFeed = await this._feedStore.openFeed(identityRecord.haloSpace.writeControlFeedKey, {
925
+ writable: true
926
+ });
927
+ const dataFeed = await this._feedStore.openFeed(identityRecord.haloSpace.writeDataFeedKey, {
928
+ writable: true
929
+ });
930
+ const space = await this._constructSpace({
931
+ spaceRecord: identityRecord.haloSpace,
932
+ swarmIdentity: {
933
+ peerKey: identityRecord.deviceKey,
934
+ credentialProvider: createAuthProvider(createCredentialSignerWithKey2(this._keyring, identityRecord.deviceKey)),
935
+ credentialAuthenticator: deferFunction(() => identity.authVerifier.verifier)
936
+ },
937
+ identityKey: identityRecord.identityKey
938
+ });
939
+ space.setControlFeed(controlFeed);
940
+ space.setDataFeed(dataFeed);
941
+ const identity = new Identity({
942
+ space,
943
+ signer: this._keyring,
944
+ identityKey: identityRecord.identityKey,
945
+ deviceKey: identityRecord.deviceKey
946
+ });
947
+ log4("done", {
948
+ identityKey: identityRecord.identityKey
949
+ }, {
950
+ file: "identity-manager.ts",
951
+ line: 196,
952
+ scope: this,
953
+ callSite: (f, a) => f(...a)
954
+ });
955
+ return identity;
956
+ }
957
+ async _constructSpace({ spaceRecord, swarmIdentity, identityKey }) {
958
+ return this._spaceManager.constructSpace({
959
+ metadata: {
960
+ key: spaceRecord.spaceKey,
961
+ genesisFeedKey: spaceRecord.genesisFeedKey
962
+ },
963
+ swarmIdentity,
964
+ onNetworkConnection: () => {
965
+ }
966
+ });
967
+ }
968
+ };
969
+
970
+ // packages/sdk/client-services/src/packlets/invitations/encoder.ts
971
+ import base from "base-x";
972
+ import { schema as schema2 } from "@dxos/protocols";
973
+ var base62 = base("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
974
+ var codec = schema2.getCodecForType("dxos.client.services.Invitation");
975
+ var InvitationEncoder = class {
976
+ static decode(text) {
977
+ return codec.decode(base62.decode(text));
978
+ }
979
+ static encode(invitation) {
980
+ return base62.encode(codec.encode(invitation));
981
+ }
982
+ };
983
+
984
+ // packages/sdk/client-services/src/packlets/invitations/invitations.ts
985
+ import assert5 from "@dxos/node-std/assert";
986
+ import { CancellableObservableProvider } from "@dxos/async";
987
+ import { Invitation } from "@dxos/protocols/proto/dxos/client/services";
988
+ var AUTHENTICATION_CODE_LENGTH = 6;
989
+ var INVITATION_TIMEOUT = 3 * 6e4;
990
+ var ON_CLOSE_DELAY = 1e3;
991
+ var InvitationObservableProvider = class extends CancellableObservableProvider {
992
+ get invitation() {
993
+ return this._invitation;
994
+ }
995
+ setInvitation(invitation) {
996
+ this._invitation = invitation;
997
+ }
998
+ };
999
+ var AuthenticatingInvitationProvider = class extends InvitationObservableProvider {
1000
+ // prettier-ignore
1001
+ constructor(_actions) {
1002
+ super(() => this._actions.onCancel());
1003
+ this._actions = _actions;
1004
+ }
1005
+ async authenticate(authenticationCode) {
1006
+ return this._actions.onAuthenticate(authenticationCode);
1007
+ }
1008
+ };
1009
+ var wrapObservable = async (observable) => {
1010
+ return new Promise((resolve, reject) => {
1011
+ const unsubscribe = observable.subscribe({
1012
+ onSuccess: (invitation) => {
1013
+ assert5(invitation.state === Invitation.State.SUCCESS);
1014
+ unsubscribe();
1015
+ resolve(invitation);
1016
+ },
1017
+ onError: (err) => {
1018
+ unsubscribe();
1019
+ reject(err);
1020
+ }
1021
+ });
1022
+ });
1023
+ };
1024
+
1025
+ // packages/sdk/client-services/src/packlets/invitations/invitations-handler.ts
1026
+ var AbstractInvitationsHandler = class {
1027
+ // prettier-ignore
1028
+ constructor(_networkManager) {
1029
+ this._networkManager = _networkManager;
1030
+ }
1031
+ };
1032
+
1033
+ // packages/sdk/client-services/src/packlets/invitations/halo-invitations-handler.ts
1034
+ import assert6 from "@dxos/node-std/assert";
1035
+ import { scheduleTask, sleep, Trigger as Trigger2 } from "@dxos/async";
1036
+ import { Context as Context3 } from "@dxos/context";
1037
+ import { generatePasscode } from "@dxos/credentials";
1038
+ import { PublicKey as PublicKey3 } from "@dxos/keys";
1039
+ import { log as log5 } from "@dxos/log";
1040
+ import { createTeleportProtocolFactory, StarTopology } from "@dxos/network-manager";
1041
+ import { schema as schema3 } from "@dxos/protocols";
1042
+ import { Invitation as Invitation2 } from "@dxos/protocols/proto/dxos/client/services";
1043
+ import { AuthenticationResponse } from "@dxos/protocols/proto/dxos/halo/invitations";
1044
+ import { RpcExtension } from "@dxos/teleport";
1045
+ var HaloInvitationsHandler = class extends AbstractInvitationsHandler {
1046
+ // prettier-ignore
1047
+ constructor(_params) {
1048
+ super(_params.networkManager);
1049
+ this._params = _params;
1050
+ }
1051
+ /**
1052
+ * Creates an invitation and listens for a join request from the invited (guest) peer.
1053
+ */
1054
+ createInvitation(context, options) {
1055
+ const { type, timeout = INVITATION_TIMEOUT, swarmKey } = options != null ? options : {};
1056
+ assert6(type !== Invitation2.Type.OFFLINE);
1057
+ const identity = this._params.getIdentity();
1058
+ const invitation = {
1059
+ type,
1060
+ invitationId: PublicKey3.random().toHex(),
1061
+ swarmKey: swarmKey != null ? swarmKey : PublicKey3.random(),
1062
+ authenticationCode: generatePasscode(AUTHENTICATION_CODE_LENGTH)
1063
+ };
1064
+ const ctx = new Context3({
1065
+ onError: (err) => {
1066
+ void ctx.dispose();
1067
+ observable.callback.onError(err);
1068
+ }
1069
+ });
1070
+ const observable = new InvitationObservableProvider(async () => {
1071
+ await ctx.dispose();
1072
+ });
1073
+ let authenticationCode;
1074
+ const complete = new Trigger2();
1075
+ const createExtension = () => new HostHaloInvitationExtension({
1076
+ requestAdmission: async () => {
1077
+ var _a, _b;
1078
+ log5("responding with admission offer", {
1079
+ host: identity.deviceKey
1080
+ }, {
1081
+ file: "halo-invitations-handler.ts",
1082
+ line: 91,
1083
+ scope: this,
1084
+ callSite: (f, a) => f(...a)
1085
+ });
1086
+ (_b = (_a = observable.callback).onAuthenticating) == null ? void 0 : _b.call(_a, invitation);
1087
+ return {
1088
+ identityKey: identity.identityKey,
1089
+ haloSpaceKey: identity.haloSpaceKey,
1090
+ genesisFeedKey: identity.haloGenesisFeedKey
1091
+ };
1092
+ },
1093
+ authenticate: async ({ authenticationCode: code }) => {
1094
+ log5("received authentication request", {
1095
+ authenticationCode: code
1096
+ }, {
1097
+ file: "halo-invitations-handler.ts",
1098
+ line: 105,
1099
+ scope: this,
1100
+ callSite: (f, a) => f(...a)
1101
+ });
1102
+ authenticationCode = code;
1103
+ return {
1104
+ status: AuthenticationResponse.Status.OK
1105
+ };
1106
+ },
1107
+ // TODO(burdon): Not used: controlFeedKey, dataFeedKey.
1108
+ presentAdmissionCredentials: async (credentials) => {
1109
+ try {
1110
+ if (invitation.type !== Invitation2.Type.INTERACTIVE_TESTING) {
1111
+ if (invitation.authenticationCode === void 0 || invitation.authenticationCode !== authenticationCode) {
1112
+ throw new Error(`invalid authentication code: ${authenticationCode}`);
1113
+ }
1114
+ }
1115
+ log5("writing guest credentials", {
1116
+ host: identity.deviceKey,
1117
+ guest: credentials.deviceKey
1118
+ }, {
1119
+ file: "halo-invitations-handler.ts",
1120
+ line: 120,
1121
+ scope: this,
1122
+ callSite: (f, a) => f(...a)
1123
+ });
1124
+ await identity.admitDevice(credentials);
1125
+ complete.wake(credentials.deviceKey);
1126
+ } catch (err) {
1127
+ observable.callback.onError(err);
1128
+ throw err;
1129
+ }
1130
+ },
1131
+ onOpen: () => {
1132
+ scheduleTask(ctx, async () => {
1133
+ var _a, _b;
1134
+ try {
1135
+ log5("connected", {
1136
+ host: identity.deviceKey
1137
+ }, {
1138
+ file: "halo-invitations-handler.ts",
1139
+ line: 136,
1140
+ scope: this,
1141
+ callSite: (f, a) => f(...a)
1142
+ });
1143
+ (_b = (_a = observable.callback).onConnected) == null ? void 0 : _b.call(_a, invitation);
1144
+ const deviceKey = await complete.wait({
1145
+ timeout
1146
+ });
1147
+ log5("admitted guest", {
1148
+ host: identity.deviceKey,
1149
+ guest: deviceKey
1150
+ }, {
1151
+ file: "halo-invitations-handler.ts",
1152
+ line: 139,
1153
+ scope: this,
1154
+ callSite: (f, a) => f(...a)
1155
+ });
1156
+ observable.callback.onSuccess(invitation);
1157
+ } catch (err) {
1158
+ if (!observable.cancelled) {
1159
+ log5.error("failed", err, {
1160
+ file: "halo-invitations-handler.ts",
1161
+ line: 143,
1162
+ scope: this,
1163
+ callSite: (f, a) => f(...a)
1164
+ });
1165
+ observable.callback.onError(err);
1166
+ }
1167
+ } finally {
1168
+ await sleep(ON_CLOSE_DELAY);
1169
+ await ctx.dispose();
1170
+ }
1171
+ });
1172
+ }
1173
+ });
1174
+ scheduleTask(ctx, async () => {
1175
+ var _a, _b;
1176
+ const topic = invitation.swarmKey;
1177
+ const swarmConnection = await this._networkManager.joinSwarm({
1178
+ topic,
1179
+ peerId: topic,
1180
+ protocolProvider: createTeleportProtocolFactory(async (teleport) => {
1181
+ teleport.addExtension("dxos.halo.invitations", createExtension());
1182
+ }),
1183
+ topology: new StarTopology(topic)
1184
+ });
1185
+ ctx.onDispose(() => swarmConnection.close());
1186
+ (_b = (_a = observable.callback).onConnecting) == null ? void 0 : _b.call(_a, invitation);
1187
+ });
1188
+ return observable;
1189
+ }
1190
+ /**
1191
+ * Waits for the host peer (inviter) to accept our join request.
1192
+ * The local guest peer (invitee) then sends the local halo invitation to the host,
1193
+ * which then writes the guest's credentials to the halo.
1194
+ */
1195
+ acceptInvitation(invitation, options) {
1196
+ const { timeout = INVITATION_TIMEOUT } = options != null ? options : {};
1197
+ const ctx = new Context3({
1198
+ onError: (err) => {
1199
+ void ctx.dispose();
1200
+ observable.callback.onError(err);
1201
+ }
1202
+ });
1203
+ const authenticated = new Trigger2();
1204
+ const observable = new AuthenticatingInvitationProvider({
1205
+ onCancel: async () => {
1206
+ await ctx.dispose();
1207
+ },
1208
+ // TODO(burdon): Consider retry.
1209
+ onAuthenticate: async (code) => {
1210
+ authenticated.wake(code);
1211
+ }
1212
+ });
1213
+ let connectionCount = 0;
1214
+ const complete = new Trigger2();
1215
+ const createExtension = () => {
1216
+ const extension = new GuestHaloInvitationExtension({
1217
+ onOpen: () => {
1218
+ scheduleTask(ctx, async () => {
1219
+ var _a, _b, _c, _d;
1220
+ try {
1221
+ if (++connectionCount > 1) {
1222
+ throw new Error(`multiple connections detected: ${connectionCount}`);
1223
+ }
1224
+ log5("connected", {}, {
1225
+ file: "halo-invitations-handler.ts",
1226
+ line: 214,
1227
+ scope: this,
1228
+ callSite: (f, a) => f(...a)
1229
+ });
1230
+ (_b = (_a = observable.callback).onConnected) == null ? void 0 : _b.call(_a, invitation);
1231
+ log5("sending admission request", {}, {
1232
+ file: "halo-invitations-handler.ts",
1233
+ line: 218,
1234
+ scope: this,
1235
+ callSite: (f, a) => f(...a)
1236
+ });
1237
+ const { identityKey, haloSpaceKey, genesisFeedKey } = await extension.rpc.HaloHostService.requestAdmission();
1238
+ if (invitation.type === void 0 || invitation.type === Invitation2.Type.INTERACTIVE) {
1239
+ log5("guest waiting for authentication code...", {}, {
1240
+ file: "halo-invitations-handler.ts",
1241
+ line: 225,
1242
+ scope: this,
1243
+ callSite: (f, a) => f(...a)
1244
+ });
1245
+ (_d = (_c = observable.callback).onAuthenticating) == null ? void 0 : _d.call(_c, invitation);
1246
+ const authenticationCode = await authenticated.wait({
1247
+ timeout
1248
+ });
1249
+ log5("sending authentication request", {}, {
1250
+ file: "halo-invitations-handler.ts",
1251
+ line: 228,
1252
+ scope: this,
1253
+ callSite: (f, a) => f(...a)
1254
+ });
1255
+ await extension.rpc.HaloHostService.authenticate({
1256
+ authenticationCode
1257
+ });
1258
+ }
1259
+ const deviceKey = await this._params.keyring.createKey();
1260
+ const controlFeedKey = await this._params.keyring.createKey();
1261
+ const dataFeedKey = await this._params.keyring.createKey();
1262
+ log5("presenting admission credentials", {
1263
+ identityKey,
1264
+ deviceKey,
1265
+ controlFeedKey,
1266
+ dataFeedKey
1267
+ }, {
1268
+ file: "halo-invitations-handler.ts",
1269
+ line: 237,
1270
+ scope: this,
1271
+ callSite: (f, a) => f(...a)
1272
+ });
1273
+ await extension.rpc.HaloHostService.presentAdmissionCredentials({
1274
+ deviceKey,
1275
+ controlFeedKey,
1276
+ dataFeedKey
1277
+ });
1278
+ const identity = await this._params.acceptIdentity({
1279
+ identityKey,
1280
+ deviceKey,
1281
+ haloSpaceKey,
1282
+ haloGenesisFeedKey: genesisFeedKey,
1283
+ controlFeedKey,
1284
+ dataFeedKey
1285
+ });
1286
+ log5("admitted by host", {
1287
+ guest: identity.deviceKey,
1288
+ identityKey
1289
+ }, {
1290
+ file: "halo-invitations-handler.ts",
1291
+ line: 256,
1292
+ scope: this,
1293
+ callSite: (f, a) => f(...a)
1294
+ });
1295
+ complete.wake(identityKey);
1296
+ } catch (err) {
1297
+ if (!observable.cancelled) {
1298
+ log5.warn("auth failed", err, {
1299
+ file: "halo-invitations-handler.ts",
1300
+ line: 260,
1301
+ scope: this,
1302
+ callSite: (f, a) => f(...a)
1303
+ });
1304
+ observable.callback.onError(err);
1305
+ }
1306
+ } finally {
1307
+ await ctx.dispose();
1308
+ }
1309
+ });
1310
+ }
1311
+ });
1312
+ return extension;
1313
+ };
1314
+ scheduleTask(ctx, async () => {
1315
+ var _a, _b;
1316
+ assert6(invitation.swarmKey);
1317
+ const topic = invitation.swarmKey;
1318
+ const swarmConnection = await this._networkManager.joinSwarm({
1319
+ topic,
1320
+ peerId: PublicKey3.random(),
1321
+ protocolProvider: createTeleportProtocolFactory(async (teleport) => {
1322
+ teleport.addExtension("dxos.halo.invitations", createExtension());
1323
+ }),
1324
+ topology: new StarTopology(topic)
1325
+ });
1326
+ ctx.onDispose(() => swarmConnection.close());
1327
+ (_b = (_a = observable.callback).onConnecting) == null ? void 0 : _b.call(_a, invitation);
1328
+ invitation.identityKey = await complete.wait();
1329
+ observable.callback.onSuccess(invitation);
1330
+ await ctx.dispose();
1331
+ });
1332
+ return observable;
1333
+ }
1334
+ };
1335
+ var HostHaloInvitationExtension = class extends RpcExtension {
1336
+ constructor(_callbacks) {
1337
+ super({
1338
+ exposed: {
1339
+ HaloHostService: schema3.getService("dxos.halo.invitations.HaloHostService")
1340
+ }
1341
+ });
1342
+ this._callbacks = _callbacks;
1343
+ }
1344
+ async getHandlers() {
1345
+ return {
1346
+ // TODO(dmaretskyi): For now this is just forwarding the data to callbacks since we don't have session-specific logic.
1347
+ // Perhaps in the future we will have more complex logic here.
1348
+ HaloHostService: {
1349
+ requestAdmission: async () => {
1350
+ return this._callbacks.requestAdmission();
1351
+ },
1352
+ authenticate: async (credentials) => {
1353
+ return this._callbacks.authenticate(credentials);
1354
+ },
1355
+ // TODO(burdon): Not used: controlFeedKey, dataFeedKey.
1356
+ presentAdmissionCredentials: async (credentials) => {
1357
+ return this._callbacks.presentAdmissionCredentials(credentials);
1358
+ }
1359
+ }
1360
+ };
1361
+ }
1362
+ async onOpen(context) {
1363
+ await super.onOpen(context);
1364
+ this._callbacks.onOpen();
1365
+ }
1366
+ };
1367
+ var GuestHaloInvitationExtension = class extends RpcExtension {
1368
+ constructor(_callbacks) {
1369
+ super({
1370
+ requested: {
1371
+ HaloHostService: schema3.getService("dxos.halo.invitations.HaloHostService")
1372
+ }
1373
+ });
1374
+ this._callbacks = _callbacks;
1375
+ }
1376
+ async getHandlers() {
1377
+ return {};
1378
+ }
1379
+ async onOpen(context) {
1380
+ await super.onOpen(context);
1381
+ this._callbacks.onOpen();
1382
+ }
1383
+ };
1384
+
1385
+ // packages/sdk/client-services/src/packlets/invitations/invitations-proxy.ts
1386
+ import assert7 from "@dxos/node-std/assert";
1387
+ import { observableError } from "@dxos/async";
1388
+ import { log as log6 } from "@dxos/log";
1389
+ import { Invitation as Invitation3 } from "@dxos/protocols/proto/dxos/client/services";
1390
+ var AbstractInvitationsProxy = class {
1391
+ // prettier-ignore
1392
+ constructor(_invitationsService) {
1393
+ this._invitationsService = _invitationsService;
1394
+ }
1395
+ createInvitation(context, options) {
1396
+ let invitationId;
1397
+ const observable = new InvitationObservableProvider(async () => {
1398
+ if (invitationId) {
1399
+ await this._invitationsService.cancelInvitation({
1400
+ invitationId
1401
+ });
1402
+ }
1403
+ });
1404
+ const invitation = {
1405
+ ...this.getInvitationOptions(context),
1406
+ ...options
1407
+ };
1408
+ const stream = this._invitationsService.createInvitation(invitation);
1409
+ stream.subscribe((invitation2) => {
1410
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1411
+ observable.setInvitation(invitation2);
1412
+ switch (invitation2.state) {
1413
+ case Invitation3.State.CONNECTING: {
1414
+ assert7(invitation2.invitationId);
1415
+ invitationId = invitation2.invitationId;
1416
+ (_b = (_a = observable.callback).onConnecting) == null ? void 0 : _b.call(_a, invitation2);
1417
+ break;
1418
+ }
1419
+ case Invitation3.State.CONNECTED: {
1420
+ (_d = (_c = observable.callback).onConnected) == null ? void 0 : _d.call(_c, invitation2);
1421
+ break;
1422
+ }
1423
+ case Invitation3.State.AUTHENTICATING: {
1424
+ (_f = (_e = observable.callback).onAuthenticating) == null ? void 0 : _f.call(_e, invitation2);
1425
+ break;
1426
+ }
1427
+ case Invitation3.State.SUCCESS: {
1428
+ (_h = (_g = observable.callback).onSuccess) == null ? void 0 : _h.call(_g, invitation2);
1429
+ break;
1430
+ }
1431
+ case Invitation3.State.CANCELLED: {
1432
+ (_j = (_i = observable.callback).onCancelled) == null ? void 0 : _j.call(_i);
1433
+ break;
1434
+ }
1435
+ default: {
1436
+ log6.error(`Invalid state: ${invitation2.state}`, {}, {
1437
+ file: "invitations-proxy.ts",
1438
+ line: 81,
1439
+ scope: this,
1440
+ callSite: (f, a) => f(...a)
1441
+ });
1442
+ }
1443
+ }
1444
+ }, (err) => {
1445
+ if (err) {
1446
+ observableError(observable, err);
1447
+ }
1448
+ });
1449
+ return observable;
1450
+ }
1451
+ acceptInvitation(invitation, options) {
1452
+ assert7(invitation && invitation.swarmKey);
1453
+ const observable = new AuthenticatingInvitationProvider({
1454
+ onCancel: async () => {
1455
+ var _a;
1456
+ const invitationId = (_a = observable.invitation) == null ? void 0 : _a.invitationId;
1457
+ assert7(invitationId);
1458
+ await this._invitationsService.cancelInvitation({
1459
+ invitationId
1460
+ });
1461
+ },
1462
+ onAuthenticate: async (authenticationCode) => {
1463
+ var _a;
1464
+ const invitationId = (_a = observable.invitation) == null ? void 0 : _a.invitationId;
1465
+ assert7(invitationId);
1466
+ await this._invitationsService.authenticate({
1467
+ invitationId,
1468
+ authenticationCode
1469
+ });
1470
+ }
1471
+ });
1472
+ const stream = this._invitationsService.acceptInvitation({
1473
+ ...invitation,
1474
+ ...options
1475
+ });
1476
+ stream.subscribe((invitation2) => {
1477
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1478
+ assert7(invitation2.invitationId);
1479
+ observable.setInvitation(invitation2);
1480
+ switch (invitation2.state) {
1481
+ case Invitation3.State.CONNECTING: {
1482
+ (_b = (_a = observable.callback).onConnecting) == null ? void 0 : _b.call(_a, invitation2);
1483
+ break;
1484
+ }
1485
+ case Invitation3.State.CONNECTED: {
1486
+ (_d = (_c = observable.callback).onConnected) == null ? void 0 : _d.call(_c, invitation2);
1487
+ break;
1488
+ }
1489
+ case Invitation3.State.AUTHENTICATING: {
1490
+ (_f = (_e = observable.callback).onAuthenticating) == null ? void 0 : _f.call(_e, invitation2);
1491
+ break;
1492
+ }
1493
+ case Invitation3.State.SUCCESS: {
1494
+ (_h = (_g = observable.callback).onSuccess) == null ? void 0 : _h.call(_g, invitation2);
1495
+ break;
1496
+ }
1497
+ case Invitation3.State.CANCELLED: {
1498
+ (_j = (_i = observable.callback).onCancelled) == null ? void 0 : _j.call(_i);
1499
+ break;
1500
+ }
1501
+ default: {
1502
+ log6.error(`Invalid state: ${invitation2.state}`, {}, {
1503
+ file: "invitations-proxy.ts",
1504
+ line: 146,
1505
+ scope: this,
1506
+ callSite: (f, a) => f(...a)
1507
+ });
1508
+ }
1509
+ }
1510
+ }, (err) => {
1511
+ if (err) {
1512
+ observableError(observable, err);
1513
+ }
1514
+ });
1515
+ return observable;
1516
+ }
1517
+ };
1518
+
1519
+ // packages/sdk/client-services/src/packlets/invitations/halo-invitations-proxy.ts
1520
+ var HaloInvitationsProxy = class extends AbstractInvitationsProxy {
1521
+ getInvitationOptions() {
1522
+ return {};
1523
+ }
1524
+ };
1525
+
1526
+ // packages/sdk/client-services/src/packlets/invitations/invitations-service.ts
1527
+ import assert8 from "@dxos/node-std/assert";
1528
+ import { Stream as Stream8 } from "@dxos/codec-protobuf";
1529
+ import { log as log7 } from "@dxos/log";
1530
+ import { Invitation as Invitation4 } from "@dxos/protocols/proto/dxos/client/services";
1531
+ var AbstractInvitationsService = class {
1532
+ // prettier-ignore
1533
+ constructor(_identityManager, _getInvitationsHandler) {
1534
+ this._identityManager = _identityManager;
1535
+ this._getInvitationsHandler = _getInvitationsHandler;
1536
+ this._createInvitations = /* @__PURE__ */ new Map();
1537
+ this._acceptInvitations = /* @__PURE__ */ new Map();
1538
+ }
1539
+ // TODO(burdon): Guest/host label.
1540
+ getLoggingContext() {
1541
+ var _a;
1542
+ return {
1543
+ deviceKey: (_a = this._identityManager.identity) == null ? void 0 : _a.deviceKey
1544
+ };
1545
+ }
1546
+ createInvitation(invitation) {
1547
+ return new Stream8(({ next, close }) => {
1548
+ const invitationsHandler = this._getInvitationsHandler();
1549
+ const context = this.getContext(invitation);
1550
+ log7("stream opened", this.getLoggingContext(), {
1551
+ file: "invitations-service.ts",
1552
+ line: 43,
1553
+ scope: this,
1554
+ callSite: (f, a) => f(...a)
1555
+ });
1556
+ let invitationId;
1557
+ const { type, swarmKey } = invitation;
1558
+ const observable = invitationsHandler.createInvitation(context, {
1559
+ type,
1560
+ swarmKey
1561
+ });
1562
+ observable.subscribe({
1563
+ onConnecting: (invitation2) => {
1564
+ assert8(invitation2.invitationId);
1565
+ invitationId = invitation2.invitationId;
1566
+ this._createInvitations.set(invitation2.invitationId, observable);
1567
+ invitation2.state = Invitation4.State.CONNECTING;
1568
+ next(invitation2);
1569
+ },
1570
+ onConnected: (invitation2) => {
1571
+ assert8(invitation2.invitationId);
1572
+ invitation2.state = Invitation4.State.CONNECTED;
1573
+ next(invitation2);
1574
+ },
1575
+ onAuthenticating: (invitation2) => {
1576
+ assert8(invitation2.invitationId);
1577
+ invitation2.state = Invitation4.State.AUTHENTICATING;
1578
+ next(invitation2);
1579
+ },
1580
+ onSuccess: (invitation2) => {
1581
+ assert8(invitation2.invitationId);
1582
+ invitation2.state = Invitation4.State.SUCCESS;
1583
+ next(invitation2);
1584
+ close();
1585
+ },
1586
+ onCancelled: () => {
1587
+ assert8(invitationId);
1588
+ invitation.invitationId = invitationId;
1589
+ invitation.state = Invitation4.State.CANCELLED;
1590
+ next(invitation);
1591
+ close();
1592
+ },
1593
+ onTimeout: (err) => {
1594
+ invitation.state = Invitation4.State.TIMEOUT;
1595
+ close(err);
1596
+ },
1597
+ onError: (err) => {
1598
+ invitation.state = Invitation4.State.ERROR;
1599
+ close(err);
1600
+ }
1601
+ });
1602
+ return (err) => {
1603
+ const context2 = this.getLoggingContext();
1604
+ if (err) {
1605
+ log7.warn("stream closed", {
1606
+ ...context2,
1607
+ err
1608
+ }, {
1609
+ file: "invitations-service.ts",
1610
+ line: 92,
1611
+ scope: this,
1612
+ callSite: (f, a) => f(...a)
1613
+ });
1614
+ } else {
1615
+ log7("stream closed", context2, {
1616
+ file: "invitations-service.ts",
1617
+ line: 94,
1618
+ scope: this,
1619
+ callSite: (f, a) => f(...a)
1620
+ });
1621
+ }
1622
+ this._createInvitations.delete(invitation.invitationId);
1623
+ };
1624
+ });
1625
+ }
1626
+ acceptInvitation(invitation, options) {
1627
+ return new Stream8(({ next, close }) => {
1628
+ log7("stream opened", this.getLoggingContext(), {
1629
+ file: "invitations-service.ts",
1630
+ line: 104,
1631
+ scope: this,
1632
+ callSite: (f, a) => f(...a)
1633
+ });
1634
+ const invitationsHandler = this._getInvitationsHandler();
1635
+ let invitationId;
1636
+ const observable = invitationsHandler.acceptInvitation(invitation, options);
1637
+ observable.subscribe({
1638
+ onConnecting: (invitation2) => {
1639
+ assert8(invitation2.invitationId);
1640
+ invitationId = invitation2.invitationId;
1641
+ this._acceptInvitations.set(invitation2.invitationId, observable);
1642
+ invitation2.state = Invitation4.State.CONNECTING;
1643
+ next(invitation2);
1644
+ },
1645
+ onConnected: (invitation2) => {
1646
+ assert8(invitation2.invitationId);
1647
+ invitation2.state = Invitation4.State.CONNECTED;
1648
+ next(invitation2);
1649
+ },
1650
+ onAuthenticating: (invitation2) => {
1651
+ assert8(invitation2.invitationId);
1652
+ invitation2.state = Invitation4.State.AUTHENTICATING;
1653
+ next(invitation2);
1654
+ },
1655
+ onSuccess: (invitation2) => {
1656
+ invitation2.state = Invitation4.State.SUCCESS;
1657
+ next(invitation2);
1658
+ close();
1659
+ },
1660
+ onCancelled: () => {
1661
+ assert8(invitationId);
1662
+ invitation.invitationId = invitationId;
1663
+ invitation.state = Invitation4.State.CANCELLED;
1664
+ next(invitation);
1665
+ close();
1666
+ },
1667
+ onTimeout: (err) => {
1668
+ invitation.state = Invitation4.State.TIMEOUT;
1669
+ close(err);
1670
+ },
1671
+ onError: (err) => {
1672
+ invitation.state = Invitation4.State.ERROR;
1673
+ close(err);
1674
+ }
1675
+ });
1676
+ return (err) => {
1677
+ const context = this.getLoggingContext();
1678
+ if (err) {
1679
+ log7.warn("stream closed", {
1680
+ ...context,
1681
+ err
1682
+ }, {
1683
+ file: "invitations-service.ts",
1684
+ line: 152,
1685
+ scope: this,
1686
+ callSite: (f, a) => f(...a)
1687
+ });
1688
+ } else {
1689
+ log7("stream closed", context, {
1690
+ file: "invitations-service.ts",
1691
+ line: 154,
1692
+ scope: this,
1693
+ callSite: (f, a) => f(...a)
1694
+ });
1695
+ }
1696
+ this._acceptInvitations.delete(invitation.invitationId);
1697
+ };
1698
+ });
1699
+ }
1700
+ async authenticate({ invitationId, authenticationCode }) {
1701
+ log7("authenticating...", {}, {
1702
+ file: "invitations-service.ts",
1703
+ line: 163,
1704
+ scope: this,
1705
+ callSite: (f, a) => f(...a)
1706
+ });
1707
+ assert8(invitationId);
1708
+ const observable = this._acceptInvitations.get(invitationId);
1709
+ if (!observable) {
1710
+ log7.warn("invalid invitation", {
1711
+ invitationId
1712
+ }, {
1713
+ file: "invitations-service.ts",
1714
+ line: 167,
1715
+ scope: this,
1716
+ callSite: (f, a) => f(...a)
1717
+ });
1718
+ } else {
1719
+ await observable.authenticate(authenticationCode);
1720
+ }
1721
+ }
1722
+ async cancelInvitation(invitation) {
1723
+ var _a;
1724
+ log7("cancelling...", {}, {
1725
+ file: "invitations-service.ts",
1726
+ line: 174,
1727
+ scope: this,
1728
+ callSite: (f, a) => f(...a)
1729
+ });
1730
+ assert8(invitation.invitationId);
1731
+ const observable = (_a = this._createInvitations.get(invitation.invitationId)) != null ? _a : this._acceptInvitations.get(invitation.invitationId);
1732
+ if (!observable) {
1733
+ log7.warn("invalid invitation", {
1734
+ invitationId: invitation.invitationId
1735
+ }, {
1736
+ file: "invitations-service.ts",
1737
+ line: 179,
1738
+ scope: this,
1739
+ callSite: (f, a) => f(...a)
1740
+ });
1741
+ } else {
1742
+ await (observable == null ? void 0 : observable.cancel());
1743
+ }
1744
+ }
1745
+ };
1746
+
1747
+ // packages/sdk/client-services/src/packlets/invitations/halo-invitations-service.ts
1748
+ var HaloInvitationsServiceImpl = class extends AbstractInvitationsService {
1749
+ // prettier-ignore
1750
+ constructor(identityManager, invitationsHandler) {
1751
+ super(identityManager, () => invitationsHandler);
1752
+ this.invitationsHandler = invitationsHandler;
1753
+ }
1754
+ getContext(invitation) {
1755
+ }
1756
+ };
1757
+
1758
+ // packages/sdk/client-services/src/packlets/invitations/space-invitations-handler.ts
1759
+ import assert9 from "@dxos/node-std/assert";
1760
+ import { scheduleTask as scheduleTask2, sleep as sleep2, Trigger as Trigger3 } from "@dxos/async";
1761
+ import { Context as Context4 } from "@dxos/context";
1762
+ import { createAdmissionCredentials, generatePasscode as generatePasscode2, getCredentialAssertion } from "@dxos/credentials";
1763
+ import { writeMessages as writeMessages2 } from "@dxos/feed-store";
1764
+ import { PublicKey as PublicKey4 } from "@dxos/keys";
1765
+ import { log as log8 } from "@dxos/log";
1766
+ import { createTeleportProtocolFactory as createTeleportProtocolFactory2, StarTopology as StarTopology2 } from "@dxos/network-manager";
1767
+ import { schema as schema4 } from "@dxos/protocols";
1768
+ import { Invitation as Invitation5 } from "@dxos/protocols/proto/dxos/client/services";
1769
+ import { AuthenticationResponse as AuthenticationResponse2 } from "@dxos/protocols/proto/dxos/halo/invitations";
1770
+ import { RpcExtension as RpcExtension2 } from "@dxos/teleport";
1771
+ var MAX_OTP_ATTEMPTS = 3;
1772
+ var SpaceInvitationsHandler = class extends AbstractInvitationsHandler {
1773
+ constructor(networkManager, _spaceManager, _signingContext, _keyring) {
1774
+ super(networkManager);
1775
+ this._spaceManager = _spaceManager;
1776
+ this._signingContext = _signingContext;
1777
+ this._keyring = _keyring;
1778
+ }
1779
+ /**
1780
+ * Creates an invitation and listens for a join request from the invited (guest) peer.
1781
+ */
1782
+ createInvitation(space, options) {
1783
+ let swarmConnection;
1784
+ const { type, timeout = INVITATION_TIMEOUT, swarmKey } = options != null ? options : {};
1785
+ assert9(type !== Invitation5.Type.OFFLINE);
1786
+ assert9(space);
1787
+ const invitation = {
1788
+ type,
1789
+ invitationId: PublicKey4.random().toHex(),
1790
+ swarmKey: swarmKey != null ? swarmKey : PublicKey4.random(),
1791
+ spaceKey: space.key,
1792
+ authenticationCode: generatePasscode2(AUTHENTICATION_CODE_LENGTH)
1793
+ };
1794
+ const ctx = new Context4({
1795
+ onError: (err) => {
1796
+ void ctx.dispose();
1797
+ observable.callback.onError(err);
1798
+ }
1799
+ });
1800
+ const observable = new InvitationObservableProvider(async () => {
1801
+ await (swarmConnection == null ? void 0 : swarmConnection.close());
1802
+ });
1803
+ let authenticationCode;
1804
+ let authenticationRetry = 0;
1805
+ const createExtension = () => {
1806
+ const complete = new Trigger3();
1807
+ let guestProfile;
1808
+ const hostInvitationExtension = new HostSpaceInvitationExtension({
1809
+ introduce: async ({ profile }) => {
1810
+ var _a, _b;
1811
+ log8("guest introduced itself", {
1812
+ guestProfile: profile,
1813
+ host: this._signingContext.deviceKey,
1814
+ spaceKey: space.key
1815
+ }, {
1816
+ file: "space-invitations-handler.ts",
1817
+ line: 98,
1818
+ scope: this,
1819
+ callSite: (f, a) => f(...a)
1820
+ });
1821
+ guestProfile = profile;
1822
+ (_b = (_a = observable.callback).onAuthenticating) == null ? void 0 : _b.call(_a, invitation);
1823
+ },
1824
+ authenticate: async ({ authenticationCode: code }) => {
1825
+ log8("received authentication request", {
1826
+ authenticationCode: code
1827
+ }, {
1828
+ file: "space-invitations-handler.ts",
1829
+ line: 112,
1830
+ scope: this,
1831
+ callSite: (f, a) => f(...a)
1832
+ });
1833
+ let status = AuthenticationResponse2.Status.OK;
1834
+ if (invitation.authenticationCode) {
1835
+ if (authenticationRetry++ > MAX_OTP_ATTEMPTS) {
1836
+ status = AuthenticationResponse2.Status.INVALID_OPT_ATTEMPTS;
1837
+ } else if (code !== invitation.authenticationCode) {
1838
+ status = AuthenticationResponse2.Status.INVALID_OTP;
1839
+ } else {
1840
+ authenticationCode = code;
1841
+ }
1842
+ }
1843
+ return {
1844
+ status
1845
+ };
1846
+ },
1847
+ requestAdmission: async ({ identityKey, deviceKey, controlFeedKey, dataFeedKey }) => {
1848
+ try {
1849
+ if (invitation.type !== Invitation5.Type.INTERACTIVE_TESTING && invitation.type !== Invitation5.Type.MULTIUSE_TESTING) {
1850
+ if (invitation.authenticationCode === void 0 || invitation.authenticationCode !== authenticationCode) {
1851
+ throw new Error(`invalid authentication code: ${authenticationCode}`);
1852
+ }
1853
+ }
1854
+ log8("writing guest credentials", {
1855
+ host: this._signingContext.deviceKey,
1856
+ guest: deviceKey
1857
+ }, {
1858
+ file: "space-invitations-handler.ts",
1859
+ line: 139,
1860
+ scope: this,
1861
+ callSite: (f, a) => f(...a)
1862
+ });
1863
+ const credentials = await createAdmissionCredentials(this._signingContext.credentialSigner, identityKey, space.key, space.inner.genesisFeedKey, guestProfile);
1864
+ assert9(credentials[0].credential);
1865
+ const spaceMemberCredential = credentials[0].credential.credential;
1866
+ assert9(getCredentialAssertion(spaceMemberCredential)["@type"] === "dxos.halo.credentials.SpaceMember");
1867
+ await writeMessages2(space.inner.controlPipeline.writer, credentials);
1868
+ complete.wake(deviceKey);
1869
+ return {
1870
+ credential: spaceMemberCredential
1871
+ };
1872
+ } catch (err) {
1873
+ observable.callback.onError(err);
1874
+ throw err;
1875
+ }
1876
+ },
1877
+ onOpen: () => {
1878
+ scheduleTask2(ctx, async () => {
1879
+ var _a, _b;
1880
+ try {
1881
+ log8("connected", {
1882
+ host: this._signingContext.deviceKey
1883
+ }, {
1884
+ file: "space-invitations-handler.ts",
1885
+ line: 170,
1886
+ scope: this,
1887
+ callSite: (f, a) => f(...a)
1888
+ });
1889
+ (_b = (_a = observable.callback).onConnected) == null ? void 0 : _b.call(_a, invitation);
1890
+ const deviceKey = await complete.wait({
1891
+ timeout
1892
+ });
1893
+ log8("admitted guest", {
1894
+ host: this._signingContext.deviceKey,
1895
+ guest: deviceKey
1896
+ }, {
1897
+ file: "space-invitations-handler.ts",
1898
+ line: 173,
1899
+ scope: this,
1900
+ callSite: (f, a) => f(...a)
1901
+ });
1902
+ observable.callback.onSuccess(invitation);
1903
+ } catch (err) {
1904
+ if (!observable.cancelled) {
1905
+ log8.error("failed", err, {
1906
+ file: "space-invitations-handler.ts",
1907
+ line: 177,
1908
+ scope: this,
1909
+ callSite: (f, a) => f(...a)
1910
+ });
1911
+ observable.callback.onError(err);
1912
+ }
1913
+ } finally {
1914
+ if (type !== Invitation5.Type.MULTIUSE_TESTING) {
1915
+ await sleep2(ON_CLOSE_DELAY);
1916
+ await ctx.dispose();
1917
+ }
1918
+ }
1919
+ });
1920
+ }
1921
+ });
1922
+ return hostInvitationExtension;
1923
+ };
1924
+ scheduleTask2(ctx, async () => {
1925
+ var _a, _b;
1926
+ const topic = invitation.swarmKey;
1927
+ const swarmConnection2 = await this._networkManager.joinSwarm({
1928
+ topic,
1929
+ peerId: topic,
1930
+ protocolProvider: createTeleportProtocolFactory2(async (teleport) => {
1931
+ teleport.addExtension("dxos.halo.invitations", createExtension());
1932
+ }),
1933
+ topology: new StarTopology2(topic)
1934
+ });
1935
+ ctx.onDispose(() => swarmConnection2.close());
1936
+ (_b = (_a = observable.callback).onConnecting) == null ? void 0 : _b.call(_a, invitation);
1937
+ });
1938
+ return observable;
1939
+ }
1940
+ /**
1941
+ * Waits for the host peer (inviter) to accept our join request.
1942
+ * The local guest peer (invitee) then sends the local space invitation to the host,
1943
+ * which then writes the guest's credentials to the space.
1944
+ */
1945
+ acceptInvitation(invitation, options) {
1946
+ const { timeout = INVITATION_TIMEOUT } = options != null ? options : {};
1947
+ const ctx = new Context4({
1948
+ onError: (err) => {
1949
+ void ctx.dispose();
1950
+ observable.callback.onError(err);
1951
+ }
1952
+ });
1953
+ const authenticated = new Trigger3();
1954
+ const observable = new AuthenticatingInvitationProvider({
1955
+ onCancel: async () => {
1956
+ await ctx.dispose();
1957
+ },
1958
+ onAuthenticate: async (code) => {
1959
+ authenticated.wake(code);
1960
+ }
1961
+ });
1962
+ let connectionCount = 0;
1963
+ const complete = new Trigger3();
1964
+ const createExtension = () => {
1965
+ const extension = new GuestSpaceInvitationExtension({
1966
+ onOpen: () => {
1967
+ scheduleTask2(ctx, async () => {
1968
+ var _a, _b, _c, _d;
1969
+ try {
1970
+ if (++connectionCount > 1) {
1971
+ throw new Error(`multiple connections detected: ${connectionCount}`);
1972
+ }
1973
+ log8("connected", {
1974
+ guest: this._signingContext.deviceKey
1975
+ }, {
1976
+ file: "space-invitations-handler.ts",
1977
+ line: 250,
1978
+ scope: this,
1979
+ callSite: (f, a) => f(...a)
1980
+ });
1981
+ (_b = (_a = observable.callback).onConnected) == null ? void 0 : _b.call(_a, invitation);
1982
+ log8("introduce", {
1983
+ guest: this._signingContext.deviceKey
1984
+ }, {
1985
+ file: "space-invitations-handler.ts",
1986
+ line: 254,
1987
+ scope: this,
1988
+ callSite: (f, a) => f(...a)
1989
+ });
1990
+ await extension.rpc.SpaceHostService.introduce({
1991
+ profile: this._signingContext.profile
1992
+ });
1993
+ if (invitation.type === void 0 || invitation.type === Invitation5.Type.INTERACTIVE) {
1994
+ for (let attempt = 1; attempt <= MAX_OTP_ATTEMPTS; attempt++) {
1995
+ log8("guest waiting for authentication code...", {}, {
1996
+ file: "space-invitations-handler.ts",
1997
+ line: 263,
1998
+ scope: this,
1999
+ callSite: (f, a) => f(...a)
2000
+ });
2001
+ (_d = (_c = observable.callback).onAuthenticating) == null ? void 0 : _d.call(_c, invitation);
2002
+ const authenticationCode = await authenticated.wait({
2003
+ timeout
2004
+ });
2005
+ log8("sending authentication request", {}, {
2006
+ file: "space-invitations-handler.ts",
2007
+ line: 267,
2008
+ scope: this,
2009
+ callSite: (f, a) => f(...a)
2010
+ });
2011
+ const response = await extension.rpc.SpaceHostService.authenticate({
2012
+ authenticationCode
2013
+ });
2014
+ if (response.status === void 0 || response.status === AuthenticationResponse2.Status.OK) {
2015
+ break;
2016
+ }
2017
+ if (response.status === AuthenticationResponse2.Status.INVALID_OTP) {
2018
+ if (attempt === MAX_OTP_ATTEMPTS) {
2019
+ throw new Error(`Maximum retry attempts: ${MAX_OTP_ATTEMPTS}`);
2020
+ } else {
2021
+ log8("retrying invalid code", {
2022
+ attempt
2023
+ }, {
2024
+ file: "space-invitations-handler.ts",
2025
+ line: 277,
2026
+ scope: this,
2027
+ callSite: (f, a) => f(...a)
2028
+ });
2029
+ authenticated.reset();
2030
+ }
2031
+ }
2032
+ }
2033
+ }
2034
+ const controlFeedKey = await this._keyring.createKey();
2035
+ const dataFeedKey = await this._keyring.createKey();
2036
+ log8("request admission", {
2037
+ guest: this._signingContext.deviceKey
2038
+ }, {
2039
+ file: "space-invitations-handler.ts",
2040
+ line: 288,
2041
+ scope: this,
2042
+ callSite: (f, a) => f(...a)
2043
+ });
2044
+ const { credential } = await extension.rpc.SpaceHostService.requestAdmission({
2045
+ identityKey: this._signingContext.identityKey,
2046
+ deviceKey: this._signingContext.deviceKey,
2047
+ controlFeedKey,
2048
+ dataFeedKey
2049
+ });
2050
+ const assertion = getCredentialAssertion(credential);
2051
+ assert9(assertion["@type"] === "dxos.halo.credentials.SpaceMember", "Invalid credential");
2052
+ assert9(credential.subject.id.equals(this._signingContext.identityKey));
2053
+ const space = await this._spaceManager.acceptSpace({
2054
+ spaceKey: assertion.spaceKey,
2055
+ genesisFeedKey: assertion.genesisFeedKey
2056
+ });
2057
+ await this._signingContext.recordCredential(credential);
2058
+ log8("admitted by host", {
2059
+ guest: this._signingContext.deviceKey,
2060
+ spaceKey: space.key
2061
+ }, {
2062
+ file: "space-invitations-handler.ts",
2063
+ line: 310,
2064
+ scope: this,
2065
+ callSite: (f, a) => f(...a)
2066
+ });
2067
+ complete.wake();
2068
+ } catch (err) {
2069
+ if (!observable.cancelled) {
2070
+ log8.warn("auth failed", err, {
2071
+ file: "space-invitations-handler.ts",
2072
+ line: 314,
2073
+ scope: this,
2074
+ callSite: (f, a) => f(...a)
2075
+ });
2076
+ observable.callback.onError(err);
2077
+ }
2078
+ } finally {
2079
+ await ctx.dispose();
2080
+ }
2081
+ });
2082
+ }
2083
+ });
2084
+ return extension;
2085
+ };
2086
+ scheduleTask2(ctx, async () => {
2087
+ var _a, _b;
2088
+ assert9(invitation.swarmKey);
2089
+ const topic = invitation.swarmKey;
2090
+ const swarmConnection = await this._networkManager.joinSwarm({
2091
+ topic,
2092
+ peerId: PublicKey4.random(),
2093
+ protocolProvider: createTeleportProtocolFactory2(async (teleport) => {
2094
+ teleport.addExtension("dxos.halo.invitations", createExtension());
2095
+ }),
2096
+ topology: new StarTopology2(topic)
2097
+ });
2098
+ ctx.onDispose(() => swarmConnection.close());
2099
+ (_b = (_a = observable.callback).onConnecting) == null ? void 0 : _b.call(_a, invitation);
2100
+ await complete.wait();
2101
+ observable.callback.onSuccess(invitation);
2102
+ await ctx.dispose();
2103
+ });
2104
+ return observable;
2105
+ }
2106
+ };
2107
+ var HostSpaceInvitationExtension = class extends RpcExtension2 {
2108
+ constructor(_callbacks) {
2109
+ super({
2110
+ exposed: {
2111
+ SpaceHostService: schema4.getService("dxos.halo.invitations.SpaceHostService")
2112
+ }
2113
+ });
2114
+ this._callbacks = _callbacks;
2115
+ }
2116
+ async getHandlers() {
2117
+ return {
2118
+ // TODO(dmaretskyi): For now this is just forwarding the data to callbacks since we don't have session-specific logic.
2119
+ // Perhaps in the future we will have more complex logic here.
2120
+ SpaceHostService: {
2121
+ introduce: async (params) => {
2122
+ return this._callbacks.introduce(params);
2123
+ },
2124
+ authenticate: async (credentials) => {
2125
+ return this._callbacks.authenticate(credentials);
2126
+ },
2127
+ requestAdmission: async (credentials) => {
2128
+ return this._callbacks.requestAdmission(credentials);
2129
+ }
2130
+ }
2131
+ };
2132
+ }
2133
+ async onOpen(context) {
2134
+ await super.onOpen(context);
2135
+ this._callbacks.onOpen();
2136
+ }
2137
+ };
2138
+ var GuestSpaceInvitationExtension = class extends RpcExtension2 {
2139
+ constructor(_callbacks) {
2140
+ super({
2141
+ requested: {
2142
+ SpaceHostService: schema4.getService("dxos.halo.invitations.SpaceHostService")
2143
+ }
2144
+ });
2145
+ this._callbacks = _callbacks;
2146
+ }
2147
+ async getHandlers() {
2148
+ return {};
2149
+ }
2150
+ async onOpen(context) {
2151
+ await super.onOpen(context);
2152
+ this._callbacks.onOpen();
2153
+ }
2154
+ };
2155
+
2156
+ // packages/sdk/client-services/src/packlets/invitations/space-invitations-proxy.ts
2157
+ var SpaceInvitationsProxy = class extends AbstractInvitationsProxy {
2158
+ getInvitationOptions(context) {
2159
+ return {
2160
+ spaceKey: context
2161
+ };
2162
+ }
2163
+ };
2164
+
2165
+ // packages/sdk/client-services/src/packlets/invitations/space-invitations-service.ts
2166
+ import assert10 from "@dxos/node-std/assert";
2167
+ var SpaceInvitationsServiceImpl = class extends AbstractInvitationsService {
2168
+ // prettier-ignore
2169
+ constructor(identityManager, invitationsHandler, _getSpaceManager) {
2170
+ super(identityManager, invitationsHandler);
2171
+ this.invitationsHandler = invitationsHandler;
2172
+ this._getSpaceManager = _getSpaceManager;
2173
+ }
2174
+ getContext(invitation) {
2175
+ assert10(invitation.spaceKey);
2176
+ const spaceManager = this._getSpaceManager();
2177
+ const space = spaceManager.spaces.get(invitation.spaceKey);
2178
+ assert10(space);
2179
+ return space;
2180
+ }
2181
+ };
2182
+
2183
+ // packages/sdk/client-services/src/packlets/services/service-context.ts
2184
+ import { Trigger as Trigger5 } from "@dxos/async";
2185
+ import { getCredentialAssertion as getCredentialAssertion3 } from "@dxos/credentials";
2186
+ import { failUndefined as failUndefined2 } from "@dxos/debug";
2187
+ import { valueEncoding, DataServiceSubscriptions, MetadataStore, SpaceManager, SnapshotStore } from "@dxos/echo-db";
2188
+ import { FeedFactory, FeedStore } from "@dxos/feed-store";
2189
+ import { Keyring } from "@dxos/keyring";
2190
+ import { log as log11 } from "@dxos/log";
2191
+
2192
+ // packages/sdk/client-services/src/packlets/spaces/data-space-manager.ts
2193
+ import assert12 from "@dxos/node-std/assert";
2194
+ import { Event as Event4, synchronized, trackLeaks as trackLeaks2 } from "@dxos/async";
2195
+ import { Context as Context7 } from "@dxos/context";
2196
+ import { getCredentialAssertion as getCredentialAssertion2 } from "@dxos/credentials";
2197
+ import { spaceGenesis, SnapshotManager } from "@dxos/echo-db";
2198
+ import { PublicKey as PublicKey7 } from "@dxos/keys";
2199
+ import { log as log10 } from "@dxos/log";
2200
+ import { Presence } from "@dxos/teleport-extension-presence";
2201
+ import { ComplexMap as ComplexMap3, deferFunction as deferFunction2 } from "@dxos/util";
2202
+
2203
+ // packages/sdk/client-services/src/packlets/spaces/data-space.ts
2204
+ import { trackLeaks } from "@dxos/async";
2205
+ import { Context as Context6 } from "@dxos/context";
2206
+ import { timed } from "@dxos/debug";
2207
+ import { DataPipelineControllerImpl, createMappedFeedWriter } from "@dxos/echo-db";
2208
+ import { PublicKey as PublicKey6 } from "@dxos/keys";
2209
+ import { AdmittedFeed as AdmittedFeed3 } from "@dxos/protocols/proto/dxos/halo/credentials";
2210
+ import { ComplexSet as ComplexSet2 } from "@dxos/util";
2211
+
2212
+ // packages/sdk/client-services/src/packlets/spaces/notarization-plugin.ts
2213
+ import assert11 from "@dxos/node-std/assert";
2214
+ import { DeferredTask, Event as Event3, scheduleTask as scheduleTask3, TimeoutError, Trigger as Trigger4 } from "@dxos/async";
2215
+ import { Context as Context5 } from "@dxos/context";
2216
+ import { PublicKey as PublicKey5 } from "@dxos/keys";
2217
+ import { log as log9 } from "@dxos/log";
2218
+ import { schema as schema5 } from "@dxos/protocols";
2219
+ import { RpcExtension as RpcExtension3 } from "@dxos/teleport";
2220
+ import { ComplexMap as ComplexMap2, ComplexSet, entry } from "@dxos/util";
2221
+ var RETRY_TIMEOUT = 1e3;
2222
+ var NOTARIZE_TIMEOUT = 1e4;
2223
+ var NotarizationPlugin = class {
2224
+ constructor() {
2225
+ this._ctx = new Context5();
2226
+ this._extensionOpened = new Event3();
2227
+ this._extensions = /* @__PURE__ */ new Set();
2228
+ this._processedCredentials = new ComplexSet(PublicKey5.hash);
2229
+ this._processCredentialsTriggers = new ComplexMap2(PublicKey5.hash);
2230
+ }
2231
+ async open() {
2232
+ }
2233
+ async close() {
2234
+ await this._ctx.dispose();
2235
+ }
2236
+ /**
2237
+ * Request credentials to be notarized.
2238
+ */
2239
+ async notarize(credentials) {
2240
+ log9("notarize", {
2241
+ credentials
2242
+ }, {
2243
+ file: "notarization-plugin.ts",
2244
+ line: 44,
2245
+ scope: this,
2246
+ callSite: (f, a) => f(...a)
2247
+ });
2248
+ assert11(credentials.every((credential) => credential.id), "Credentials must have an id");
2249
+ const errors = new Trigger4();
2250
+ const ctx = this._ctx.derive({
2251
+ onError: (err) => {
2252
+ log9.warn("Notarization error", {
2253
+ err
2254
+ }, {
2255
+ file: "notarization-plugin.ts",
2256
+ line: 53,
2257
+ scope: this,
2258
+ callSite: (f, a) => f(...a)
2259
+ });
2260
+ void ctx.dispose();
2261
+ errors.throw(err);
2262
+ }
2263
+ });
2264
+ scheduleTask3(ctx, () => {
2265
+ log9.warn("Notarization timeout", {}, {
2266
+ file: "notarization-plugin.ts",
2267
+ line: 61,
2268
+ scope: this,
2269
+ callSite: (f, a) => f(...a)
2270
+ });
2271
+ void ctx.dispose();
2272
+ errors.throw(new TimeoutError(NOTARIZE_TIMEOUT, "Notarization timed out"));
2273
+ }, NOTARIZE_TIMEOUT);
2274
+ const allNotarized = Promise.all(credentials.map((credential) => this._waitUntilProcessed(credential.id)));
2275
+ const peersTried = /* @__PURE__ */ new Set();
2276
+ const notarizeTask = new DeferredTask(ctx, async () => {
2277
+ try {
2278
+ if (this._extensions.size === 0) {
2279
+ log9.warn("No peers to notarize with", {}, {
2280
+ file: "notarization-plugin.ts",
2281
+ line: 76,
2282
+ scope: this,
2283
+ callSite: (f, a) => f(...a)
2284
+ });
2285
+ return;
2286
+ }
2287
+ const peer = [
2288
+ ...this._extensions
2289
+ ].find((peer2) => !peersTried.has(peer2));
2290
+ if (!peer) {
2291
+ log9.warn("Exhausted all peers to notarize with", {
2292
+ retryIn: RETRY_TIMEOUT
2293
+ }, {
2294
+ file: "notarization-plugin.ts",
2295
+ line: 83,
2296
+ scope: this,
2297
+ callSite: (f, a) => f(...a)
2298
+ });
2299
+ peersTried.clear();
2300
+ scheduleTask3(ctx, () => notarizeTask.schedule(), RETRY_TIMEOUT);
2301
+ return;
2302
+ }
2303
+ peersTried.add(peer);
2304
+ log9("try notarizing", {
2305
+ peer: peer.localPeerId,
2306
+ credentialId: credentials.map((credential) => credential.id)
2307
+ }, {
2308
+ file: "notarization-plugin.ts",
2309
+ line: 90,
2310
+ scope: this,
2311
+ callSite: (f, a) => f(...a)
2312
+ });
2313
+ await peer.rpc.NotarizationService.notarize({
2314
+ credentials: credentials.filter((credential) => !this._processedCredentials.has(credential.id))
2315
+ });
2316
+ log9("success", {}, {
2317
+ file: "notarization-plugin.ts",
2318
+ line: 94,
2319
+ scope: this,
2320
+ callSite: (f, a) => f(...a)
2321
+ });
2322
+ } catch (err) {
2323
+ log9.warn("error notarizing (recoverable)", err, {
2324
+ file: "notarization-plugin.ts",
2325
+ line: 96,
2326
+ scope: this,
2327
+ callSite: (f, a) => f(...a)
2328
+ });
2329
+ notarizeTask.schedule();
2330
+ }
2331
+ });
2332
+ notarizeTask.schedule();
2333
+ this._extensionOpened.on(ctx, () => notarizeTask.schedule());
2334
+ try {
2335
+ await Promise.race([
2336
+ allNotarized,
2337
+ errors.wait()
2338
+ ]);
2339
+ log9("done", {}, {
2340
+ file: "notarization-plugin.ts",
2341
+ line: 107,
2342
+ scope: this,
2343
+ callSite: (f, a) => f(...a)
2344
+ });
2345
+ } finally {
2346
+ await ctx.dispose();
2347
+ }
2348
+ }
2349
+ /**
2350
+ * Called with credentials arriving from the control pipeline.
2351
+ */
2352
+ async process(credential) {
2353
+ var _a;
2354
+ if (!credential.id) {
2355
+ return;
2356
+ }
2357
+ (_a = this._processCredentialsTriggers.get(credential.id)) == null ? void 0 : _a.wake();
2358
+ this._processedCredentials.add(credential.id);
2359
+ this._processCredentialsTriggers.delete(credential.id);
2360
+ }
2361
+ setWriter(writer) {
2362
+ assert11(!this._writer, "Writer already set.");
2363
+ this._writer = writer;
2364
+ }
2365
+ async _waitUntilProcessed(id) {
2366
+ if (this._processedCredentials.has(id)) {
2367
+ return;
2368
+ }
2369
+ await entry(this._processCredentialsTriggers, id).orInsert(new Trigger4()).value.wait();
2370
+ }
2371
+ /**
2372
+ * Requests from other peers to notarize credentials.
2373
+ */
2374
+ async _onNotarize(request) {
2375
+ var _a;
2376
+ if (!this._writer) {
2377
+ throw new Error("Writer not set");
2378
+ }
2379
+ for (const credential of (_a = request.credentials) != null ? _a : []) {
2380
+ assert11(credential.id, "Credential must have an id");
2381
+ if (this._processedCredentials.has(credential.id)) {
2382
+ continue;
2383
+ }
2384
+ await this._writer.write(credential);
2385
+ }
2386
+ }
2387
+ createExtension() {
2388
+ const extension = new NotarizationTeleportExtension({
2389
+ onOpen: async () => {
2390
+ log9("extension opened", {
2391
+ peer: extension.localPeerId
2392
+ }, {
2393
+ file: "notarization-plugin.ts",
2394
+ line: 156,
2395
+ scope: this,
2396
+ callSite: (f, a) => f(...a)
2397
+ });
2398
+ this._extensions.add(extension);
2399
+ this._extensionOpened.emit();
2400
+ },
2401
+ onClose: async () => {
2402
+ log9("extension closed", {
2403
+ peer: extension.localPeerId
2404
+ }, {
2405
+ file: "notarization-plugin.ts",
2406
+ line: 161,
2407
+ scope: this,
2408
+ callSite: (f, a) => f(...a)
2409
+ });
2410
+ this._extensions.delete(extension);
2411
+ },
2412
+ onNotarize: this._onNotarize.bind(this)
2413
+ });
2414
+ return extension;
2415
+ }
2416
+ };
2417
+ var NotarizationTeleportExtension = class extends RpcExtension3 {
2418
+ constructor(_params) {
2419
+ super({
2420
+ requested: {
2421
+ NotarizationService: schema5.getService("dxos.mesh.teleport.notarization.NotarizationService")
2422
+ },
2423
+ exposed: {
2424
+ NotarizationService: schema5.getService("dxos.mesh.teleport.notarization.NotarizationService")
2425
+ }
2426
+ });
2427
+ this._params = _params;
2428
+ }
2429
+ async getHandlers() {
2430
+ return {
2431
+ NotarizationService: {
2432
+ notarize: async (request) => {
2433
+ await this._params.onNotarize(request);
2434
+ }
2435
+ }
2436
+ };
2437
+ }
2438
+ async onOpen(ctx) {
2439
+ await super.onOpen(ctx);
2440
+ await this._params.onOpen();
2441
+ }
2442
+ async onClose(err) {
2443
+ await this._params.onClose();
2444
+ await super.onClose(err);
2445
+ }
2446
+ };
2447
+
2448
+ // packages/sdk/client-services/src/packlets/spaces/data-space.ts
2449
+ var __decorate = function(decorators, target, key, desc) {
2450
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2451
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
2452
+ r = Reflect.decorate(decorators, target, key, desc);
2453
+ else
2454
+ for (var i = decorators.length - 1; i >= 0; i--)
2455
+ if (d = decorators[i])
2456
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2457
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2458
+ };
2459
+ var AUTH_TIMEOUT2 = 3e4;
2460
+ var CONTROL_PIPELINE_READY_TIMEFRAME = 3e3;
2461
+ var DataSpace = class DataSpace2 {
2462
+ constructor(params) {
2463
+ this._ctx = new Context6();
2464
+ this._inner = params.inner;
2465
+ this._presence = params.presence;
2466
+ this._keyring = params.keyring;
2467
+ this._feedStore = params.feedStore;
2468
+ this._metadataStore = params.metadataStore;
2469
+ this._signingContext = params.signingContext;
2470
+ this._dataPipelineController = new DataPipelineControllerImpl({
2471
+ modelFactory: params.modelFactory,
2472
+ metadataStore: params.metadataStore,
2473
+ snapshotManager: params.snapshotManager,
2474
+ memberKey: params.memberKey,
2475
+ spaceKey: this._inner.key,
2476
+ feedInfoProvider: (feedKey) => this._inner.spaceState.feeds.get(feedKey),
2477
+ snapshotId: params.snapshotId
2478
+ });
2479
+ this.authVerifier = new TrustedKeySetAuthVerifier({
2480
+ trustedKeysProvider: () => new ComplexSet2(PublicKey6.hash, Array.from(this._inner.spaceState.members.keys())),
2481
+ update: this._inner.stateUpdate,
2482
+ authTimeout: AUTH_TIMEOUT2
2483
+ });
2484
+ this._notarizationPluginConsumer = this._inner.spaceState.registerProcessor(new NotarizationPlugin());
2485
+ }
2486
+ get key() {
2487
+ return this._inner.key;
2488
+ }
2489
+ get isOpen() {
2490
+ return this._inner.isOpen;
2491
+ }
2492
+ // TODO(burdon): Can we mark this for debugging only?
2493
+ get inner() {
2494
+ return this._inner;
2495
+ }
2496
+ get dataPipelineController() {
2497
+ return this._dataPipelineController;
2498
+ }
2499
+ get stateUpdate() {
2500
+ return this._inner.stateUpdate;
2501
+ }
2502
+ get presence() {
2503
+ return this._presence;
2504
+ }
2505
+ get notarizationPlugin() {
2506
+ return this._notarizationPluginConsumer.processor;
2507
+ }
2508
+ async open() {
2509
+ await this.notarizationPlugin.open();
2510
+ await this._notarizationPluginConsumer.open();
2511
+ await this._inner.open();
2512
+ }
2513
+ async close() {
2514
+ await this._ctx.dispose();
2515
+ await this.authVerifier.close();
2516
+ await this._inner.close();
2517
+ await this._notarizationPluginConsumer.close();
2518
+ await this.notarizationPlugin.close();
2519
+ await this._presence.destroy();
2520
+ }
2521
+ async initializeDataPipeline() {
2522
+ await this._inner.controlPipeline.state.waitUntilReachedTargetTimeframe({
2523
+ timeout: CONTROL_PIPELINE_READY_TIMEFRAME
2524
+ });
2525
+ await this._createWritableFeeds();
2526
+ this.notarizationPlugin.setWriter(createMappedFeedWriter((credential) => ({
2527
+ credential: {
2528
+ credential
2529
+ }
2530
+ }), this._inner.controlPipeline.writer));
2531
+ await this._inner.initDataPipeline(this._dataPipelineController);
2532
+ }
2533
+ async _createWritableFeeds() {
2534
+ const credentials = [];
2535
+ if (!this.inner.controlFeedKey) {
2536
+ const controlFeed = await this._feedStore.openFeed(await this._keyring.createKey(), {
2537
+ writable: true
2538
+ });
2539
+ this.inner.setControlFeed(controlFeed);
2540
+ credentials.push(await this._signingContext.credentialSigner.createCredential({
2541
+ subject: controlFeed.key,
2542
+ assertion: {
2543
+ "@type": "dxos.halo.credentials.AdmittedFeed",
2544
+ spaceKey: this.key,
2545
+ deviceKey: this._signingContext.deviceKey,
2546
+ identityKey: this._signingContext.identityKey,
2547
+ designation: AdmittedFeed3.Designation.CONTROL
2548
+ }
2549
+ }));
2550
+ }
2551
+ if (!this.inner.dataFeedKey) {
2552
+ const dataFeed = await this._feedStore.openFeed(await this._keyring.createKey(), {
2553
+ writable: true
2554
+ });
2555
+ this.inner.setDataFeed(dataFeed);
2556
+ credentials.push(await this._signingContext.credentialSigner.createCredential({
2557
+ subject: dataFeed.key,
2558
+ assertion: {
2559
+ "@type": "dxos.halo.credentials.AdmittedFeed",
2560
+ spaceKey: this.key,
2561
+ deviceKey: this._signingContext.deviceKey,
2562
+ identityKey: this._signingContext.identityKey,
2563
+ designation: AdmittedFeed3.Designation.DATA
2564
+ }
2565
+ }));
2566
+ }
2567
+ if (credentials.length > 0) {
2568
+ await this.notarizationPlugin.notarize(credentials);
2569
+ }
2570
+ await this._metadataStore.setWritableFeedKeys(this.key, this.inner.controlFeedKey, this.inner.dataFeedKey);
2571
+ }
2572
+ };
2573
+ __decorate([
2574
+ timed(1e4)
2575
+ ], DataSpace.prototype, "_createWritableFeeds", null);
2576
+ DataSpace = __decorate([
2577
+ trackLeaks("open", "close")
2578
+ ], DataSpace);
2579
+
2580
+ // packages/sdk/client-services/src/packlets/spaces/data-space-manager.ts
2581
+ var __decorate2 = function(decorators, target, key, desc) {
2582
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2583
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
2584
+ r = Reflect.decorate(decorators, target, key, desc);
2585
+ else
2586
+ for (var i = decorators.length - 1; i >= 0; i--)
2587
+ if (d = decorators[i])
2588
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2589
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2590
+ };
2591
+ var DATA_PIPELINE_READY_TIMEOUT = 3e3;
2592
+ var DataSpaceManager = class DataSpaceManager2 {
2593
+ constructor(_spaceManager, _metadataStore, _dataServiceSubscriptions, _keyring, _signingContext, _modelFactory, _feedStore, _snapshotStore) {
2594
+ this._spaceManager = _spaceManager;
2595
+ this._metadataStore = _metadataStore;
2596
+ this._dataServiceSubscriptions = _dataServiceSubscriptions;
2597
+ this._keyring = _keyring;
2598
+ this._signingContext = _signingContext;
2599
+ this._modelFactory = _modelFactory;
2600
+ this._feedStore = _feedStore;
2601
+ this._snapshotStore = _snapshotStore;
2602
+ this._ctx = new Context7();
2603
+ this.updated = new Event4();
2604
+ this._spaces = new ComplexMap3(PublicKey7.hash);
2605
+ }
2606
+ // TODO(burdon): Remove.
2607
+ get spaces() {
2608
+ return this._spaces;
2609
+ }
2610
+ async open() {
2611
+ await this._metadataStore.load();
2612
+ log10("metadata loaded", {
2613
+ spaces: this._metadataStore.spaces.length
2614
+ }, {
2615
+ file: "data-space-manager.ts",
2616
+ line: 67,
2617
+ scope: this,
2618
+ callSite: (f, a) => f(...a)
2619
+ });
2620
+ for (const spaceMetadata of this._metadataStore.spaces) {
2621
+ log10("load space", {
2622
+ spaceMetadata
2623
+ }, {
2624
+ file: "data-space-manager.ts",
2625
+ line: 70,
2626
+ scope: this,
2627
+ callSite: (f, a) => f(...a)
2628
+ });
2629
+ const space = await this._constructSpace(spaceMetadata);
2630
+ await space.initializeDataPipeline();
2631
+ if (spaceMetadata.dataTimeframe) {
2632
+ log10("waiting for latest timeframe", {
2633
+ spaceMetadata
2634
+ }, {
2635
+ file: "data-space-manager.ts",
2636
+ line: 74,
2637
+ scope: this,
2638
+ callSite: (f, a) => f(...a)
2639
+ });
2640
+ await space.dataPipelineController.pipelineState.setTargetTimeframe(spaceMetadata.dataTimeframe);
2641
+ }
2642
+ await space.dataPipelineController.pipelineState.waitUntilReachedTargetTimeframe({
2643
+ timeout: DATA_PIPELINE_READY_TIMEOUT
2644
+ });
2645
+ this._dataServiceSubscriptions.registerSpace(space.key, space.dataPipelineController.databaseBackend.createDataServiceHost());
2646
+ }
2647
+ }
2648
+ async close() {
2649
+ await this._ctx.dispose();
2650
+ for (const space of this._spaces.values()) {
2651
+ await space.close();
2652
+ }
2653
+ }
2654
+ /**
2655
+ * Creates a new space writing the genesis credentials to the control feed.
2656
+ */
2657
+ async createSpace() {
2658
+ const spaceKey = await this._keyring.createKey();
2659
+ const controlFeedKey = await this._keyring.createKey();
2660
+ const dataFeedKey = await this._keyring.createKey();
2661
+ const metadata = {
2662
+ key: spaceKey,
2663
+ genesisFeedKey: controlFeedKey,
2664
+ controlFeedKey,
2665
+ dataFeedKey
2666
+ };
2667
+ log10("creating space...", {
2668
+ spaceKey
2669
+ }, {
2670
+ file: "data-space-manager.ts",
2671
+ line: 110,
2672
+ scope: this,
2673
+ callSite: (f, a) => f(...a)
2674
+ });
2675
+ const space = await this._constructSpace(metadata);
2676
+ const credentials = await spaceGenesis(this._keyring, this._signingContext, space.inner);
2677
+ await this._metadataStore.addSpace(metadata);
2678
+ const memberCredential = credentials[1];
2679
+ assert12(getCredentialAssertion2(memberCredential)["@type"] === "dxos.halo.credentials.SpaceMember");
2680
+ await this._signingContext.recordCredential(memberCredential);
2681
+ await space.initializeDataPipeline();
2682
+ this._dataServiceSubscriptions.registerSpace(space.key, space.dataPipelineController.databaseBackend.createDataServiceHost());
2683
+ this.updated.emit();
2684
+ return space;
2685
+ }
2686
+ // TODO(burdon): Rename join space.
2687
+ async acceptSpace(opts) {
2688
+ assert12(!this._spaces.has(opts.spaceKey), "Space already exists.");
2689
+ const metadata = {
2690
+ key: opts.spaceKey,
2691
+ genesisFeedKey: opts.genesisFeedKey
2692
+ };
2693
+ const space = await this._constructSpace(metadata);
2694
+ await this._metadataStore.addSpace(metadata);
2695
+ await space.initializeDataPipeline();
2696
+ this._dataServiceSubscriptions.registerSpace(space.key, space.dataPipelineController.databaseBackend.createDataServiceHost());
2697
+ this.updated.emit();
2698
+ return space;
2699
+ }
2700
+ async _constructSpace(metadata) {
2701
+ const presence = new Presence({
2702
+ localPeerId: this._signingContext.deviceKey,
2703
+ announceInterval: 1e3,
2704
+ offlineTimeout: 3e4,
2705
+ identityKey: this._signingContext.identityKey
2706
+ });
2707
+ const snapshotManager = new SnapshotManager(this._snapshotStore);
2708
+ const controlFeed = metadata.controlFeedKey && await this._feedStore.openFeed(metadata.controlFeedKey, {
2709
+ writable: true
2710
+ });
2711
+ const dataFeed = metadata.dataFeedKey && await this._feedStore.openFeed(metadata.dataFeedKey, {
2712
+ writable: true
2713
+ });
2714
+ const space = await this._spaceManager.constructSpace({
2715
+ metadata,
2716
+ swarmIdentity: {
2717
+ peerKey: this._signingContext.deviceKey,
2718
+ credentialProvider: createAuthProvider(this._signingContext.credentialSigner),
2719
+ credentialAuthenticator: deferFunction2(() => dataSpace.authVerifier.verifier)
2720
+ },
2721
+ onNetworkConnection: (session) => {
2722
+ session.addExtension("dxos.mesh.teleport.presence", presence.createExtension({
2723
+ remotePeerId: session.remotePeerId
2724
+ }));
2725
+ session.addExtension("dxos.mesh.teleport.objectsync", snapshotManager.objectSync.createExtension());
2726
+ session.addExtension("dxos.mesh.teleport.notarization", dataSpace.notarizationPlugin.createExtension());
2727
+ }
2728
+ });
2729
+ controlFeed && space.setControlFeed(controlFeed);
2730
+ dataFeed && space.setDataFeed(dataFeed);
2731
+ const dataSpace = new DataSpace({
2732
+ inner: space,
2733
+ modelFactory: this._modelFactory,
2734
+ metadataStore: this._metadataStore,
2735
+ snapshotManager,
2736
+ presence,
2737
+ memberKey: this._signingContext.identityKey,
2738
+ keyring: this._keyring,
2739
+ feedStore: this._feedStore,
2740
+ signingContext: this._signingContext,
2741
+ snapshotId: metadata.snapshot
2742
+ });
2743
+ await dataSpace.open();
2744
+ this._spaces.set(metadata.key, dataSpace);
2745
+ return dataSpace;
2746
+ }
2747
+ };
2748
+ __decorate2([
2749
+ synchronized
2750
+ ], DataSpaceManager.prototype, "open", null);
2751
+ __decorate2([
2752
+ synchronized
2753
+ ], DataSpaceManager.prototype, "close", null);
2754
+ __decorate2([
2755
+ synchronized
2756
+ ], DataSpaceManager.prototype, "createSpace", null);
2757
+ __decorate2([
2758
+ synchronized
2759
+ ], DataSpaceManager.prototype, "acceptSpace", null);
2760
+ DataSpaceManager = __decorate2([
2761
+ trackLeaks2("open", "close")
2762
+ ], DataSpaceManager);
2763
+
2764
+ // packages/sdk/client-services/src/packlets/services/service-context.ts
2765
+ var ServiceContext = class {
2766
+ // prettier-ignore
2767
+ constructor(storage, networkManager, modelFactory) {
2768
+ this.storage = storage;
2769
+ this.networkManager = networkManager;
2770
+ this.modelFactory = modelFactory;
2771
+ this.initialized = new Trigger5();
2772
+ this.dataServiceSubscriptions = new DataServiceSubscriptions();
2773
+ this.metadataStore = new MetadataStore(storage.createDirectory("metadata"));
2774
+ this.snapshotStore = new SnapshotStore(storage.createDirectory("snapshots"));
2775
+ this.keyring = new Keyring(storage.createDirectory("keyring"));
2776
+ this.feedStore = new FeedStore({
2777
+ factory: new FeedFactory({
2778
+ root: storage.createDirectory("feeds"),
2779
+ signer: this.keyring,
2780
+ hypercore: {
2781
+ valueEncoding
2782
+ }
2783
+ })
2784
+ });
2785
+ this.spaceManager = new SpaceManager({
2786
+ feedStore: this.feedStore,
2787
+ networkManager: this.networkManager
2788
+ });
2789
+ this.identityManager = new IdentityManager(this.metadataStore, this.keyring, this.feedStore, this.spaceManager);
2790
+ this.haloInvitations = new HaloInvitationsHandler({
2791
+ networkManager: this.networkManager,
2792
+ getIdentity: () => {
2793
+ var _a;
2794
+ return (_a = this.identityManager.identity) != null ? _a : failUndefined2();
2795
+ },
2796
+ acceptIdentity: this._acceptIdentity.bind(this),
2797
+ keyring: this.keyring
2798
+ });
2799
+ }
2800
+ async open() {
2801
+ log11("opening...", {}, {
2802
+ file: "service-context.ts",
2803
+ line: 94,
2804
+ scope: this,
2805
+ callSite: (f, a) => f(...a)
2806
+ });
2807
+ await this.networkManager.open();
2808
+ await this.spaceManager.open();
2809
+ await this.identityManager.open();
2810
+ if (this.identityManager.identity) {
2811
+ await this._initialize();
2812
+ }
2813
+ log11("opened", {}, {
2814
+ file: "service-context.ts",
2815
+ line: 101,
2816
+ scope: this,
2817
+ callSite: (f, a) => f(...a)
2818
+ });
2819
+ }
2820
+ async close() {
2821
+ var _a, _b;
2822
+ log11("closing...", {}, {
2823
+ file: "service-context.ts",
2824
+ line: 105,
2825
+ scope: this,
2826
+ callSite: (f, a) => f(...a)
2827
+ });
2828
+ await ((_a = this._deviceSpaceSync) == null ? void 0 : _a.close());
2829
+ await ((_b = this.dataSpaceManager) == null ? void 0 : _b.close());
2830
+ await this.identityManager.close();
2831
+ await this.spaceManager.close();
2832
+ await this.feedStore.close();
2833
+ await this.networkManager.close();
2834
+ this.dataServiceSubscriptions.clear();
2835
+ log11("closed", {}, {
2836
+ file: "service-context.ts",
2837
+ line: 113,
2838
+ scope: this,
2839
+ callSite: (f, a) => f(...a)
2840
+ });
2841
+ }
2842
+ async reset() {
2843
+ log11("resetting...", {}, {
2844
+ file: "service-context.ts",
2845
+ line: 117,
2846
+ scope: this,
2847
+ callSite: (f, a) => f(...a)
2848
+ });
2849
+ await this.close();
2850
+ await this.storage.reset();
2851
+ log11("reset", {}, {
2852
+ file: "service-context.ts",
2853
+ line: 120,
2854
+ scope: this,
2855
+ callSite: (f, a) => f(...a)
2856
+ });
2857
+ }
2858
+ async createIdentity(params = {}) {
2859
+ const identity = await this.identityManager.createIdentity(params);
2860
+ await this._initialize();
2861
+ return identity;
2862
+ }
2863
+ async _acceptIdentity(params) {
2864
+ const identity = await this.identityManager.acceptIdentity(params);
2865
+ await this._initialize();
2866
+ return identity;
2867
+ }
2868
+ // Called when identity is created.
2869
+ async _initialize() {
2870
+ var _a;
2871
+ log11("initializing spaces...", {}, {
2872
+ file: "service-context.ts",
2873
+ line: 139,
2874
+ scope: this,
2875
+ callSite: (f, a) => f(...a)
2876
+ });
2877
+ const identity = (_a = this.identityManager.identity) != null ? _a : failUndefined2();
2878
+ const signingContext = {
2879
+ credentialSigner: identity.getIdentityCredentialSigner(),
2880
+ identityKey: identity.identityKey,
2881
+ deviceKey: identity.deviceKey,
2882
+ profile: identity.profileDocument,
2883
+ recordCredential: async (credential) => {
2884
+ await identity.controlPipeline.writer.write({
2885
+ credential: {
2886
+ credential
2887
+ }
2888
+ });
2889
+ }
2890
+ };
2891
+ this.dataSpaceManager = new DataSpaceManager(this.spaceManager, this.metadataStore, this.dataServiceSubscriptions, this.keyring, signingContext, this.modelFactory, this.feedStore, this.snapshotStore);
2892
+ await this.dataSpaceManager.open();
2893
+ this.spaceInvitations = new SpaceInvitationsHandler(this.networkManager, this.dataSpaceManager, signingContext, this.keyring);
2894
+ this.initialized.wake();
2895
+ this._deviceSpaceSync = identity.space.spaceState.registerProcessor({
2896
+ process: async (credential) => {
2897
+ const assertion = getCredentialAssertion3(credential);
2898
+ if (assertion["@type"] !== "dxos.halo.credentials.SpaceMember") {
2899
+ return;
2900
+ }
2901
+ if (assertion.spaceKey.equals(identity.space.key)) {
2902
+ return;
2903
+ }
2904
+ if (!this.dataSpaceManager) {
2905
+ log11("dataSpaceManager not initialized yet, ignoring space admission", {
2906
+ details: assertion
2907
+ }, {
2908
+ file: "service-context.ts",
2909
+ line: 182,
2910
+ scope: this,
2911
+ callSite: (f, a) => f(...a)
2912
+ });
2913
+ return;
2914
+ }
2915
+ if (this.dataSpaceManager.spaces.has(assertion.spaceKey)) {
2916
+ log11("space already exists, ignoring space admission", {
2917
+ details: assertion
2918
+ }, {
2919
+ file: "service-context.ts",
2920
+ line: 186,
2921
+ scope: this,
2922
+ callSite: (f, a) => f(...a)
2923
+ });
2924
+ return;
2925
+ }
2926
+ try {
2927
+ log11("accepting space recorded in halo", {
2928
+ details: assertion
2929
+ }, {
2930
+ file: "service-context.ts",
2931
+ line: 191,
2932
+ scope: this,
2933
+ callSite: (f, a) => f(...a)
2934
+ });
2935
+ await this.dataSpaceManager.acceptSpace({
2936
+ spaceKey: assertion.spaceKey,
2937
+ genesisFeedKey: assertion.genesisFeedKey
2938
+ });
2939
+ } catch (err) {
2940
+ log11.catch(err, {}, {
2941
+ file: "service-context.ts",
2942
+ line: 197,
2943
+ scope: this,
2944
+ callSite: (f, a) => f(...a)
2945
+ });
2946
+ }
2947
+ }
2948
+ });
2949
+ await this._deviceSpaceSync.open();
2950
+ }
2951
+ };
2952
+
2953
+ // packages/sdk/client-services/src/packlets/services/service-definitions.ts
2954
+ import { schema as schema6 } from "@dxos/protocols";
2955
+ import { createServiceBundle } from "@dxos/rpc";
2956
+ var clientServiceBundle = createServiceBundle({
2957
+ HaloInvitationsService: schema6.getService("dxos.client.services.HaloInvitationsService"),
2958
+ DevicesService: schema6.getService("dxos.client.services.DevicesService"),
2959
+ SpaceInvitationsService: schema6.getService("dxos.client.services.SpaceInvitationsService"),
2960
+ SpacesService: schema6.getService("dxos.client.services.SpacesService"),
2961
+ NetworkService: schema6.getService("dxos.client.services.NetworkService"),
2962
+ // TODO(burdon): Deprecated.
2963
+ SpaceService: schema6.getService("dxos.client.SpaceService"),
2964
+ DataService: schema6.getService("dxos.echo.service.DataService"),
2965
+ ProfileService: schema6.getService("dxos.client.ProfileService"),
2966
+ SystemService: schema6.getService("dxos.client.SystemService"),
2967
+ DevtoolsHost: schema6.getService("dxos.devtools.host.DevtoolsHost"),
2968
+ TracingService: schema6.getService("dxos.devtools.host.TracingService")
2969
+ });
2970
+
2971
+ // packages/sdk/client-services/src/packlets/storage/storage.ts
2972
+ import { InvalidConfigError } from "@dxos/errors";
2973
+ import { Runtime } from "@dxos/protocols/proto/dxos/config";
2974
+ import { createStorage, StorageType } from "@dxos/random-access-storage";
2975
+ var StorageDriver = Runtime.Client.Storage.StorageDriver;
2976
+ var createStorageObjects = (config) => {
2977
+ const { path = "dxos/storage", storageType, keyStorage, persistent = false } = config != null ? config : {};
2978
+ if (persistent && storageType === StorageDriver.RAM) {
2979
+ throw new InvalidConfigError("RAM storage cannot be used in persistent mode.");
2980
+ }
2981
+ if (!persistent && storageType !== void 0 && storageType !== StorageDriver.RAM) {
2982
+ throw new InvalidConfigError("Cannot use a persistent storage in not persistent mode.");
2983
+ }
2984
+ if (persistent && keyStorage === StorageDriver.RAM) {
2985
+ throw new InvalidConfigError("RAM key storage cannot be used in persistent mode.");
2986
+ }
2987
+ if (!persistent && keyStorage !== StorageDriver.RAM && keyStorage !== void 0) {
2988
+ throw new InvalidConfigError("Cannot use a persistent key storage in not persistent mode.");
2989
+ }
2990
+ return {
2991
+ storage: createStorage({
2992
+ type: persistent ? toStorageType(storageType) : StorageType.RAM,
2993
+ root: `${path}/`
2994
+ })
2995
+ };
2996
+ };
2997
+ var toStorageType = (type) => {
2998
+ switch (type) {
2999
+ case void 0:
3000
+ return void 0;
3001
+ case StorageDriver.RAM:
3002
+ return StorageType.RAM;
3003
+ case StorageDriver.CHROME:
3004
+ return StorageType.CHROME;
3005
+ case StorageDriver.FIREFOX:
3006
+ return StorageType.FIREFOX;
3007
+ case StorageDriver.IDB:
3008
+ return StorageType.IDB;
3009
+ case StorageDriver.NODE:
3010
+ return StorageType.NODE;
3011
+ default:
3012
+ throw new Error(`Invalid storage type: ${StorageDriver[type]}`);
3013
+ }
3014
+ };
3015
+
3016
+ // packages/sdk/client-services/src/packlets/vault/iframe-host-runtime.ts
3017
+ import { Trigger as Trigger9 } from "@dxos/async";
3018
+ import { log as log16, logInfo as logInfo2 } from "@dxos/log";
3019
+ import { MemorySignalManager as MemorySignalManager2, MemorySignalManagerContext as MemorySignalManagerContext2, WebsocketSignalManager as WebsocketSignalManager2 } from "@dxos/messaging";
3020
+ import { createWebRTCTransportFactory, NetworkManager as NetworkManager2 } from "@dxos/network-manager";
3021
+ import { createProtoRpcPeer as createProtoRpcPeer4 } from "@dxos/rpc";
3022
+
3023
+ // packages/sdk/client-services/src/packlets/services/service-host.ts
3024
+ import { raise as raise2 } from "@dxos/debug";
3025
+ import { DocumentModel } from "@dxos/document-model";
3026
+ import { DataServiceImpl } from "@dxos/echo-db";
3027
+ import { log as log15 } from "@dxos/log";
3028
+ import { ModelFactory } from "@dxos/model-factory";
3029
+ import { Status } from "@dxos/protocols/proto/dxos/client";
3030
+ import { TextModel } from "@dxos/text-model";
3031
+
3032
+ // packages/sdk/client-services/src/packlets/identity/devices-service-impl.ts
3033
+ import { EventSubscriptions as EventSubscriptions2 } from "@dxos/async";
3034
+ import { Stream as Stream9 } from "@dxos/codec-protobuf";
3035
+ var DevicesServiceImpl = class {
3036
+ constructor(_identityManager) {
3037
+ this._identityManager = _identityManager;
3038
+ }
3039
+ updateDevice() {
3040
+ throw new Error("Method not implemented.");
3041
+ }
3042
+ queryDevices() {
3043
+ return new Stream9(({ next }) => {
3044
+ const update = () => {
3045
+ var _a;
3046
+ const deviceKeys = (_a = this._identityManager.identity) == null ? void 0 : _a.authorizedDeviceKeys;
3047
+ if (!deviceKeys) {
3048
+ next({
3049
+ devices: []
3050
+ });
3051
+ } else {
3052
+ next({
3053
+ devices: Array.from(deviceKeys.values()).map((key) => ({
3054
+ deviceKey: key
3055
+ }))
3056
+ });
3057
+ }
3058
+ };
3059
+ const dispose = new EventSubscriptions2();
3060
+ dispose.add(this._identityManager.stateUpdate.on(() => {
3061
+ update();
3062
+ if (this._identityManager.identity) {
3063
+ dispose.add(this._identityManager.identity.stateUpdate.on(() => {
3064
+ update();
3065
+ }));
3066
+ }
3067
+ }));
3068
+ update();
3069
+ return () => dispose.clear();
3070
+ });
3071
+ }
3072
+ };
3073
+
3074
+ // packages/sdk/client-services/src/packlets/network/network-service.ts
3075
+ import { Stream as Stream10 } from "@dxos/codec-protobuf";
3076
+ var NetworkServiceImpl = class {
3077
+ constructor(networkManager) {
3078
+ this.networkManager = networkManager;
3079
+ }
3080
+ subscribeToNetworkStatus() {
3081
+ return new Stream10(({ next }) => {
3082
+ const unsubscribe = this.networkManager.connectionStateChanged.on((state) => next({
3083
+ state
3084
+ }));
3085
+ next({
3086
+ state: this.networkManager.connectionState
3087
+ });
3088
+ return unsubscribe;
3089
+ });
3090
+ }
3091
+ async setNetworkOptions(request) {
3092
+ await this.networkManager.setConnectionState(request.state);
3093
+ }
3094
+ };
3095
+
3096
+ // packages/sdk/client-services/src/packlets/spaces/spaces-service.ts
3097
+ import { scheduleTask as scheduleTask4 } from "@dxos/async";
3098
+ import { Stream as Stream11 } from "@dxos/codec-protobuf";
3099
+ import { raise } from "@dxos/debug";
3100
+ import { SpaceNotFoundError } from "@dxos/echo-db";
3101
+ var SpacesServiceImpl = class {
3102
+ constructor(_spaceManager) {
3103
+ this._spaceManager = _spaceManager;
3104
+ }
3105
+ async createSpace() {
3106
+ throw new Error();
3107
+ }
3108
+ querySpaces() {
3109
+ throw new Error();
3110
+ }
3111
+ queryMembers(query) {
3112
+ throw new Error();
3113
+ }
3114
+ queryCredentials({ spaceKey }) {
3115
+ return new Stream11(({ ctx, next }) => {
3116
+ var _a;
3117
+ const space = (_a = this._spaceManager.spaces.get(spaceKey)) != null ? _a : raise(new SpaceNotFoundError(spaceKey));
3118
+ const processor = space.spaceState.registerProcessor({
3119
+ process: async (credential) => {
3120
+ next(credential);
3121
+ }
3122
+ });
3123
+ ctx.onDispose(() => processor.close());
3124
+ scheduleTask4(ctx, () => processor.open());
3125
+ });
3126
+ }
3127
+ async writeCredentials({ spaceKey, credentials }) {
3128
+ var _a;
3129
+ const space = (_a = this._spaceManager.spaces.get(spaceKey)) != null ? _a : raise(new SpaceNotFoundError(spaceKey));
3130
+ for (const credential of credentials != null ? credentials : []) {
3131
+ await space.controlPipeline.writer.write({
3132
+ credential: {
3133
+ credential
3134
+ }
3135
+ });
3136
+ }
3137
+ }
3138
+ };
3139
+
3140
+ // packages/sdk/client-services/src/packlets/vault/iframe-proxy-runtime.ts
3141
+ import { WebRTCTransportService } from "@dxos/network-manager";
3142
+ import { createProtoRpcPeer } from "@dxos/rpc";
3143
+
3144
+ // packages/sdk/client-services/src/packlets/vault/services.ts
3145
+ import { schema as schema7 } from "@dxos/protocols";
3146
+ var iframeServiceBundle = {
3147
+ IframeService: schema7.getService("dxos.iframe.IframeService"),
3148
+ BridgeService: schema7.getService("dxos.mesh.bridge.BridgeService")
3149
+ };
3150
+ var workerServiceBundle = {
3151
+ WorkerService: schema7.getService("dxos.iframe.WorkerService")
3152
+ };
3153
+
3154
+ // packages/sdk/client-services/src/packlets/vault/iframe-proxy-runtime.ts
3155
+ var IFrameProxyRuntime = class {
3156
+ constructor({ systemPort, workerAppPort, windowAppPort }) {
3157
+ this._transportService = new WebRTCTransportService();
3158
+ this._systemPort = systemPort;
3159
+ this._windowAppPort = windowAppPort;
3160
+ this._workerAppPort = workerAppPort;
3161
+ this._systemRpc = createProtoRpcPeer({
3162
+ requested: workerServiceBundle,
3163
+ exposed: iframeServiceBundle,
3164
+ handlers: {
3165
+ BridgeService: this._transportService,
3166
+ IframeService: {
3167
+ async heartbeat() {
3168
+ }
3169
+ }
3170
+ },
3171
+ port: this._systemPort,
3172
+ timeout: 200
3173
+ });
3174
+ this._workerAppPort.subscribe((msg) => this._windowAppPort.send(msg));
3175
+ this._windowAppPort.subscribe((msg) => this._workerAppPort.send(msg));
3176
+ }
3177
+ async open(origin) {
3178
+ await this._systemRpc.open();
3179
+ await this._systemRpc.rpc.WorkerService.start({
3180
+ origin
3181
+ });
3182
+ }
3183
+ async close() {
3184
+ await this._systemRpc.rpc.WorkerService.stop();
3185
+ await this._systemRpc.close();
3186
+ }
3187
+ };
3188
+
3189
+ // packages/sdk/client-services/src/packlets/vault/vault-resource-lock.ts
3190
+ import { asyncTimeout, Trigger as Trigger6 } from "@dxos/async";
3191
+ import { log as log12 } from "@dxos/log";
3192
+ var Message;
3193
+ (function(Message2) {
3194
+ Message2["ACQUIRING"] = "acquiring";
3195
+ })(Message || (Message = {}));
3196
+ var VaultResourceLock = class {
3197
+ constructor({ lockKey, onAcquire, onRelease }) {
3198
+ this._broadcastChannel = new BroadcastChannel("vault-resource-lock");
3199
+ this._releaseTrigger = new Trigger6();
3200
+ this._lockKey = lockKey;
3201
+ this._onAcquire = onAcquire;
3202
+ this._onRelease = onRelease;
3203
+ this._broadcastChannel.onmessage = this._onMessage.bind(this);
3204
+ }
3205
+ async acquire() {
3206
+ this._broadcastChannel.postMessage({
3207
+ message: Message.ACQUIRING
3208
+ });
3209
+ try {
3210
+ await asyncTimeout(this._requestLock(), 3e3);
3211
+ } catch (e) {
3212
+ await this._requestLock(true);
3213
+ }
3214
+ }
3215
+ async release() {
3216
+ this._releaseTrigger.wake();
3217
+ }
3218
+ _onMessage(event) {
3219
+ if (event.data.message === Message.ACQUIRING) {
3220
+ this._releaseTrigger.wake();
3221
+ }
3222
+ }
3223
+ async _requestLock(steal = false) {
3224
+ log12("requesting lock...", {
3225
+ steal
3226
+ }, {
3227
+ file: "vault-resource-lock.ts",
3228
+ line: 56,
3229
+ scope: this,
3230
+ callSite: (f, a) => f(...a)
3231
+ });
3232
+ const acquired = new Trigger6();
3233
+ void navigator.locks.request(this._lockKey, {
3234
+ steal
3235
+ }, async () => {
3236
+ var _a, _b;
3237
+ await ((_a = this._onAcquire) == null ? void 0 : _a.call(this));
3238
+ acquired.wake();
3239
+ this._releaseTrigger = new Trigger6();
3240
+ await this._releaseTrigger.wait();
3241
+ log12("releasing lock...", {}, {
3242
+ file: "vault-resource-lock.ts",
3243
+ line: 65,
3244
+ scope: this,
3245
+ callSite: (f, a) => f(...a)
3246
+ });
3247
+ await ((_b = this._onRelease) == null ? void 0 : _b.call(this));
3248
+ log12("released lock", {}, {
3249
+ file: "vault-resource-lock.ts",
3250
+ line: 67,
3251
+ scope: this,
3252
+ callSite: (f, a) => f(...a)
3253
+ });
3254
+ }).catch(async () => {
3255
+ var _a;
3256
+ await ((_a = this._onRelease) == null ? void 0 : _a.call(this));
3257
+ });
3258
+ await acquired.wait();
3259
+ log12("recieved lock", {
3260
+ steal
3261
+ }, {
3262
+ file: "vault-resource-lock.ts",
3263
+ line: 74,
3264
+ scope: this,
3265
+ callSite: (f, a) => f(...a)
3266
+ });
3267
+ }
3268
+ };
3269
+
3270
+ // packages/sdk/client-services/src/packlets/vault/worker-runtime.ts
3271
+ import { Trigger as Trigger8 } from "@dxos/async";
3272
+ import { log as log14 } from "@dxos/log";
3273
+ import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from "@dxos/messaging";
3274
+ import { NetworkManager, WebRTCTransportProxyFactory } from "@dxos/network-manager";
3275
+
3276
+ // packages/sdk/client-services/src/packlets/vault/worker-session.ts
3277
+ import assert13 from "@dxos/node-std/assert";
3278
+ import { Trigger as Trigger7 } from "@dxos/async";
3279
+ import { log as log13, logInfo } from "@dxos/log";
3280
+ import { createProtoRpcPeer as createProtoRpcPeer2 } from "@dxos/rpc";
3281
+ import { Callback } from "@dxos/util";
3282
+ var __decorate3 = function(decorators, target, key, desc) {
3283
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3284
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
3285
+ r = Reflect.decorate(decorators, target, key, desc);
3286
+ else
3287
+ for (var i = decorators.length - 1; i >= 0; i--)
3288
+ if (d = decorators[i])
3289
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3290
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3291
+ };
3292
+ var WorkerSession = class {
3293
+ constructor({ getService, systemPort, appPort, options = {
3294
+ heartbeatInterval: 1e3
3295
+ } }) {
3296
+ this._startTrigger = new Trigger7();
3297
+ this.onClose = new Callback();
3298
+ assert13(options);
3299
+ assert13(getService);
3300
+ this._options = options;
3301
+ this._getService = getService;
3302
+ this._clientRpc = createProtoRpcPeer2({
3303
+ exposed: clientServiceBundle,
3304
+ handlers: {
3305
+ DataService: async () => await this._getService((services) => services.DataService),
3306
+ DevicesService: async () => await this._getService((services) => services.DevicesService),
3307
+ DevtoolsHost: async () => await this._getService((services) => services.DevtoolsHost),
3308
+ HaloInvitationsService: async () => await this._getService((services) => services.HaloInvitationsService),
3309
+ NetworkService: async () => await this._getService((services) => services.NetworkService),
3310
+ ProfileService: async () => await this._getService((services) => services.ProfileService),
3311
+ SpaceInvitationsService: async () => await this._getService((services) => services.SpaceInvitationsService),
3312
+ SpaceService: async () => await this._getService((services) => services.SpaceService),
3313
+ SpacesService: async () => await this._getService((services) => services.SpacesService),
3314
+ SystemService: async () => await this._getService((services) => services.SystemService),
3315
+ TracingService: async () => await this._getService((services) => services.TracingService)
3316
+ },
3317
+ port: appPort
3318
+ });
3319
+ this._iframeRpc = createProtoRpcPeer2({
3320
+ requested: iframeServiceBundle,
3321
+ exposed: workerServiceBundle,
3322
+ handlers: {
3323
+ WorkerService: {
3324
+ start: async (request) => {
3325
+ this.origin = request.origin;
3326
+ this._startTrigger.wake();
3327
+ },
3328
+ stop: async () => {
3329
+ setTimeout(async () => {
3330
+ try {
3331
+ await this.close();
3332
+ } catch (err) {
3333
+ log13.catch(err, {}, {
3334
+ file: "worker-session.ts",
3335
+ line: 90,
3336
+ scope: this,
3337
+ callSite: (f, a) => f(...a)
3338
+ });
3339
+ }
3340
+ });
3341
+ }
3342
+ }
3343
+ },
3344
+ port: systemPort,
3345
+ timeout: 1e3
3346
+ // With low timeout heartbeat may fail if the tab's thread is saturated.
3347
+ });
3348
+ this.bridgeService = this._iframeRpc.rpc.BridgeService;
3349
+ }
3350
+ async open() {
3351
+ log13.info("opening..", {}, {
3352
+ file: "worker-session.ts",
3353
+ line: 104,
3354
+ scope: this,
3355
+ callSite: (f, a) => f(...a)
3356
+ });
3357
+ await Promise.all([
3358
+ this._clientRpc.open(),
3359
+ this._iframeRpc.open()
3360
+ ]);
3361
+ await this._startTrigger.wait({
3362
+ timeout: 3e3
3363
+ });
3364
+ this._heartbeatTimer = setInterval(async () => {
3365
+ try {
3366
+ await this._iframeRpc.rpc.IframeService.heartbeat();
3367
+ } catch (err1) {
3368
+ log13.warn("Heartbeat failed", {
3369
+ err: err1
3370
+ }, {
3371
+ file: "worker-session.ts",
3372
+ line: 116,
3373
+ scope: this,
3374
+ callSite: (f, a) => f(...a)
3375
+ });
3376
+ try {
3377
+ await this.close();
3378
+ } catch (err) {
3379
+ log13.catch(err, {}, {
3380
+ file: "worker-session.ts",
3381
+ line: 120,
3382
+ scope: this,
3383
+ callSite: (f, a) => f(...a)
3384
+ });
3385
+ }
3386
+ }
3387
+ }, this._options.heartbeatInterval);
3388
+ }
3389
+ async close() {
3390
+ log13.info("closing..", {}, {
3391
+ file: "worker-session.ts",
3392
+ line: 127,
3393
+ scope: this,
3394
+ callSite: (f, a) => f(...a)
3395
+ });
3396
+ try {
3397
+ await this.onClose.callIfSet();
3398
+ } catch (err) {
3399
+ log13.catch(err, {}, {
3400
+ file: "worker-session.ts",
3401
+ line: 131,
3402
+ scope: this,
3403
+ callSite: (f, a) => f(...a)
3404
+ });
3405
+ }
3406
+ if (this._heartbeatTimer !== void 0) {
3407
+ clearInterval(this._heartbeatTimer);
3408
+ }
3409
+ await Promise.all([
3410
+ this._clientRpc.close(),
3411
+ this._iframeRpc.close()
3412
+ ]);
3413
+ }
3414
+ };
3415
+ __decorate3([
3416
+ logInfo
3417
+ ], WorkerSession.prototype, "origin", void 0);
3418
+
3419
+ // packages/sdk/client-services/src/packlets/vault/worker-runtime.ts
3420
+ var WorkerRuntime = class {
3421
+ // prettier-ignore
3422
+ constructor(_configProvider) {
3423
+ this._configProvider = _configProvider;
3424
+ this._transportFactory = new WebRTCTransportProxyFactory();
3425
+ this._ready = new Trigger8();
3426
+ this.sessions = /* @__PURE__ */ new Set();
3427
+ }
3428
+ async start() {
3429
+ log14("starting...", {}, {
3430
+ file: "worker-runtime.ts",
3431
+ line: 41,
3432
+ scope: this,
3433
+ callSite: (f, a) => f(...a)
3434
+ });
3435
+ try {
3436
+ this._config = await this._configProvider();
3437
+ const signalServer = this._config.get("runtime.services.signal.server");
3438
+ this._clientServices = new ClientServicesHost({
3439
+ config: this._config,
3440
+ networkManager: new NetworkManager({
3441
+ log: true,
3442
+ signalManager: signalServer ? new WebsocketSignalManager([
3443
+ signalServer
3444
+ ]) : new MemorySignalManager(new MemorySignalManagerContext()),
3445
+ transportFactory: this._transportFactory
3446
+ })
3447
+ });
3448
+ await this._clientServices.open();
3449
+ this._ready.wake(void 0);
3450
+ log14("started", {}, {
3451
+ file: "worker-runtime.ts",
3452
+ line: 58,
3453
+ scope: this,
3454
+ callSite: (f, a) => f(...a)
3455
+ });
3456
+ } catch (err) {
3457
+ this._ready.wake(err);
3458
+ log14.catch(err, {}, {
3459
+ file: "worker-runtime.ts",
3460
+ line: 61,
3461
+ scope: this,
3462
+ callSite: (f, a) => f(...a)
3463
+ });
3464
+ }
3465
+ }
3466
+ async stop() {
3467
+ await this._clientServices.close();
3468
+ }
3469
+ /**
3470
+ * Create a new session.
3471
+ */
3472
+ async createSession({ appPort, systemPort }) {
3473
+ const session = new WorkerSession({
3474
+ getService: async (find) => {
3475
+ const error = await this._ready.wait();
3476
+ if (error) {
3477
+ throw error;
3478
+ }
3479
+ const service = find(this._clientServices.services);
3480
+ if (!service) {
3481
+ throw new Error("Service not found");
3482
+ }
3483
+ return service;
3484
+ },
3485
+ appPort,
3486
+ systemPort,
3487
+ readySignal: this._ready
3488
+ });
3489
+ session.onClose.set(async () => {
3490
+ this.sessions.delete(session);
3491
+ this._reconnectWebrtc();
3492
+ });
3493
+ await session.open();
3494
+ this.sessions.add(session);
3495
+ this._reconnectWebrtc();
3496
+ }
3497
+ /**
3498
+ * Selects one of the existing session fro WebRTC networking.
3499
+ */
3500
+ _reconnectWebrtc() {
3501
+ if (this._sessionForNetworking) {
3502
+ if (!this.sessions.has(this._sessionForNetworking)) {
3503
+ this._sessionForNetworking = void 0;
3504
+ }
3505
+ }
3506
+ if (!this._sessionForNetworking) {
3507
+ const selected = Array.from(this.sessions).find((session) => session.bridgeService);
3508
+ if (selected) {
3509
+ this._sessionForNetworking = selected;
3510
+ this._transportFactory.setBridgeService(selected.bridgeService);
3511
+ } else {
3512
+ this._transportFactory.setBridgeService(void 0);
3513
+ }
3514
+ }
3515
+ }
3516
+ };
3517
+
3518
+ // packages/sdk/client-services/src/packlets/services/service-registry.ts
3519
+ var ServiceRegistry = class {
3520
+ // prettier-ignore
3521
+ constructor(_serviceBundle, _handlers) {
3522
+ this._serviceBundle = _serviceBundle;
3523
+ this._handlers = _handlers;
3524
+ }
3525
+ get descriptors() {
3526
+ return this._serviceBundle;
3527
+ }
3528
+ get services() {
3529
+ return this._handlers;
3530
+ }
3531
+ setServices(services) {
3532
+ this._handlers = services;
3533
+ }
3534
+ };
3535
+
3536
+ // packages/sdk/client-services/src/packlets/services/service-host.ts
3537
+ var createDefaultModelFactory = () => {
3538
+ return new ModelFactory().registerModel(DocumentModel).registerModel(TextModel);
3539
+ };
3540
+ var ClientServicesHost = class {
3541
+ constructor({
3542
+ config,
3543
+ modelFactory = createDefaultModelFactory(),
3544
+ // TODO(burdon): Create ApolloLink abstraction (see Client).
3545
+ networkManager,
3546
+ storage = createStorageObjects(config.get("runtime.client.storage", {})).storage,
3547
+ lockKey
3548
+ }) {
3549
+ this._open = false;
3550
+ this._config = config;
3551
+ this._modelFactory = modelFactory;
3552
+ this._networkManager = networkManager;
3553
+ this._storage = storage;
3554
+ this._resourceLock = lockKey ? new VaultResourceLock({
3555
+ lockKey,
3556
+ onAcquire: () => this.open(),
3557
+ onRelease: () => this.close()
3558
+ }) : void 0;
3559
+ this._systemService = new SystemServiceImpl({
3560
+ config: this._config,
3561
+ onInit: async () => {
3562
+ var _a;
3563
+ await ((_a = this._resourceLock) == null ? void 0 : _a.acquire());
3564
+ },
3565
+ onStatus: async () => {
3566
+ if (!this.isOpen) {
3567
+ return {
3568
+ status: Status.INACTIVE
3569
+ };
3570
+ }
3571
+ return {
3572
+ status: Status.ACTIVE
3573
+ };
3574
+ },
3575
+ onReset: async () => {
3576
+ var _a;
3577
+ await ((_a = this._serviceContext) == null ? void 0 : _a.reset());
3578
+ }
3579
+ });
3580
+ this._serviceRegistry = new ServiceRegistry(clientServiceBundle, {
3581
+ SystemService: this._systemService
3582
+ });
3583
+ }
3584
+ get isOpen() {
3585
+ return this._open;
3586
+ }
3587
+ get descriptors() {
3588
+ return this._serviceRegistry.descriptors;
3589
+ }
3590
+ get services() {
3591
+ return this._serviceRegistry.services;
3592
+ }
3593
+ async open() {
3594
+ var _a;
3595
+ if (this._open) {
3596
+ return;
3597
+ }
3598
+ log15("opening...", {}, {
3599
+ file: "service-host.ts",
3600
+ line: 125,
3601
+ scope: this,
3602
+ callSite: (f, a) => f(...a)
3603
+ });
3604
+ this._serviceContext = new ServiceContext(this._storage, this._networkManager, this._modelFactory);
3605
+ this._serviceRegistry.setServices({
3606
+ // TODO(burdon): Move to new protobuf definitions.
3607
+ SystemService: this._systemService,
3608
+ HaloInvitationsService: new HaloInvitationsServiceImpl(this._serviceContext.identityManager, this._serviceContext.haloInvitations),
3609
+ DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
3610
+ SpaceInvitationsService: new SpaceInvitationsServiceImpl(this._serviceContext.identityManager, () => {
3611
+ var _a2;
3612
+ return (_a2 = this._serviceContext.spaceInvitations) != null ? _a2 : raise2(new Error("SpaceInvitations not initialized"));
3613
+ }, () => {
3614
+ var _a2;
3615
+ return (_a2 = this._serviceContext.dataSpaceManager) != null ? _a2 : raise2(new Error("SpaceManager not initialized"));
3616
+ }),
3617
+ SpacesService: new SpacesServiceImpl(this._serviceContext.spaceManager),
3618
+ DataService: new DataServiceImpl(this._serviceContext.dataServiceSubscriptions),
3619
+ NetworkService: new NetworkServiceImpl(this._serviceContext.networkManager),
3620
+ // TODO(burdon): Move to new protobuf definitions.
3621
+ ProfileService: new ProfileServiceImpl(this._serviceContext),
3622
+ // TODO(burdon): Port old SubscribeSpaces to QueryServices>
3623
+ SpaceService: new SpaceServiceImpl(this._serviceContext),
3624
+ TracingService: new TracingServiceImpl(this._config),
3625
+ DevtoolsHost: new DevtoolsServiceImpl({
3626
+ events: new DevtoolsHostEvents(),
3627
+ config: this._config,
3628
+ context: this._serviceContext
3629
+ })
3630
+ });
3631
+ await this._serviceContext.open();
3632
+ this._open = true;
3633
+ const deviceKey = (_a = this._serviceContext.identityManager.identity) == null ? void 0 : _a.deviceKey;
3634
+ log15("opened", {
3635
+ deviceKey
3636
+ }, {
3637
+ file: "service-host.ts",
3638
+ line: 172,
3639
+ scope: this,
3640
+ callSite: (f, a) => f(...a)
3641
+ });
3642
+ }
3643
+ async close() {
3644
+ var _a;
3645
+ if (!this._open) {
3646
+ return;
3647
+ }
3648
+ const deviceKey = (_a = this._serviceContext.identityManager.identity) == null ? void 0 : _a.deviceKey;
3649
+ log15("closing...", {
3650
+ deviceKey
3651
+ }, {
3652
+ file: "service-host.ts",
3653
+ line: 181,
3654
+ scope: this,
3655
+ callSite: (f, a) => f(...a)
3656
+ });
3657
+ this._serviceRegistry.setServices({
3658
+ SystemService: this._systemService
3659
+ });
3660
+ await this._serviceContext.close();
3661
+ this._open = false;
3662
+ log15("closed", {
3663
+ deviceKey
3664
+ }, {
3665
+ file: "service-host.ts",
3666
+ line: 185,
3667
+ scope: this,
3668
+ callSite: (f, a) => f(...a)
3669
+ });
3670
+ }
3671
+ };
3672
+
3673
+ // packages/sdk/client-services/src/packlets/services/service-proxy.ts
3674
+ import { asyncTimeout as asyncTimeout2 } from "@dxos/async";
3675
+ import { RemoteServiceConnectionTimeout } from "@dxos/errors";
3676
+ import { createProtoRpcPeer as createProtoRpcPeer3 } from "@dxos/rpc";
3677
+ var ClientServicesProxy = class {
3678
+ // prettier-ignore
3679
+ constructor(port, _timeout = 3e4) {
3680
+ this._timeout = _timeout;
3681
+ this._proxy = createProtoRpcPeer3({
3682
+ requested: clientServiceBundle,
3683
+ exposed: {},
3684
+ handlers: {},
3685
+ port
3686
+ });
3687
+ }
3688
+ get proxy() {
3689
+ return this._proxy;
3690
+ }
3691
+ get descriptors() {
3692
+ return clientServiceBundle;
3693
+ }
3694
+ get services() {
3695
+ return this._proxy.rpc;
3696
+ }
3697
+ async open() {
3698
+ await asyncTimeout2(this._proxy.open(), this._timeout, new RemoteServiceConnectionTimeout());
3699
+ }
3700
+ async close() {
3701
+ await this._proxy.close();
3702
+ }
3703
+ };
3704
+
3705
+ // packages/sdk/client-services/src/packlets/vault/iframe-host-runtime.ts
3706
+ var __decorate4 = function(decorators, target, key, desc) {
3707
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3708
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
3709
+ r = Reflect.decorate(decorators, target, key, desc);
3710
+ else
3711
+ for (var i = decorators.length - 1; i >= 0; i--)
3712
+ if (d = decorators[i])
3713
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3714
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3715
+ };
3716
+ var LOCK_KEY = "DXOS_RESOURCE_LOCK";
3717
+ var IFrameHostRuntime = class {
3718
+ constructor({ configProvider, appPort }) {
3719
+ this._transportFactory = createWebRTCTransportFactory();
3720
+ this._ready = new Trigger9();
3721
+ this._configProvider = configProvider;
3722
+ this._appPort = appPort;
3723
+ this._getService = async (find) => {
3724
+ const error = await this._ready.wait();
3725
+ if (error) {
3726
+ throw error;
3727
+ }
3728
+ const service = await find(this._clientServices.services);
3729
+ if (!service) {
3730
+ throw new Error("Service not found");
3731
+ }
3732
+ return service;
3733
+ };
3734
+ }
3735
+ async start() {
3736
+ log16("starting...", {}, {
3737
+ file: "iframe-host-runtime.ts",
3738
+ line: 63,
3739
+ scope: this,
3740
+ callSite: (f, a) => f(...a)
3741
+ });
3742
+ try {
3743
+ this._config = await this._configProvider();
3744
+ const signalServer = this._config.get("runtime.services.signal.server");
3745
+ this._clientServices = new ClientServicesHost({
3746
+ lockKey: LOCK_KEY,
3747
+ config: this._config,
3748
+ networkManager: new NetworkManager2({
3749
+ log: true,
3750
+ signalManager: signalServer ? new WebsocketSignalManager2([
3751
+ signalServer
3752
+ ]) : new MemorySignalManager2(new MemorySignalManagerContext2()),
3753
+ transportFactory: this._transportFactory
3754
+ })
3755
+ });
3756
+ this._clientRpc = createProtoRpcPeer4({
3757
+ exposed: clientServiceBundle,
3758
+ handlers: {
3759
+ DataService: async () => await this._getService((services) => services.DataService),
3760
+ DevicesService: async () => await this._getService((services) => services.DevicesService),
3761
+ DevtoolsHost: async () => await this._getService((services) => services.DevtoolsHost),
3762
+ HaloInvitationsService: async () => await this._getService((services) => services.HaloInvitationsService),
3763
+ NetworkService: async () => await this._getService((services) => services.NetworkService),
3764
+ ProfileService: async () => await this._getService((services) => services.ProfileService),
3765
+ SpaceInvitationsService: async () => await this._getService((services) => services.SpaceInvitationsService),
3766
+ SpaceService: async () => await this._getService((services) => services.SpaceService),
3767
+ SpacesService: async () => await this._getService((services) => services.SpacesService),
3768
+ SystemService: async () => await this._getService((services) => services.SystemService),
3769
+ TracingService: async () => await this._getService((services) => services.TracingService)
3770
+ },
3771
+ port: this._appPort
3772
+ });
3773
+ await Promise.all([
3774
+ this._clientServices.open(),
3775
+ this._clientRpc.open()
3776
+ ]);
3777
+ this._ready.wake(void 0);
3778
+ log16("started", {}, {
3779
+ file: "iframe-host-runtime.ts",
3780
+ line: 99,
3781
+ scope: this,
3782
+ callSite: (f, a) => f(...a)
3783
+ });
3784
+ } catch (err) {
3785
+ this._ready.wake(err);
3786
+ log16.catch(err, {}, {
3787
+ file: "iframe-host-runtime.ts",
3788
+ line: 102,
3789
+ scope: this,
3790
+ callSite: (f, a) => f(...a)
3791
+ });
3792
+ }
3793
+ }
3794
+ async stop() {
3795
+ log16("stopping...", {}, {
3796
+ file: "iframe-host-runtime.ts",
3797
+ line: 107,
3798
+ scope: this,
3799
+ callSite: (f, a) => f(...a)
3800
+ });
3801
+ await this._clientRpc.close();
3802
+ await this._clientServices.close();
3803
+ log16("stopped", {}, {
3804
+ file: "iframe-host-runtime.ts",
3805
+ line: 110,
3806
+ scope: this,
3807
+ callSite: (f, a) => f(...a)
3808
+ });
3809
+ }
3810
+ };
3811
+ __decorate4([
3812
+ logInfo2
3813
+ ], IFrameHostRuntime.prototype, "origin", void 0);
3814
+
3815
+ export {
3816
+ SpaceServiceImpl,
3817
+ ProfileServiceImpl,
3818
+ SystemServiceImpl,
3819
+ TracingServiceImpl,
3820
+ subscribeToFeeds,
3821
+ subscribeToFeedBlocks,
3822
+ subscribeToNetworkStatus,
3823
+ subscribeToSignal,
3824
+ subscribeToNetworkTopics,
3825
+ subscribeToSwarmInfo,
3826
+ getNetworkPeers,
3827
+ subscribeToSpaces,
3828
+ DevtoolsHostEvents,
3829
+ DevtoolsServiceImpl,
3830
+ createAuthProvider,
3831
+ TrustedKeySetAuthVerifier,
3832
+ Identity,
3833
+ IdentityManager,
3834
+ InvitationEncoder,
3835
+ AUTHENTICATION_CODE_LENGTH,
3836
+ INVITATION_TIMEOUT,
3837
+ ON_CLOSE_DELAY,
3838
+ InvitationObservableProvider,
3839
+ AuthenticatingInvitationProvider,
3840
+ wrapObservable,
3841
+ AbstractInvitationsHandler,
3842
+ HaloInvitationsHandler,
3843
+ AbstractInvitationsProxy,
3844
+ HaloInvitationsProxy,
3845
+ AbstractInvitationsService,
3846
+ HaloInvitationsServiceImpl,
3847
+ SpaceInvitationsHandler,
3848
+ SpaceInvitationsProxy,
3849
+ SpaceInvitationsServiceImpl,
3850
+ ServiceContext,
3851
+ clientServiceBundle,
3852
+ createStorageObjects,
3853
+ IFrameHostRuntime,
3854
+ iframeServiceBundle,
3855
+ workerServiceBundle,
3856
+ IFrameProxyRuntime,
3857
+ VaultResourceLock,
3858
+ WorkerSession,
3859
+ WorkerRuntime,
3860
+ ServiceRegistry,
3861
+ createDefaultModelFactory,
3862
+ ClientServicesHost,
3863
+ ClientServicesProxy
3864
+ };
3865
+ //# sourceMappingURL=chunk-R2FEBB66.mjs.map