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