@dxos/edge-client 0.6.12-main.f9d0246 → 0.6.12-staging.e11e696

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.
@@ -12,9 +12,11 @@ export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
12
12
  import WebSocket from "isomorphic-ws";
13
13
  import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from "@dxos/async";
14
14
  import { Context, LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
15
+ import { randomBytes } from "@dxos/crypto";
15
16
  import { log as log2 } from "@dxos/log";
16
17
  import { buf } from "@dxos/protocols/buf";
17
18
  import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
19
+ import { schema } from "@dxos/protocols/proto";
18
20
 
19
21
  // packages/core/mesh/edge-client/src/errors.ts
20
22
  var EdgeConnectionClosedError = class extends Error {
@@ -125,11 +127,11 @@ _ts_decorate([
125
127
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
126
128
  var DEFAULT_TIMEOUT = 1e4;
127
129
  var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
130
+ var DISABLE_AUTH = true;
128
131
  var EdgeClient = class extends Resource2 {
129
- constructor(_identityKey, _peerKey, _config) {
132
+ constructor(_identity, _config) {
130
133
  super();
131
- this._identityKey = _identityKey;
132
- this._peerKey = _peerKey;
134
+ this._identity = _identity;
133
135
  this._config = _config;
134
136
  this.reconnect = new Event();
135
137
  this.connected = new Event();
@@ -148,22 +150,21 @@ var EdgeClient = class extends Resource2 {
148
150
  get info() {
149
151
  return {
150
152
  open: this.isOpen,
151
- identity: this._identityKey,
152
- device: this._peerKey
153
+ identity: this._identity.identityKey,
154
+ device: this._identity.peerKey
153
155
  };
154
156
  }
155
157
  get isConnected() {
156
158
  return Boolean(this._ws) && this._ready.state === TriggerState.RESOLVED;
157
159
  }
158
160
  get identityKey() {
159
- return this._identityKey;
161
+ return this._identity.identityKey;
160
162
  }
161
163
  get peerKey() {
162
- return this._peerKey;
164
+ return this._identity.peerKey;
163
165
  }
164
- setIdentity({ peerKey, identityKey }) {
165
- this._peerKey = peerKey;
166
- this._identityKey = identityKey;
166
+ setIdentity(identity) {
167
+ this._identity = identity;
167
168
  this._persistentLifecycle.scheduleRestart();
168
169
  }
169
170
  addListener(listener) {
@@ -178,7 +179,7 @@ var EdgeClient = class extends Resource2 {
178
179
  info: this.info
179
180
  }, {
180
181
  F: __dxlog_file2,
181
- L: 105,
182
+ L: 119,
182
183
  S: this,
183
184
  C: (f, a) => f(...a)
184
185
  });
@@ -187,7 +188,7 @@ var EdgeClient = class extends Resource2 {
187
188
  err
188
189
  }, {
189
190
  F: __dxlog_file2,
190
- L: 107,
191
+ L: 121,
191
192
  S: this,
192
193
  C: (f, a) => f(...a)
193
194
  });
@@ -198,22 +199,41 @@ var EdgeClient = class extends Resource2 {
198
199
  */
199
200
  async _close() {
200
201
  log2("closing...", {
201
- peerKey: this._peerKey
202
+ peerKey: this._identity.peerKey
202
203
  }, {
203
204
  F: __dxlog_file2,
204
- L: 115,
205
+ L: 129,
205
206
  S: this,
206
207
  C: (f, a) => f(...a)
207
208
  });
208
209
  await this._persistentLifecycle.close();
209
210
  }
210
211
  async _openWebSocket() {
211
- const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);
212
- this._ws = new WebSocket(url);
212
+ let protocolHeader;
213
+ if (!DISABLE_AUTH) {
214
+ const challenge = randomBytes(32);
215
+ const credential = await this._identity.presentCredentials({
216
+ challenge
217
+ });
218
+ protocolHeader = encodePresentationIntoAuthHeader(credential);
219
+ }
220
+ const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._config.socketEndpoint);
221
+ log2("Opening websocket", {
222
+ url: url.toString(),
223
+ protocolHeader
224
+ }, {
225
+ F: __dxlog_file2,
226
+ L: 144,
227
+ S: this,
228
+ C: (f, a) => f(...a)
229
+ });
230
+ this._ws = new WebSocket(url, protocolHeader ? [
231
+ protocolHeader
232
+ ] : []);
213
233
  this._ws.onopen = () => {
214
234
  log2("opened", this.info, {
215
235
  F: __dxlog_file2,
216
- L: 124,
236
+ L: 148,
217
237
  S: this,
218
238
  C: (f, a) => f(...a)
219
239
  });
@@ -223,7 +243,7 @@ var EdgeClient = class extends Resource2 {
223
243
  this._ws.onclose = () => {
224
244
  log2("closed", this.info, {
225
245
  F: __dxlog_file2,
226
- L: 129,
246
+ L: 153,
227
247
  S: this,
228
248
  C: (f, a) => f(...a)
229
249
  });
@@ -235,7 +255,7 @@ var EdgeClient = class extends Resource2 {
235
255
  info: event.message
236
256
  }, {
237
257
  F: __dxlog_file2,
238
- L: 133,
258
+ L: 157,
239
259
  S: this,
240
260
  C: (f, a) => f(...a)
241
261
  });
@@ -249,11 +269,11 @@ var EdgeClient = class extends Resource2 {
249
269
  const data = await toUint8Array(event.data);
250
270
  const message = buf.fromBinary(MessageSchema, data);
251
271
  log2("received", {
252
- peerKey: this._peerKey,
272
+ peerKey: this._identity.peerKey,
253
273
  payload: protocol.getPayloadType(message)
254
274
  }, {
255
275
  F: __dxlog_file2,
256
- L: 146,
276
+ L: 170,
257
277
  S: this,
258
278
  C: (f, a) => f(...a)
259
279
  });
@@ -267,7 +287,7 @@ var EdgeClient = class extends Resource2 {
267
287
  payload: protocol.getPayloadType(message)
268
288
  }, {
269
289
  F: __dxlog_file2,
270
- L: 152,
290
+ L: 176,
271
291
  S: this,
272
292
  C: (f, a) => f(...a)
273
293
  });
@@ -280,7 +300,7 @@ var EdgeClient = class extends Resource2 {
280
300
  });
281
301
  this._keepaliveCtx = new Context(void 0, {
282
302
  F: __dxlog_file2,
283
- L: 159
303
+ L: 186
284
304
  });
285
305
  scheduleTaskInterval(this._keepaliveCtx, async () => {
286
306
  this._ws?.send("__ping__");
@@ -315,7 +335,7 @@ var EdgeClient = class extends Resource2 {
315
335
  err
316
336
  }, {
317
337
  F: __dxlog_file2,
318
- L: 195,
338
+ L: 222,
319
339
  S: this,
320
340
  C: (f, a) => f(...a)
321
341
  });
@@ -329,7 +349,7 @@ var EdgeClient = class extends Resource2 {
329
349
  if (this._ready.state !== TriggerState.RESOLVED) {
330
350
  log2("waiting for websocket to become ready", void 0, {
331
351
  F: __dxlog_file2,
332
- L: 205,
352
+ L: 232,
333
353
  S: this,
334
354
  C: (f, a) => f(...a)
335
355
  });
@@ -340,15 +360,15 @@ var EdgeClient = class extends Resource2 {
340
360
  if (!this._ws) {
341
361
  throw new EdgeConnectionClosedError();
342
362
  }
343
- if (message.source && (message.source.peerKey !== this._peerKey || message.source.identityKey !== this.identityKey)) {
363
+ if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
344
364
  throw new EdgeIdentityChangedError();
345
365
  }
346
366
  log2("sending...", {
347
- peerKey: this._peerKey,
367
+ peerKey: this._identity.peerKey,
348
368
  payload: protocol.getPayloadType(message)
349
369
  }, {
350
370
  F: __dxlog_file2,
351
- L: 218,
371
+ L: 245,
352
372
  S: this,
353
373
  C: (f, a) => f(...a)
354
374
  });
@@ -361,18 +381,257 @@ var EdgeClient = class extends Resource2 {
361
381
  void this._heartBeatContext?.dispose();
362
382
  this._heartBeatContext = new Context(void 0, {
363
383
  F: __dxlog_file2,
364
- L: 227
384
+ L: 254
365
385
  });
366
386
  scheduleTask(this._heartBeatContext, () => {
367
387
  this._persistentLifecycle.scheduleRestart();
368
388
  }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
369
389
  }
370
390
  };
391
+ var encodePresentationIntoAuthHeader = (presentation) => {
392
+ const encoded = schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
393
+ const encodedToken = Buffer.from(encoded).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
394
+ return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
395
+ };
396
+
397
+ // packages/core/mesh/edge-client/src/auth.ts
398
+ import { createCredential, signPresentation } from "@dxos/credentials";
399
+ import { Keyring } from "@dxos/keyring";
400
+ import { PublicKey } from "@dxos/keys";
401
+ var createDeviceEdgeIdentity = async (signer, key) => {
402
+ return {
403
+ identityKey: key.toHex(),
404
+ peerKey: key.toHex(),
405
+ presentCredentials: async ({ challenge }) => {
406
+ return signPresentation({
407
+ presentation: {
408
+ credentials: [
409
+ // Verifier requires at least one credential in the presentation to establish the subject.
410
+ await createCredential({
411
+ assertion: {
412
+ "@type": "dxos.halo.credentials.Auth"
413
+ },
414
+ issuer: key,
415
+ subject: key,
416
+ signer
417
+ })
418
+ ]
419
+ },
420
+ signer,
421
+ signerKey: key,
422
+ nonce: challenge
423
+ });
424
+ }
425
+ };
426
+ };
427
+ var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
428
+ const credentialsToSign = credentials.length > 0 ? credentials : [
429
+ await createCredential({
430
+ assertion: {
431
+ "@type": "dxos.halo.credentials.Auth"
432
+ },
433
+ issuer: identityKey,
434
+ subject: identityKey,
435
+ signer,
436
+ chain,
437
+ signingKey: peerKey
438
+ })
439
+ ];
440
+ return {
441
+ identityKey: identityKey.toHex(),
442
+ peerKey: peerKey.toHex(),
443
+ presentCredentials: async ({ challenge }) => {
444
+ return signPresentation({
445
+ presentation: {
446
+ credentials: credentialsToSign
447
+ },
448
+ signer,
449
+ nonce: challenge,
450
+ signerKey: peerKey,
451
+ chain
452
+ });
453
+ }
454
+ };
455
+ };
456
+ var createEphemeralEdgeIdentity = async () => {
457
+ const keyring = new Keyring();
458
+ const key = await keyring.createKey();
459
+ return createDeviceEdgeIdentity(keyring, key);
460
+ };
461
+ var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
462
+ const deviceAdmission = await createCredential({
463
+ assertion: {
464
+ "@type": "dxos.halo.credentials.AuthorizedDevice",
465
+ deviceKey,
466
+ identityKey
467
+ },
468
+ issuer: identityKey,
469
+ subject: deviceKey,
470
+ signer
471
+ });
472
+ return createChainEdgeIdentity(signer, identityKey, deviceKey, {
473
+ credential: deviceAdmission
474
+ }, [
475
+ await createCredential({
476
+ assertion: {
477
+ "@type": "dxos.halo.credentials.Auth"
478
+ },
479
+ issuer: identityKey,
480
+ subject: identityKey,
481
+ signer
482
+ })
483
+ ]);
484
+ };
485
+ var createStubEdgeIdentity = () => {
486
+ const identityKey = PublicKey.random();
487
+ const deviceKey = PublicKey.random();
488
+ return {
489
+ identityKey: identityKey.toHex(),
490
+ peerKey: deviceKey.toHex(),
491
+ presentCredentials: async () => {
492
+ throw new Error("Stub identity does not support authentication.");
493
+ }
494
+ };
495
+ };
496
+
497
+ // packages/core/mesh/edge-client/src/edge-http-client.ts
498
+ import { sleep as sleep2 } from "@dxos/async";
499
+ import { Context as Context2 } from "@dxos/context";
500
+ import { log as log3 } from "@dxos/log";
501
+ import { EdgeCallFailedError } from "@dxos/protocols";
502
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
503
+ var DEFAULT_RETRY_TIMEOUT = 1500;
504
+ var DEFAULT_RETRY_JITTER = 500;
505
+ var DEFAULT_MAX_RETRIES_COUNT = 3;
506
+ var EdgeHttpClient = class {
507
+ constructor(baseUrl) {
508
+ const url = new URL(baseUrl);
509
+ url.protocol = "https";
510
+ this._baseUrl = url.toString();
511
+ log3("created", {
512
+ url: this._baseUrl
513
+ }, {
514
+ F: __dxlog_file3,
515
+ L: 27,
516
+ S: this,
517
+ C: (f, a) => f(...a)
518
+ });
519
+ }
520
+ getCredentialsForNotarization(spaceId, args) {
521
+ return this._call(`/spaces/${spaceId}/notarization`, {
522
+ ...args,
523
+ method: "GET"
524
+ });
525
+ }
526
+ async notarizeCredentials(spaceId, body, args) {
527
+ await this._call(`/spaces/${spaceId}/notarization`, {
528
+ ...args,
529
+ body,
530
+ method: "POST"
531
+ });
532
+ }
533
+ async _call(path, args) {
534
+ const requestContext = args.context ?? new Context2(void 0, {
535
+ F: __dxlog_file3,
536
+ L: 43
537
+ });
538
+ const shouldRetry = createRetryHandler(args);
539
+ const request = createRequest(args);
540
+ const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
541
+ log3.info("call", {
542
+ method: args.method,
543
+ path
544
+ }, {
545
+ F: __dxlog_file3,
546
+ L: 48,
547
+ S: this,
548
+ C: (f, a) => f(...a)
549
+ });
550
+ while (true) {
551
+ let processingError;
552
+ let retryAfterHeaderValue = Number.NaN;
553
+ try {
554
+ const response = await fetch(url, request);
555
+ retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
556
+ if (response.ok) {
557
+ const body = await response.json();
558
+ if (body.success) {
559
+ return body.data;
560
+ }
561
+ const isNonRetryable = body.errorData != null;
562
+ if (isNonRetryable) {
563
+ throw new EdgeCallFailedError(body.reason, body.errorData);
564
+ }
565
+ processingError = new EdgeCallFailedError(body.reason);
566
+ } else {
567
+ processingError = EdgeCallFailedError.fromFailureResponse(response);
568
+ if (!isRetryable(response.status)) {
569
+ throw processingError;
570
+ }
571
+ }
572
+ } catch (error) {
573
+ processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
574
+ }
575
+ if (await shouldRetry(requestContext, retryAfterHeaderValue)) {
576
+ log3.info("retrying edge request", {
577
+ path,
578
+ processingError
579
+ }, {
580
+ F: __dxlog_file3,
581
+ L: 81,
582
+ S: this,
583
+ C: (f, a) => f(...a)
584
+ });
585
+ } else {
586
+ throw processingError;
587
+ }
588
+ }
589
+ }
590
+ };
591
+ var createRequest = (args) => {
592
+ return {
593
+ method: args.method,
594
+ body: args.body && JSON.stringify(args.body)
595
+ };
596
+ };
597
+ var isRetryable = (status) => {
598
+ if (status === 501) {
599
+ return false;
600
+ }
601
+ return !(status >= 400 && status < 500);
602
+ };
603
+ var createRetryHandler = (args) => {
604
+ if (!args.retry || args.retry.count < 1) {
605
+ return async () => false;
606
+ }
607
+ let retries = 0;
608
+ const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
609
+ const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
610
+ const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;
611
+ return async (ctx, retryAfter) => {
612
+ if (++retries > maxRetries || ctx.disposed) {
613
+ return false;
614
+ }
615
+ if (retryAfter) {
616
+ await sleep2(retryAfter);
617
+ } else {
618
+ const timeout = baseTimeout + Math.random() * jitter;
619
+ await sleep2(timeout);
620
+ }
621
+ return true;
622
+ };
623
+ };
371
624
  export {
372
625
  EdgeClient,
373
626
  EdgeConnectionClosedError,
627
+ EdgeHttpClient,
374
628
  EdgeIdentityChangedError,
375
629
  Protocol,
630
+ createChainEdgeIdentity,
631
+ createDeviceEdgeIdentity,
632
+ createEphemeralEdgeIdentity,
633
+ createStubEdgeIdentity,
634
+ createTestHaloEdgeIdentity,
376
635
  getTypename,
377
636
  protocol,
378
637
  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 get isConnected(): 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 isConnected() {\n return Boolean(this._ws) && this._ready.state === TriggerState.RESOLVED;\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;;;ACNrC,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;;;;AFvBb,IAAM6B,kBAAkB;AACxB,IAAMC,4BAA4B;AA2B3B,IAAMC,aAAN,cAAyBC,UAAAA;EAe9BC,YACUC,cACAC,UACSC,SACjB;AACA,UAAK;SAJGF,eAAAA;SACAC,WAAAA;SACSC,UAAAA;SAjBHC,YAAY,IAAIC,MAAAA;SAChBC,YAAY,IAAID,MAAAA;SACfE,uBAAuB,IAAIC,oBAAoB;MAC9DC,OAAO,YAAY,KAAKC,eAAc;MACtCC,MAAM,YAAY,KAAKC,gBAAe;MACtCC,WAAW,YAAY,KAAKT,UAAUU,KAAI;IAC5C,CAAA;SAEiBC,aAAa,oBAAIC,IAAAA;SAC1BC,SAAS,IAAIC,QAAAA;SACbC,MAAkBC;SAClBC,gBAA0BD;SAC1BE,oBAA8BF;EAQtC;;EAGA,IAAWG,OAAO;AAChB,WAAO;MACLC,MAAM,KAAKC;MACXC,UAAU,KAAKzB;MACf0B,QAAQ,KAAKzB;IACf;EACF;EAEA,IAAI0B,cAAc;AAChB,WAAOC,QAAQ,KAAKV,GAAG,KAAK,KAAKF,OAAOa,UAAUC,aAAaC;EACjE;EAEA,IAAIC,cAAc;AAChB,WAAO,KAAKhC;EACd;EAEA,IAAIiC,UAAU;AACZ,WAAO,KAAKhC;EACd;EAEAiC,YAAY,EAAED,SAASD,YAAW,GAA8C;AAC9E,SAAK/B,WAAWgC;AAChB,SAAKjC,eAAegC;AACpB,SAAK1B,qBAAqB6B,gBAAe;EAC3C;EAEOC,YAAYC,UAAuC;AACxD,SAAKvB,WAAWwB,IAAID,QAAAA;AACpB,WAAO,MAAM,KAAKvB,WAAWyB,OAAOF,QAAAA;EACtC;;;;EAKA,MAAyBG,QAAQ;AAC/BC,IAAAA,KAAI,cAAc;MAAEnB,MAAM,KAAKA;IAAK,GAAA;;;;;;AACpC,SAAKhB,qBAAqBiB,KAAI,EAAGmB,MAAM,CAACC,QAAAA;AACtCF,MAAAA,KAAIG,KAAK,kCAAkC;QAAED;MAAI,GAAA;;;;;;IACnD,CAAA;EACF;;;;EAKA,MAAyBE,SAAS;AAChCJ,IAAAA,KAAI,cAAc;MAAER,SAAS,KAAKhC;IAAS,GAAA;;;;;;AAC3C,UAAM,KAAKK,qBAAqBwC,MAAK;EACvC;EAEA,MAAcrC,iBAAiB;AAC7B,UAAMsC,MAAM,IAAIC,IAAI,OAAO,KAAKhD,YAAY,IAAI,KAAKC,QAAQ,IAAI,KAAKC,QAAQ+C,cAAc;AAC5F,SAAK/B,MAAM,IAAIgC,UAAUH,GAAAA;AAEzB,SAAK7B,IAAIiC,SAAS,MAAA;AAChBV,MAAAA,KAAI,UAAU,KAAKnB,MAAI;;;;;;AACvB,WAAKN,OAAOoC,KAAI;AAChB,WAAK/C,UAAUQ,KAAI;IACrB;AACA,SAAKK,IAAImC,UAAU,MAAA;AACjBZ,MAAAA,KAAI,UAAU,KAAKnB,MAAI;;;;;;AACvB,WAAKhB,qBAAqB6B,gBAAe;IAC3C;AACA,SAAKjB,IAAIoC,UAAU,CAACC,UAAAA;AAClBd,MAAAA,KAAIG,KAAK,2BAA2B;QAAEY,OAAOD,MAAMC;QAAOlC,MAAMiC,MAAME;MAAQ,GAAA;;;;;;AAC9E,WAAKnD,qBAAqB6B,gBAAe;IAC3C;AAIA,SAAKjB,IAAIwC,YAAY,OAAOH,UAAAA;AAC1B,UAAIA,MAAMI,SAAS,YAAY;AAC7B,aAAKC,aAAY;AACjB;MACF;AACA,YAAMD,OAAO,MAAME,aAAaN,MAAMI,IAAI;AAC1C,YAAMF,UAAUK,IAAIC,WAAWC,eAAeL,IAAAA;AAC9ClB,MAAAA,KAAI,YAAY;QAAER,SAAS,KAAKhC;QAAUgE,SAASC,SAASC,eAAeV,OAAAA;MAAS,GAAA;;;;;;AACpF,UAAIA,SAAS;AACX,mBAAWpB,YAAY,KAAKvB,YAAY;AACtC,cAAI;AACF,kBAAMuB,SAASoB,OAAAA;UACjB,SAASd,KAAK;AACZF,YAAAA,KAAIe,MAAM,cAAc;cAAEb;cAAKsB,SAASC,SAASC,eAAeV,OAAAA;YAAS,GAAA;;;;;;UAC3E;QACF;MACF;IACF;AAEA,UAAM,KAAKzC,OAAOoD,KAAK;MAAEC,SAAS,KAAKnE,QAAQmE,WAAW1E;IAAgB,CAAA;AAC1E,SAAKyB,gBAAgB,IAAIkD,QAAAA,QAAAA;;;;AACzBC,yBACE,KAAKnD,eACL,YAAA;AAGE,WAAKF,KAAKsD,KAAK,UAAA;IACjB,GACA5E,yBAAAA;AAEF,SAAKsB,IAAIsD,KAAK,UAAA;AACd,SAAKZ,aAAY;EACnB;EAEA,MAAcjD,kBAAkB;AAC9B,QAAI,CAAC,KAAKO,KAAK;AACb;IACF;AACA,QAAI;AACF,WAAKF,OAAOyD,MAAM,KAAKjD,SAAS,IAAIkD,yBAAAA,IAA6B,IAAIC,0BAAAA,CAAAA;AACrE,WAAK3D,OAAO4D,MAAK;AACjB,WAAK,KAAKxD,eAAeyD,QAAAA;AACzB,WAAKzD,gBAAgBD;AACrB,WAAK,KAAKE,mBAAmBwD,QAAAA;AAC7B,WAAKxD,oBAAoBF;AAGzB,WAAKD,IAAIiC,SAAS,MAAA;MAAO;AACzB,WAAKjC,IAAImC,UAAU,MAAA;MAAO;AAC1B,WAAKnC,IAAIoC,UAAU,MAAA;MAAO;AAC1B,WAAKpC,IAAI4B,MAAK;AACd,WAAK5B,MAAMC;IACb,SAASwB,KAAK;AACZ,UAAIA,eAAemC,SAASnC,IAAIc,QAAQsB,SAAS,2DAAA,GAA8D;AAC7G;MACF;AACAtC,MAAAA,KAAIG,KAAK,2BAA2B;QAAED;MAAI,GAAA;;;;;;IAC5C;EACF;;;;;EAMA,MAAa6B,KAAKf,SAAiC;AACjD,QAAI,KAAKzC,OAAOa,UAAUC,aAAaC,UAAU;AAC/CU,MAAAA,KAAI,yCAAA,QAAA;;;;;;AACJ,YAAM,KAAKzB,OAAOoD,KAAK;QAAEC,SAAS,KAAKnE,QAAQmE,WAAW1E;MAAgB,CAAA;IAC5E;AACA,QAAI,CAAC,KAAKuB,KAAK;AACb,YAAM,IAAIyD,0BAAAA;IACZ;AACA,QACElB,QAAQuB,WACPvB,QAAQuB,OAAO/C,YAAY,KAAKhC,YAAYwD,QAAQuB,OAAOhD,gBAAgB,KAAKA,cACjF;AACA,YAAM,IAAI0C,yBAAAA;IACZ;AAEAjC,IAAAA,KAAI,cAAc;MAAER,SAAS,KAAKhC;MAAUgE,SAASC,SAASC,eAAeV,OAAAA;IAAS,GAAA;;;;;;AACtF,SAAKvC,IAAIsD,KAAKV,IAAImB,SAASjB,eAAeP,OAAAA,CAAAA;EAC5C;EAEQG,eAAe;AACrB,QAAI,KAAKsB,oBAAoBC,gBAAeC,MAAM;AAChD;IACF;AACA,SAAK,KAAK/D,mBAAmBwD,QAAAA;AAC7B,SAAKxD,oBAAoB,IAAIiD,QAAAA,QAAAA;;;;AAC7Be,iBACE,KAAKhE,mBACL,MAAA;AACE,WAAKf,qBAAqB6B,gBAAe;IAC3C,GACA,IAAIvC,yBAAAA;EAER;AACF;",
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", "EdgeClient", "Resource", "constructor", "_identityKey", "_peerKey", "_config", "reconnect", "Event", "connected", "_persistentLifecycle", "PersistentLifecycle", "start", "_openWebSocket", "stop", "_closeWebSocket", "onRestart", "emit", "_listeners", "Set", "_ready", "Trigger", "_ws", "undefined", "_keepaliveCtx", "_heartBeatContext", "info", "open", "isOpen", "identity", "device", "isConnected", "Boolean", "state", "TriggerState", "RESOLVED", "identityKey", "peerKey", "setIdentity", "scheduleRestart", "addListener", "listener", "add", "delete", "_open", "log", "catch", "err", "warn", "_close", "close", "url", "URL", "socketEndpoint", "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"]
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
  }