@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.
- package/dist/lib/browser/chunk-R2FEBB66.mjs +3865 -0
- package/dist/lib/browser/chunk-R2FEBB66.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +56 -3066
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +198 -0
- package/dist/lib/browser/packlets/testing/index.mjs.map +7 -0
- package/dist/lib/node/index.cjs +1401 -645
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +3688 -0
- package/dist/lib/node/packlets/testing/index.cjs.map +7 -0
- package/dist/types/src/packlets/deprecated/profile.d.ts +3 -1
- package/dist/types/src/packlets/deprecated/profile.d.ts.map +1 -1
- package/dist/types/src/packlets/deprecated/space.d.ts.map +1 -1
- package/dist/types/src/packlets/deprecated/system.d.ts +15 -9
- package/dist/types/src/packlets/deprecated/system.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts +2 -2
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts +3 -3
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +7 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +1 -0
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts +11 -3
- package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations.d.ts +1 -1
- package/dist/types/src/packlets/invitations/invitations.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +2 -0
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.test.d.ts +2 -0
- package/dist/types/src/packlets/services/service-context.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/service-definitions.d.ts +1 -1
- package/dist/types/src/packlets/services/service-definitions.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +9 -6
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-registry.d.ts +4 -3
- package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +9 -2
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +18 -4
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +50 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.test.d.ts +2 -0
- package/dist/types/src/packlets/spaces/notarization-plugin.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +2 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/credential-utils.d.ts +8 -0
- package/dist/types/src/packlets/testing/credential-utils.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/index.d.ts +2 -0
- package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +3 -0
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/test-builder.d.ts +2 -2
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +28 -0
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/{iframe-runtime.d.ts → iframe-proxy-runtime.d.ts} +4 -4
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/index.d.ts +4 -1
- package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/vault-resource-lock.d.ts +19 -0
- package/dist/types/src/packlets/vault/vault-resource-lock.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +4 -4
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +29 -29
- package/src/packlets/deprecated/profile.ts +20 -2
- package/src/packlets/deprecated/space.ts +41 -37
- package/src/packlets/deprecated/system.ts +26 -13
- package/src/packlets/devtools/devtools.ts +4 -4
- package/src/packlets/devtools/feeds.ts +11 -6
- package/src/packlets/devtools/network.ts +20 -9
- package/src/packlets/devtools/spaces.ts +7 -6
- package/src/packlets/identity/authenticator.ts +11 -6
- package/src/packlets/identity/identity-manager.test.ts +24 -15
- package/src/packlets/identity/identity-manager.ts +22 -8
- package/src/packlets/identity/identity.test.ts +21 -22
- package/src/packlets/identity/identity.ts +10 -5
- package/src/packlets/invitations/halo-invitations-handler.test.ts +4 -45
- package/src/packlets/invitations/halo-invitations-handler.ts +33 -17
- package/src/packlets/invitations/invitations.ts +2 -1
- package/src/packlets/invitations/space-invitations-handler.test.ts +43 -26
- package/src/packlets/invitations/space-invitations-handler.ts +8 -11
- package/src/packlets/services/service-context.test.ts +56 -0
- package/src/packlets/services/service-context.ts +60 -4
- package/src/packlets/services/service-definitions.ts +1 -1
- package/src/packlets/services/service-host.test.ts +74 -5
- package/src/packlets/services/service-host.ts +85 -23
- package/src/packlets/services/service-registry.test.ts +2 -1
- package/src/packlets/services/service-registry.ts +5 -1
- package/src/packlets/spaces/data-space-manager.test.ts +71 -14
- package/src/packlets/spaces/data-space-manager.ts +49 -8
- package/src/packlets/spaces/data-space.ts +113 -14
- package/src/packlets/spaces/notarization-plugin.test.ts +81 -0
- package/src/packlets/spaces/notarization-plugin.ts +211 -0
- package/src/packlets/spaces/spaces-service.ts +9 -1
- package/src/packlets/testing/credential-utils.ts +28 -0
- package/src/packlets/testing/index.ts +2 -0
- package/src/packlets/testing/invitation-utils.ts +44 -0
- package/src/packlets/testing/test-builder.ts +14 -18
- package/src/packlets/vault/iframe-host-runtime.ts +112 -0
- package/src/packlets/vault/{iframe-runtime.ts → iframe-proxy-runtime.ts} +3 -3
- package/src/packlets/vault/index.ts +4 -1
- package/src/packlets/vault/vault-resource-lock.ts +76 -0
- package/src/packlets/vault/worker-runtime.ts +13 -3
- package/src/packlets/vault/worker-session.ts +17 -17
- 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
|