@dxos/edge-client 0.6.12 → 0.6.13-main.041e8aa
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-ZWJXA37R.mjs +113 -0
- package/dist/lib/browser/chunk-ZWJXA37R.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +368 -179
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +125 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/lib/node/chunk-ANV2HBEH.cjs +136 -0
- package/dist/lib/node/chunk-ANV2HBEH.cjs.map +7 -0
- package/dist/lib/node/index.cjs +367 -176
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +155 -0
- package/dist/lib/node/testing/index.cjs.map +7 -0
- package/dist/lib/node-esm/chunk-HNVT57AU.mjs +115 -0
- package/dist/lib/node-esm/chunk-HNVT57AU.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +667 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/testing/index.mjs +126 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/types/src/auth.d.ts +22 -0
- package/dist/types/src/auth.d.ts.map +1 -0
- package/dist/types/src/defs.d.ts.map +1 -1
- package/dist/types/src/edge-client.d.ts +24 -13
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/edge-http-client.d.ts +35 -0
- package/dist/types/src/edge-http-client.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +4 -1
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/protocol.d.ts +2 -2
- package/dist/types/src/protocol.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/test-utils.d.ts +21 -0
- package/dist/types/src/testing/test-utils.d.ts.map +1 -0
- package/dist/types/src/utils.d.ts +2 -0
- package/dist/types/src/utils.d.ts.map +1 -0
- package/package.json +29 -14
- package/src/auth.ts +135 -0
- package/src/defs.ts +2 -3
- package/src/edge-client.test.ts +50 -18
- package/src/edge-client.ts +84 -24
- package/src/edge-http-client.ts +151 -0
- package/src/errors.ts +8 -2
- package/src/index.ts +3 -0
- package/src/persistent-lifecycle.test.ts +2 -2
- package/src/protocol.test.ts +1 -2
- package/src/protocol.ts +2 -2
- package/src/testing/index.ts +5 -0
- package/src/testing/test-utils.ts +114 -0
- package/src/utils.ts +10 -0
- package/src/websocket.test.ts +5 -4
- package/dist/types/src/test-utils.d.ts +0 -11
- package/dist/types/src/test-utils.d.ts.map +0 -1
- package/src/test-utils.ts +0 -49
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Protocol,
|
|
3
|
+
getTypename,
|
|
4
|
+
protocol,
|
|
5
|
+
toUint8Array
|
|
6
|
+
} from "./chunk-ZWJXA37R.mjs";
|
|
7
|
+
|
|
1
8
|
// packages/core/mesh/edge-client/src/index.ts
|
|
2
9
|
export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
3
10
|
|
|
@@ -5,123 +12,21 @@ export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
|
5
12
|
import WebSocket from "isomorphic-ws";
|
|
6
13
|
import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from "@dxos/async";
|
|
7
14
|
import { Context, LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
|
|
8
|
-
import {
|
|
15
|
+
import { randomBytes } from "@dxos/crypto";
|
|
9
16
|
import { log as log2 } from "@dxos/log";
|
|
10
|
-
import { buf
|
|
11
|
-
import { MessageSchema as MessageSchema2 } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
12
|
-
|
|
13
|
-
// packages/core/mesh/edge-client/src/defs.ts
|
|
14
|
-
import { AnySchema } from "@bufbuild/protobuf/wkt";
|
|
15
|
-
import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
16
|
-
|
|
17
|
-
// packages/core/mesh/edge-client/src/protocol.ts
|
|
18
|
-
import { invariant } from "@dxos/invariant";
|
|
19
|
-
import { buf, bufWkt } from "@dxos/protocols/buf";
|
|
17
|
+
import { buf } from "@dxos/protocols/buf";
|
|
20
18
|
import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
21
|
-
import {
|
|
22
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/protocol.ts";
|
|
23
|
-
var getTypename = (typeName) => `type.googleapis.com/${typeName}`;
|
|
24
|
-
var Protocol = class {
|
|
25
|
-
constructor(types) {
|
|
26
|
-
this._typeRegistry = buf.createRegistry(...types);
|
|
27
|
-
}
|
|
28
|
-
get typeRegistry() {
|
|
29
|
-
return this._typeRegistry;
|
|
30
|
-
}
|
|
31
|
-
toJson(message) {
|
|
32
|
-
try {
|
|
33
|
-
return buf.toJson(MessageSchema, message, {
|
|
34
|
-
registry: this.typeRegistry
|
|
35
|
-
});
|
|
36
|
-
} catch (err) {
|
|
37
|
-
return {
|
|
38
|
-
type: this.getPayloadType(message)
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Return the payload with the given type.
|
|
44
|
-
*/
|
|
45
|
-
getPayload(message, type) {
|
|
46
|
-
invariant(message.payload, void 0, {
|
|
47
|
-
F: __dxlog_file,
|
|
48
|
-
L: 40,
|
|
49
|
-
S: this,
|
|
50
|
-
A: [
|
|
51
|
-
"message.payload",
|
|
52
|
-
""
|
|
53
|
-
]
|
|
54
|
-
});
|
|
55
|
-
const payloadTypename = this.getPayloadType(message);
|
|
56
|
-
if (type && type.typeName !== payloadTypename) {
|
|
57
|
-
throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);
|
|
58
|
-
}
|
|
59
|
-
invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`, {
|
|
60
|
-
F: __dxlog_file,
|
|
61
|
-
L: 46,
|
|
62
|
-
S: this,
|
|
63
|
-
A: [
|
|
64
|
-
"bufWkt.anyIs(message.payload, type)",
|
|
65
|
-
"`Unexpected payload type: ${payloadTypename}}`"
|
|
66
|
-
]
|
|
67
|
-
});
|
|
68
|
-
const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry);
|
|
69
|
-
invariant(payload, `Empty payload: ${payloadTypename}}`, {
|
|
70
|
-
F: __dxlog_file,
|
|
71
|
-
L: 48,
|
|
72
|
-
S: this,
|
|
73
|
-
A: [
|
|
74
|
-
"payload",
|
|
75
|
-
"`Empty payload: ${payloadTypename}}`"
|
|
76
|
-
]
|
|
77
|
-
});
|
|
78
|
-
return payload;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Get the payload type.
|
|
82
|
-
*/
|
|
83
|
-
getPayloadType(message) {
|
|
84
|
-
if (!message.payload) {
|
|
85
|
-
return void 0;
|
|
86
|
-
}
|
|
87
|
-
const [, type] = message.payload.typeUrl.split("/");
|
|
88
|
-
return type;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Create a packed message.
|
|
92
|
-
*/
|
|
93
|
-
createMessage(type, { source, target, payload, serviceId }) {
|
|
94
|
-
return buf.create(MessageSchema, {
|
|
95
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
96
|
-
source,
|
|
97
|
-
target,
|
|
98
|
-
serviceId,
|
|
99
|
-
payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : void 0
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
var toUint8Array = async (data) => {
|
|
104
|
-
if (data instanceof Buffer) {
|
|
105
|
-
return bufferToArray(data);
|
|
106
|
-
}
|
|
107
|
-
if (data instanceof Blob) {
|
|
108
|
-
return new Uint8Array(await data.arrayBuffer());
|
|
109
|
-
}
|
|
110
|
-
throw new Error(`Unexpected datatype: ${data}`);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
// packages/core/mesh/edge-client/src/defs.ts
|
|
114
|
-
var protocol = new Protocol([
|
|
115
|
-
SwarmRequestSchema,
|
|
116
|
-
SwarmResponseSchema,
|
|
117
|
-
TextMessageSchema,
|
|
118
|
-
AnySchema
|
|
119
|
-
]);
|
|
19
|
+
import { schema } from "@dxos/protocols/proto";
|
|
120
20
|
|
|
121
21
|
// packages/core/mesh/edge-client/src/errors.ts
|
|
122
|
-
var
|
|
22
|
+
var EdgeConnectionClosedError = class extends Error {
|
|
23
|
+
constructor() {
|
|
24
|
+
super("Edge connection closed.");
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var EdgeIdentityChangedError = class extends Error {
|
|
123
28
|
constructor() {
|
|
124
|
-
super("
|
|
29
|
+
super("Edge identity changed.");
|
|
125
30
|
}
|
|
126
31
|
};
|
|
127
32
|
|
|
@@ -136,7 +41,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
136
41
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
137
42
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
138
43
|
}
|
|
139
|
-
var
|
|
44
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
|
|
140
45
|
var INIT_RESTART_DELAY = 100;
|
|
141
46
|
var DEFAULT_MAX_RESTART_DELAY = 5e3;
|
|
142
47
|
var PersistentLifecycle = class extends Resource {
|
|
@@ -157,7 +62,7 @@ var PersistentLifecycle = class extends Resource {
|
|
|
157
62
|
log.warn("Restart failed", {
|
|
158
63
|
err
|
|
159
64
|
}, {
|
|
160
|
-
F:
|
|
65
|
+
F: __dxlog_file,
|
|
161
66
|
L: 64,
|
|
162
67
|
S: this,
|
|
163
68
|
C: (f, a) => f(...a)
|
|
@@ -169,7 +74,7 @@ var PersistentLifecycle = class extends Resource {
|
|
|
169
74
|
log.warn("Start failed", {
|
|
170
75
|
err
|
|
171
76
|
}, {
|
|
172
|
-
F:
|
|
77
|
+
F: __dxlog_file,
|
|
173
78
|
L: 69,
|
|
174
79
|
S: this,
|
|
175
80
|
C: (f, a) => f(...a)
|
|
@@ -186,7 +91,7 @@ var PersistentLifecycle = class extends Resource {
|
|
|
186
91
|
log(`restarting in ${this._restartAfter}ms`, {
|
|
187
92
|
state: this._lifecycleState
|
|
188
93
|
}, {
|
|
189
|
-
F:
|
|
94
|
+
F: __dxlog_file,
|
|
190
95
|
L: 81,
|
|
191
96
|
S: this,
|
|
192
97
|
C: (f, a) => f(...a)
|
|
@@ -218,17 +123,25 @@ _ts_decorate([
|
|
|
218
123
|
synchronized
|
|
219
124
|
], PersistentLifecycle.prototype, "scheduleRestart", null);
|
|
220
125
|
|
|
126
|
+
// packages/core/mesh/edge-client/src/utils.ts
|
|
127
|
+
var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
|
|
128
|
+
const isSecure = baseUrl.startsWith("https") || baseUrl.startsWith("wss");
|
|
129
|
+
const url = new URL(baseUrl);
|
|
130
|
+
url.protocol = protocol2 + (isSecure ? "s" : "");
|
|
131
|
+
return url.toString();
|
|
132
|
+
};
|
|
133
|
+
|
|
221
134
|
// packages/core/mesh/edge-client/src/edge-client.ts
|
|
222
|
-
var
|
|
135
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
223
136
|
var DEFAULT_TIMEOUT = 1e4;
|
|
224
137
|
var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
|
|
225
138
|
var EdgeClient = class extends Resource2 {
|
|
226
|
-
constructor(
|
|
139
|
+
constructor(_identity, _config) {
|
|
227
140
|
super();
|
|
228
|
-
this.
|
|
229
|
-
this._peerKey = _peerKey;
|
|
141
|
+
this._identity = _identity;
|
|
230
142
|
this._config = _config;
|
|
231
143
|
this.reconnect = new Event();
|
|
144
|
+
this.connected = new Event();
|
|
232
145
|
this._persistentLifecycle = new PersistentLifecycle({
|
|
233
146
|
start: async () => this._openWebSocket(),
|
|
234
147
|
stop: async () => this._closeWebSocket(),
|
|
@@ -239,26 +152,39 @@ var EdgeClient = class extends Resource2 {
|
|
|
239
152
|
this._ws = void 0;
|
|
240
153
|
this._keepaliveCtx = void 0;
|
|
241
154
|
this._heartBeatContext = void 0;
|
|
242
|
-
this.
|
|
155
|
+
this._baseUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
|
|
243
156
|
}
|
|
244
157
|
// TODO(burdon): Attach logging.
|
|
245
158
|
get info() {
|
|
246
159
|
return {
|
|
247
160
|
open: this.isOpen,
|
|
248
|
-
identity: this.
|
|
249
|
-
device: this.
|
|
161
|
+
identity: this._identity.identityKey,
|
|
162
|
+
device: this._identity.peerKey
|
|
250
163
|
};
|
|
251
164
|
}
|
|
165
|
+
get isConnected() {
|
|
166
|
+
return Boolean(this._ws) && this._ready.state === TriggerState.RESOLVED;
|
|
167
|
+
}
|
|
252
168
|
get identityKey() {
|
|
253
|
-
return this.
|
|
169
|
+
return this._identity.identityKey;
|
|
254
170
|
}
|
|
255
171
|
get peerKey() {
|
|
256
|
-
return this.
|
|
172
|
+
return this._identity.peerKey;
|
|
257
173
|
}
|
|
258
|
-
setIdentity(
|
|
259
|
-
this.
|
|
260
|
-
|
|
261
|
-
|
|
174
|
+
setIdentity(identity) {
|
|
175
|
+
if (identity.identityKey !== this._identity.identityKey || identity.peerKey !== this._identity.peerKey) {
|
|
176
|
+
log2("Edge identity changed", {
|
|
177
|
+
identity,
|
|
178
|
+
oldIdentity: this._identity
|
|
179
|
+
}, {
|
|
180
|
+
F: __dxlog_file2,
|
|
181
|
+
L: 110,
|
|
182
|
+
S: this,
|
|
183
|
+
C: (f, a) => f(...a)
|
|
184
|
+
});
|
|
185
|
+
this._identity = identity;
|
|
186
|
+
this._persistentLifecycle.scheduleRestart();
|
|
187
|
+
}
|
|
262
188
|
}
|
|
263
189
|
addListener(listener) {
|
|
264
190
|
this._listeners.add(listener);
|
|
@@ -271,8 +197,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
271
197
|
log2("opening...", {
|
|
272
198
|
info: this.info
|
|
273
199
|
}, {
|
|
274
|
-
F:
|
|
275
|
-
L:
|
|
200
|
+
F: __dxlog_file2,
|
|
201
|
+
L: 125,
|
|
276
202
|
S: this,
|
|
277
203
|
C: (f, a) => f(...a)
|
|
278
204
|
});
|
|
@@ -280,8 +206,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
280
206
|
log2.warn("Error while opening connection", {
|
|
281
207
|
err
|
|
282
208
|
}, {
|
|
283
|
-
F:
|
|
284
|
-
L:
|
|
209
|
+
F: __dxlog_file2,
|
|
210
|
+
L: 127,
|
|
285
211
|
S: this,
|
|
286
212
|
C: (f, a) => f(...a)
|
|
287
213
|
});
|
|
@@ -292,31 +218,54 @@ var EdgeClient = class extends Resource2 {
|
|
|
292
218
|
*/
|
|
293
219
|
async _close() {
|
|
294
220
|
log2("closing...", {
|
|
295
|
-
peerKey: this.
|
|
221
|
+
peerKey: this._identity.peerKey
|
|
296
222
|
}, {
|
|
297
|
-
F:
|
|
298
|
-
L:
|
|
223
|
+
F: __dxlog_file2,
|
|
224
|
+
L: 135,
|
|
299
225
|
S: this,
|
|
300
226
|
C: (f, a) => f(...a)
|
|
301
227
|
});
|
|
302
228
|
await this._persistentLifecycle.close();
|
|
303
229
|
}
|
|
304
230
|
async _openWebSocket() {
|
|
305
|
-
|
|
306
|
-
this.
|
|
231
|
+
let protocolHeader;
|
|
232
|
+
if (!this._config.disableAuth) {
|
|
233
|
+
const challenge = randomBytes(32);
|
|
234
|
+
const credential = await this._identity.presentCredentials({
|
|
235
|
+
challenge
|
|
236
|
+
});
|
|
237
|
+
protocolHeader = encodePresentationIntoAuthHeader(credential);
|
|
238
|
+
}
|
|
239
|
+
if (this._ctx.disposed) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._baseUrl);
|
|
243
|
+
log2("Opening websocket", {
|
|
244
|
+
url: url.toString(),
|
|
245
|
+
protocolHeader
|
|
246
|
+
}, {
|
|
247
|
+
F: __dxlog_file2,
|
|
248
|
+
L: 154,
|
|
249
|
+
S: this,
|
|
250
|
+
C: (f, a) => f(...a)
|
|
251
|
+
});
|
|
252
|
+
this._ws = new WebSocket(url, protocolHeader ? [
|
|
253
|
+
protocolHeader
|
|
254
|
+
] : []);
|
|
307
255
|
this._ws.onopen = () => {
|
|
308
256
|
log2("opened", this.info, {
|
|
309
|
-
F:
|
|
310
|
-
L:
|
|
257
|
+
F: __dxlog_file2,
|
|
258
|
+
L: 158,
|
|
311
259
|
S: this,
|
|
312
260
|
C: (f, a) => f(...a)
|
|
313
261
|
});
|
|
314
262
|
this._ready.wake();
|
|
263
|
+
this.connected.emit();
|
|
315
264
|
};
|
|
316
265
|
this._ws.onclose = () => {
|
|
317
266
|
log2("closed", this.info, {
|
|
318
|
-
F:
|
|
319
|
-
L:
|
|
267
|
+
F: __dxlog_file2,
|
|
268
|
+
L: 163,
|
|
320
269
|
S: this,
|
|
321
270
|
C: (f, a) => f(...a)
|
|
322
271
|
});
|
|
@@ -327,8 +276,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
327
276
|
error: event.error,
|
|
328
277
|
info: event.message
|
|
329
278
|
}, {
|
|
330
|
-
F:
|
|
331
|
-
L:
|
|
279
|
+
F: __dxlog_file2,
|
|
280
|
+
L: 167,
|
|
332
281
|
S: this,
|
|
333
282
|
C: (f, a) => f(...a)
|
|
334
283
|
});
|
|
@@ -340,13 +289,13 @@ var EdgeClient = class extends Resource2 {
|
|
|
340
289
|
return;
|
|
341
290
|
}
|
|
342
291
|
const data = await toUint8Array(event.data);
|
|
343
|
-
const message =
|
|
292
|
+
const message = buf.fromBinary(MessageSchema, data);
|
|
344
293
|
log2("received", {
|
|
345
|
-
peerKey: this.
|
|
294
|
+
peerKey: this._identity.peerKey,
|
|
346
295
|
payload: protocol.getPayloadType(message)
|
|
347
296
|
}, {
|
|
348
|
-
F:
|
|
349
|
-
L:
|
|
297
|
+
F: __dxlog_file2,
|
|
298
|
+
L: 180,
|
|
350
299
|
S: this,
|
|
351
300
|
C: (f, a) => f(...a)
|
|
352
301
|
});
|
|
@@ -359,8 +308,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
359
308
|
err,
|
|
360
309
|
payload: protocol.getPayloadType(message)
|
|
361
310
|
}, {
|
|
362
|
-
F:
|
|
363
|
-
L:
|
|
311
|
+
F: __dxlog_file2,
|
|
312
|
+
L: 186,
|
|
364
313
|
S: this,
|
|
365
314
|
C: (f, a) => f(...a)
|
|
366
315
|
});
|
|
@@ -371,9 +320,18 @@ var EdgeClient = class extends Resource2 {
|
|
|
371
320
|
await this._ready.wait({
|
|
372
321
|
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
373
322
|
});
|
|
323
|
+
log2("Websocket is ready", {
|
|
324
|
+
identity: this._identity.identityKey,
|
|
325
|
+
peer: this._identity.peerKey
|
|
326
|
+
}, {
|
|
327
|
+
F: __dxlog_file2,
|
|
328
|
+
L: 194,
|
|
329
|
+
S: this,
|
|
330
|
+
C: (f, a) => f(...a)
|
|
331
|
+
});
|
|
374
332
|
this._keepaliveCtx = new Context(void 0, {
|
|
375
|
-
F:
|
|
376
|
-
L:
|
|
333
|
+
F: __dxlog_file2,
|
|
334
|
+
L: 197
|
|
377
335
|
});
|
|
378
336
|
scheduleTaskInterval(this._keepaliveCtx, async () => {
|
|
379
337
|
this._ws?.send("__ping__");
|
|
@@ -386,7 +344,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
386
344
|
return;
|
|
387
345
|
}
|
|
388
346
|
try {
|
|
389
|
-
this._ready.throw(new
|
|
347
|
+
this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());
|
|
390
348
|
this._ready.reset();
|
|
391
349
|
void this._keepaliveCtx?.dispose();
|
|
392
350
|
this._keepaliveCtx = void 0;
|
|
@@ -407,8 +365,8 @@ var EdgeClient = class extends Resource2 {
|
|
|
407
365
|
log2.warn("Error closing websocket", {
|
|
408
366
|
err
|
|
409
367
|
}, {
|
|
410
|
-
F:
|
|
411
|
-
L:
|
|
368
|
+
F: __dxlog_file2,
|
|
369
|
+
L: 233,
|
|
412
370
|
S: this,
|
|
413
371
|
C: (f, a) => f(...a)
|
|
414
372
|
});
|
|
@@ -420,38 +378,32 @@ var EdgeClient = class extends Resource2 {
|
|
|
420
378
|
*/
|
|
421
379
|
async send(message) {
|
|
422
380
|
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
381
|
+
log2("waiting for websocket to become ready", void 0, {
|
|
382
|
+
F: __dxlog_file2,
|
|
383
|
+
L: 243,
|
|
384
|
+
S: this,
|
|
385
|
+
C: (f, a) => f(...a)
|
|
386
|
+
});
|
|
423
387
|
await this._ready.wait({
|
|
424
388
|
timeout: this._config.timeout ?? DEFAULT_TIMEOUT
|
|
425
389
|
});
|
|
426
390
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
""
|
|
434
|
-
]
|
|
435
|
-
});
|
|
436
|
-
invariant2(!message.source || message.source.peerKey === this._peerKey, void 0, {
|
|
437
|
-
F: __dxlog_file3,
|
|
438
|
-
L: 203,
|
|
439
|
-
S: this,
|
|
440
|
-
A: [
|
|
441
|
-
"!message.source || message.source.peerKey === this._peerKey",
|
|
442
|
-
""
|
|
443
|
-
]
|
|
444
|
-
});
|
|
391
|
+
if (!this._ws) {
|
|
392
|
+
throw new EdgeConnectionClosedError();
|
|
393
|
+
}
|
|
394
|
+
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
395
|
+
throw new EdgeIdentityChangedError();
|
|
396
|
+
}
|
|
445
397
|
log2("sending...", {
|
|
446
|
-
peerKey: this.
|
|
398
|
+
peerKey: this._identity.peerKey,
|
|
447
399
|
payload: protocol.getPayloadType(message)
|
|
448
400
|
}, {
|
|
449
|
-
F:
|
|
450
|
-
L:
|
|
401
|
+
F: __dxlog_file2,
|
|
402
|
+
L: 256,
|
|
451
403
|
S: this,
|
|
452
404
|
C: (f, a) => f(...a)
|
|
453
405
|
});
|
|
454
|
-
this._ws.send(
|
|
406
|
+
this._ws.send(buf.toBinary(MessageSchema, message));
|
|
455
407
|
}
|
|
456
408
|
_onHeartbeat() {
|
|
457
409
|
if (this._lifecycleState !== LifecycleState2.OPEN) {
|
|
@@ -459,17 +411,254 @@ var EdgeClient = class extends Resource2 {
|
|
|
459
411
|
}
|
|
460
412
|
void this._heartBeatContext?.dispose();
|
|
461
413
|
this._heartBeatContext = new Context(void 0, {
|
|
462
|
-
F:
|
|
463
|
-
L:
|
|
414
|
+
F: __dxlog_file2,
|
|
415
|
+
L: 265
|
|
464
416
|
});
|
|
465
417
|
scheduleTask(this._heartBeatContext, () => {
|
|
466
418
|
this._persistentLifecycle.scheduleRestart();
|
|
467
419
|
}, 2 * SIGNAL_KEEPALIVE_INTERVAL);
|
|
468
420
|
}
|
|
469
421
|
};
|
|
422
|
+
var encodePresentationIntoAuthHeader = (presentation) => {
|
|
423
|
+
const encoded = schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
|
|
424
|
+
const encodedToken = Buffer.from(encoded).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
|
|
425
|
+
return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// packages/core/mesh/edge-client/src/auth.ts
|
|
429
|
+
import { createCredential, signPresentation } from "@dxos/credentials";
|
|
430
|
+
import { Keyring } from "@dxos/keyring";
|
|
431
|
+
import { PublicKey } from "@dxos/keys";
|
|
432
|
+
var createDeviceEdgeIdentity = async (signer, key) => {
|
|
433
|
+
return {
|
|
434
|
+
identityKey: key.toHex(),
|
|
435
|
+
peerKey: key.toHex(),
|
|
436
|
+
presentCredentials: async ({ challenge }) => {
|
|
437
|
+
return signPresentation({
|
|
438
|
+
presentation: {
|
|
439
|
+
credentials: [
|
|
440
|
+
// Verifier requires at least one credential in the presentation to establish the subject.
|
|
441
|
+
await createCredential({
|
|
442
|
+
assertion: {
|
|
443
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
444
|
+
},
|
|
445
|
+
issuer: key,
|
|
446
|
+
subject: key,
|
|
447
|
+
signer
|
|
448
|
+
})
|
|
449
|
+
]
|
|
450
|
+
},
|
|
451
|
+
signer,
|
|
452
|
+
signerKey: key,
|
|
453
|
+
nonce: challenge
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
};
|
|
458
|
+
var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
|
|
459
|
+
const credentialsToSign = credentials.length > 0 ? credentials : [
|
|
460
|
+
await createCredential({
|
|
461
|
+
assertion: {
|
|
462
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
463
|
+
},
|
|
464
|
+
issuer: identityKey,
|
|
465
|
+
subject: identityKey,
|
|
466
|
+
signer,
|
|
467
|
+
chain,
|
|
468
|
+
signingKey: peerKey
|
|
469
|
+
})
|
|
470
|
+
];
|
|
471
|
+
return {
|
|
472
|
+
identityKey: identityKey.toHex(),
|
|
473
|
+
peerKey: peerKey.toHex(),
|
|
474
|
+
presentCredentials: async ({ challenge }) => {
|
|
475
|
+
return signPresentation({
|
|
476
|
+
presentation: {
|
|
477
|
+
credentials: credentialsToSign
|
|
478
|
+
},
|
|
479
|
+
signer,
|
|
480
|
+
nonce: challenge,
|
|
481
|
+
signerKey: peerKey,
|
|
482
|
+
chain
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
var createEphemeralEdgeIdentity = async () => {
|
|
488
|
+
const keyring = new Keyring();
|
|
489
|
+
const key = await keyring.createKey();
|
|
490
|
+
return createDeviceEdgeIdentity(keyring, key);
|
|
491
|
+
};
|
|
492
|
+
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
493
|
+
const deviceAdmission = await createCredential({
|
|
494
|
+
assertion: {
|
|
495
|
+
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
496
|
+
deviceKey,
|
|
497
|
+
identityKey
|
|
498
|
+
},
|
|
499
|
+
issuer: identityKey,
|
|
500
|
+
subject: deviceKey,
|
|
501
|
+
signer
|
|
502
|
+
});
|
|
503
|
+
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
504
|
+
credential: deviceAdmission
|
|
505
|
+
}, [
|
|
506
|
+
await createCredential({
|
|
507
|
+
assertion: {
|
|
508
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
509
|
+
},
|
|
510
|
+
issuer: identityKey,
|
|
511
|
+
subject: identityKey,
|
|
512
|
+
signer
|
|
513
|
+
})
|
|
514
|
+
]);
|
|
515
|
+
};
|
|
516
|
+
var createStubEdgeIdentity = () => {
|
|
517
|
+
const identityKey = PublicKey.random();
|
|
518
|
+
const deviceKey = PublicKey.random();
|
|
519
|
+
return {
|
|
520
|
+
identityKey: identityKey.toHex(),
|
|
521
|
+
peerKey: deviceKey.toHex(),
|
|
522
|
+
presentCredentials: async () => {
|
|
523
|
+
throw new Error("Stub identity does not support authentication.");
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// packages/core/mesh/edge-client/src/edge-http-client.ts
|
|
529
|
+
import { sleep as sleep2 } from "@dxos/async";
|
|
530
|
+
import { Context as Context2 } from "@dxos/context";
|
|
531
|
+
import { log as log3 } from "@dxos/log";
|
|
532
|
+
import { EdgeCallFailedError, EdgeAuthChallengeError } from "@dxos/protocols";
|
|
533
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
|
|
534
|
+
var DEFAULT_RETRY_TIMEOUT = 1500;
|
|
535
|
+
var DEFAULT_RETRY_JITTER = 500;
|
|
536
|
+
var DEFAULT_MAX_RETRIES_COUNT = 3;
|
|
537
|
+
var EdgeHttpClient = class {
|
|
538
|
+
constructor(baseUrl) {
|
|
539
|
+
this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
|
|
540
|
+
log3("created", {
|
|
541
|
+
url: this._baseUrl
|
|
542
|
+
}, {
|
|
543
|
+
F: __dxlog_file3,
|
|
544
|
+
L: 30,
|
|
545
|
+
S: this,
|
|
546
|
+
C: (f, a) => f(...a)
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
getCredentialsForNotarization(spaceId, args) {
|
|
550
|
+
return this._call(`/spaces/${spaceId}/notarization`, {
|
|
551
|
+
...args,
|
|
552
|
+
method: "GET"
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
async notarizeCredentials(spaceId, body, args) {
|
|
556
|
+
await this._call(`/spaces/${spaceId}/notarization`, {
|
|
557
|
+
...args,
|
|
558
|
+
body,
|
|
559
|
+
method: "POST"
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
async joinSpaceByInvitation(spaceId, body, args) {
|
|
563
|
+
return this._call(`/spaces/${spaceId}/join`, {
|
|
564
|
+
...args,
|
|
565
|
+
body,
|
|
566
|
+
method: "POST"
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
async _call(path, args) {
|
|
570
|
+
const requestContext = args.context ?? new Context2(void 0, {
|
|
571
|
+
F: __dxlog_file3,
|
|
572
|
+
L: 54
|
|
573
|
+
});
|
|
574
|
+
const shouldRetry = createRetryHandler(args);
|
|
575
|
+
const request = createRequest(args);
|
|
576
|
+
const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
|
|
577
|
+
log3.info("call", {
|
|
578
|
+
method: args.method,
|
|
579
|
+
path
|
|
580
|
+
}, {
|
|
581
|
+
F: __dxlog_file3,
|
|
582
|
+
L: 59,
|
|
583
|
+
S: this,
|
|
584
|
+
C: (f, a) => f(...a)
|
|
585
|
+
});
|
|
586
|
+
while (true) {
|
|
587
|
+
let processingError;
|
|
588
|
+
let retryAfterHeaderValue = Number.NaN;
|
|
589
|
+
try {
|
|
590
|
+
const response = await fetch(url, request);
|
|
591
|
+
retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
|
|
592
|
+
if (response.ok) {
|
|
593
|
+
const body = await response.json();
|
|
594
|
+
if (body.success) {
|
|
595
|
+
return body.data;
|
|
596
|
+
}
|
|
597
|
+
if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
|
|
598
|
+
processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
|
|
599
|
+
} else {
|
|
600
|
+
processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
601
|
+
}
|
|
602
|
+
} else {
|
|
603
|
+
processingError = EdgeCallFailedError.fromHttpFailure(response);
|
|
604
|
+
}
|
|
605
|
+
} catch (error) {
|
|
606
|
+
processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
|
|
607
|
+
}
|
|
608
|
+
if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
|
|
609
|
+
log3.info("retrying edge request", {
|
|
610
|
+
path,
|
|
611
|
+
processingError
|
|
612
|
+
}, {
|
|
613
|
+
F: __dxlog_file3,
|
|
614
|
+
L: 88,
|
|
615
|
+
S: this,
|
|
616
|
+
C: (f, a) => f(...a)
|
|
617
|
+
});
|
|
618
|
+
} else {
|
|
619
|
+
throw processingError;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
var createRequest = (args) => {
|
|
625
|
+
return {
|
|
626
|
+
method: args.method,
|
|
627
|
+
body: args.body && JSON.stringify(args.body)
|
|
628
|
+
};
|
|
629
|
+
};
|
|
630
|
+
var createRetryHandler = (args) => {
|
|
631
|
+
if (!args.retry || args.retry.count < 1) {
|
|
632
|
+
return async () => false;
|
|
633
|
+
}
|
|
634
|
+
let retries = 0;
|
|
635
|
+
const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
|
|
636
|
+
const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
|
|
637
|
+
const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;
|
|
638
|
+
return async (ctx, retryAfter) => {
|
|
639
|
+
if (++retries > maxRetries || ctx.disposed) {
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
if (retryAfter) {
|
|
643
|
+
await sleep2(retryAfter);
|
|
644
|
+
} else {
|
|
645
|
+
const timeout = baseTimeout + Math.random() * jitter;
|
|
646
|
+
await sleep2(timeout);
|
|
647
|
+
}
|
|
648
|
+
return true;
|
|
649
|
+
};
|
|
650
|
+
};
|
|
470
651
|
export {
|
|
471
652
|
EdgeClient,
|
|
653
|
+
EdgeConnectionClosedError,
|
|
654
|
+
EdgeHttpClient,
|
|
655
|
+
EdgeIdentityChangedError,
|
|
472
656
|
Protocol,
|
|
657
|
+
createChainEdgeIdentity,
|
|
658
|
+
createDeviceEdgeIdentity,
|
|
659
|
+
createEphemeralEdgeIdentity,
|
|
660
|
+
createStubEdgeIdentity,
|
|
661
|
+
createTestHaloEdgeIdentity,
|
|
473
662
|
getTypename,
|
|
474
663
|
protocol,
|
|
475
664
|
toUint8Array
|