@persistica/flux-agent 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -40,6 +40,7 @@ var ON_NETWORK_CHANNEL_PUBLISH = "nc-on-pub";
40
40
  var SUBSCRIBE_NETWORK_CHANNEL_NAME = "subscribe-to-nc-name";
41
41
  var SUBSCRIBED_NETWORK_CHANNEL_NAME = "subscribed-to-nc-name";
42
42
  var UNSUBSCRIBE_NETWORK_CHANNEL_NAME = "unsubscribe-nc-name";
43
+ var UNSUBSCRIBED_NETWORK_CHANNEL_NAME = "unsubscribed-nc-name";
43
44
  var AUTHORITY_CHANNEL_SUBSCRIBE = "acs";
44
45
  var AUTHORITY_DISCONNECT_AGENT = "ada";
45
46
  var ERROR = "e";
@@ -420,7 +421,7 @@ var FluxAgentNetworkConnection = class {
420
421
  const fluxNetworkChannel = await this._fluxWebSocketConnection.joinChannel(
421
422
  channelName
422
423
  );
423
- this.connectedChannelSet.add(fluxNetworkChannel.channelName);
424
+ this.connectedChannelSet.add(channelName);
424
425
  return fluxNetworkChannel;
425
426
  }
426
427
  /**
@@ -486,8 +487,8 @@ var PicoLogger = /* @__PURE__ */ (() => {
486
487
 
487
488
  // libs/flux/shared/connection/src/lib/flux-network-channel.class.ts
488
489
  var FluxNetworkChannel = class {
489
- constructor(channelName, _fluxWebSocketConnection) {
490
- this.channelName = channelName;
490
+ constructor(_channelName, _fluxWebSocketConnection) {
491
+ this._channelName = _channelName;
491
492
  this._fluxWebSocketConnection = _fluxWebSocketConnection;
492
493
  }
493
494
  /**
@@ -495,7 +496,7 @@ var FluxNetworkChannel = class {
495
496
  */
496
497
  publish(message) {
497
498
  this._fluxWebSocketConnection.publish(
498
- this.channelName,
499
+ this._channelName,
499
500
  message
500
501
  );
501
502
  }
@@ -504,7 +505,7 @@ var FluxNetworkChannel = class {
504
505
  */
505
506
  onPublish(fn) {
506
507
  this._fluxWebSocketConnection.onPublish(
507
- this.channelName,
508
+ this._channelName,
508
509
  fn
509
510
  // TODO
510
511
  );
@@ -515,11 +516,17 @@ var FluxNetworkChannel = class {
515
516
  var CONNECTION_TIMEOUT_MS = 2e3;
516
517
  var ChannelStateManager = class {
517
518
  connectionTimeouts = /* @__PURE__ */ new Map();
519
+ joinedChannels = /* @__PURE__ */ new Map();
518
520
  /**
519
521
  * Join a channel.
520
522
  */
521
523
  async joinChannel(channelName, fluxWebSocketConnection, webSocketClient) {
522
524
  if (webSocketClient) {
525
+ const existingChannel = this.joinedChannels.get(channelName);
526
+ if (existingChannel) {
527
+ existingChannel.useCount++;
528
+ return Promise.resolve(existingChannel.channel);
529
+ }
523
530
  return new Promise((resolve, reject) => {
524
531
  const existingTimeout = this.connectionTimeouts.get(channelName);
525
532
  if (existingTimeout) {
@@ -537,7 +544,9 @@ var ChannelStateManager = class {
537
544
  this.connectionTimeouts.delete(channelName);
538
545
  }
539
546
  fluxWebSocketConnection.removePackageTypeInterceptor(SUBSCRIBED_NETWORK_CHANNEL_NAME, cb);
540
- resolve(new FluxNetworkChannel(channelName, fluxWebSocketConnection));
547
+ const channel = new FluxNetworkChannel(channelName, fluxWebSocketConnection);
548
+ this.joinedChannels.set(channelName, { channel, useCount: 1 });
549
+ resolve(channel);
541
550
  };
542
551
  fluxWebSocketConnection.interceptPackageTypeMessages(
543
552
  SUBSCRIBED_NETWORK_CHANNEL_NAME,
@@ -559,9 +568,46 @@ var ChannelStateManager = class {
559
568
  /**
560
569
  * Leave a channel.
561
570
  */
562
- async leaveChannel(channelName, webSocketClient) {
571
+ async leaveChannel(channelName, fluxWebSocketConnection, webSocketClient) {
572
+ const existingChannel = this.joinedChannels.get(channelName);
573
+ if (!existingChannel) {
574
+ return Promise.reject(new Error("No channel instance found"));
575
+ }
576
+ existingChannel.useCount--;
577
+ if (existingChannel.useCount <= 0) {
578
+ this.joinedChannels.delete(channelName);
579
+ }
580
+ if (webSocketClient && existingChannel.useCount <= 0) {
581
+ return new Promise((resolve, reject) => {
582
+ const cb = (message) => {
583
+ const receivedChannelName = message.substring(message.indexOf(":") + 1);
584
+ if (channelName !== receivedChannelName) {
585
+ return;
586
+ }
587
+ const timeout = this.connectionTimeouts.get(channelName);
588
+ if (timeout) {
589
+ clearTimeout(timeout);
590
+ this.connectionTimeouts.delete(channelName);
591
+ }
592
+ fluxWebSocketConnection.removePackageTypeInterceptor(UNSUBSCRIBED_NETWORK_CHANNEL_NAME, cb);
593
+ resolve(void 0);
594
+ };
595
+ fluxWebSocketConnection.interceptPackageTypeMessages(
596
+ UNSUBSCRIBED_NETWORK_CHANNEL_NAME,
597
+ cb
598
+ );
599
+ this.connectionTimeouts.set(
600
+ channelName,
601
+ setTimeout(() => {
602
+ this.connectionTimeouts.delete(channelName);
603
+ fluxWebSocketConnection.removePackageTypeInterceptor(UNSUBSCRIBED_NETWORK_CHANNEL_NAME, cb);
604
+ reject(new Error(`Channel unsubscription timed out for channel "${channelName}"`));
605
+ }, CONNECTION_TIMEOUT_MS)
606
+ );
607
+ webSocketClient.send(`${UNSUBSCRIBE_NETWORK_CHANNEL_NAME}:${channelName}`);
608
+ });
609
+ }
563
610
  if (webSocketClient) {
564
- webSocketClient.send(`${UNSUBSCRIBE_NETWORK_CHANNEL_NAME}:${channelName}`);
565
611
  return Promise.resolve(void 0);
566
612
  }
567
613
  return Promise.reject(new Error("Not connected"));
@@ -675,7 +721,6 @@ var FluxWebSocketConnection = class {
675
721
  });
676
722
  this.socket.clearEventSubscribers();
677
723
  this.socket.on("message", this.socketMessageHandler).on("close", this.socketCloseHandler).on("connecting", this.socketConnectingHandler).on("error", this.socketErrorHandler);
678
- this.stateManager.emitNetworkState("connecting");
679
724
  void this.socket.connect();
680
725
  return this.connectPromise;
681
726
  }
@@ -729,6 +774,7 @@ var FluxWebSocketConnection = class {
729
774
  async leaveChannel(channelName) {
730
775
  return this.channelStateManager.leaveChannel(
731
776
  channelName,
777
+ this,
732
778
  this.webSocketClient
733
779
  );
734
780
  }
@@ -815,7 +861,7 @@ var FluxWebSocketConnection = class {
815
861
  this.stateManager.emitNetworkState(reason === "kicked" ? "kicked" : "disconnected");
816
862
  }
817
863
  handleSocketConnecting(retryAttempt) {
818
- this.stateManager.emitNetworkState("disconnected");
864
+ this.stateManager.emitNetworkState("connecting");
819
865
  if (retryAttempt > 0) {
820
866
  PicoLogger.log(`\u{1F504} Connecting attempt: #${retryAttempt} of ${this.options.retries ?? "none"}`, this.fluxInstanceId);
821
867
  } else {
@@ -1148,15 +1194,19 @@ var FluxClientData = class {
1148
1194
  // packages/flux/agent/src/lib/flux-agent.class.ts
1149
1195
  var DEFAULT_FLUX_DOMAIN = "https://mesh.persistica.io";
1150
1196
  var FluxAgent = class {
1151
- constructor(networkId, options) {
1152
- this.networkId = networkId;
1153
- this.options = options;
1154
- validateNetworkIdOrThrow(this.networkId);
1155
- }
1156
1197
  id = nanoid();
1157
1198
  fluxWebSocketConnection;
1158
1199
  fluxClientData = new FluxClientData();
1159
1200
  stateManager = new StateManager();
1201
+ networkId;
1202
+ options;
1203
+ constructor(networkId, options) {
1204
+ if (!validateNetworkIdOrThrow(networkId)) {
1205
+ throw new Error("Will never be thrown");
1206
+ }
1207
+ this.networkId = networkId;
1208
+ this.options = options;
1209
+ }
1160
1210
  /**
1161
1211
  * Connect to the network using provided identification.
1162
1212
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@persistica/flux-agent",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "Persistica Flux Agent",
5
5
  "type": "module",
6
6
  "keywords": [],
@@ -1,17 +1,17 @@
1
1
  import type { TMessageCallback } from '@flux/shared/ws';
2
2
  import type { FluxAgentNetworkConnection } from '@flux/shared/connection';
3
3
  export declare class FluxAgent {
4
- private readonly networkId;
5
- private readonly options?;
6
4
  readonly id: string;
7
5
  private fluxWebSocketConnection;
8
6
  private readonly fluxClientData;
9
7
  private readonly stateManager;
8
+ private readonly networkId;
9
+ private readonly options;
10
10
  constructor(networkId: string, options?: {
11
11
  domain?: string;
12
12
  secretKey?: string;
13
13
  retries?: number;
14
- } | undefined);
14
+ });
15
15
  /**
16
16
  * Connect to the network using provided identification.
17
17
  *