@dxos/edge-client 0.6.8-main.3be982f → 0.6.8-staging.63bcb81

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.
@@ -4,12 +4,14 @@ export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
4
4
  // packages/core/mesh/edge-client/src/client.ts
5
5
  import WebSocket from "isomorphic-ws";
6
6
  import { Trigger } from "@dxos/async";
7
+ import { LifecycleState, Resource } from "@dxos/context";
7
8
  import { invariant as invariant2 } from "@dxos/invariant";
8
9
  import { log } from "@dxos/log";
9
10
  import { buf as buf2 } from "@dxos/protocols/buf";
10
11
  import { MessageSchema as MessageSchema2 } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
11
12
 
12
13
  // packages/core/mesh/edge-client/src/defs.ts
14
+ import { AnySchema } from "@bufbuild/protobuf/wkt";
13
15
  import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
14
16
 
15
17
  // packages/core/mesh/edge-client/src/protocol.ts
@@ -112,18 +114,23 @@ var toUint8Array = async (data) => {
112
114
  var protocol = new Protocol([
113
115
  SwarmRequestSchema,
114
116
  SwarmResponseSchema,
115
- TextMessageSchema
117
+ TextMessageSchema,
118
+ AnySchema
116
119
  ]);
117
120
 
118
121
  // packages/core/mesh/edge-client/src/client.ts
119
122
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/client.ts";
120
123
  var DEFAULT_TIMEOUT = 5e3;
121
- var EdgeClient = class {
124
+ var EdgeClient = class extends Resource {
122
125
  constructor(_identityKey, _deviceKey, _config) {
126
+ super();
123
127
  this._identityKey = _identityKey;
124
128
  this._deviceKey = _deviceKey;
125
129
  this._config = _config;
126
130
  this._listeners = /* @__PURE__ */ new Set();
131
+ this._reconnect = void 0;
132
+ this._ready = new Trigger();
133
+ this._ws = void 0;
127
134
  this._protocol = this._config.protocol ?? protocol;
128
135
  }
129
136
  // TODO(burdon): Attach logging.
@@ -141,7 +148,19 @@ var EdgeClient = class {
141
148
  return this._deviceKey;
142
149
  }
143
150
  get isOpen() {
144
- return !!this._ws;
151
+ return this._lifecycleState === LifecycleState.OPEN;
152
+ }
153
+ setIdentity({ deviceKey, identityKey }) {
154
+ this._deviceKey = deviceKey;
155
+ this._identityKey = identityKey;
156
+ this._reconnect = this._closeWebSocket().then(async () => {
157
+ await this._openWebSocket();
158
+ }).catch((err) => log.catch(err, void 0, {
159
+ F: __dxlog_file2,
160
+ L: 87,
161
+ S: this,
162
+ C: (f, a) => f(...a)
163
+ }));
145
164
  }
146
165
  addListener(listener) {
147
166
  this._listeners.add(listener);
@@ -150,13 +169,17 @@ var EdgeClient = class {
150
169
  /**
151
170
  * Open connection to messaging service.
152
171
  */
153
- async open() {
154
- invariant2(!this._ws, void 0, {
172
+ async _open() {
173
+ await this._reconnect;
174
+ if (this._ws) {
175
+ return;
176
+ }
177
+ invariant2(this._deviceKey && this._identityKey, void 0, {
155
178
  F: __dxlog_file2,
156
- L: 88,
179
+ L: 103,
157
180
  S: this,
158
181
  A: [
159
- "!this._ws",
182
+ "this._deviceKey && this._identityKey",
160
183
  ""
161
184
  ]
162
185
  });
@@ -164,40 +187,72 @@ var EdgeClient = class {
164
187
  info: this.info
165
188
  }, {
166
189
  F: __dxlog_file2,
167
- L: 89,
190
+ L: 104,
191
+ S: this,
192
+ C: (f, a) => f(...a)
193
+ });
194
+ await this._openWebSocket();
195
+ log.info("opened", {
196
+ info: this.info
197
+ }, {
198
+ F: __dxlog_file2,
199
+ L: 108,
200
+ S: this,
201
+ C: (f, a) => f(...a)
202
+ });
203
+ }
204
+ /**
205
+ * Close connection and free resources.
206
+ */
207
+ async _close() {
208
+ log("closing...", {
209
+ deviceKey: this._deviceKey
210
+ }, {
211
+ F: __dxlog_file2,
212
+ L: 115,
213
+ S: this,
214
+ C: (f, a) => f(...a)
215
+ });
216
+ await this._reconnect;
217
+ await this._closeWebSocket();
218
+ log("closed", {
219
+ deviceKey: this._deviceKey
220
+ }, {
221
+ F: __dxlog_file2,
222
+ L: 118,
168
223
  S: this,
169
224
  C: (f, a) => f(...a)
170
225
  });
171
- const ready = new Trigger();
226
+ }
227
+ async _openWebSocket() {
172
228
  const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);
173
229
  this._ws = new WebSocket(url);
174
230
  Object.assign(this._ws, {
175
231
  onopen: () => {
176
- log.info("opened", this.info, {
232
+ log("opened", this.info, {
177
233
  F: __dxlog_file2,
178
- L: 97,
234
+ L: 126,
179
235
  S: this,
180
236
  C: (f, a) => f(...a)
181
237
  });
182
- ready.wake(true);
238
+ this._ready.wake();
183
239
  },
184
240
  onclose: () => {
185
- log.info("closed", this.info, {
241
+ log("closed", this.info, {
186
242
  F: __dxlog_file2,
187
- L: 102,
243
+ L: 131,
188
244
  S: this,
189
245
  C: (f, a) => f(...a)
190
246
  });
191
- ready.wake(false);
192
247
  },
193
248
  onerror: (event) => {
194
249
  log.catch(event.error, this.info, {
195
250
  F: __dxlog_file2,
196
- L: 107,
251
+ L: 135,
197
252
  S: this,
198
253
  C: (f, a) => f(...a)
199
254
  });
200
- ready.throw(event.error);
255
+ this._ready.throw(event.error);
201
256
  },
202
257
  /**
203
258
  * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data
@@ -210,7 +265,7 @@ var EdgeClient = class {
210
265
  payload: protocol.getPayloadType(message)
211
266
  }, {
212
267
  F: __dxlog_file2,
213
- L: 117,
268
+ L: 145,
214
269
  S: this,
215
270
  C: (f, a) => f(...a)
216
271
  });
@@ -224,7 +279,7 @@ var EdgeClient = class {
224
279
  payload: protocol.getPayloadType(message)
225
280
  }, {
226
281
  F: __dxlog_file2,
227
- L: 123,
282
+ L: 151,
228
283
  S: this,
229
284
  C: (f, a) => f(...a)
230
285
  });
@@ -233,43 +288,14 @@ var EdgeClient = class {
233
288
  }
234
289
  }
235
290
  });
236
- const result = await ready.wait({
291
+ await this._ready.wait({
237
292
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
238
293
  });
239
- log.info("opened", {
240
- info: this.info
241
- }, {
242
- F: __dxlog_file2,
243
- L: 131,
244
- S: this,
245
- C: (f, a) => f(...a)
246
- });
247
- return result;
248
294
  }
249
- /**
250
- * Close connection and free resources.
251
- */
252
- async close() {
253
- if (this._ws) {
254
- log.info("closing...", {
255
- deviceKey: this._deviceKey
256
- }, {
257
- F: __dxlog_file2,
258
- L: 140,
259
- S: this,
260
- C: (f, a) => f(...a)
261
- });
262
- this._ws.close();
263
- this._ws = void 0;
264
- log.info("closed", {
265
- deviceKey: this._deviceKey
266
- }, {
267
- F: __dxlog_file2,
268
- L: 143,
269
- S: this,
270
- C: (f, a) => f(...a)
271
- });
272
- }
295
+ async _closeWebSocket() {
296
+ this._ready.reset();
297
+ this._ws.close();
298
+ this._ws = void 0;
273
299
  }
274
300
  /**
275
301
  * Send message.
@@ -277,21 +303,33 @@ var EdgeClient = class {
277
303
  */
278
304
  // TODO(burdon): Implement ACK?
279
305
  async send(message) {
306
+ await this._ready.wait({
307
+ timeout: this._config.timeout ?? DEFAULT_TIMEOUT
308
+ });
280
309
  invariant2(this._ws, void 0, {
281
310
  F: __dxlog_file2,
282
- L: 153,
311
+ L: 174,
283
312
  S: this,
284
313
  A: [
285
314
  "this._ws",
286
315
  ""
287
316
  ]
288
317
  });
318
+ invariant2(!message.source || message.source.peerKey === this._deviceKey.toHex(), void 0, {
319
+ F: __dxlog_file2,
320
+ L: 175,
321
+ S: this,
322
+ A: [
323
+ "!message.source || message.source.peerKey === this._deviceKey.toHex()",
324
+ ""
325
+ ]
326
+ });
289
327
  log("sending...", {
290
328
  deviceKey: this._deviceKey,
291
329
  payload: protocol.getPayloadType(message)
292
330
  }, {
293
331
  F: __dxlog_file2,
294
- L: 154,
332
+ L: 176,
295
333
  S: this,
296
334
  C: (f, a) => f(...a)
297
335
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts", "../../../src/client.ts", "../../../src/defs.ts", "../../../src/protocol.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './client';\nexport * from './defs';\nexport * from './protocol';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger } from '@dxos/async';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\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 { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\n/**\n *\n */\nexport interface EdgeConnection {\n get info(): any;\n get identityKey(): PublicKey;\n get deviceKey(): PublicKey;\n get isOpen(): boolean;\n addListener(listener: MessageListener): () => void;\n open(): Promise<boolean>;\n close(): Promise<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 */\n// TODO(dmaretskyi): Rename EdgeClient.\nexport class EdgeClient implements EdgeConnection {\n private readonly _listeners: Set<MessageListener> = new Set();\n private readonly _protocol: Protocol;\n private _ws?: WebSocket;\n\n constructor(\n private readonly _identityKey: PublicKey,\n private readonly _deviceKey: PublicKey,\n private readonly _config: MessengerConfig,\n ) {\n this._protocol = this._config.protocol ?? protocol;\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._deviceKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get deviceKey() {\n return this._deviceKey;\n }\n\n public get isOpen() {\n return !!this._ws;\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 public async open(): Promise<boolean> {\n invariant(!this._ws);\n log.info('opening...', { info: this.info });\n const ready = new Trigger<boolean>();\n\n // TODO: handle reconnects\n const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n Object.assign<WebSocket, Partial<WebSocket>>(this._ws, {\n onopen: () => {\n log.info('opened', this.info);\n ready.wake(true);\n },\n\n onclose: () => {\n log.info('closed', this.info);\n ready.wake(false);\n },\n\n onerror: (event) => {\n log.catch(event.error, this.info);\n ready.throw(event.error);\n },\n\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n onmessage: async (event) => {\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { deviceKey: this._deviceKey, 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\n const result = await ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n log.info('opened', { info: this.info });\n return result;\n }\n\n /**\n * Close connection and free resources.\n */\n public async close() {\n if (this._ws) {\n log.info('closing...', { deviceKey: this._deviceKey });\n this._ws.close();\n this._ws = undefined;\n log.info('closed', { deviceKey: this._deviceKey });\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 // TODO(burdon): Implement ACK?\n public async send(message: Message): Promise<void> {\n invariant(this._ws);\n log('sending...', { deviceKey: this._deviceKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = Partial<PeerProto>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n"],
5
- "mappings": "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",
6
- "names": ["WebSocket", "Trigger", "invariant", "log", "buf", "MessageSchema", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "invariant", "buf", "bufWkt", "MessageSchema", "bufferToArray", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "createRegistry", "typeRegistry", "toJson", "message", "registry", "err", "type", "getPayloadType", "getPayload", "payload", "payloadTypename", "Error", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "Blob", "Uint8Array", "arrayBuffer", "protocol", "Protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "DEFAULT_TIMEOUT", "EdgeClient", "constructor", "_identityKey", "_deviceKey", "_config", "_listeners", "Set", "_protocol", "protocol", "info", "open", "isOpen", "identity", "device", "identityKey", "deviceKey", "_ws", "addListener", "listener", "add", "delete", "invariant", "log", "ready", "Trigger", "url", "URL", "toHex", "socketEndpoint", "WebSocket", "Object", "assign", "onopen", "wake", "onclose", "onerror", "event", "catch", "error", "throw", "onmessage", "data", "toUint8Array", "message", "buf", "fromBinary", "MessageSchema", "payload", "getPayloadType", "err", "result", "wait", "timeout", "close", "undefined", "send", "toBinary"]
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './client';\nexport * from './defs';\nexport * from './protocol';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger } from '@dxos/async';\nimport { LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\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 { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n get info(): any;\n get identityKey(): PublicKey;\n get deviceKey(): PublicKey;\n get isOpen(): boolean;\n setIdentity(params: { deviceKey: PublicKey; identityKey: PublicKey }): 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 */\n// TODO(dmaretskyi): Rename EdgeClient.\n// TODO(mykola): Handle reconnections.\nexport class EdgeClient extends Resource implements EdgeConnection {\n private readonly _listeners = new Set<MessageListener>();\n private _reconnect?: Promise<void> = undefined;\n private readonly _protocol: Protocol;\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n\n constructor(\n private _identityKey: PublicKey,\n private _deviceKey: PublicKey,\n private readonly _config: MessengerConfig,\n ) {\n super();\n this._protocol = this._config.protocol ?? protocol;\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._deviceKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get deviceKey() {\n return this._deviceKey;\n }\n\n public get isOpen() {\n return this._lifecycleState === LifecycleState.OPEN;\n }\n\n setIdentity({ deviceKey, identityKey }: { deviceKey: PublicKey; identityKey: PublicKey }) {\n this._deviceKey = deviceKey;\n this._identityKey = identityKey;\n this._reconnect = this._closeWebSocket()\n .then(async () => {\n await this._openWebSocket();\n })\n .catch((err) => log.catch(err));\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 await this._reconnect;\n if (this._ws) {\n return;\n }\n invariant(this._deviceKey && this._identityKey);\n log.info('opening...', { info: this.info });\n\n // TODO: handle reconnects\n await this._openWebSocket();\n log.info('opened', { info: this.info });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { deviceKey: this._deviceKey });\n await this._reconnect;\n await this._closeWebSocket();\n log('closed', { deviceKey: this._deviceKey });\n }\n\n private async _openWebSocket() {\n const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n Object.assign<WebSocket, Partial<WebSocket>>(this._ws, {\n onopen: () => {\n log('opened', this.info);\n this._ready.wake();\n },\n\n onclose: () => {\n log('closed', this.info);\n },\n\n onerror: (event) => {\n log.catch(event.error, this.info);\n this._ready.throw(event.error);\n },\n\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n onmessage: async (event) => {\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { deviceKey: this._deviceKey, 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\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n\n private async _closeWebSocket() {\n this._ready.reset();\n this._ws!.close();\n this._ws = undefined;\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 // TODO(burdon): Implement ACK?\n public async send(message: Message): Promise<void> {\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n invariant(this._ws);\n invariant(!message.source || message.source.peerKey === this._deviceKey.toHex());\n log('sending...', { deviceKey: this._deviceKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AnySchema } from '@bufbuild/protobuf/wkt';\n\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, AnySchema]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = Partial<PeerProto>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n"],
5
+ "mappings": ";AAIA,cAAc;;;ACAd,OAAOA,eAAe;AAEtB,SAASC,eAAe;AACxB,SAASC,gBAAgBC,gBAAgC;AACzD,SAASC,aAAAA,kBAAiB;AAE1B,SAASC,WAAW;AACpB,SAASC,OAAAA,YAAW;AACpB,SAAuBC,iBAAAA,sBAAqB;;;ACR5C,SAASC,iBAAiB;AAE1B,SAASC,oBAAoBC,qBAAqBC,yBAAyB;;;ACF3E,SAASC,iBAAiB;AAC1B,SAASC,KAAKC,cAAc;AAC5B,SAAuBC,qBAA6C;AACpE,SAASC,qBAAqB;;AAIvB,IAAMC,cAAc,CAACC,aAAqB,uBAAuBA,QAAAA;AAKjE,IAAMC,WAAN,MAAMA;EAGXC,YAAYC,OAA0B;AACpC,SAAKC,gBAAgBT,IAAIU,eAAc,GAAIF,KAAAA;EAC7C;EAEA,IAAIG,eAA6B;AAC/B,WAAO,KAAKF;EACd;EAEAG,OAAOC,SAAuB;AAC5B,QAAI;AACF,aAAOb,IAAIY,OAAOV,eAAeW,SAAS;QAAEC,UAAU,KAAKH;MAAa,CAAA;IAC1E,SAASI,KAAK;AACZ,aAAO;QAAEC,MAAM,KAAKC,eAAeJ,OAAAA;MAAS;IAC9C;EACF;;;;EAKAK,WAAyCL,SAAkBG,MAAoC;AAC7FjB,cAAUc,QAAQM,SAAO,QAAA;;;;;;;;;AACzB,UAAMC,kBAAkB,KAAKH,eAAeJ,OAAAA;AAC5C,QAAIG,QAAQA,KAAKX,aAAae,iBAAiB;AAC7C,YAAM,IAAIC,MAAM,4BAA4BD,eAAAA,cAA6BJ,KAAKX,QAAQ,EAAE;IAC1F;AAEAN,cAAUE,OAAOqB,MAAMT,QAAQM,SAASH,IAAAA,GAAO,4BAA4BI,eAAAA,KAAkB;;;;;;;;;AAC7F,UAAMD,UAAUlB,OAAOsB,UAAUV,QAAQM,SAAS,KAAKR,YAAY;AACnEZ,cAAUoB,SAAS,kBAAkBC,eAAAA,KAAkB;;;;;;;;;AACvD,WAAOD;EACT;;;;EAKAF,eAAeJ,SAAsC;AACnD,QAAI,CAACA,QAAQM,SAAS;AACpB,aAAOK;IACT;AAEA,UAAM,CAAA,EAAGR,IAAAA,IAAQH,QAAQM,QAAQM,QAAQC,MAAM,GAAA;AAC/C,WAAOV;EACT;;;;EAKAW,cACEX,MACA,EACEY,QACAC,QACAV,SACAW,UAAS,GAOX;AACA,WAAO9B,IAAI+B,OAAO7B,eAAe;MAC/B8B,YAAW,oBAAIC,KAAAA,GAAOC,YAAW;MACjCN;MACAC;MACAC;MACAX,SAASA,UAAUlB,OAAOkC,QAAQnB,MAAMhB,IAAI+B,OAAOf,MAAMG,OAAAA,CAAAA,IAAYK;IACvE,CAAA;EACF;AACF;AAKO,IAAMY,eAAe,OAAOC,SAAAA;AAEjC,MAAIA,gBAAgBC,QAAQ;AAC1B,WAAOnC,cAAckC,IAAAA;EACvB;AAGA,MAAIA,gBAAgBE,MAAM;AACxB,WAAO,IAAIC,WAAW,MAAOH,KAAcI,YAAW,CAAA;EACxD;AAEA,QAAM,IAAIpB,MAAM,wBAAwBgB,IAAAA,EAAM;AAChD;;;AD/FO,IAAMK,WAAW,IAAIC,SAAS;EAACC;EAAoBC;EAAqBC;EAAmBC;CAAU;;;;ADO5G,IAAMC,kBAAkB;AAyBjB,IAAMC,aAAN,cAAyBC,SAAAA;EAO9BC,YACUC,cACAC,YACSC,SACjB;AACA,UAAK;SAJGF,eAAAA;SACAC,aAAAA;SACSC,UAAAA;SATFC,aAAa,oBAAIC,IAAAA;SAC1BC,aAA6BC;SAE7BC,SAAS,IAAIC,QAAAA;SACbC,MAAkBH;AAQxB,SAAKI,YAAY,KAAKR,QAAQS,YAAYA;EAC5C;;EAGA,IAAWC,OAAO;AAChB,WAAO;MACLC,MAAM,KAAKC;MACXC,UAAU,KAAKf;MACfgB,QAAQ,KAAKf;IACf;EACF;EAEA,IAAIgB,cAAc;AAChB,WAAO,KAAKjB;EACd;EAEA,IAAIkB,YAAY;AACd,WAAO,KAAKjB;EACd;EAEA,IAAWa,SAAS;AAClB,WAAO,KAAKK,oBAAoBC,eAAeC;EACjD;EAEAC,YAAY,EAAEJ,WAAWD,YAAW,GAAsD;AACxF,SAAKhB,aAAaiB;AAClB,SAAKlB,eAAeiB;AACpB,SAAKZ,aAAa,KAAKkB,gBAAe,EACnCC,KAAK,YAAA;AACJ,YAAM,KAAKC,eAAc;IAC3B,CAAA,EACCC,MAAM,CAACC,QAAQC,IAAIF,MAAMC,KAAAA,QAAAA;;;;;;EAC9B;EAEOE,YAAYC,UAAuC;AACxD,SAAK3B,WAAW4B,IAAID,QAAAA;AACpB,WAAO,MAAM,KAAK3B,WAAW6B,OAAOF,QAAAA;EACtC;;;;EAKA,MAAyBG,QAAQ;AAC/B,UAAM,KAAK5B;AACX,QAAI,KAAKI,KAAK;AACZ;IACF;AACAyB,IAAAA,WAAU,KAAKjC,cAAc,KAAKD,cAAY,QAAA;;;;;;;;;AAC9C4B,QAAIhB,KAAK,cAAc;MAAEA,MAAM,KAAKA;IAAK,GAAA;;;;;;AAGzC,UAAM,KAAKa,eAAc;AACzBG,QAAIhB,KAAK,UAAU;MAAEA,MAAM,KAAKA;IAAK,GAAA;;;;;;EACvC;;;;EAKA,MAAyBuB,SAAS;AAChCP,QAAI,cAAc;MAAEV,WAAW,KAAKjB;IAAW,GAAA;;;;;;AAC/C,UAAM,KAAKI;AACX,UAAM,KAAKkB,gBAAe;AAC1BK,QAAI,UAAU;MAAEV,WAAW,KAAKjB;IAAW,GAAA;;;;;;EAC7C;EAEA,MAAcwB,iBAAiB;AAC7B,UAAMW,MAAM,IAAIC,IAAI,OAAO,KAAKrC,aAAasC,MAAK,CAAA,IAAM,KAAKrC,WAAWqC,MAAK,CAAA,IAAM,KAAKpC,QAAQqC,cAAc;AAC9G,SAAK9B,MAAM,IAAI+B,UAAUJ,GAAAA;AACzBK,WAAOC,OAAsC,KAAKjC,KAAK;MACrDkC,QAAQ,MAAA;AACNf,YAAI,UAAU,KAAKhB,MAAI;;;;;;AACvB,aAAKL,OAAOqC,KAAI;MAClB;MAEAC,SAAS,MAAA;AACPjB,YAAI,UAAU,KAAKhB,MAAI;;;;;;MACzB;MAEAkC,SAAS,CAACC,UAAAA;AACRnB,YAAIF,MAAMqB,MAAMC,OAAO,KAAKpC,MAAI;;;;;;AAChC,aAAKL,OAAO0C,MAAMF,MAAMC,KAAK;MAC/B;;;;MAKAE,WAAW,OAAOH,UAAAA;AAChB,cAAMI,OAAO,MAAMC,aAAaL,MAAMI,IAAI;AAC1C,cAAME,UAAUC,KAAIC,WAAWC,gBAAeL,IAAAA;AAC9CvB,YAAI,YAAY;UAAEV,WAAW,KAAKjB;UAAYwD,SAAS9C,SAAS+C,eAAeL,OAAAA;QAAS,GAAA;;;;;;AACxF,YAAIA,SAAS;AACX,qBAAWvB,YAAY,KAAK3B,YAAY;AACtC,gBAAI;AACF,oBAAM2B,SAASuB,OAAAA;YACjB,SAAS1B,KAAK;AACZC,kBAAIoB,MAAM,cAAc;gBAAErB;gBAAK8B,SAAS9C,SAAS+C,eAAeL,OAAAA;cAAS,GAAA;;;;;;YAC3E;UACF;QACF;MACF;IACF,CAAA;AAEA,UAAM,KAAK9C,OAAOoD,KAAK;MAAEC,SAAS,KAAK1D,QAAQ0D,WAAWhE;IAAgB,CAAA;EAC5E;EAEA,MAAc2B,kBAAkB;AAC9B,SAAKhB,OAAOsD,MAAK;AACjB,SAAKpD,IAAKqD,MAAK;AACf,SAAKrD,MAAMH;EACb;;;;;;EAOA,MAAayD,KAAKV,SAAiC;AACjD,UAAM,KAAK9C,OAAOoD,KAAK;MAAEC,SAAS,KAAK1D,QAAQ0D,WAAWhE;IAAgB,CAAA;AAC1EsC,IAAAA,WAAU,KAAKzB,KAAG,QAAA;;;;;;;;;AAClByB,IAAAA,WAAU,CAACmB,QAAQW,UAAUX,QAAQW,OAAOC,YAAY,KAAKhE,WAAWqC,MAAK,GAAA,QAAA;;;;;;;;;AAC7EV,QAAI,cAAc;MAAEV,WAAW,KAAKjB;MAAYwD,SAAS9C,SAAS+C,eAAeL,OAAAA;IAAS,GAAA;;;;;;AAC1F,SAAK5C,IAAIsD,KAAKT,KAAIY,SAASV,gBAAeH,OAAAA,CAAAA;EAC5C;AACF;",
6
+ "names": ["WebSocket", "Trigger", "LifecycleState", "Resource", "invariant", "log", "buf", "MessageSchema", "AnySchema", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "invariant", "buf", "bufWkt", "MessageSchema", "bufferToArray", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "createRegistry", "typeRegistry", "toJson", "message", "registry", "err", "type", "getPayloadType", "getPayload", "payload", "payloadTypename", "Error", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "Blob", "Uint8Array", "arrayBuffer", "protocol", "Protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "AnySchema", "DEFAULT_TIMEOUT", "EdgeClient", "Resource", "constructor", "_identityKey", "_deviceKey", "_config", "_listeners", "Set", "_reconnect", "undefined", "_ready", "Trigger", "_ws", "_protocol", "protocol", "info", "open", "isOpen", "identity", "device", "identityKey", "deviceKey", "_lifecycleState", "LifecycleState", "OPEN", "setIdentity", "_closeWebSocket", "then", "_openWebSocket", "catch", "err", "log", "addListener", "listener", "add", "delete", "_open", "invariant", "_close", "url", "URL", "toHex", "socketEndpoint", "WebSocket", "Object", "assign", "onopen", "wake", "onclose", "onerror", "event", "error", "throw", "onmessage", "data", "toUint8Array", "message", "buf", "fromBinary", "MessageSchema", "payload", "getPayloadType", "wait", "timeout", "reset", "close", "send", "source", "peerKey", "toBinary"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10314,"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":1359,"imports":[{"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/client.ts":{"bytes":16849,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","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/index.ts":{"bytes":836,"imports":[{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/client.ts","kind":"import-statement","original":"./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"}],"format":"esm"}},"outputs":{"packages/core/mesh/edge-client/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":13078},"packages/core/mesh/edge-client/dist/lib/browser/index.mjs":{"imports":[{"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/invariant","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/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"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}],"exports":["EdgeClient","Protocol","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/client.ts":{"bytesInOutput":4723},"packages/core/mesh/edge-client/src/defs.ts":{"bytesInOutput":220},"packages/core/mesh/edge-client/src/protocol.ts":{"bytesInOutput":2600}},"bytes":8008}}}
1
+ {"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10314,"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":1578,"imports":[{"path":"@bufbuild/protobuf/wkt","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/client.ts":{"bytes":20675,"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/invariant","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/index.ts":{"bytes":836,"imports":[{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/client.ts","kind":"import-statement","original":"./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"}],"format":"esm"}},"outputs":{"packages/core/mesh/edge-client/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":14946},"packages/core/mesh/edge-client/dist/lib/browser/index.mjs":{"imports":[{"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/invariant","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":"@bufbuild/protobuf/wkt","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"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}],"exports":["EdgeClient","Protocol","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/client.ts":{"bytesInOutput":5789},"packages/core/mesh/edge-client/src/defs.ts":{"bytesInOutput":285},"packages/core/mesh/edge-client/src/protocol.ts":{"bytesInOutput":2600}},"bytes":9139}}}
@@ -39,10 +39,12 @@ module.exports = __toCommonJS(node_exports);
39
39
  __reExport(node_exports, require("@dxos/protocols/buf/dxos/edge/messenger_pb"), module.exports);
40
40
  var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
41
41
  var import_async = require("@dxos/async");
42
+ var import_context = require("@dxos/context");
42
43
  var import_invariant = require("@dxos/invariant");
43
44
  var import_log = require("@dxos/log");
44
45
  var import_buf = require("@dxos/protocols/buf");
45
46
  var import_messenger_pb = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
47
+ var import_wkt = require("@bufbuild/protobuf/wkt");
46
48
  var import_messenger_pb2 = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
47
49
  var import_invariant2 = require("@dxos/invariant");
48
50
  var import_buf2 = require("@dxos/protocols/buf");
@@ -141,16 +143,21 @@ var toUint8Array = async (data) => {
141
143
  var protocol = new Protocol([
142
144
  import_messenger_pb2.SwarmRequestSchema,
143
145
  import_messenger_pb2.SwarmResponseSchema,
144
- import_messenger_pb2.TextMessageSchema
146
+ import_messenger_pb2.TextMessageSchema,
147
+ import_wkt.AnySchema
145
148
  ]);
146
149
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/client.ts";
147
150
  var DEFAULT_TIMEOUT = 5e3;
148
- var EdgeClient = class {
151
+ var EdgeClient = class extends import_context.Resource {
149
152
  constructor(_identityKey, _deviceKey, _config) {
153
+ super();
150
154
  this._identityKey = _identityKey;
151
155
  this._deviceKey = _deviceKey;
152
156
  this._config = _config;
153
157
  this._listeners = /* @__PURE__ */ new Set();
158
+ this._reconnect = void 0;
159
+ this._ready = new import_async.Trigger();
160
+ this._ws = void 0;
154
161
  this._protocol = this._config.protocol ?? protocol;
155
162
  }
156
163
  // TODO(burdon): Attach logging.
@@ -168,7 +175,19 @@ var EdgeClient = class {
168
175
  return this._deviceKey;
169
176
  }
170
177
  get isOpen() {
171
- return !!this._ws;
178
+ return this._lifecycleState === import_context.LifecycleState.OPEN;
179
+ }
180
+ setIdentity({ deviceKey, identityKey }) {
181
+ this._deviceKey = deviceKey;
182
+ this._identityKey = identityKey;
183
+ this._reconnect = this._closeWebSocket().then(async () => {
184
+ await this._openWebSocket();
185
+ }).catch((err) => import_log.log.catch(err, void 0, {
186
+ F: __dxlog_file2,
187
+ L: 87,
188
+ S: this,
189
+ C: (f, a) => f(...a)
190
+ }));
172
191
  }
173
192
  addListener(listener) {
174
193
  this._listeners.add(listener);
@@ -177,13 +196,17 @@ var EdgeClient = class {
177
196
  /**
178
197
  * Open connection to messaging service.
179
198
  */
180
- async open() {
181
- (0, import_invariant.invariant)(!this._ws, void 0, {
199
+ async _open() {
200
+ await this._reconnect;
201
+ if (this._ws) {
202
+ return;
203
+ }
204
+ (0, import_invariant.invariant)(this._deviceKey && this._identityKey, void 0, {
182
205
  F: __dxlog_file2,
183
- L: 88,
206
+ L: 103,
184
207
  S: this,
185
208
  A: [
186
- "!this._ws",
209
+ "this._deviceKey && this._identityKey",
187
210
  ""
188
211
  ]
189
212
  });
@@ -191,40 +214,72 @@ var EdgeClient = class {
191
214
  info: this.info
192
215
  }, {
193
216
  F: __dxlog_file2,
194
- L: 89,
217
+ L: 104,
218
+ S: this,
219
+ C: (f, a) => f(...a)
220
+ });
221
+ await this._openWebSocket();
222
+ import_log.log.info("opened", {
223
+ info: this.info
224
+ }, {
225
+ F: __dxlog_file2,
226
+ L: 108,
227
+ S: this,
228
+ C: (f, a) => f(...a)
229
+ });
230
+ }
231
+ /**
232
+ * Close connection and free resources.
233
+ */
234
+ async _close() {
235
+ (0, import_log.log)("closing...", {
236
+ deviceKey: this._deviceKey
237
+ }, {
238
+ F: __dxlog_file2,
239
+ L: 115,
240
+ S: this,
241
+ C: (f, a) => f(...a)
242
+ });
243
+ await this._reconnect;
244
+ await this._closeWebSocket();
245
+ (0, import_log.log)("closed", {
246
+ deviceKey: this._deviceKey
247
+ }, {
248
+ F: __dxlog_file2,
249
+ L: 118,
195
250
  S: this,
196
251
  C: (f, a) => f(...a)
197
252
  });
198
- const ready = new import_async.Trigger();
253
+ }
254
+ async _openWebSocket() {
199
255
  const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);
200
256
  this._ws = new import_isomorphic_ws.default(url);
201
257
  Object.assign(this._ws, {
202
258
  onopen: () => {
203
- import_log.log.info("opened", this.info, {
259
+ (0, import_log.log)("opened", this.info, {
204
260
  F: __dxlog_file2,
205
- L: 97,
261
+ L: 126,
206
262
  S: this,
207
263
  C: (f, a) => f(...a)
208
264
  });
209
- ready.wake(true);
265
+ this._ready.wake();
210
266
  },
211
267
  onclose: () => {
212
- import_log.log.info("closed", this.info, {
268
+ (0, import_log.log)("closed", this.info, {
213
269
  F: __dxlog_file2,
214
- L: 102,
270
+ L: 131,
215
271
  S: this,
216
272
  C: (f, a) => f(...a)
217
273
  });
218
- ready.wake(false);
219
274
  },
220
275
  onerror: (event) => {
221
276
  import_log.log.catch(event.error, this.info, {
222
277
  F: __dxlog_file2,
223
- L: 107,
278
+ L: 135,
224
279
  S: this,
225
280
  C: (f, a) => f(...a)
226
281
  });
227
- ready.throw(event.error);
282
+ this._ready.throw(event.error);
228
283
  },
229
284
  /**
230
285
  * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data
@@ -237,7 +292,7 @@ var EdgeClient = class {
237
292
  payload: protocol.getPayloadType(message)
238
293
  }, {
239
294
  F: __dxlog_file2,
240
- L: 117,
295
+ L: 145,
241
296
  S: this,
242
297
  C: (f, a) => f(...a)
243
298
  });
@@ -251,7 +306,7 @@ var EdgeClient = class {
251
306
  payload: protocol.getPayloadType(message)
252
307
  }, {
253
308
  F: __dxlog_file2,
254
- L: 123,
309
+ L: 151,
255
310
  S: this,
256
311
  C: (f, a) => f(...a)
257
312
  });
@@ -260,43 +315,14 @@ var EdgeClient = class {
260
315
  }
261
316
  }
262
317
  });
263
- const result = await ready.wait({
318
+ await this._ready.wait({
264
319
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
265
320
  });
266
- import_log.log.info("opened", {
267
- info: this.info
268
- }, {
269
- F: __dxlog_file2,
270
- L: 131,
271
- S: this,
272
- C: (f, a) => f(...a)
273
- });
274
- return result;
275
321
  }
276
- /**
277
- * Close connection and free resources.
278
- */
279
- async close() {
280
- if (this._ws) {
281
- import_log.log.info("closing...", {
282
- deviceKey: this._deviceKey
283
- }, {
284
- F: __dxlog_file2,
285
- L: 140,
286
- S: this,
287
- C: (f, a) => f(...a)
288
- });
289
- this._ws.close();
290
- this._ws = void 0;
291
- import_log.log.info("closed", {
292
- deviceKey: this._deviceKey
293
- }, {
294
- F: __dxlog_file2,
295
- L: 143,
296
- S: this,
297
- C: (f, a) => f(...a)
298
- });
299
- }
322
+ async _closeWebSocket() {
323
+ this._ready.reset();
324
+ this._ws.close();
325
+ this._ws = void 0;
300
326
  }
301
327
  /**
302
328
  * Send message.
@@ -304,21 +330,33 @@ var EdgeClient = class {
304
330
  */
305
331
  // TODO(burdon): Implement ACK?
306
332
  async send(message) {
333
+ await this._ready.wait({
334
+ timeout: this._config.timeout ?? DEFAULT_TIMEOUT
335
+ });
307
336
  (0, import_invariant.invariant)(this._ws, void 0, {
308
337
  F: __dxlog_file2,
309
- L: 153,
338
+ L: 174,
310
339
  S: this,
311
340
  A: [
312
341
  "this._ws",
313
342
  ""
314
343
  ]
315
344
  });
345
+ (0, import_invariant.invariant)(!message.source || message.source.peerKey === this._deviceKey.toHex(), void 0, {
346
+ F: __dxlog_file2,
347
+ L: 175,
348
+ S: this,
349
+ A: [
350
+ "!message.source || message.source.peerKey === this._deviceKey.toHex()",
351
+ ""
352
+ ]
353
+ });
316
354
  (0, import_log.log)("sending...", {
317
355
  deviceKey: this._deviceKey,
318
356
  payload: protocol.getPayloadType(message)
319
357
  }, {
320
358
  F: __dxlog_file2,
321
- L: 154,
359
+ L: 176,
322
360
  S: this,
323
361
  C: (f, a) => f(...a)
324
362
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts", "../../../src/client.ts", "../../../src/defs.ts", "../../../src/protocol.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './client';\nexport * from './defs';\nexport * from './protocol';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger } from '@dxos/async';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\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 { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\n/**\n *\n */\nexport interface EdgeConnection {\n get info(): any;\n get identityKey(): PublicKey;\n get deviceKey(): PublicKey;\n get isOpen(): boolean;\n addListener(listener: MessageListener): () => void;\n open(): Promise<boolean>;\n close(): Promise<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 */\n// TODO(dmaretskyi): Rename EdgeClient.\nexport class EdgeClient implements EdgeConnection {\n private readonly _listeners: Set<MessageListener> = new Set();\n private readonly _protocol: Protocol;\n private _ws?: WebSocket;\n\n constructor(\n private readonly _identityKey: PublicKey,\n private readonly _deviceKey: PublicKey,\n private readonly _config: MessengerConfig,\n ) {\n this._protocol = this._config.protocol ?? protocol;\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._deviceKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get deviceKey() {\n return this._deviceKey;\n }\n\n public get isOpen() {\n return !!this._ws;\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 public async open(): Promise<boolean> {\n invariant(!this._ws);\n log.info('opening...', { info: this.info });\n const ready = new Trigger<boolean>();\n\n // TODO: handle reconnects\n const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n Object.assign<WebSocket, Partial<WebSocket>>(this._ws, {\n onopen: () => {\n log.info('opened', this.info);\n ready.wake(true);\n },\n\n onclose: () => {\n log.info('closed', this.info);\n ready.wake(false);\n },\n\n onerror: (event) => {\n log.catch(event.error, this.info);\n ready.throw(event.error);\n },\n\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n onmessage: async (event) => {\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { deviceKey: this._deviceKey, 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\n const result = await ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n log.info('opened', { info: this.info });\n return result;\n }\n\n /**\n * Close connection and free resources.\n */\n public async close() {\n if (this._ws) {\n log.info('closing...', { deviceKey: this._deviceKey });\n this._ws.close();\n this._ws = undefined;\n log.info('closed', { deviceKey: this._deviceKey });\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 // TODO(burdon): Implement ACK?\n public async send(message: Message): Promise<void> {\n invariant(this._ws);\n log('sending...', { deviceKey: this._deviceKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = Partial<PeerProto>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n"],
5
- "mappings": "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",
6
- "names": ["import_messenger_pb", "import_invariant", "import_buf", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "buf", "createRegistry", "typeRegistry", "toJson", "message", "MessageSchema", "registry", "err", "type", "getPayloadType", "getPayload", "invariant", "payload", "payloadTypename", "Error", "bufWkt", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "bufferToArray", "Blob", "Uint8Array", "arrayBuffer", "protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "DEFAULT_TIMEOUT", "EdgeClient", "_identityKey", "_deviceKey", "_config", "_listeners", "Set", "_protocol", "info", "open", "isOpen", "identity", "device", "identityKey", "deviceKey", "_ws", "addListener", "listener", "add", "delete", "log", "ready", "Trigger", "url", "URL", "toHex", "socketEndpoint", "WebSocket", "Object", "assign", "onopen", "wake", "onclose", "onerror", "event", "catch", "error", "throw", "onmessage", "fromBinary", "result", "wait", "timeout", "close", "send", "toBinary"]
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './client';\nexport * from './defs';\nexport * from './protocol';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger } from '@dxos/async';\nimport { LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\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 { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n get info(): any;\n get identityKey(): PublicKey;\n get deviceKey(): PublicKey;\n get isOpen(): boolean;\n setIdentity(params: { deviceKey: PublicKey; identityKey: PublicKey }): 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 */\n// TODO(dmaretskyi): Rename EdgeClient.\n// TODO(mykola): Handle reconnections.\nexport class EdgeClient extends Resource implements EdgeConnection {\n private readonly _listeners = new Set<MessageListener>();\n private _reconnect?: Promise<void> = undefined;\n private readonly _protocol: Protocol;\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n\n constructor(\n private _identityKey: PublicKey,\n private _deviceKey: PublicKey,\n private readonly _config: MessengerConfig,\n ) {\n super();\n this._protocol = this._config.protocol ?? protocol;\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._deviceKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get deviceKey() {\n return this._deviceKey;\n }\n\n public get isOpen() {\n return this._lifecycleState === LifecycleState.OPEN;\n }\n\n setIdentity({ deviceKey, identityKey }: { deviceKey: PublicKey; identityKey: PublicKey }) {\n this._deviceKey = deviceKey;\n this._identityKey = identityKey;\n this._reconnect = this._closeWebSocket()\n .then(async () => {\n await this._openWebSocket();\n })\n .catch((err) => log.catch(err));\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 await this._reconnect;\n if (this._ws) {\n return;\n }\n invariant(this._deviceKey && this._identityKey);\n log.info('opening...', { info: this.info });\n\n // TODO: handle reconnects\n await this._openWebSocket();\n log.info('opened', { info: this.info });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { deviceKey: this._deviceKey });\n await this._reconnect;\n await this._closeWebSocket();\n log('closed', { deviceKey: this._deviceKey });\n }\n\n private async _openWebSocket() {\n const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n Object.assign<WebSocket, Partial<WebSocket>>(this._ws, {\n onopen: () => {\n log('opened', this.info);\n this._ready.wake();\n },\n\n onclose: () => {\n log('closed', this.info);\n },\n\n onerror: (event) => {\n log.catch(event.error, this.info);\n this._ready.throw(event.error);\n },\n\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n onmessage: async (event) => {\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { deviceKey: this._deviceKey, 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\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n\n private async _closeWebSocket() {\n this._ready.reset();\n this._ws!.close();\n this._ws = undefined;\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 // TODO(burdon): Implement ACK?\n public async send(message: Message): Promise<void> {\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n invariant(this._ws);\n invariant(!message.source || message.source.peerKey === this._deviceKey.toHex());\n log('sending...', { deviceKey: this._deviceKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AnySchema } from '@bufbuild/protobuf/wkt';\n\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, AnySchema]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = Partial<PeerProto>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["import_messenger_pb", "import_invariant", "import_buf", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "buf", "createRegistry", "typeRegistry", "toJson", "message", "MessageSchema", "registry", "err", "type", "getPayloadType", "getPayload", "invariant", "payload", "payloadTypename", "Error", "bufWkt", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "bufferToArray", "Blob", "Uint8Array", "arrayBuffer", "protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "AnySchema", "DEFAULT_TIMEOUT", "EdgeClient", "Resource", "_identityKey", "_deviceKey", "_config", "_listeners", "Set", "_reconnect", "_ready", "Trigger", "_ws", "_protocol", "info", "open", "isOpen", "identity", "device", "identityKey", "deviceKey", "_lifecycleState", "LifecycleState", "OPEN", "setIdentity", "_closeWebSocket", "then", "_openWebSocket", "catch", "log", "addListener", "listener", "add", "delete", "_open", "_close", "url", "URL", "toHex", "socketEndpoint", "WebSocket", "Object", "assign", "onopen", "wake", "onclose", "onerror", "event", "error", "throw", "onmessage", "fromBinary", "wait", "timeout", "reset", "close", "send", "peerKey", "toBinary"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10314,"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":1359,"imports":[{"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/client.ts":{"bytes":16849,"imports":[{"path":"isomorphic-ws","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","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/index.ts":{"bytes":836,"imports":[{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/client.ts","kind":"import-statement","original":"./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"}],"format":"esm"}},"outputs":{"packages/core/mesh/edge-client/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":13078},"packages/core/mesh/edge-client/dist/lib/node/index.cjs":{"imports":[{"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/invariant","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/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"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}],"exports":["EdgeClient","Protocol","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/client.ts":{"bytesInOutput":4723},"packages/core/mesh/edge-client/src/defs.ts":{"bytesInOutput":220},"packages/core/mesh/edge-client/src/protocol.ts":{"bytesInOutput":2600}},"bytes":8008}}}
1
+ {"inputs":{"packages/core/mesh/edge-client/src/protocol.ts":{"bytes":10314,"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":1578,"imports":[{"path":"@bufbuild/protobuf/wkt","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/client.ts":{"bytes":20675,"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/invariant","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/index.ts":{"bytes":836,"imports":[{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"path":"packages/core/mesh/edge-client/src/client.ts","kind":"import-statement","original":"./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"}],"format":"esm"}},"outputs":{"packages/core/mesh/edge-client/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":14946},"packages/core/mesh/edge-client/dist/lib/node/index.cjs":{"imports":[{"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/invariant","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":"@bufbuild/protobuf/wkt","kind":"import-statement","external":true},{"path":"@dxos/protocols/buf/dxos/edge/messenger_pb","kind":"import-statement","external":true},{"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}],"exports":["EdgeClient","Protocol","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/client.ts":{"bytesInOutput":5789},"packages/core/mesh/edge-client/src/defs.ts":{"bytesInOutput":285},"packages/core/mesh/edge-client/src/protocol.ts":{"bytesInOutput":2600}},"bytes":9139}}}
@@ -1,18 +1,18 @@
1
+ import { Resource, type Lifecycle } from '@dxos/context';
1
2
  import { type PublicKey } from '@dxos/keys';
2
3
  import { type Message } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
3
4
  import { type Protocol } from './protocol';
4
5
  export type MessageListener = (message: Message) => void | Promise<void>;
5
- /**
6
- *
7
- */
8
- export interface EdgeConnection {
6
+ export interface EdgeConnection extends Required<Lifecycle> {
9
7
  get info(): any;
10
8
  get identityKey(): PublicKey;
11
9
  get deviceKey(): PublicKey;
12
10
  get isOpen(): boolean;
11
+ setIdentity(params: {
12
+ deviceKey: PublicKey;
13
+ identityKey: PublicKey;
14
+ }): void;
13
15
  addListener(listener: MessageListener): () => void;
14
- open(): Promise<boolean>;
15
- close(): Promise<void>;
16
16
  send(message: Message): Promise<void>;
17
17
  }
18
18
  export type MessengerConfig = {
@@ -23,12 +23,14 @@ export type MessengerConfig = {
23
23
  /**
24
24
  * Messenger client.
25
25
  */
26
- export declare class EdgeClient implements EdgeConnection {
27
- private readonly _identityKey;
28
- private readonly _deviceKey;
26
+ export declare class EdgeClient extends Resource implements EdgeConnection {
27
+ private _identityKey;
28
+ private _deviceKey;
29
29
  private readonly _config;
30
30
  private readonly _listeners;
31
+ private _reconnect?;
31
32
  private readonly _protocol;
33
+ private _ready;
32
34
  private _ws?;
33
35
  constructor(_identityKey: PublicKey, _deviceKey: PublicKey, _config: MessengerConfig);
34
36
  get info(): {
@@ -39,15 +41,21 @@ export declare class EdgeClient implements EdgeConnection {
39
41
  get identityKey(): PublicKey;
40
42
  get deviceKey(): PublicKey;
41
43
  get isOpen(): boolean;
44
+ setIdentity({ deviceKey, identityKey }: {
45
+ deviceKey: PublicKey;
46
+ identityKey: PublicKey;
47
+ }): void;
42
48
  addListener(listener: MessageListener): () => void;
43
49
  /**
44
50
  * Open connection to messaging service.
45
51
  */
46
- open(): Promise<boolean>;
52
+ protected _open(): Promise<void>;
47
53
  /**
48
54
  * Close connection and free resources.
49
55
  */
50
- close(): Promise<void>;
56
+ protected _close(): Promise<void>;
57
+ private _openWebSocket;
58
+ private _closeWebSocket;
51
59
  /**
52
60
  * Send message.
53
61
  * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/client.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,4CAA4C,CAAC;AAGzF,OAAO,EAAE,KAAK,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAIzD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,IAAI,IAAI,GAAG,CAAC;IAChB,IAAI,WAAW,IAAI,SAAS,CAAC;IAC7B,IAAI,SAAS,IAAI,SAAS,CAAC;IAC3B,IAAI,MAAM,IAAI,OAAO,CAAC;IACtB,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI,CAAC;IACnD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF;;GAEG;AAEH,qBAAa,UAAW,YAAW,cAAc;IAM7C,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,GAAG,CAAC,CAAY;gBAGL,YAAY,EAAE,SAAS,EACvB,UAAU,EAAE,SAAS,EACrB,OAAO,EAAE,eAAe;IAM3C,IAAW,IAAI;;;;MAMd;IAED,IAAI,WAAW,cAEd;IAED,IAAI,SAAS,cAEZ;IAED,IAAW,MAAM,YAEhB;IAEM,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI;IAKzD;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAgDrC;;OAEG;IACU,KAAK;IASlB;;;OAGG;IAEU,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAKnD"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/client.ts"],"names":[],"mappings":"AAOA,OAAO,EAAkB,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAEzE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,KAAK,OAAO,EAAiB,MAAM,4CAA4C,CAAC;AAGzF,OAAO,EAAE,KAAK,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAIzD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEzE,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAAC,SAAS,CAAC;IACzD,IAAI,IAAI,IAAI,GAAG,CAAC;IAChB,IAAI,WAAW,IAAI,SAAS,CAAC;IAC7B,IAAI,SAAS,IAAI,SAAS,CAAC;IAC3B,IAAI,MAAM,IAAI,OAAO,CAAC;IACtB,WAAW,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,SAAS,CAAC;QAAC,WAAW,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5E,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF;;GAEG;AAGH,qBAAa,UAAW,SAAQ,QAAS,YAAW,cAAc;IAQ9D,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAT1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,UAAU,CAAC,CAA4B;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,GAAG,CAAC,CAAwB;gBAG1B,YAAY,EAAE,SAAS,EACvB,UAAU,EAAE,SAAS,EACZ,OAAO,EAAE,eAAe;IAO3C,IAAW,IAAI;;;;MAMd;IAED,IAAI,WAAW,cAEd;IAED,IAAI,SAAS,cAEZ;IAED,IAAW,MAAM,YAEhB;IAED,WAAW,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE;QAAE,SAAS,EAAE,SAAS,CAAC;QAAC,WAAW,EAAE,SAAS,CAAA;KAAE;IAUjF,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI;IAKzD;;OAEG;cACsB,KAAK;IAa9B;;OAEG;cACsB,MAAM;YAOjB,cAAc;YAwCd,eAAe;IAM7B;;;OAGG;IAEU,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAOnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../src/defs.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,eAAO,MAAM,QAAQ,UAA6E,CAAC"}
1
+ {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../src/defs.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,eAAO,MAAM,QAAQ,UAAwF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/edge-client",
3
- "version": "0.6.8-main.3be982f",
3
+ "version": "0.6.8-staging.63bcb81",
4
4
  "description": "EDGE Client",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -25,14 +25,16 @@
25
25
  "README.md"
26
26
  ],
27
27
  "dependencies": {
28
+ "@bufbuild/protobuf": "^2.0.0",
28
29
  "isomorphic-ws": "^5.0.0",
29
30
  "ws": "^8.14.2",
30
- "@dxos/async": "0.6.8-main.3be982f",
31
- "@dxos/invariant": "0.6.8-main.3be982f",
32
- "@dxos/node-std": "0.6.8-main.3be982f",
33
- "@dxos/log": "0.6.8-main.3be982f",
34
- "@dxos/util": "0.6.8-main.3be982f",
35
- "@dxos/protocols": "0.6.8-main.3be982f"
31
+ "@dxos/async": "0.6.8-staging.63bcb81",
32
+ "@dxos/context": "0.6.8-staging.63bcb81",
33
+ "@dxos/log": "0.6.8-staging.63bcb81",
34
+ "@dxos/invariant": "0.6.8-staging.63bcb81",
35
+ "@dxos/node-std": "0.6.8-staging.63bcb81",
36
+ "@dxos/protocols": "0.6.8-staging.63bcb81",
37
+ "@dxos/util": "0.6.8-staging.63bcb81"
36
38
  },
37
39
  "devDependencies": {},
38
40
  "publishConfig": {
package/src/client.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  import WebSocket from 'isomorphic-ws';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
+ import { LifecycleState, Resource, type Lifecycle } from '@dxos/context';
8
9
  import { invariant } from '@dxos/invariant';
9
10
  import { type PublicKey } from '@dxos/keys';
10
11
  import { log } from '@dxos/log';
@@ -18,17 +19,13 @@ const DEFAULT_TIMEOUT = 5_000;
18
19
 
19
20
  export type MessageListener = (message: Message) => void | Promise<void>;
20
21
 
21
- /**
22
- *
23
- */
24
- export interface EdgeConnection {
22
+ export interface EdgeConnection extends Required<Lifecycle> {
25
23
  get info(): any;
26
24
  get identityKey(): PublicKey;
27
25
  get deviceKey(): PublicKey;
28
26
  get isOpen(): boolean;
27
+ setIdentity(params: { deviceKey: PublicKey; identityKey: PublicKey }): void;
29
28
  addListener(listener: MessageListener): () => void;
30
- open(): Promise<boolean>;
31
- close(): Promise<void>;
32
29
  send(message: Message): Promise<void>;
33
30
  }
34
31
 
@@ -42,16 +39,20 @@ export type MessengerConfig = {
42
39
  * Messenger client.
43
40
  */
44
41
  // TODO(dmaretskyi): Rename EdgeClient.
45
- export class EdgeClient implements EdgeConnection {
46
- private readonly _listeners: Set<MessageListener> = new Set();
42
+ // TODO(mykola): Handle reconnections.
43
+ export class EdgeClient extends Resource implements EdgeConnection {
44
+ private readonly _listeners = new Set<MessageListener>();
45
+ private _reconnect?: Promise<void> = undefined;
47
46
  private readonly _protocol: Protocol;
48
- private _ws?: WebSocket;
47
+ private _ready = new Trigger();
48
+ private _ws?: WebSocket = undefined;
49
49
 
50
50
  constructor(
51
- private readonly _identityKey: PublicKey,
52
- private readonly _deviceKey: PublicKey,
51
+ private _identityKey: PublicKey,
52
+ private _deviceKey: PublicKey,
53
53
  private readonly _config: MessengerConfig,
54
54
  ) {
55
+ super();
55
56
  this._protocol = this._config.protocol ?? protocol;
56
57
  }
57
58
 
@@ -73,7 +74,17 @@ export class EdgeClient implements EdgeConnection {
73
74
  }
74
75
 
75
76
  public get isOpen() {
76
- return !!this._ws;
77
+ return this._lifecycleState === LifecycleState.OPEN;
78
+ }
79
+
80
+ setIdentity({ deviceKey, identityKey }: { deviceKey: PublicKey; identityKey: PublicKey }) {
81
+ this._deviceKey = deviceKey;
82
+ this._identityKey = identityKey;
83
+ this._reconnect = this._closeWebSocket()
84
+ .then(async () => {
85
+ await this._openWebSocket();
86
+ })
87
+ .catch((err) => log.catch(err));
77
88
  }
78
89
 
79
90
  public addListener(listener: MessageListener): () => void {
@@ -84,28 +95,45 @@ export class EdgeClient implements EdgeConnection {
84
95
  /**
85
96
  * Open connection to messaging service.
86
97
  */
87
- public async open(): Promise<boolean> {
88
- invariant(!this._ws);
98
+ protected override async _open() {
99
+ await this._reconnect;
100
+ if (this._ws) {
101
+ return;
102
+ }
103
+ invariant(this._deviceKey && this._identityKey);
89
104
  log.info('opening...', { info: this.info });
90
- const ready = new Trigger<boolean>();
91
105
 
92
106
  // TODO: handle reconnects
107
+ await this._openWebSocket();
108
+ log.info('opened', { info: this.info });
109
+ }
110
+
111
+ /**
112
+ * Close connection and free resources.
113
+ */
114
+ protected override async _close() {
115
+ log('closing...', { deviceKey: this._deviceKey });
116
+ await this._reconnect;
117
+ await this._closeWebSocket();
118
+ log('closed', { deviceKey: this._deviceKey });
119
+ }
120
+
121
+ private async _openWebSocket() {
93
122
  const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);
94
123
  this._ws = new WebSocket(url);
95
124
  Object.assign<WebSocket, Partial<WebSocket>>(this._ws, {
96
125
  onopen: () => {
97
- log.info('opened', this.info);
98
- ready.wake(true);
126
+ log('opened', this.info);
127
+ this._ready.wake();
99
128
  },
100
129
 
101
130
  onclose: () => {
102
- log.info('closed', this.info);
103
- ready.wake(false);
131
+ log('closed', this.info);
104
132
  },
105
133
 
106
134
  onerror: (event) => {
107
135
  log.catch(event.error, this.info);
108
- ready.throw(event.error);
136
+ this._ready.throw(event.error);
109
137
  },
110
138
 
111
139
  /**
@@ -127,21 +155,13 @@ export class EdgeClient implements EdgeConnection {
127
155
  },
128
156
  });
129
157
 
130
- const result = await ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });
131
- log.info('opened', { info: this.info });
132
- return result;
158
+ await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });
133
159
  }
134
160
 
135
- /**
136
- * Close connection and free resources.
137
- */
138
- public async close() {
139
- if (this._ws) {
140
- log.info('closing...', { deviceKey: this._deviceKey });
141
- this._ws.close();
142
- this._ws = undefined;
143
- log.info('closed', { deviceKey: this._deviceKey });
144
- }
161
+ private async _closeWebSocket() {
162
+ this._ready.reset();
163
+ this._ws!.close();
164
+ this._ws = undefined;
145
165
  }
146
166
 
147
167
  /**
@@ -150,7 +170,9 @@ export class EdgeClient implements EdgeConnection {
150
170
  */
151
171
  // TODO(burdon): Implement ACK?
152
172
  public async send(message: Message): Promise<void> {
173
+ await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });
153
174
  invariant(this._ws);
175
+ invariant(!message.source || message.source.peerKey === this._deviceKey.toHex());
154
176
  log('sending...', { deviceKey: this._deviceKey, payload: protocol.getPayloadType(message) });
155
177
  this._ws.send(buf.toBinary(MessageSchema, message));
156
178
  }
package/src/defs.ts CHANGED
@@ -2,8 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { AnySchema } from '@bufbuild/protobuf/wkt';
6
+
5
7
  import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';
6
8
 
7
9
  import { Protocol } from './protocol';
8
10
 
9
- export const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema]);
11
+ export const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, AnySchema]);