@dxos/edge-client 0.6.12-staging.e11e696 → 0.6.13-main.548ca8d
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 +47 -40
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +5 -2
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node/index.cjs +44 -39
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +5 -2
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/lib/node-esm/index.mjs +47 -40
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +5 -2
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/edge-client.d.ts +2 -0
- package/dist/types/src/edge-client.d.ts.map +1 -1
- package/dist/types/src/edge-http-client.d.ts +2 -1
- package/dist/types/src/edge-http-client.d.ts.map +1 -1
- package/dist/types/src/testing/test-utils.d.ts +1 -0
- package/dist/types/src/testing/test-utils.d.ts.map +1 -1
- package/dist/types/src/utils.d.ts +2 -0
- package/dist/types/src/utils.d.ts.map +1 -0
- package/package.json +14 -14
- package/src/edge-client.ts +11 -4
- package/src/edge-http-client.ts +20 -22
- package/src/testing/test-utils.ts +3 -0
- package/src/utils.ts +10 -0
|
@@ -124,11 +124,18 @@ _ts_decorate([
|
|
|
124
124
|
synchronized
|
|
125
125
|
], PersistentLifecycle.prototype, "scheduleRestart", null);
|
|
126
126
|
|
|
127
|
+
// packages/core/mesh/edge-client/src/utils.ts
|
|
128
|
+
var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
|
|
129
|
+
const isSecure = baseUrl.startsWith("https") || baseUrl.startsWith("wss");
|
|
130
|
+
const url = new URL(baseUrl);
|
|
131
|
+
url.protocol = protocol2 + (isSecure ? "s" : "");
|
|
132
|
+
return url.toString();
|
|
133
|
+
};
|
|
134
|
+
|
|
127
135
|
// packages/core/mesh/edge-client/src/edge-client.ts
|
|
128
136
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
|
|
129
137
|
var DEFAULT_TIMEOUT = 1e4;
|
|
130
138
|
var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
|
|
131
|
-
var DISABLE_AUTH = true;
|
|
132
139
|
var EdgeClient = class extends Resource2 {
|
|
133
140
|
constructor(_identity, _config) {
|
|
134
141
|
super();
|
|
@@ -146,6 +153,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
146
153
|
this._ws = void 0;
|
|
147
154
|
this._keepaliveCtx = void 0;
|
|
148
155
|
this._heartBeatContext = void 0;
|
|
156
|
+
this._baseUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
|
|
149
157
|
}
|
|
150
158
|
// TODO(burdon): Attach logging.
|
|
151
159
|
get info() {
|
|
@@ -180,7 +188,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
180
188
|
info: this.info
|
|
181
189
|
}, {
|
|
182
190
|
F: __dxlog_file2,
|
|
183
|
-
L:
|
|
191
|
+
L: 122,
|
|
184
192
|
S: this,
|
|
185
193
|
C: (f, a) => f(...a)
|
|
186
194
|
});
|
|
@@ -189,7 +197,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
189
197
|
err
|
|
190
198
|
}, {
|
|
191
199
|
F: __dxlog_file2,
|
|
192
|
-
L:
|
|
200
|
+
L: 124,
|
|
193
201
|
S: this,
|
|
194
202
|
C: (f, a) => f(...a)
|
|
195
203
|
});
|
|
@@ -203,7 +211,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
203
211
|
peerKey: this._identity.peerKey
|
|
204
212
|
}, {
|
|
205
213
|
F: __dxlog_file2,
|
|
206
|
-
L:
|
|
214
|
+
L: 132,
|
|
207
215
|
S: this,
|
|
208
216
|
C: (f, a) => f(...a)
|
|
209
217
|
});
|
|
@@ -211,20 +219,23 @@ var EdgeClient = class extends Resource2 {
|
|
|
211
219
|
}
|
|
212
220
|
async _openWebSocket() {
|
|
213
221
|
let protocolHeader;
|
|
214
|
-
if (!
|
|
222
|
+
if (!this._config.disableAuth) {
|
|
215
223
|
const challenge = randomBytes(32);
|
|
216
224
|
const credential = await this._identity.presentCredentials({
|
|
217
225
|
challenge
|
|
218
226
|
});
|
|
219
227
|
protocolHeader = encodePresentationIntoAuthHeader(credential);
|
|
220
228
|
}
|
|
221
|
-
|
|
229
|
+
if (this._ctx.disposed) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._baseUrl);
|
|
222
233
|
log2("Opening websocket", {
|
|
223
234
|
url: url.toString(),
|
|
224
235
|
protocolHeader
|
|
225
236
|
}, {
|
|
226
237
|
F: __dxlog_file2,
|
|
227
|
-
L:
|
|
238
|
+
L: 151,
|
|
228
239
|
S: this,
|
|
229
240
|
C: (f, a) => f(...a)
|
|
230
241
|
});
|
|
@@ -234,7 +245,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
234
245
|
this._ws.onopen = () => {
|
|
235
246
|
log2("opened", this.info, {
|
|
236
247
|
F: __dxlog_file2,
|
|
237
|
-
L:
|
|
248
|
+
L: 155,
|
|
238
249
|
S: this,
|
|
239
250
|
C: (f, a) => f(...a)
|
|
240
251
|
});
|
|
@@ -244,7 +255,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
244
255
|
this._ws.onclose = () => {
|
|
245
256
|
log2("closed", this.info, {
|
|
246
257
|
F: __dxlog_file2,
|
|
247
|
-
L:
|
|
258
|
+
L: 160,
|
|
248
259
|
S: this,
|
|
249
260
|
C: (f, a) => f(...a)
|
|
250
261
|
});
|
|
@@ -256,7 +267,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
256
267
|
info: event.message
|
|
257
268
|
}, {
|
|
258
269
|
F: __dxlog_file2,
|
|
259
|
-
L:
|
|
270
|
+
L: 164,
|
|
260
271
|
S: this,
|
|
261
272
|
C: (f, a) => f(...a)
|
|
262
273
|
});
|
|
@@ -274,7 +285,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
274
285
|
payload: protocol.getPayloadType(message)
|
|
275
286
|
}, {
|
|
276
287
|
F: __dxlog_file2,
|
|
277
|
-
L:
|
|
288
|
+
L: 177,
|
|
278
289
|
S: this,
|
|
279
290
|
C: (f, a) => f(...a)
|
|
280
291
|
});
|
|
@@ -288,7 +299,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
288
299
|
payload: protocol.getPayloadType(message)
|
|
289
300
|
}, {
|
|
290
301
|
F: __dxlog_file2,
|
|
291
|
-
L:
|
|
302
|
+
L: 183,
|
|
292
303
|
S: this,
|
|
293
304
|
C: (f, a) => f(...a)
|
|
294
305
|
});
|
|
@@ -301,7 +312,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
301
312
|
});
|
|
302
313
|
this._keepaliveCtx = new Context(void 0, {
|
|
303
314
|
F: __dxlog_file2,
|
|
304
|
-
L:
|
|
315
|
+
L: 193
|
|
305
316
|
});
|
|
306
317
|
scheduleTaskInterval(this._keepaliveCtx, async () => {
|
|
307
318
|
this._ws?.send("__ping__");
|
|
@@ -336,7 +347,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
336
347
|
err
|
|
337
348
|
}, {
|
|
338
349
|
F: __dxlog_file2,
|
|
339
|
-
L:
|
|
350
|
+
L: 229,
|
|
340
351
|
S: this,
|
|
341
352
|
C: (f, a) => f(...a)
|
|
342
353
|
});
|
|
@@ -350,7 +361,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
350
361
|
if (this._ready.state !== TriggerState.RESOLVED) {
|
|
351
362
|
log2("waiting for websocket to become ready", void 0, {
|
|
352
363
|
F: __dxlog_file2,
|
|
353
|
-
L:
|
|
364
|
+
L: 239,
|
|
354
365
|
S: this,
|
|
355
366
|
C: (f, a) => f(...a)
|
|
356
367
|
});
|
|
@@ -369,7 +380,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
369
380
|
payload: protocol.getPayloadType(message)
|
|
370
381
|
}, {
|
|
371
382
|
F: __dxlog_file2,
|
|
372
|
-
L:
|
|
383
|
+
L: 252,
|
|
373
384
|
S: this,
|
|
374
385
|
C: (f, a) => f(...a)
|
|
375
386
|
});
|
|
@@ -382,7 +393,7 @@ var EdgeClient = class extends Resource2 {
|
|
|
382
393
|
void this._heartBeatContext?.dispose();
|
|
383
394
|
this._heartBeatContext = new Context(void 0, {
|
|
384
395
|
F: __dxlog_file2,
|
|
385
|
-
L:
|
|
396
|
+
L: 261
|
|
386
397
|
});
|
|
387
398
|
scheduleTask(this._heartBeatContext, () => {
|
|
388
399
|
this._persistentLifecycle.scheduleRestart();
|
|
@@ -499,21 +510,19 @@ var createStubEdgeIdentity = () => {
|
|
|
499
510
|
import { sleep as sleep2 } from "@dxos/async";
|
|
500
511
|
import { Context as Context2 } from "@dxos/context";
|
|
501
512
|
import { log as log3 } from "@dxos/log";
|
|
502
|
-
import { EdgeCallFailedError } from "@dxos/protocols";
|
|
513
|
+
import { EdgeCallFailedError, EdgeAuthChallengeError } from "@dxos/protocols";
|
|
503
514
|
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
|
|
504
515
|
var DEFAULT_RETRY_TIMEOUT = 1500;
|
|
505
516
|
var DEFAULT_RETRY_JITTER = 500;
|
|
506
517
|
var DEFAULT_MAX_RETRIES_COUNT = 3;
|
|
507
518
|
var EdgeHttpClient = class {
|
|
508
519
|
constructor(baseUrl) {
|
|
509
|
-
|
|
510
|
-
url.protocol = "https";
|
|
511
|
-
this._baseUrl = url.toString();
|
|
520
|
+
this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
|
|
512
521
|
log3("created", {
|
|
513
522
|
url: this._baseUrl
|
|
514
523
|
}, {
|
|
515
524
|
F: __dxlog_file3,
|
|
516
|
-
L:
|
|
525
|
+
L: 30,
|
|
517
526
|
S: this,
|
|
518
527
|
C: (f, a) => f(...a)
|
|
519
528
|
});
|
|
@@ -531,10 +540,17 @@ var EdgeHttpClient = class {
|
|
|
531
540
|
method: "POST"
|
|
532
541
|
});
|
|
533
542
|
}
|
|
543
|
+
async joinSpaceByInvitation(spaceId, body, args) {
|
|
544
|
+
return this._call(`/spaces/${spaceId}/join`, {
|
|
545
|
+
...args,
|
|
546
|
+
body,
|
|
547
|
+
method: "POST"
|
|
548
|
+
});
|
|
549
|
+
}
|
|
534
550
|
async _call(path, args) {
|
|
535
551
|
const requestContext = args.context ?? new Context2(void 0, {
|
|
536
552
|
F: __dxlog_file3,
|
|
537
|
-
L:
|
|
553
|
+
L: 54
|
|
538
554
|
});
|
|
539
555
|
const shouldRetry = createRetryHandler(args);
|
|
540
556
|
const request = createRequest(args);
|
|
@@ -544,7 +560,7 @@ var EdgeHttpClient = class {
|
|
|
544
560
|
path
|
|
545
561
|
}, {
|
|
546
562
|
F: __dxlog_file3,
|
|
547
|
-
L:
|
|
563
|
+
L: 59,
|
|
548
564
|
S: this,
|
|
549
565
|
C: (f, a) => f(...a)
|
|
550
566
|
});
|
|
@@ -559,27 +575,24 @@ var EdgeHttpClient = class {
|
|
|
559
575
|
if (body.success) {
|
|
560
576
|
return body.data;
|
|
561
577
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
578
|
+
if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
|
|
579
|
+
processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
|
|
580
|
+
} else {
|
|
581
|
+
processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
|
|
565
582
|
}
|
|
566
|
-
processingError = new EdgeCallFailedError(body.reason);
|
|
567
583
|
} else {
|
|
568
|
-
processingError = EdgeCallFailedError.
|
|
569
|
-
if (!isRetryable(response.status)) {
|
|
570
|
-
throw processingError;
|
|
571
|
-
}
|
|
584
|
+
processingError = EdgeCallFailedError.fromHttpFailure(response);
|
|
572
585
|
}
|
|
573
586
|
} catch (error) {
|
|
574
587
|
processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
|
|
575
588
|
}
|
|
576
|
-
if (await shouldRetry(requestContext, retryAfterHeaderValue)) {
|
|
589
|
+
if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
|
|
577
590
|
log3.info("retrying edge request", {
|
|
578
591
|
path,
|
|
579
592
|
processingError
|
|
580
593
|
}, {
|
|
581
594
|
F: __dxlog_file3,
|
|
582
|
-
L:
|
|
595
|
+
L: 88,
|
|
583
596
|
S: this,
|
|
584
597
|
C: (f, a) => f(...a)
|
|
585
598
|
});
|
|
@@ -595,12 +608,6 @@ var createRequest = (args) => {
|
|
|
595
608
|
body: args.body && JSON.stringify(args.body)
|
|
596
609
|
};
|
|
597
610
|
};
|
|
598
|
-
var isRetryable = (status) => {
|
|
599
|
-
if (status === 501) {
|
|
600
|
-
return false;
|
|
601
|
-
}
|
|
602
|
-
return !(status >= 400 && status < 500);
|
|
603
|
-
};
|
|
604
611
|
var createRetryHandler = (args) => {
|
|
605
612
|
if (!args.retry || args.retry.count < 1) {
|
|
606
613
|
return async () => false;
|
|
@@ -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", "../../../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": ";;;;;;;;;AAIA,cAAc;;;ACAd,OAAOA,eAAe;AAEtB,SAASC,SAASC,OAAOC,sBAAsBC,cAAcC,oBAAoB;AACjF,SAASC,SAASC,kBAAAA,iBAAgBC,YAAAA,iBAAgC;AAClE,SAASC,mBAAmB;AAC5B,SAASC,OAAAA,YAAW;AACpB,SAASC,WAAW;AACpB,SAAuBC,qBAAqB;AAC5C,SAASC,cAAc;;;ACRhB,IAAMC,4BAAN,cAAwCC,MAAAA;EAC7CC,cAAc;AACZ,UAAM,yBAAA;EACR;AACF;AAEO,IAAMC,2BAAN,cAAuCF,MAAAA;EAC5CC,cAAc;AACZ,UAAM,wBAAA;EACR;AACF;;;ACVA,SAASE,cAAcC,OAAOC,oBAAoB;AAClD,SAASC,mBAAmBC,gBAAgBC,gBAAgB;AAC5D,SAASC,wBAAwB;AACjC,SAASC,WAAW;;;;;;;;AAEpB,IAAMC,qBAAqB;AAC3B,IAAMC,4BAA4B;AA8B3B,IAAMC,sBAAN,cAAkCL,SAAAA;EASvCM,YAAY,EAAEC,OAAOC,MAAMC,WAAWC,kBAAkBN,0BAAyB,GAA+B;AAC9G,UAAK;AAJCO,wBAA8BC;AAC9BC,yBAAgB;AAItB,SAAKC,SAASP;AACd,SAAKQ,QAAQP;AACb,SAAKQ,aAAaP;AAClB,SAAKQ,mBAAmBP;EAC1B;EAEA,MACyBQ,QAAQ;AAC/B,SAAKP,eAAe,IAAIhB,aAAa,KAAKwB,MAAM,YAAA;AAC9C,UAAI;AACF,cAAM,KAAKC,SAAQ;MACrB,SAASC,KAAK;AACZnB,YAAIoB,KAAK,kBAAkB;UAAED;QAAI,GAAA;;;;;;AACjC,aAAKV,cAAcY,SAAAA;MACrB;IACF,CAAA;AACA,UAAM,KAAKT,OAAM,EAAGU,MAAM,CAACH,QAAAA;AACzBnB,UAAIoB,KAAK,gBAAgB;QAAED;MAAI,GAAA;;;;;;AAC/B,WAAKV,cAAcY,SAAAA;IACrB,CAAA;EACF;EAEA,MAAyBE,SAAS;AAChC,UAAM,KAAKd,cAAce,KAAAA;AACzB,UAAM,KAAKX,MAAK;AAChB,SAAKJ,eAAeC;EACtB;EAEA,MAAcQ,WAAW;AACvBlB,QAAI,iBAAiB,KAAKW,aAAa,MAAM;MAAEc,OAAO,KAAKC;IAAgB,GAAA;;;;;;AAC3E,UAAM,KAAKb,MAAK;AAChB,QAAI,KAAKa,oBAAoB7B,eAAe8B,MAAM;AAChD;IACF;AACA,UAAM/B,kBAAkB,KAAKqB,MAAOvB,MAAM,KAAKiB,aAAa,CAAA;AAC5D,SAAKA,gBAAgBiB,KAAKC,IAAID,KAAKE,IAAI,KAAKnB,gBAAgB,GAAGV,kBAAAA,GAAqB,KAAKc,gBAAgB;AAGzG,UAAMhB,iBAAiB,KAAO,2CAA2C,MAAM,KAAKa,OAAM,CAAA;AAE1F,SAAKD,gBAAgB;AACrB,UAAM,KAAKG,aAAU;EACvB;;;;EAMAiB,kBAAkB;AAChB,QAAI,KAAKL,oBAAoB7B,eAAe8B,MAAM;AAChD;IACF;AACA,SAAKlB,aAAcY,SAAQ;EAC7B;AACF;;EAhDG1B;GAjBUQ,oBAAAA,WAAAA,SAAAA,IAAAA;;EA0DVR;GA1DUQ,oBAAAA,WAAAA,mBAAAA,IAAAA
|
|
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", "
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/edge-client.ts", "../../../src/errors.ts", "../../../src/persistent-lifecycle.ts", "../../../src/utils.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';\nimport { getEdgeUrlWithProtocol } from './utils';\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 disableAuth?: boolean;\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\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 private _baseUrl: string;\n\n constructor(\n private _identity: EdgeIdentity,\n private readonly _config: MessengerConfig,\n ) {\n super();\n this._baseUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, 'ws');\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 (!this._config.disableAuth) {\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 if (this._ctx.disposed) {\n return;\n }\n\n const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._baseUrl);\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\nexport const getEdgeUrlWithProtocol = (baseUrl: string, protocol: 'http' | 'ws') => {\n const isSecure = baseUrl.startsWith('https') || baseUrl.startsWith('wss');\n const url = new URL(baseUrl);\n url.protocol = protocol + (isSecure ? 's' : '');\n return url.toString();\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 type JoinSpaceRequest,\n type JoinSpaceResponseBody,\n EdgeAuthChallengeError,\n} from '@dxos/protocols';\n\nimport { getEdgeUrlWithProtocol } from './utils';\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 this._baseUrl = getEdgeUrlWithProtocol(baseUrl, 'http');\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 public async joinSpaceByInvitation(\n spaceId: SpaceId,\n body: JoinSpaceRequest,\n args?: EdgeHttpGetArgs,\n ): Promise<JoinSpaceResponseBody> {\n return this._call(`/spaces/${spaceId}/join`, { ...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 if (body.errorData?.type === 'auth_challenge' && typeof body.errorData?.challenge === 'string') {\n processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);\n } else {\n processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);\n }\n } else {\n processingError = EdgeCallFailedError.fromHttpFailure(response);\n }\n } catch (error: any) {\n processingError = EdgeCallFailedError.fromProcessingFailureCause(error);\n }\n\n if (processingError.isRetryable && (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 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", "getEdgeUrlWithProtocol", "baseUrl", "protocol", "isSecure", "startsWith", "url", "URL", "toString", "DEFAULT_TIMEOUT", "SIGNAL_KEEPALIVE_INTERVAL", "EdgeClient", "Resource", "constructor", "_identity", "_config", "reconnect", "Event", "connected", "_persistentLifecycle", "PersistentLifecycle", "start", "_openWebSocket", "stop", "_closeWebSocket", "onRestart", "emit", "_listeners", "Set", "_ready", "Trigger", "_ws", "undefined", "_keepaliveCtx", "_heartBeatContext", "_baseUrl", "getEdgeUrlWithProtocol", "socketEndpoint", "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", "disableAuth", "challenge", "randomBytes", "credential", "presentCredentials", "encodePresentationIntoAuthHeader", "_ctx", "disposed", "url", "URL", "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", "EdgeAuthChallengeError", "DEFAULT_RETRY_TIMEOUT", "DEFAULT_RETRY_JITTER", "DEFAULT_MAX_RETRIES_COUNT", "EdgeHttpClient", "constructor", "baseUrl", "_baseUrl", "getEdgeUrlWithProtocol", "log", "url", "getCredentialsForNotarization", "spaceId", "args", "_call", "method", "notarizeCredentials", "body", "joinSpaceByInvitation", "path", "requestContext", "context", "Context", "shouldRetry", "createRetryHandler", "request", "createRequest", "startsWith", "slice", "info", "processingError", "retryAfterHeaderValue", "Number", "NaN", "response", "fetch", "headers", "get", "ok", "json", "success", "data", "errorData", "type", "challenge", "EdgeAuthChallengeError", "EdgeCallFailedError", "fromUnsuccessfulResponse", "fromHttpFailure", "error", "fromProcessingFailureCause", "isRetryable", "JSON", "stringify", "retry", "count", "retries", "maxRetries", "baseTimeout", "timeout", "jitter", "ctx", "retryAfter", "disposed", "sleep", "Math", "random"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10334,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/defs.ts":{"bytes":1607,"imports":[{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/errors.ts":{"bytes":1265,"imports":[],"format":"esm"},"packages/core/mesh/edge-client/src/persistent-lifecycle.ts":{"bytes":10868,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/edge-client.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10334,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/defs.ts":{"bytes":1607,"imports":[{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/errors.ts":{"bytes":1265,"imports":[],"format":"esm"},"packages/core/mesh/edge-client/src/persistent-lifecycle.ts":{"bytes":10868,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/utils.ts":{"bytes":1451,"imports":[],"format":"esm"},"packages/core/mesh/edge-client/src/edge-client.ts":{"bytes":33114,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/protocols/proto","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/core/mesh/edge-client/src/errors.ts","kind":"import-statement","original":"./errors"},{"path":"packages/core/mesh/edge-client/src/persistent-lifecycle.ts","kind":"import-statement","original":"./persistent-lifecycle"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"},{"path":"packages/core/mesh/edge-client/src/utils.ts","kind":"import-statement","original":"./utils"}],"format":"esm"},"packages/core/mesh/edge-client/src/auth.ts":{"bytes":11621,"imports":[{"path":"@dxos/credentials","kind":"import-statement","external":true},{"path":"@dxos/keyring","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/edge-client/src/edge-http-client.ts":{"bytes":15505,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/utils.ts","kind":"import-statement","original":"./utils"}],"format":"esm"},"packages/core/mesh/edge-client/src/index.ts":{"bytes":1127,"imports":[{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/edge-client.ts","kind":"import-statement","original":"./edge-client"},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"./protocol"},{"path":"packages/core/mesh/edge-client/src/errors.ts","kind":"import-statement","original":"./errors"},{"path":"packages/core/mesh/edge-client/src/auth.ts","kind":"import-statement","original":"./auth"},{"path":"packages/core/mesh/edge-client/src/edge-http-client.ts","kind":"import-statement","original":"./edge-http-client"}],"format":"esm"},"packages/core/mesh/edge-client/src/testing/test-utils.ts":{"bytes":12827,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/defs.ts","kind":"import-statement","original":"../defs"},{"path":"packages/core/mesh/edge-client/src/protocol.ts","kind":"import-statement","original":"../protocol"}],"format":"esm"},"packages/core/mesh/edge-client/src/testing/index.ts":{"bytes":516,"imports":[{"path":"packages/core/mesh/edge-client/src/testing/test-utils.ts","kind":"import-statement","original":"./test-utils"}],"format":"esm"}},"outputs":{"packages/core/mesh/edge-client/dist/lib/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":35688},"packages/core/mesh/edge-client/dist/lib/node-esm/index.mjs":{"imports":[{"path":"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs","kind":"import-statement"},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/crypto","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/protocols/proto","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/credentials","kind":"import-statement","external":true},{"path":"@dxos/keyring","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true}],"exports":["EdgeClient","EdgeConnectionClosedError","EdgeHttpClient","EdgeIdentityChangedError","Protocol","createChainEdgeIdentity","createDeviceEdgeIdentity","createEphemeralEdgeIdentity","createStubEdgeIdentity","createTestHaloEdgeIdentity","getTypename","protocol","toUint8Array"],"entryPoint":"packages/core/mesh/edge-client/src/index.ts","inputs":{"packages/core/mesh/edge-client/src/index.ts":{"bytesInOutput":60},"packages/core/mesh/edge-client/src/edge-client.ts":{"bytesInOutput":8074},"packages/core/mesh/edge-client/src/errors.ts":{"bytesInOutput":232},"packages/core/mesh/edge-client/src/persistent-lifecycle.ts":{"bytesInOutput":3015},"packages/core/mesh/edge-client/src/utils.ts":{"bytesInOutput":244},"packages/core/mesh/edge-client/src/auth.ts":{"bytesInOutput":2681},"packages/core/mesh/edge-client/src/edge-http-client.ts":{"bytesInOutput":3701}},"bytes":18947},"packages/core/mesh/edge-client/dist/lib/node-esm/testing/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":6550},"packages/core/mesh/edge-client/dist/lib/node-esm/testing/index.mjs":{"imports":[{"path":"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs","kind":"import-statement"},{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true}],"exports":["DEFAULT_PORT","createTestEdgeWsServer"],"entryPoint":"packages/core/mesh/edge-client/src/testing/index.ts","inputs":{"packages/core/mesh/edge-client/src/testing/test-utils.ts":{"bytesInOutput":3368},"packages/core/mesh/edge-client/src/testing/index.ts":{"bytesInOutput":0}},"bytes":3677},"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":5678},"packages/core/mesh/edge-client/dist/lib/node-esm/chunk-HNVT57AU.mjs":{"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true}],"exports":["Protocol","getTypename","protocol","toUint8Array"],"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytesInOutput":2600},"packages/core/mesh/edge-client/src/defs.ts":{"bytesInOutput":298}},"bytes":3199}}}
|
|
@@ -63,6 +63,9 @@ var createTestEdgeWsServer = async (port = DEFAULT_PORT, params) => {
|
|
|
63
63
|
cleanup: () => server.close(),
|
|
64
64
|
currentConnection: () => connection,
|
|
65
65
|
sendResponseMessage,
|
|
66
|
+
sendMessage: (msg) => {
|
|
67
|
+
connection.send(buf.toBinary(MessageSchema, msg));
|
|
68
|
+
},
|
|
66
69
|
closeConnection: () => {
|
|
67
70
|
closeTrigger.reset();
|
|
68
71
|
connection.close(1011);
|
|
@@ -75,7 +78,7 @@ var createConnectionDelayHandler = (params) => {
|
|
|
75
78
|
if (params?.admitConnection) {
|
|
76
79
|
log("delaying edge connection admission", void 0, {
|
|
77
80
|
F: __dxlog_file,
|
|
78
|
-
L:
|
|
81
|
+
L: 78,
|
|
79
82
|
S: void 0,
|
|
80
83
|
C: (f, a) => f(...a)
|
|
81
84
|
});
|
|
@@ -83,7 +86,7 @@ var createConnectionDelayHandler = (params) => {
|
|
|
83
86
|
callback(true);
|
|
84
87
|
log("edge connection admitted", void 0, {
|
|
85
88
|
F: __dxlog_file,
|
|
86
|
-
L:
|
|
89
|
+
L: 81,
|
|
87
90
|
S: void 0,
|
|
88
91
|
C: (f, a) => f(...a)
|
|
89
92
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/testing/test-utils.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger } from '@dxos/async';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { MessageSchema, TextMessageSchema, type Message } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { protocol } from '../defs';\nimport { toUint8Array } from '../protocol';\n\nexport const DEFAULT_PORT = 8080;\n\ntype TestEdgeWsServerParams = {\n admitConnection?: Trigger;\n payloadDecoder?: (payload: Uint8Array) => any;\n messageHandler?: (payload: any) => Promise<Uint8Array | undefined>;\n};\n\nexport const createTestEdgeWsServer = async (port = DEFAULT_PORT, params?: TestEdgeWsServerParams) => {\n const server = new WebSocket.Server({ port, verifyClient: createConnectionDelayHandler(params) });\n\n let connection: WebSocket | undefined;\n\n const messageSink: any[] = [];\n const closeTrigger = new Trigger();\n const sendResponseMessage = createResponseSender(() => connection!);\n\n server.on('connection', (ws) => {\n connection = ws;\n ws.on('error', (err) => log.catch(err));\n ws.on('message', async (data) => {\n if (String(data) === '__ping__') {\n ws.send('__pong__');\n return;\n }\n const { request, requestPayload } = await decodeRequest(params, data);\n if (params?.messageHandler) {\n const responsePayload = await params.messageHandler(requestPayload);\n if (responsePayload && connection) {\n sendResponseMessage(request, responsePayload);\n }\n }\n log('message', { payload: requestPayload });\n messageSink.push(requestPayload);\n });\n\n ws.on('close', () => {\n connection = undefined;\n closeTrigger.wake();\n });\n });\n\n return {\n server,\n messageSink,\n endpoint: `ws://localhost:${port}`,\n cleanup: () => server.close(),\n currentConnection: () => connection,\n sendResponseMessage,\n closeConnection: () => {\n closeTrigger.reset();\n connection!.close(1011);\n return closeTrigger.wait();\n },\n };\n};\n\nconst createConnectionDelayHandler = (params: TestEdgeWsServerParams | undefined) => {\n return (_: any, callback: (admit: boolean) => void) => {\n if (params?.admitConnection) {\n log('delaying edge connection admission');\n void params.admitConnection.wait().then(() => {\n callback(true);\n log('edge connection admitted');\n });\n } else {\n callback(true);\n }\n };\n};\n\nconst createResponseSender = (connection: () => WebSocket) => {\n return (request: Message, responsePayload: Uint8Array) => {\n const recipient = request.source!;\n connection().send(\n buf.toBinary(\n MessageSchema,\n buf.create(MessageSchema, {\n source: {\n identityKey: recipient.identityKey,\n peerKey: recipient.peerKey,\n },\n serviceId: request.serviceId!,\n payload: { value: responsePayload },\n }),\n ),\n );\n };\n};\n\nconst decodeRequest = async (params: TestEdgeWsServerParams | undefined, data: any) => {\n const request = buf.fromBinary(MessageSchema, await toUint8Array(data));\n const requestPayload = params?.payloadDecoder\n ? params.payloadDecoder(request.payload!.value!)\n : protocol.getPayload(request, TextMessageSchema);\n return { request, requestPayload };\n};\n"],
|
|
5
|
-
"mappings": ";;;;;;;AAIA,OAAOA,eAAe;AAEtB,SAASC,eAAe;AACxB,SAASC,WAAW;AACpB,SAASC,WAAW;AACpB,SAASC,eAAeC,yBAAuC;;AAKxD,IAAMC,eAAe;AAQrB,IAAMC,yBAAyB,OAAOC,OAAOF,cAAcG,WAAAA;AAChE,QAAMC,SAAS,IAAIC,UAAUC,OAAO;IAAEJ;IAAMK,cAAcC,6BAA6BL,MAAAA;EAAQ,CAAA;AAE/F,MAAIM;AAEJ,QAAMC,cAAqB,CAAA;AAC3B,QAAMC,eAAe,IAAIC,QAAAA;AACzB,QAAMC,sBAAsBC,qBAAqB,MAAML,UAAAA;AAEvDL,SAAOW,GAAG,cAAc,CAACC,OAAAA;AACvBP,iBAAaO;AACbA,OAAGD,GAAG,SAAS,CAACE,QAAQC,IAAIC,MAAMF,KAAAA,QAAAA;;;;;;AAClCD,OAAGD,GAAG,WAAW,OAAOK,SAAAA;AACtB,UAAIC,OAAOD,IAAAA,MAAU,YAAY;AAC/BJ,WAAGM,KAAK,UAAA;AACR;MACF;AACA,YAAM,EAAEC,SAASC,eAAc,IAAK,MAAMC,cAActB,QAAQiB,IAAAA;AAChE,UAAIjB,QAAQuB,gBAAgB;AAC1B,cAAMC,kBAAkB,MAAMxB,OAAOuB,eAAeF,cAAAA;AACpD,YAAIG,mBAAmBlB,YAAY;AACjCI,8BAAoBU,SAASI,eAAAA;QAC/B;MACF;AACAT,UAAI,WAAW;QAAEU,SAASJ;MAAe,GAAA;;;;;;AACzCd,kBAAYmB,KAAKL,cAAAA;IACnB,CAAA;AAEAR,OAAGD,GAAG,SAAS,MAAA;AACbN,mBAAaqB;AACbnB,mBAAaoB,KAAI;IACnB,CAAA;EACF,CAAA;AAEA,SAAO;IACL3B;IACAM;IACAsB,UAAU,kBAAkB9B,IAAAA;IAC5B+B,SAAS,MAAM7B,OAAO8B,MAAK;IAC3BC,mBAAmB,MAAM1B;IACzBI;IACAuB,iBAAiB,MAAA;
|
|
6
|
-
"names": ["WebSocket", "Trigger", "log", "buf", "MessageSchema", "TextMessageSchema", "DEFAULT_PORT", "createTestEdgeWsServer", "port", "params", "server", "WebSocket", "Server", "verifyClient", "createConnectionDelayHandler", "connection", "messageSink", "closeTrigger", "Trigger", "sendResponseMessage", "createResponseSender", "on", "ws", "err", "log", "catch", "data", "String", "send", "request", "requestPayload", "decodeRequest", "messageHandler", "responsePayload", "payload", "push", "undefined", "wake", "endpoint", "cleanup", "close", "currentConnection", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger } from '@dxos/async';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { MessageSchema, TextMessageSchema, type Message } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { protocol } from '../defs';\nimport { toUint8Array } from '../protocol';\n\nexport const DEFAULT_PORT = 8080;\n\ntype TestEdgeWsServerParams = {\n admitConnection?: Trigger;\n payloadDecoder?: (payload: Uint8Array) => any;\n messageHandler?: (payload: any) => Promise<Uint8Array | undefined>;\n};\n\nexport const createTestEdgeWsServer = async (port = DEFAULT_PORT, params?: TestEdgeWsServerParams) => {\n const server = new WebSocket.Server({ port, verifyClient: createConnectionDelayHandler(params) });\n\n let connection: WebSocket | undefined;\n\n const messageSink: any[] = [];\n const closeTrigger = new Trigger();\n const sendResponseMessage = createResponseSender(() => connection!);\n\n server.on('connection', (ws) => {\n connection = ws;\n ws.on('error', (err) => log.catch(err));\n ws.on('message', async (data) => {\n if (String(data) === '__ping__') {\n ws.send('__pong__');\n return;\n }\n const { request, requestPayload } = await decodeRequest(params, data);\n if (params?.messageHandler) {\n const responsePayload = await params.messageHandler(requestPayload);\n if (responsePayload && connection) {\n sendResponseMessage(request, responsePayload);\n }\n }\n log('message', { payload: requestPayload });\n messageSink.push(requestPayload);\n });\n\n ws.on('close', () => {\n connection = undefined;\n closeTrigger.wake();\n });\n });\n\n return {\n server,\n messageSink,\n endpoint: `ws://localhost:${port}`,\n cleanup: () => server.close(),\n currentConnection: () => connection,\n sendResponseMessage,\n sendMessage: (msg: Message) => {\n connection!.send(buf.toBinary(MessageSchema, msg));\n },\n closeConnection: () => {\n closeTrigger.reset();\n connection!.close(1011);\n return closeTrigger.wait();\n },\n };\n};\n\nconst createConnectionDelayHandler = (params: TestEdgeWsServerParams | undefined) => {\n return (_: any, callback: (admit: boolean) => void) => {\n if (params?.admitConnection) {\n log('delaying edge connection admission');\n void params.admitConnection.wait().then(() => {\n callback(true);\n log('edge connection admitted');\n });\n } else {\n callback(true);\n }\n };\n};\n\nconst createResponseSender = (connection: () => WebSocket) => {\n return (request: Message, responsePayload: Uint8Array) => {\n const recipient = request.source!;\n connection().send(\n buf.toBinary(\n MessageSchema,\n buf.create(MessageSchema, {\n source: {\n identityKey: recipient.identityKey,\n peerKey: recipient.peerKey,\n },\n serviceId: request.serviceId!,\n payload: { value: responsePayload },\n }),\n ),\n );\n };\n};\n\nconst decodeRequest = async (params: TestEdgeWsServerParams | undefined, data: any) => {\n const request = buf.fromBinary(MessageSchema, await toUint8Array(data));\n const requestPayload = params?.payloadDecoder\n ? params.payloadDecoder(request.payload!.value!)\n : protocol.getPayload(request, TextMessageSchema);\n return { request, requestPayload };\n};\n"],
|
|
5
|
+
"mappings": ";;;;;;;AAIA,OAAOA,eAAe;AAEtB,SAASC,eAAe;AACxB,SAASC,WAAW;AACpB,SAASC,WAAW;AACpB,SAASC,eAAeC,yBAAuC;;AAKxD,IAAMC,eAAe;AAQrB,IAAMC,yBAAyB,OAAOC,OAAOF,cAAcG,WAAAA;AAChE,QAAMC,SAAS,IAAIC,UAAUC,OAAO;IAAEJ;IAAMK,cAAcC,6BAA6BL,MAAAA;EAAQ,CAAA;AAE/F,MAAIM;AAEJ,QAAMC,cAAqB,CAAA;AAC3B,QAAMC,eAAe,IAAIC,QAAAA;AACzB,QAAMC,sBAAsBC,qBAAqB,MAAML,UAAAA;AAEvDL,SAAOW,GAAG,cAAc,CAACC,OAAAA;AACvBP,iBAAaO;AACbA,OAAGD,GAAG,SAAS,CAACE,QAAQC,IAAIC,MAAMF,KAAAA,QAAAA;;;;;;AAClCD,OAAGD,GAAG,WAAW,OAAOK,SAAAA;AACtB,UAAIC,OAAOD,IAAAA,MAAU,YAAY;AAC/BJ,WAAGM,KAAK,UAAA;AACR;MACF;AACA,YAAM,EAAEC,SAASC,eAAc,IAAK,MAAMC,cAActB,QAAQiB,IAAAA;AAChE,UAAIjB,QAAQuB,gBAAgB;AAC1B,cAAMC,kBAAkB,MAAMxB,OAAOuB,eAAeF,cAAAA;AACpD,YAAIG,mBAAmBlB,YAAY;AACjCI,8BAAoBU,SAASI,eAAAA;QAC/B;MACF;AACAT,UAAI,WAAW;QAAEU,SAASJ;MAAe,GAAA;;;;;;AACzCd,kBAAYmB,KAAKL,cAAAA;IACnB,CAAA;AAEAR,OAAGD,GAAG,SAAS,MAAA;AACbN,mBAAaqB;AACbnB,mBAAaoB,KAAI;IACnB,CAAA;EACF,CAAA;AAEA,SAAO;IACL3B;IACAM;IACAsB,UAAU,kBAAkB9B,IAAAA;IAC5B+B,SAAS,MAAM7B,OAAO8B,MAAK;IAC3BC,mBAAmB,MAAM1B;IACzBI;IACAuB,aAAa,CAACC,QAAAA;AACZ5B,iBAAYa,KAAKgB,IAAIC,SAASC,eAAeH,GAAAA,CAAAA;IAC/C;IACAI,iBAAiB,MAAA;AACf9B,mBAAa+B,MAAK;AAClBjC,iBAAYyB,MAAM,IAAA;AAClB,aAAOvB,aAAagC,KAAI;IAC1B;EACF;AACF;AAEA,IAAMnC,+BAA+B,CAACL,WAAAA;AACpC,SAAO,CAACyC,GAAQC,aAAAA;AACd,QAAI1C,QAAQ2C,iBAAiB;AAC3B5B,UAAI,sCAAA,QAAA;;;;;;AACJ,WAAKf,OAAO2C,gBAAgBH,KAAI,EAAGI,KAAK,MAAA;AACtCF,iBAAS,IAAA;AACT3B,YAAI,4BAAA,QAAA;;;;;;MACN,CAAA;IACF,OAAO;AACL2B,eAAS,IAAA;IACX;EACF;AACF;AAEA,IAAM/B,uBAAuB,CAACL,eAAAA;AAC5B,SAAO,CAACc,SAAkBI,oBAAAA;AACxB,UAAMqB,YAAYzB,QAAQ0B;AAC1BxC,eAAAA,EAAaa,KACXgB,IAAIC,SACFC,eACAF,IAAIY,OAAOV,eAAe;MACxBS,QAAQ;QACNE,aAAaH,UAAUG;QACvBC,SAASJ,UAAUI;MACrB;MACAC,WAAW9B,QAAQ8B;MACnBzB,SAAS;QAAE0B,OAAO3B;MAAgB;IACpC,CAAA,CAAA,CAAA;EAGN;AACF;AAEA,IAAMF,gBAAgB,OAAOtB,QAA4CiB,SAAAA;AACvE,QAAMG,UAAUe,IAAIiB,WAAWf,eAAe,MAAMgB,aAAapC,IAAAA,CAAAA;AACjE,QAAMI,iBAAiBrB,QAAQsD,iBAC3BtD,OAAOsD,eAAelC,QAAQK,QAAS0B,KAAK,IAC5CI,SAASC,WAAWpC,SAASqC,iBAAAA;AACjC,SAAO;IAAErC;IAASC;EAAe;AACnC;",
|
|
6
|
+
"names": ["WebSocket", "Trigger", "log", "buf", "MessageSchema", "TextMessageSchema", "DEFAULT_PORT", "createTestEdgeWsServer", "port", "params", "server", "WebSocket", "Server", "verifyClient", "createConnectionDelayHandler", "connection", "messageSink", "closeTrigger", "Trigger", "sendResponseMessage", "createResponseSender", "on", "ws", "err", "log", "catch", "data", "String", "send", "request", "requestPayload", "decodeRequest", "messageHandler", "responsePayload", "payload", "push", "undefined", "wake", "endpoint", "cleanup", "close", "currentConnection", "sendMessage", "msg", "buf", "toBinary", "MessageSchema", "closeConnection", "reset", "wait", "_", "callback", "admitConnection", "then", "recipient", "source", "create", "identityKey", "peerKey", "serviceId", "value", "fromBinary", "toUint8Array", "payloadDecoder", "protocol", "getPayload", "TextMessageSchema"]
|
|
7
7
|
}
|