@dxos/edge-client 0.6.12-main.78ddbdf → 0.6.12-main.89e9959
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/index.mjs +291 -29
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +293 -29
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +291 -29
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/auth.d.ts +22 -0
- package/dist/types/src/auth.d.ts.map +1 -0
- package/dist/types/src/edge-client.d.ts +19 -11
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/edge-http-client.d.ts +34 -0
- package/dist/types/src/edge-http-client.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/package.json +14 -11
- package/src/auth.ts +135 -0
- package/src/edge-client.test.ts +40 -8
- package/src/edge-client.ts +56 -16
- package/src/edge-http-client.ts +153 -0
- package/src/index.ts +2 -0
|
@@ -13,9 +13,11 @@ export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
|
13
13
|
import WebSocket from "isomorphic-ws";
|
|
14
14
|
import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from "@dxos/async";
|
|
15
15
|
import { Context, LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
|
|
16
|
+
import { randomBytes } from "@dxos/crypto";
|
|
16
17
|
import { log as log2 } from "@dxos/log";
|
|
17
18
|
import { buf } from "@dxos/protocols/buf";
|
|
18
19
|
import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
|
|
20
|
+
import { schema } from "@dxos/protocols/proto";
|
|
19
21
|
|
|
20
22
|
// packages/core/mesh/edge-client/src/errors.ts
|
|
21
23
|
var EdgeConnectionClosedError = class extends Error {
|
|
@@ -126,11 +128,11 @@ _ts_decorate([
|
|
|
126
128
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
127
129
|
var DEFAULT_TIMEOUT = 1e4;
|
|
128
130
|
var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
|
|
131
|
+
var DISABLE_AUTH = true;
|
|
129
132
|
var EdgeClient = class extends Resource2 {
|
|
130
|
-
constructor(
|
|
133
|
+
constructor(_identity, _config) {
|
|
131
134
|
super();
|
|
132
|
-
this.
|
|
133
|
-
this._peerKey = _peerKey;
|
|
135
|
+
this._identity = _identity;
|
|
134
136
|
this._config = _config;
|
|
135
137
|
this.reconnect = new Event();
|
|
136
138
|
this.connected = new Event();
|
|
@@ -149,19 +151,21 @@ var EdgeClient = class extends Resource2 {
|
|
|
149
151
|
get info() {
|
|
150
152
|
return {
|
|
151
153
|
open: this.isOpen,
|
|
152
|
-
identity: this.
|
|
153
|
-
device: this.
|
|
154
|
+
identity: this._identity.identityKey,
|
|
155
|
+
device: this._identity.peerKey
|
|
154
156
|
};
|
|
155
157
|
}
|
|
158
|
+
get isConnected() {
|
|
159
|
+
return Boolean(this._ws) && this._ready.state === TriggerState.RESOLVED;
|
|
160
|
+
}
|
|
156
161
|
get identityKey() {
|
|
157
|
-
return this.
|
|
162
|
+
return this._identity.identityKey;
|
|
158
163
|
}
|
|
159
164
|
get peerKey() {
|
|
160
|
-
return this.
|
|
165
|
+
return this._identity.peerKey;
|
|
161
166
|
}
|
|
162
|
-
setIdentity(
|
|
163
|
-
this.
|
|
164
|
-
this._identityKey = identityKey;
|
|
167
|
+
setIdentity(identity) {
|
|
168
|
+
this._identity = identity;
|
|
165
169
|
this._persistentLifecycle.scheduleRestart();
|
|
166
170
|
}
|
|
167
171
|
addListener(listener) {
|
|
@@ -176,7 +180,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
176
180
|
info: this.info
|
|
177
181
|
}, {
|
|
178
182
|
F: __dxlog_file2,
|
|
179
|
-
L:
|
|
183
|
+
L: 119,
|
|
180
184
|
S: this,
|
|
181
185
|
C: (f, a) => f(...a)
|
|
182
186
|
});
|
|
@@ -185,7 +189,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
185
189
|
err
|
|
186
190
|
}, {
|
|
187
191
|
F: __dxlog_file2,
|
|
188
|
-
L:
|
|
192
|
+
L: 121,
|
|
189
193
|
S: this,
|
|
190
194
|
C: (f, a) => f(...a)
|
|
191
195
|
});
|
|
@@ -196,22 +200,41 @@ var EdgeClient = class extends Resource2 {
|
|
|
196
200
|
*/
|
|
197
201
|
async _close() {
|
|
198
202
|
log2("closing...", {
|
|
199
|
-
peerKey: this.
|
|
203
|
+
peerKey: this._identity.peerKey
|
|
200
204
|
}, {
|
|
201
205
|
F: __dxlog_file2,
|
|
202
|
-
L:
|
|
206
|
+
L: 129,
|
|
203
207
|
S: this,
|
|
204
208
|
C: (f, a) => f(...a)
|
|
205
209
|
});
|
|
206
210
|
await this._persistentLifecycle.close();
|
|
207
211
|
}
|
|
208
212
|
async _openWebSocket() {
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
let protocolHeader;
|
|
214
|
+
if (!DISABLE_AUTH) {
|
|
215
|
+
const challenge = randomBytes(32);
|
|
216
|
+
const credential = await this._identity.presentCredentials({
|
|
217
|
+
challenge
|
|
218
|
+
});
|
|
219
|
+
protocolHeader = encodePresentationIntoAuthHeader(credential);
|
|
220
|
+
}
|
|
221
|
+
const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._config.socketEndpoint);
|
|
222
|
+
log2("Opening websocket", {
|
|
223
|
+
url: url.toString(),
|
|
224
|
+
protocolHeader
|
|
225
|
+
}, {
|
|
226
|
+
F: __dxlog_file2,
|
|
227
|
+
L: 144,
|
|
228
|
+
S: this,
|
|
229
|
+
C: (f, a) => f(...a)
|
|
230
|
+
});
|
|
231
|
+
this._ws = new WebSocket(url, protocolHeader ? [
|
|
232
|
+
protocolHeader
|
|
233
|
+
] : []);
|
|
211
234
|
this._ws.onopen = () => {
|
|
212
235
|
log2("opened", this.info, {
|
|
213
236
|
F: __dxlog_file2,
|
|
214
|
-
L:
|
|
237
|
+
L: 148,
|
|
215
238
|
S: this,
|
|
216
239
|
C: (f, a) => f(...a)
|
|
217
240
|
});
|
|
@@ -221,7 +244,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
221
244
|
this._ws.onclose = () => {
|
|
222
245
|
log2("closed", this.info, {
|
|
223
246
|
F: __dxlog_file2,
|
|
224
|
-
L:
|
|
247
|
+
L: 153,
|
|
225
248
|
S: this,
|
|
226
249
|
C: (f, a) => f(...a)
|
|
227
250
|
});
|
|
@@ -233,7 +256,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
233
256
|
info: event.message
|
|
234
257
|
}, {
|
|
235
258
|
F: __dxlog_file2,
|
|
236
|
-
L:
|
|
259
|
+
L: 157,
|
|
237
260
|
S: this,
|
|
238
261
|
C: (f, a) => f(...a)
|
|
239
262
|
});
|
|
@@ -247,11 +270,11 @@ var EdgeClient = class extends Resource2 {
|
|
|
247
270
|
const data = await toUint8Array(event.data);
|
|
248
271
|
const message = buf.fromBinary(MessageSchema, data);
|
|
249
272
|
log2("received", {
|
|
250
|
-
peerKey: this.
|
|
273
|
+
peerKey: this._identity.peerKey,
|
|
251
274
|
payload: protocol.getPayloadType(message)
|
|
252
275
|
}, {
|
|
253
276
|
F: __dxlog_file2,
|
|
254
|
-
L:
|
|
277
|
+
L: 170,
|
|
255
278
|
S: this,
|
|
256
279
|
C: (f, a) => f(...a)
|
|
257
280
|
});
|
|
@@ -265,7 +288,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
265
288
|
payload: protocol.getPayloadType(message)
|
|
266
289
|
}, {
|
|
267
290
|
F: __dxlog_file2,
|
|
268
|
-
L:
|
|
291
|
+
L: 176,
|
|
269
292
|
S: this,
|
|
270
293
|
C: (f, a) => f(...a)
|
|
271
294
|
});
|
|
@@ -278,7 +301,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
278
301
|
});
|
|
279
302
|
this._keepaliveCtx = new Context(void 0, {
|
|
280
303
|
F: __dxlog_file2,
|
|
281
|
-
L:
|
|
304
|
+
L: 186
|
|
282
305
|
});
|
|
283
306
|
scheduleTaskInterval(this._keepaliveCtx, async () => {
|
|
284
307
|
this._ws?.send("__ping__");
|
|
@@ -313,7 +336,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
313
336
|
err
|
|
314
337
|
}, {
|
|
315
338
|
F: __dxlog_file2,
|
|
316
|
-
L:
|
|
339
|
+
L: 222,
|
|
317
340
|
S: this,
|
|
318
341
|
C: (f, a) => f(...a)
|
|
319
342
|
});
|
|
@@ -327,7 +350,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
327
350
|
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
328
351
|
log2("waiting for websocket to become ready", void 0, {
|
|
329
352
|
F: __dxlog_file2,
|
|
330
|
-
L:
|
|
353
|
+
L: 232,
|
|
331
354
|
S: this,
|
|
332
355
|
C: (f, a) => f(...a)
|
|
333
356
|
});
|
|
@@ -338,15 +361,15 @@ var EdgeClient = class extends Resource2 {
|
|
|
338
361
|
if (!this._ws) {
|
|
339
362
|
throw new EdgeConnectionClosedError();
|
|
340
363
|
}
|
|
341
|
-
if (message.source && (message.source.peerKey !== this.
|
|
364
|
+
if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
|
|
342
365
|
throw new EdgeIdentityChangedError();
|
|
343
366
|
}
|
|
344
367
|
log2("sending...", {
|
|
345
|
-
peerKey: this.
|
|
368
|
+
peerKey: this._identity.peerKey,
|
|
346
369
|
payload: protocol.getPayloadType(message)
|
|
347
370
|
}, {
|
|
348
371
|
F: __dxlog_file2,
|
|
349
|
-
L:
|
|
372
|
+
L: 245,
|
|
350
373
|
S: this,
|
|
351
374
|
C: (f, a) => f(...a)
|
|
352
375
|
});
|
|
@@ -359,18 +382,257 @@ var EdgeClient = class extends Resource2 {
|
|
|
359
382
|
void this._heartBeatContext?.dispose();
|
|
360
383
|
this._heartBeatContext = new Context(void 0, {
|
|
361
384
|
F: __dxlog_file2,
|
|
362
|
-
L:
|
|
385
|
+
L: 254
|
|
363
386
|
});
|
|
364
387
|
scheduleTask(this._heartBeatContext, () => {
|
|
365
388
|
this._persistentLifecycle.scheduleRestart();
|
|
366
389
|
}, 2 * SIGNAL_KEEPALIVE_INTERVAL);
|
|
367
390
|
}
|
|
368
391
|
};
|
|
392
|
+
var encodePresentationIntoAuthHeader = (presentation) => {
|
|
393
|
+
const encoded = schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
|
|
394
|
+
const encodedToken = Buffer.from(encoded).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
|
|
395
|
+
return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// packages/core/mesh/edge-client/src/auth.ts
|
|
399
|
+
import { createCredential, signPresentation } from "@dxos/credentials";
|
|
400
|
+
import { Keyring } from "@dxos/keyring";
|
|
401
|
+
import { PublicKey } from "@dxos/keys";
|
|
402
|
+
var createDeviceEdgeIdentity = async (signer, key) => {
|
|
403
|
+
return {
|
|
404
|
+
identityKey: key.toHex(),
|
|
405
|
+
peerKey: key.toHex(),
|
|
406
|
+
presentCredentials: async ({ challenge }) => {
|
|
407
|
+
return signPresentation({
|
|
408
|
+
presentation: {
|
|
409
|
+
credentials: [
|
|
410
|
+
// Verifier requires at least one credential in the presentation to establish the subject.
|
|
411
|
+
await createCredential({
|
|
412
|
+
assertion: {
|
|
413
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
414
|
+
},
|
|
415
|
+
issuer: key,
|
|
416
|
+
subject: key,
|
|
417
|
+
signer
|
|
418
|
+
})
|
|
419
|
+
]
|
|
420
|
+
},
|
|
421
|
+
signer,
|
|
422
|
+
signerKey: key,
|
|
423
|
+
nonce: challenge
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
};
|
|
428
|
+
var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
|
|
429
|
+
const credentialsToSign = credentials.length > 0 ? credentials : [
|
|
430
|
+
await createCredential({
|
|
431
|
+
assertion: {
|
|
432
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
433
|
+
},
|
|
434
|
+
issuer: identityKey,
|
|
435
|
+
subject: identityKey,
|
|
436
|
+
signer,
|
|
437
|
+
chain,
|
|
438
|
+
signingKey: peerKey
|
|
439
|
+
})
|
|
440
|
+
];
|
|
441
|
+
return {
|
|
442
|
+
identityKey: identityKey.toHex(),
|
|
443
|
+
peerKey: peerKey.toHex(),
|
|
444
|
+
presentCredentials: async ({ challenge }) => {
|
|
445
|
+
return signPresentation({
|
|
446
|
+
presentation: {
|
|
447
|
+
credentials: credentialsToSign
|
|
448
|
+
},
|
|
449
|
+
signer,
|
|
450
|
+
nonce: challenge,
|
|
451
|
+
signerKey: peerKey,
|
|
452
|
+
chain
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
};
|
|
457
|
+
var createEphemeralEdgeIdentity = async () => {
|
|
458
|
+
const keyring = new Keyring();
|
|
459
|
+
const key = await keyring.createKey();
|
|
460
|
+
return createDeviceEdgeIdentity(keyring, key);
|
|
461
|
+
};
|
|
462
|
+
var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
|
|
463
|
+
const deviceAdmission = await createCredential({
|
|
464
|
+
assertion: {
|
|
465
|
+
"@type": "dxos.halo.credentials.AuthorizedDevice",
|
|
466
|
+
deviceKey,
|
|
467
|
+
identityKey
|
|
468
|
+
},
|
|
469
|
+
issuer: identityKey,
|
|
470
|
+
subject: deviceKey,
|
|
471
|
+
signer
|
|
472
|
+
});
|
|
473
|
+
return createChainEdgeIdentity(signer, identityKey, deviceKey, {
|
|
474
|
+
credential: deviceAdmission
|
|
475
|
+
}, [
|
|
476
|
+
await createCredential({
|
|
477
|
+
assertion: {
|
|
478
|
+
"@type": "dxos.halo.credentials.Auth"
|
|
479
|
+
},
|
|
480
|
+
issuer: identityKey,
|
|
481
|
+
subject: identityKey,
|
|
482
|
+
signer
|
|
483
|
+
})
|
|
484
|
+
]);
|
|
485
|
+
};
|
|
486
|
+
var createStubEdgeIdentity = () => {
|
|
487
|
+
const identityKey = PublicKey.random();
|
|
488
|
+
const deviceKey = PublicKey.random();
|
|
489
|
+
return {
|
|
490
|
+
identityKey: identityKey.toHex(),
|
|
491
|
+
peerKey: deviceKey.toHex(),
|
|
492
|
+
presentCredentials: async () => {
|
|
493
|
+
throw new Error("Stub identity does not support authentication.");
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
// packages/core/mesh/edge-client/src/edge-http-client.ts
|
|
499
|
+
import { sleep as sleep2 } from "@dxos/async";
|
|
500
|
+
import { Context as Context2 } from "@dxos/context";
|
|
501
|
+
import { log as log3 } from "@dxos/log";
|
|
502
|
+
import { EdgeCallFailedError } from "@dxos/protocols";
|
|
503
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
|
|
504
|
+
var DEFAULT_RETRY_TIMEOUT = 1500;
|
|
505
|
+
var DEFAULT_RETRY_JITTER = 500;
|
|
506
|
+
var DEFAULT_MAX_RETRIES_COUNT = 3;
|
|
507
|
+
var EdgeHttpClient = class {
|
|
508
|
+
constructor(baseUrl) {
|
|
509
|
+
const url = new URL(baseUrl);
|
|
510
|
+
url.protocol = "https";
|
|
511
|
+
this._baseUrl = url.toString();
|
|
512
|
+
log3("created", {
|
|
513
|
+
url: this._baseUrl
|
|
514
|
+
}, {
|
|
515
|
+
F: __dxlog_file3,
|
|
516
|
+
L: 27,
|
|
517
|
+
S: this,
|
|
518
|
+
C: (f, a) => f(...a)
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
getCredentialsForNotarization(spaceId, args) {
|
|
522
|
+
return this._call(`/spaces/${spaceId}/notarization`, {
|
|
523
|
+
...args,
|
|
524
|
+
method: "GET"
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
async notarizeCredentials(spaceId, body, args) {
|
|
528
|
+
await this._call(`/spaces/${spaceId}/notarization`, {
|
|
529
|
+
...args,
|
|
530
|
+
body,
|
|
531
|
+
method: "POST"
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
async _call(path, args) {
|
|
535
|
+
const requestContext = args.context ?? new Context2(void 0, {
|
|
536
|
+
F: __dxlog_file3,
|
|
537
|
+
L: 43
|
|
538
|
+
});
|
|
539
|
+
const shouldRetry = createRetryHandler(args);
|
|
540
|
+
const request = createRequest(args);
|
|
541
|
+
const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
|
|
542
|
+
log3.info("call", {
|
|
543
|
+
method: args.method,
|
|
544
|
+
path
|
|
545
|
+
}, {
|
|
546
|
+
F: __dxlog_file3,
|
|
547
|
+
L: 48,
|
|
548
|
+
S: this,
|
|
549
|
+
C: (f, a) => f(...a)
|
|
550
|
+
});
|
|
551
|
+
while (true) {
|
|
552
|
+
let processingError;
|
|
553
|
+
let retryAfterHeaderValue = Number.NaN;
|
|
554
|
+
try {
|
|
555
|
+
const response = await fetch(url, request);
|
|
556
|
+
retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
|
|
557
|
+
if (response.ok) {
|
|
558
|
+
const body = await response.json();
|
|
559
|
+
if (body.success) {
|
|
560
|
+
return body.data;
|
|
561
|
+
}
|
|
562
|
+
const isNonRetryable = body.errorData != null;
|
|
563
|
+
if (isNonRetryable) {
|
|
564
|
+
throw new EdgeCallFailedError(body.reason, body.errorData);
|
|
565
|
+
}
|
|
566
|
+
processingError = new EdgeCallFailedError(body.reason);
|
|
567
|
+
} else {
|
|
568
|
+
processingError = EdgeCallFailedError.fromFailureResponse(response);
|
|
569
|
+
if (!isRetryable(response.status)) {
|
|
570
|
+
throw processingError;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
} catch (error) {
|
|
574
|
+
processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
|
|
575
|
+
}
|
|
576
|
+
if (await shouldRetry(requestContext, retryAfterHeaderValue)) {
|
|
577
|
+
log3.info("retrying edge request", {
|
|
578
|
+
path,
|
|
579
|
+
processingError
|
|
580
|
+
}, {
|
|
581
|
+
F: __dxlog_file3,
|
|
582
|
+
L: 81,
|
|
583
|
+
S: this,
|
|
584
|
+
C: (f, a) => f(...a)
|
|
585
|
+
});
|
|
586
|
+
} else {
|
|
587
|
+
throw processingError;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
var createRequest = (args) => {
|
|
593
|
+
return {
|
|
594
|
+
method: args.method,
|
|
595
|
+
body: args.body && JSON.stringify(args.body)
|
|
596
|
+
};
|
|
597
|
+
};
|
|
598
|
+
var isRetryable = (status) => {
|
|
599
|
+
if (status === 501) {
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
return !(status >= 400 && status < 500);
|
|
603
|
+
};
|
|
604
|
+
var createRetryHandler = (args) => {
|
|
605
|
+
if (!args.retry || args.retry.count < 1) {
|
|
606
|
+
return async () => false;
|
|
607
|
+
}
|
|
608
|
+
let retries = 0;
|
|
609
|
+
const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
|
|
610
|
+
const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
|
|
611
|
+
const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;
|
|
612
|
+
return async (ctx, retryAfter) => {
|
|
613
|
+
if (++retries > maxRetries || ctx.disposed) {
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
if (retryAfter) {
|
|
617
|
+
await sleep2(retryAfter);
|
|
618
|
+
} else {
|
|
619
|
+
const timeout = baseTimeout + Math.random() * jitter;
|
|
620
|
+
await sleep2(timeout);
|
|
621
|
+
}
|
|
622
|
+
return true;
|
|
623
|
+
};
|
|
624
|
+
};
|
|
369
625
|
export {
|
|
370
626
|
EdgeClient,
|
|
371
627
|
EdgeConnectionClosedError,
|
|
628
|
+
EdgeHttpClient,
|
|
372
629
|
EdgeIdentityChangedError,
|
|
373
630
|
Protocol,
|
|
631
|
+
createChainEdgeIdentity,
|
|
632
|
+
createDeviceEdgeIdentity,
|
|
633
|
+
createEphemeralEdgeIdentity,
|
|
634
|
+
createStubEdgeIdentity,
|
|
635
|
+
createTestHaloEdgeIdentity,
|
|
374
636
|
getTypename,
|
|
375
637
|
protocol,
|
|
376
638
|
toUint8Array
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/edge-client.ts", "../../../src/errors.ts", "../../../src/persistent-lifecycle.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './edge-client';\nexport * from './defs';\nexport * from './protocol';\nexport * from './errors';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from '@dxos/async';\nimport { Context, LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { protocol } from './defs';\nimport { EdgeConnectionClosedError, EdgeIdentityChangedError } from './errors';\nimport { PersistentLifecycle } from './persistent-lifecycle';\nimport { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 10_000;\nconst SIGNAL_KEEPALIVE_INTERVAL = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n connected: Event;\n reconnect: Event;\n\n get info(): any;\n get identityKey(): string;\n get peerKey(): string;\n get isOpen(): boolean;\n setIdentity(params: { peerKey: string; identityKey: string }): void;\n addListener(listener: MessageListener): () => void;\n send(message: Message): Promise<void>;\n}\n\nexport type MessengerConfig = {\n socketEndpoint: string;\n timeout?: number;\n protocol?: Protocol;\n};\n\n/**\n * Messenger client.\n */\nexport class EdgeClient extends Resource implements EdgeConnection {\n public readonly reconnect = new Event();\n public readonly connected = new Event();\n private readonly _persistentLifecycle = new PersistentLifecycle({\n start: async () => this._openWebSocket(),\n stop: async () => this._closeWebSocket(),\n onRestart: async () => this.reconnect.emit(),\n });\n\n private readonly _listeners = new Set<MessageListener>();\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n private _keepaliveCtx?: Context = undefined;\n private _heartBeatContext?: Context = undefined;\n\n constructor(\n private _identityKey: string,\n private _peerKey: string,\n private readonly _config: MessengerConfig,\n ) {\n super();\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._peerKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get peerKey() {\n return this._peerKey;\n }\n\n setIdentity({ peerKey, identityKey }: { peerKey: string; identityKey: string }) {\n this._peerKey = peerKey;\n this._identityKey = identityKey;\n this._persistentLifecycle.scheduleRestart();\n }\n\n public addListener(listener: MessageListener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /**\n * Open connection to messaging service.\n */\n protected override async _open() {\n log('opening...', { info: this.info });\n this._persistentLifecycle.open().catch((err) => {\n log.warn('Error while opening connection', { err });\n });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { peerKey: this._peerKey });\n await this._persistentLifecycle.close();\n }\n\n private async _openWebSocket() {\n const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n\n this._ws.onopen = () => {\n log('opened', this.info);\n this._ready.wake();\n this.connected.emit();\n };\n this._ws.onclose = () => {\n log('closed', this.info);\n this._persistentLifecycle.scheduleRestart();\n };\n this._ws.onerror = (event) => {\n log.warn('EdgeClient socket error', { error: event.error, info: event.message });\n this._persistentLifecycle.scheduleRestart();\n };\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n this._ws.onmessage = async (event) => {\n if (event.data === '__pong__') {\n this._onHeartbeat();\n return;\n }\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n if (message) {\n for (const listener of this._listeners) {\n try {\n await listener(message);\n } catch (err) {\n log.error('processing', { err, payload: protocol.getPayloadType(message) });\n }\n }\n }\n };\n\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n this._keepaliveCtx = new Context();\n scheduleTaskInterval(\n this._keepaliveCtx,\n async () => {\n // TODO(mykola): use RFC6455 ping/pong once implemented in the browser?\n // Cloudflare's worker responds to this `without interrupting hibernation`. https://developers.cloudflare.com/durable-objects/api/websockets/#setwebsocketautoresponse\n this._ws?.send('__ping__');\n },\n SIGNAL_KEEPALIVE_INTERVAL,\n );\n this._ws.send('__ping__');\n this._onHeartbeat();\n }\n\n private async _closeWebSocket() {\n if (!this._ws) {\n return;\n }\n try {\n this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());\n this._ready.reset();\n void this._keepaliveCtx?.dispose();\n this._keepaliveCtx = undefined;\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = undefined;\n\n // NOTE: Remove event handlers to avoid scheduling restart.\n this._ws.onopen = () => {};\n this._ws.onclose = () => {};\n this._ws.onerror = () => {};\n this._ws.close();\n this._ws = undefined;\n } catch (err) {\n if (err instanceof Error && err.message.includes('WebSocket is closed before the connection is established.')) {\n return;\n }\n log.warn('Error closing websocket', { err });\n }\n }\n\n /**\n * Send message.\n * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.\n */\n public async send(message: Message): Promise<void> {\n if (this._ready.state !== TriggerState.RESOLVED) {\n log('waiting for websocket to become ready');\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n if (!this._ws) {\n throw new EdgeConnectionClosedError();\n }\n if (\n message.source &&\n (message.source.peerKey !== this._peerKey || message.source.identityKey !== this.identityKey)\n ) {\n throw new EdgeIdentityChangedError();\n }\n\n log('sending...', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n\n private _onHeartbeat() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = new Context();\n scheduleTask(\n this._heartBeatContext,\n () => {\n this._persistentLifecycle.scheduleRestart();\n },\n 2 * SIGNAL_KEEPALIVE_INTERVAL,\n );\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nexport class EdgeConnectionClosedError extends Error {\n constructor() {\n super('Edge connection closed.');\n }\n}\n\nexport class EdgeIdentityChangedError extends Error {\n constructor() {\n super('Edge identity changed.');\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { DeferredTask, sleep, synchronized } from '@dxos/async';\nimport { cancelWithContext, LifecycleState, Resource } from '@dxos/context';\nimport { warnAfterTimeout } from '@dxos/debug';\nimport { log } from '@dxos/log';\n\nconst INIT_RESTART_DELAY = 100;\nconst DEFAULT_MAX_RESTART_DELAY = 5000;\n\nexport type PersistentLifecycleParams = {\n /**\n * Create connection.\n * If promise resolves successfully, connection is considered established.\n */\n start: () => Promise<void>;\n\n /**\n * Reset connection to initial state.\n */\n stop: () => Promise<void>;\n\n /**\n * Called after successful start.\n */\n onRestart?: () => Promise<void>;\n\n /**\n * Maximum delay between restartion attempts.\n * Default: 5000ms\n */\n maxRestartDelay?: number;\n};\n\n/**\n * Handles restarts (e.g. persists connection).\n * Restarts are scheduled with exponential backoff.\n */\nexport class PersistentLifecycle extends Resource {\n private readonly _start: () => Promise<void>;\n private readonly _stop: () => Promise<void>;\n private readonly _onRestart?: () => Promise<void>;\n private readonly _maxRestartDelay: number;\n\n private _restartTask?: DeferredTask = undefined;\n private _restartAfter = 0;\n\n constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }: PersistentLifecycleParams) {\n super();\n this._start = start;\n this._stop = stop;\n this._onRestart = onRestart;\n this._maxRestartDelay = maxRestartDelay;\n }\n\n @synchronized\n protected override async _open() {\n this._restartTask = new DeferredTask(this._ctx, async () => {\n try {\n await this._restart();\n } catch (err) {\n log.warn('Restart failed', { err });\n this._restartTask?.schedule();\n }\n });\n await this._start().catch((err) => {\n log.warn('Start failed', { err });\n this._restartTask?.schedule();\n });\n }\n\n protected override async _close() {\n await this._restartTask?.join();\n await this._stop();\n this._restartTask = undefined;\n }\n\n private async _restart() {\n log(`restarting in ${this._restartAfter}ms`, { state: this._lifecycleState });\n await this._stop();\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n await cancelWithContext(this._ctx!, sleep(this._restartAfter));\n this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);\n\n // May fail if the connection is not established.\n await warnAfterTimeout(5_000, 'Connection establishment takes too long', () => this._start());\n\n this._restartAfter = 0;\n await this._onRestart?.();\n }\n\n /**\n * Scheduling restart should be done from outside.\n */\n @synchronized\n scheduleRestart() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n this._restartTask!.schedule();\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;AAIA,cAAc;;;ACAd,OAAOA,eAAe;AAEtB,SAASC,SAASC,OAAOC,sBAAsBC,cAAcC,oBAAoB;AACjF,SAASC,SAASC,kBAAAA,iBAAgBC,YAAAA,iBAAgC;AAClE,SAASC,OAAAA,YAAW;AACpB,SAASC,WAAW;AACpB,SAAuBC,qBAAqB;;;
|
|
6
|
-
"names": ["WebSocket", "Trigger", "Event", "scheduleTaskInterval", "scheduleTask", "TriggerState", "Context", "LifecycleState", "Resource", "log", "buf", "MessageSchema", "EdgeConnectionClosedError", "Error", "constructor", "EdgeIdentityChangedError", "DeferredTask", "sleep", "synchronized", "cancelWithContext", "LifecycleState", "Resource", "warnAfterTimeout", "log", "INIT_RESTART_DELAY", "DEFAULT_MAX_RESTART_DELAY", "PersistentLifecycle", "constructor", "start", "stop", "onRestart", "maxRestartDelay", "_restartTask", "undefined", "_restartAfter", "_start", "_stop", "_onRestart", "_maxRestartDelay", "_open", "_ctx", "_restart", "err", "warn", "schedule", "catch", "_close", "join", "state", "_lifecycleState", "OPEN", "Math", "min", "max", "scheduleRestart", "DEFAULT_TIMEOUT", "SIGNAL_KEEPALIVE_INTERVAL", "
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/edge-client.ts", "../../../src/errors.ts", "../../../src/persistent-lifecycle.ts", "../../../src/auth.ts", "../../../src/edge-http-client.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './edge-client';\nexport * from './defs';\nexport * from './protocol';\nexport * from './errors';\nexport * from './auth';\nexport * from './edge-http-client';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from '@dxos/async';\nimport { Context, LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { randomBytes } from '@dxos/crypto';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { schema } from '@dxos/protocols/proto';\nimport { type Presentation } from '@dxos/protocols/proto/dxos/halo/credentials';\n\nimport { protocol } from './defs';\nimport { EdgeConnectionClosedError, EdgeIdentityChangedError } from './errors';\nimport { PersistentLifecycle } from './persistent-lifecycle';\nimport { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 10_000;\nconst SIGNAL_KEEPALIVE_INTERVAL = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n connected: Event;\n reconnect: Event;\n\n get info(): any;\n get identityKey(): string;\n get peerKey(): string;\n get isOpen(): boolean;\n get isConnected(): boolean;\n setIdentity(identity: EdgeIdentity): void;\n addListener(listener: MessageListener): () => void;\n send(message: Message): Promise<void>;\n}\n\nexport type MessengerConfig = {\n socketEndpoint: string;\n timeout?: number;\n protocol?: Protocol;\n};\n\nexport interface EdgeIdentity {\n peerKey: string;\n identityKey: string;\n /**\n * Returns credential presentation issued by the identity key.\n * Presentation must have the provided challenge.\n * Presentation may include ServiceAccess credentials.\n */\n presentCredentials({ challenge }: { challenge: Uint8Array }): Promise<Presentation>;\n}\n\nconst DISABLE_AUTH = true;\n\n/**\n * Messenger client.\n */\nexport class EdgeClient extends Resource implements EdgeConnection {\n public readonly reconnect = new Event();\n public readonly connected = new Event();\n private readonly _persistentLifecycle = new PersistentLifecycle({\n start: async () => this._openWebSocket(),\n stop: async () => this._closeWebSocket(),\n onRestart: async () => this.reconnect.emit(),\n });\n\n private readonly _listeners = new Set<MessageListener>();\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n private _keepaliveCtx?: Context = undefined;\n private _heartBeatContext?: Context = undefined;\n\n constructor(\n private _identity: EdgeIdentity,\n private readonly _config: MessengerConfig,\n ) {\n super();\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identity.identityKey,\n device: this._identity.peerKey,\n };\n }\n\n get isConnected() {\n return Boolean(this._ws) && this._ready.state === TriggerState.RESOLVED;\n }\n\n get identityKey() {\n return this._identity.identityKey;\n }\n\n get peerKey() {\n return this._identity.peerKey;\n }\n\n setIdentity(identity: EdgeIdentity) {\n this._identity = identity;\n this._persistentLifecycle.scheduleRestart();\n }\n\n public addListener(listener: MessageListener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /**\n * Open connection to messaging service.\n */\n protected override async _open() {\n log('opening...', { info: this.info });\n this._persistentLifecycle.open().catch((err) => {\n log.warn('Error while opening connection', { err });\n });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { peerKey: this._identity.peerKey });\n await this._persistentLifecycle.close();\n }\n\n private async _openWebSocket() {\n let protocolHeader: string | undefined;\n\n if (!DISABLE_AUTH) {\n // TODO(dmaretskyi): Get challenge from the WWW-Authenticate header returned by the endpoint.\n const challenge = randomBytes(32);\n const credential = await this._identity.presentCredentials({ challenge });\n protocolHeader = encodePresentationIntoAuthHeader(credential);\n }\n\n const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._config.socketEndpoint);\n log('Opening websocket', { url: url.toString(), protocolHeader });\n this._ws = new WebSocket(url, protocolHeader ? [protocolHeader] : []);\n\n this._ws.onopen = () => {\n log('opened', this.info);\n this._ready.wake();\n this.connected.emit();\n };\n this._ws.onclose = () => {\n log('closed', this.info);\n this._persistentLifecycle.scheduleRestart();\n };\n this._ws.onerror = (event) => {\n log.warn('EdgeClient socket error', { error: event.error, info: event.message });\n this._persistentLifecycle.scheduleRestart();\n };\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n this._ws.onmessage = async (event) => {\n if (event.data === '__pong__') {\n this._onHeartbeat();\n return;\n }\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { peerKey: this._identity.peerKey, payload: protocol.getPayloadType(message) });\n if (message) {\n for (const listener of this._listeners) {\n try {\n await listener(message);\n } catch (err) {\n log.error('processing', { err, payload: protocol.getPayloadType(message) });\n }\n }\n }\n };\n\n // TODO(dmaretskyi): Potential race condition here since web socket errors don't resolve this trigger.\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n\n // TODO(dmaretskyi): Potential leak: context re-assigned without disposing the previous one.\n this._keepaliveCtx = new Context();\n scheduleTaskInterval(\n this._keepaliveCtx,\n async () => {\n // TODO(mykola): use RFC6455 ping/pong once implemented in the browser?\n // Cloudflare's worker responds to this `without interrupting hibernation`. https://developers.cloudflare.com/durable-objects/api/websockets/#setwebsocketautoresponse\n this._ws?.send('__ping__');\n },\n SIGNAL_KEEPALIVE_INTERVAL,\n );\n this._ws.send('__ping__');\n this._onHeartbeat();\n }\n\n private async _closeWebSocket() {\n if (!this._ws) {\n return;\n }\n try {\n this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());\n this._ready.reset();\n void this._keepaliveCtx?.dispose();\n this._keepaliveCtx = undefined;\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = undefined;\n\n // NOTE: Remove event handlers to avoid scheduling restart.\n this._ws.onopen = () => {};\n this._ws.onclose = () => {};\n this._ws.onerror = () => {};\n this._ws.close();\n this._ws = undefined;\n } catch (err) {\n if (err instanceof Error && err.message.includes('WebSocket is closed before the connection is established.')) {\n return;\n }\n log.warn('Error closing websocket', { err });\n }\n }\n\n /**\n * Send message.\n * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.\n */\n public async send(message: Message): Promise<void> {\n if (this._ready.state !== TriggerState.RESOLVED) {\n log('waiting for websocket to become ready');\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n if (!this._ws) {\n throw new EdgeConnectionClosedError();\n }\n if (\n message.source &&\n (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)\n ) {\n throw new EdgeIdentityChangedError();\n }\n\n log('sending...', { peerKey: this._identity.peerKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n\n private _onHeartbeat() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = new Context();\n scheduleTask(\n this._heartBeatContext,\n () => {\n this._persistentLifecycle.scheduleRestart();\n },\n 2 * SIGNAL_KEEPALIVE_INTERVAL,\n );\n }\n}\n\nconst encodePresentationIntoAuthHeader = (presentation: Presentation): string => {\n const encoded = schema.getCodecForType('dxos.halo.credentials.Presentation').encode(presentation);\n // = and / characters are not allowed in the WebSocket subprotocol header.\n const encodedToken = Buffer.from(encoded).toString('base64').replace(/=*$/, '').replaceAll('/', '|');\n\n return `base64url.bearer.authorization.dxos.org.${encodedToken}`;\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nexport class EdgeConnectionClosedError extends Error {\n constructor() {\n super('Edge connection closed.');\n }\n}\n\nexport class EdgeIdentityChangedError extends Error {\n constructor() {\n super('Edge identity changed.');\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { DeferredTask, sleep, synchronized } from '@dxos/async';\nimport { cancelWithContext, LifecycleState, Resource } from '@dxos/context';\nimport { warnAfterTimeout } from '@dxos/debug';\nimport { log } from '@dxos/log';\n\nconst INIT_RESTART_DELAY = 100;\nconst DEFAULT_MAX_RESTART_DELAY = 5000;\n\nexport type PersistentLifecycleParams = {\n /**\n * Create connection.\n * If promise resolves successfully, connection is considered established.\n */\n start: () => Promise<void>;\n\n /**\n * Reset connection to initial state.\n */\n stop: () => Promise<void>;\n\n /**\n * Called after successful start.\n */\n onRestart?: () => Promise<void>;\n\n /**\n * Maximum delay between restartion attempts.\n * Default: 5000ms\n */\n maxRestartDelay?: number;\n};\n\n/**\n * Handles restarts (e.g. persists connection).\n * Restarts are scheduled with exponential backoff.\n */\nexport class PersistentLifecycle extends Resource {\n private readonly _start: () => Promise<void>;\n private readonly _stop: () => Promise<void>;\n private readonly _onRestart?: () => Promise<void>;\n private readonly _maxRestartDelay: number;\n\n private _restartTask?: DeferredTask = undefined;\n private _restartAfter = 0;\n\n constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }: PersistentLifecycleParams) {\n super();\n this._start = start;\n this._stop = stop;\n this._onRestart = onRestart;\n this._maxRestartDelay = maxRestartDelay;\n }\n\n @synchronized\n protected override async _open() {\n this._restartTask = new DeferredTask(this._ctx, async () => {\n try {\n await this._restart();\n } catch (err) {\n log.warn('Restart failed', { err });\n this._restartTask?.schedule();\n }\n });\n await this._start().catch((err) => {\n log.warn('Start failed', { err });\n this._restartTask?.schedule();\n });\n }\n\n protected override async _close() {\n await this._restartTask?.join();\n await this._stop();\n this._restartTask = undefined;\n }\n\n private async _restart() {\n log(`restarting in ${this._restartAfter}ms`, { state: this._lifecycleState });\n await this._stop();\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n await cancelWithContext(this._ctx!, sleep(this._restartAfter));\n this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);\n\n // May fail if the connection is not established.\n await warnAfterTimeout(5_000, 'Connection establishment takes too long', () => this._start());\n\n this._restartAfter = 0;\n await this._onRestart?.();\n }\n\n /**\n * Scheduling restart should be done from outside.\n */\n @synchronized\n scheduleRestart() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n this._restartTask!.schedule();\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { createCredential, signPresentation } from '@dxos/credentials';\nimport { type Signer } from '@dxos/crypto';\nimport { Keyring } from '@dxos/keyring';\nimport { PublicKey } from '@dxos/keys';\nimport { type Chain, type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';\n\nimport type { EdgeIdentity } from './edge-client';\n\n/**\n * Edge identity backed by a device key without a credential chain.\n */\nexport const createDeviceEdgeIdentity = async (signer: Signer, key: PublicKey): Promise<EdgeIdentity> => {\n return {\n identityKey: key.toHex(),\n peerKey: key.toHex(),\n presentCredentials: async ({ challenge }) => {\n return signPresentation({\n presentation: {\n credentials: [\n // Verifier requires at least one credential in the presentation to establish the subject.\n await createCredential({\n assertion: {\n '@type': 'dxos.halo.credentials.Auth',\n },\n issuer: key,\n subject: key,\n signer,\n }),\n ],\n },\n signer,\n signerKey: key,\n nonce: challenge,\n });\n },\n };\n};\n\n/**\n * Edge identity backed by a chain of credentials.\n */\nexport const createChainEdgeIdentity = async (\n signer: Signer,\n identityKey: PublicKey,\n peerKey: PublicKey,\n chain: Chain,\n credentials: Credential[],\n): Promise<EdgeIdentity> => {\n const credentialsToSign =\n credentials.length > 0\n ? credentials\n : [\n await createCredential({\n assertion: {\n '@type': 'dxos.halo.credentials.Auth',\n },\n issuer: identityKey,\n subject: identityKey,\n signer,\n chain,\n signingKey: peerKey,\n }),\n ];\n\n return {\n identityKey: identityKey.toHex(),\n peerKey: peerKey.toHex(),\n presentCredentials: async ({ challenge }) => {\n return signPresentation({\n presentation: {\n credentials: credentialsToSign,\n },\n signer,\n nonce: challenge,\n signerKey: peerKey,\n chain,\n });\n },\n };\n};\n\n/**\n * Edge identity backed by a random ephemeral key without HALO.\n */\nexport const createEphemeralEdgeIdentity = async (): Promise<EdgeIdentity> => {\n const keyring = new Keyring();\n const key = await keyring.createKey();\n return createDeviceEdgeIdentity(keyring, key);\n};\n\n/**\n * Creates a HALO chain of credentials to act as an edge identity.\n */\nexport const createTestHaloEdgeIdentity = async (\n signer: Signer,\n identityKey: PublicKey,\n deviceKey: PublicKey,\n): Promise<EdgeIdentity> => {\n const deviceAdmission = await createCredential({\n assertion: {\n '@type': 'dxos.halo.credentials.AuthorizedDevice',\n deviceKey,\n identityKey,\n },\n issuer: identityKey,\n subject: deviceKey,\n signer,\n });\n return createChainEdgeIdentity(signer, identityKey, deviceKey, { credential: deviceAdmission }, [\n await createCredential({\n assertion: {\n '@type': 'dxos.halo.credentials.Auth',\n },\n issuer: identityKey,\n subject: identityKey,\n signer,\n }),\n ]);\n};\n\nexport const createStubEdgeIdentity = (): EdgeIdentity => {\n const identityKey = PublicKey.random();\n const deviceKey = PublicKey.random();\n return {\n identityKey: identityKey.toHex(),\n peerKey: deviceKey.toHex(),\n presentCredentials: async () => {\n throw new Error('Stub identity does not support authentication.');\n },\n };\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { sleep } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { type SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport {\n EdgeCallFailedError,\n type EdgeHttpResponse,\n type GetNotarizationResponseBody,\n type PostNotarizationRequestBody,\n} from '@dxos/protocols';\n\nconst DEFAULT_RETRY_TIMEOUT = 1500;\nconst DEFAULT_RETRY_JITTER = 500;\nconst DEFAULT_MAX_RETRIES_COUNT = 3;\n\nexport class EdgeHttpClient {\n private readonly _baseUrl: string;\n\n constructor(baseUrl: string) {\n const url = new URL(baseUrl);\n url.protocol = 'https';\n this._baseUrl = url.toString();\n log('created', { url: this._baseUrl });\n }\n\n public getCredentialsForNotarization(spaceId: SpaceId, args?: EdgeHttpGetArgs): Promise<GetNotarizationResponseBody> {\n return this._call(`/spaces/${spaceId}/notarization`, { ...args, method: 'GET' });\n }\n\n public async notarizeCredentials(\n spaceId: SpaceId,\n body: PostNotarizationRequestBody,\n args?: EdgeHttpGetArgs,\n ): Promise<void> {\n await this._call(`/spaces/${spaceId}/notarization`, { ...args, body, method: 'POST' });\n }\n\n private async _call<T>(path: string, args: EdgeHttpCallArgs): Promise<T> {\n const requestContext = args.context ?? new Context();\n const shouldRetry = createRetryHandler(args);\n const request = createRequest(args);\n const url = `${this._baseUrl}${path.startsWith('/') ? path.slice(1) : path}`;\n\n log.info('call', { method: args.method, path });\n\n while (true) {\n let processingError: EdgeCallFailedError;\n let retryAfterHeaderValue: number = Number.NaN;\n try {\n const response = await fetch(url, request);\n\n retryAfterHeaderValue = Number(response.headers.get('Retry-After'));\n\n if (response.ok) {\n const body = (await response.json()) as EdgeHttpResponse<T>;\n if (body.success) {\n return body.data;\n }\n\n const isNonRetryable = body.errorData != null;\n if (isNonRetryable) {\n throw new EdgeCallFailedError(body.reason, body.errorData);\n }\n\n processingError = new EdgeCallFailedError(body.reason);\n } else {\n processingError = EdgeCallFailedError.fromFailureResponse(response);\n if (!isRetryable(response.status)) {\n throw processingError;\n }\n }\n } catch (error: any) {\n processingError = EdgeCallFailedError.fromProcessingFailureCause(error);\n }\n\n if (await shouldRetry(requestContext, retryAfterHeaderValue)) {\n log.info('retrying edge request', { path, processingError });\n } else {\n throw processingError;\n }\n }\n }\n}\n\nconst createRequest = (args: EdgeHttpCallArgs): RequestInit => {\n return {\n method: args.method,\n body: args.body && JSON.stringify(args.body),\n };\n};\n\nconst isRetryable = (status: number) => {\n if (status === 501) {\n // Not Implemented\n return false;\n }\n // TODO: handle 401 Not Authorized\n return !(status >= 400 && status < 500);\n};\n\nconst createRetryHandler = (args: EdgeHttpCallArgs) => {\n if (!args.retry || args.retry.count < 1) {\n return async () => false;\n }\n let retries = 0;\n const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;\n const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;\n const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;\n return async (ctx: Context, retryAfter: number) => {\n if (++retries > maxRetries || ctx.disposed) {\n return false;\n }\n\n if (retryAfter) {\n await sleep(retryAfter);\n } else {\n const timeout = baseTimeout + Math.random() * jitter;\n await sleep(timeout);\n }\n\n return true;\n };\n};\n\nexport type RetryConfig = {\n /**\n * A number of call retries, not counting the initial request.\n */\n count: number;\n /**\n * Delay before retries in ms.\n */\n timeout?: number;\n /**\n * A random amount of time before retrying to help prevent large bursts of requests.\n */\n jitter?: number;\n};\n\nexport type EdgeHttpGetArgs = { context?: Context; retry?: RetryConfig };\n\nexport type EdgeHttpPostArgs = { context?: Context; body?: any; retry?: RetryConfig };\n\ntype EdgeHttpCallArgs = {\n method: string;\n body?: any;\n context?: Context;\n retry?: RetryConfig;\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["WebSocket", "Trigger", "Event", "scheduleTaskInterval", "scheduleTask", "TriggerState", "Context", "LifecycleState", "Resource", "randomBytes", "log", "buf", "MessageSchema", "schema", "EdgeConnectionClosedError", "Error", "constructor", "EdgeIdentityChangedError", "DeferredTask", "sleep", "synchronized", "cancelWithContext", "LifecycleState", "Resource", "warnAfterTimeout", "log", "INIT_RESTART_DELAY", "DEFAULT_MAX_RESTART_DELAY", "PersistentLifecycle", "constructor", "start", "stop", "onRestart", "maxRestartDelay", "_restartTask", "undefined", "_restartAfter", "_start", "_stop", "_onRestart", "_maxRestartDelay", "_open", "_ctx", "_restart", "err", "warn", "schedule", "catch", "_close", "join", "state", "_lifecycleState", "OPEN", "Math", "min", "max", "scheduleRestart", "DEFAULT_TIMEOUT", "SIGNAL_KEEPALIVE_INTERVAL", "DISABLE_AUTH", "EdgeClient", "Resource", "constructor", "_identity", "_config", "reconnect", "Event", "connected", "_persistentLifecycle", "PersistentLifecycle", "start", "_openWebSocket", "stop", "_closeWebSocket", "onRestart", "emit", "_listeners", "Set", "_ready", "Trigger", "_ws", "undefined", "_keepaliveCtx", "_heartBeatContext", "info", "open", "isOpen", "identity", "identityKey", "device", "peerKey", "isConnected", "Boolean", "state", "TriggerState", "RESOLVED", "setIdentity", "scheduleRestart", "addListener", "listener", "add", "delete", "_open", "log", "catch", "err", "warn", "_close", "close", "protocolHeader", "challenge", "randomBytes", "credential", "presentCredentials", "encodePresentationIntoAuthHeader", "url", "URL", "socketEndpoint", "toString", "WebSocket", "onopen", "wake", "onclose", "onerror", "event", "error", "message", "onmessage", "data", "_onHeartbeat", "toUint8Array", "buf", "fromBinary", "MessageSchema", "payload", "protocol", "getPayloadType", "wait", "timeout", "Context", "scheduleTaskInterval", "send", "throw", "EdgeIdentityChangedError", "EdgeConnectionClosedError", "reset", "dispose", "Error", "includes", "source", "toBinary", "_lifecycleState", "LifecycleState", "OPEN", "scheduleTask", "presentation", "encoded", "schema", "getCodecForType", "encode", "encodedToken", "Buffer", "from", "replace", "replaceAll", "createCredential", "signPresentation", "Keyring", "PublicKey", "createDeviceEdgeIdentity", "signer", "key", "identityKey", "toHex", "peerKey", "presentCredentials", "challenge", "signPresentation", "presentation", "credentials", "createCredential", "assertion", "issuer", "subject", "signerKey", "nonce", "createChainEdgeIdentity", "chain", "credentialsToSign", "length", "signingKey", "createEphemeralEdgeIdentity", "keyring", "Keyring", "createKey", "createTestHaloEdgeIdentity", "deviceKey", "deviceAdmission", "credential", "createStubEdgeIdentity", "PublicKey", "random", "Error", "sleep", "Context", "log", "EdgeCallFailedError", "DEFAULT_RETRY_TIMEOUT", "DEFAULT_RETRY_JITTER", "DEFAULT_MAX_RETRIES_COUNT", "EdgeHttpClient", "constructor", "baseUrl", "url", "URL", "protocol", "_baseUrl", "toString", "getCredentialsForNotarization", "spaceId", "args", "_call", "method", "notarizeCredentials", "body", "path", "requestContext", "context", "shouldRetry", "createRetryHandler", "request", "createRequest", "startsWith", "slice", "info", "processingError", "retryAfterHeaderValue", "Number", "NaN", "response", "fetch", "headers", "get", "ok", "json", "success", "data", "isNonRetryable", "errorData", "reason", "fromFailureResponse", "isRetryable", "status", "error", "fromProcessingFailureCause", "JSON", "stringify", "retry", "count", "retries", "maxRetries", "baseTimeout", "timeout", "jitter", "ctx", "retryAfter", "disposed", "Math", "random"]
|
|
7
7
|
}
|