@persistica/flux-agent 0.0.39 → 0.0.40
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 +87 -30
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -703,6 +703,18 @@ var ChannelStateManager = class {
|
|
|
703
703
|
}
|
|
704
704
|
return Promise.reject(new Error("Not connected"));
|
|
705
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* Re-subscribes every joined channel on a fresh socket. The mesh ties
|
|
708
|
+
* channel membership to the socket, so after a re-sign-on nothing is joined
|
|
709
|
+
* even though the channels — and their use counts — live on here unchanged.
|
|
710
|
+
* The mesh answers each with a subscribe ack nobody awaits, which
|
|
711
|
+
* `FluxWebSocketConnection.handleMessage` swallows.
|
|
712
|
+
*/
|
|
713
|
+
resubscribeJoinedChannels(webSocketClient) {
|
|
714
|
+
for (const channelName of this.joinedChannels.keys()) {
|
|
715
|
+
webSocketClient.send(`${SUBSCRIBE_NETWORK_CHANNEL_NAME}:${channelName}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
706
718
|
/**
|
|
707
719
|
* Leave a channel.
|
|
708
720
|
*/
|
|
@@ -780,20 +792,7 @@ var FluxWebSocketConnection = class {
|
|
|
780
792
|
secretKey: this.options.secretKey,
|
|
781
793
|
retries: this.options.retries ?? 1e4
|
|
782
794
|
};
|
|
783
|
-
|
|
784
|
-
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
785
|
-
url.searchParams.set("token", this.token);
|
|
786
|
-
this.socket = new FluxWebSocketClientConnection(
|
|
787
|
-
{
|
|
788
|
-
url: url.toString(),
|
|
789
|
-
// The URL carries a mesh-issued ticket that expires (15 minutes)
|
|
790
|
-
// long before this connection does. Re-dialling it is pointless —
|
|
791
|
-
// the mesh answers 'jwt expired' every time — so coming back is
|
|
792
|
-
// `onReconnectCallback`'s job: it signs on again from scratch.
|
|
793
|
-
autoReconnect: false,
|
|
794
|
-
retries: this.options.retries
|
|
795
|
-
}
|
|
796
|
-
);
|
|
795
|
+
this.socket = this.createSocket(this.token);
|
|
797
796
|
this.interceptPackageTypeMessages("isReady", this.readyInterceptor);
|
|
798
797
|
}
|
|
799
798
|
fluxInstanceId;
|
|
@@ -804,6 +803,9 @@ var FluxWebSocketConnection = class {
|
|
|
804
803
|
// ****************************************************************************
|
|
805
804
|
// *** State
|
|
806
805
|
// ****************************************************************************
|
|
806
|
+
// Mutable: a re-sign-on builds a fresh socket — the ticket is baked into its
|
|
807
|
+
// URL — but keeps this connection object, so every handle and listener
|
|
808
|
+
// registered against it survives (#536).
|
|
807
809
|
socket;
|
|
808
810
|
callbacks = /* @__PURE__ */ new Set();
|
|
809
811
|
channelCallbacks = /* @__PURE__ */ new Map();
|
|
@@ -813,6 +815,9 @@ var FluxWebSocketConnection = class {
|
|
|
813
815
|
connectPromise;
|
|
814
816
|
connectPromiseResolver;
|
|
815
817
|
channelStateManager = new ChannelStateManager();
|
|
818
|
+
// Whether the authority-side channel-change subscription was requested. The
|
|
819
|
+
// mesh ties it to the socket, so a re-signed-on connection has to ask again.
|
|
820
|
+
subscribedToChannelChanges = false;
|
|
816
821
|
// ****************************************************************************
|
|
817
822
|
// *** Reused socket callbacks
|
|
818
823
|
// ****************************************************************************
|
|
@@ -824,6 +829,27 @@ var FluxWebSocketConnection = class {
|
|
|
824
829
|
socketConnectFailedHandler = () => this.handleSocketConnectFailed();
|
|
825
830
|
socketConnectingHandler = (retryAttempt) => this.handleSocketConnecting(retryAttempt);
|
|
826
831
|
socketErrorHandler = (error) => this.handleSocketError(error);
|
|
832
|
+
/**
|
|
833
|
+
* Builds the low-level socket. The URL embeds the single-use, expiring
|
|
834
|
+
* ticket, so every sign-on — the first one and every one after a drop —
|
|
835
|
+
* needs its own socket. `reconnect()` swaps the fresh one in.
|
|
836
|
+
*/
|
|
837
|
+
createSocket(ticket) {
|
|
838
|
+
const url = new URL(this.options.domain);
|
|
839
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
840
|
+
url.searchParams.set("token", ticket);
|
|
841
|
+
return new FluxWebSocketClientConnection(
|
|
842
|
+
{
|
|
843
|
+
url: url.toString(),
|
|
844
|
+
// The URL carries a mesh-issued ticket that expires (15 minutes)
|
|
845
|
+
// long before this connection does. Re-dialling it is pointless —
|
|
846
|
+
// the mesh answers 'jwt expired' every time — so coming back is
|
|
847
|
+
// `onReconnectCallback`'s job: it signs on again from scratch.
|
|
848
|
+
autoReconnect: false,
|
|
849
|
+
retries: this.options.retries
|
|
850
|
+
}
|
|
851
|
+
);
|
|
852
|
+
}
|
|
827
853
|
/**
|
|
828
854
|
* Intercepts messages of a given package type.
|
|
829
855
|
*/
|
|
@@ -867,6 +893,23 @@ var FluxWebSocketConnection = class {
|
|
|
867
893
|
this.socket.connect().catch(this.socketErrorHandler);
|
|
868
894
|
return this.connectPromise;
|
|
869
895
|
}
|
|
896
|
+
/**
|
|
897
|
+
* Signs on again with a fresh ticket, keeping this connection object — and
|
|
898
|
+
* with it every channel handle and listener registered before the drop.
|
|
899
|
+
*
|
|
900
|
+
* A sign-on used to build a whole new connection, whose empty channel state
|
|
901
|
+
* left the old handles pointing at a dead socket: `publish()` was a silent
|
|
902
|
+
* no-op and `onPublish` listeners never fired again (#536).
|
|
903
|
+
*
|
|
904
|
+
* Only swaps the socket in; the caller's next `connect()` dials it.
|
|
905
|
+
*/
|
|
906
|
+
reconnect(ticket) {
|
|
907
|
+
this.socket.close();
|
|
908
|
+
this.webSocketClient = void 0;
|
|
909
|
+
this.connectPromise = void 0;
|
|
910
|
+
this.connectPromiseResolver = void 0;
|
|
911
|
+
this.socket = this.createSocket(ticket);
|
|
912
|
+
}
|
|
870
913
|
/**
|
|
871
914
|
* Disconnects from the Flux platform.
|
|
872
915
|
*/
|
|
@@ -929,6 +972,8 @@ var FluxWebSocketConnection = class {
|
|
|
929
972
|
if (this.webSocketClient) {
|
|
930
973
|
const messageString = typeof message === "string" ? `s:${message}` : `o:${JSON.stringify(message)}`;
|
|
931
974
|
this.webSocketClient.send(`${NETWORK_CHANNEL_PUBLISH}:${channelName}:${messageString}`);
|
|
975
|
+
} else {
|
|
976
|
+
console.warn(`Cannot publish to channel "${channelName}": the connection is down. Message dropped.`);
|
|
932
977
|
}
|
|
933
978
|
}
|
|
934
979
|
/**
|
|
@@ -966,6 +1011,7 @@ var FluxWebSocketConnection = class {
|
|
|
966
1011
|
* Subscribes to the channel changes.
|
|
967
1012
|
*/
|
|
968
1013
|
subscribeToChannelChanges() {
|
|
1014
|
+
this.subscribedToChannelChanges = true;
|
|
969
1015
|
if (this.webSocketClient) {
|
|
970
1016
|
this.webSocketClient.send(AUTHORITY_CHANNEL_SUBSCRIBE);
|
|
971
1017
|
} else {
|
|
@@ -991,6 +1037,10 @@ var FluxWebSocketConnection = class {
|
|
|
991
1037
|
resolveConnectedSocket() {
|
|
992
1038
|
this.stateManager.emitNetworkState("connected");
|
|
993
1039
|
this.webSocketClient = this.socket;
|
|
1040
|
+
this.channelStateManager.resubscribeJoinedChannels(this.socket);
|
|
1041
|
+
if (this.subscribedToChannelChanges) {
|
|
1042
|
+
this.socket.send(AUTHORITY_CHANNEL_SUBSCRIBE);
|
|
1043
|
+
}
|
|
994
1044
|
const connectPromiseResolver = this.connectPromiseResolver;
|
|
995
1045
|
this.connectPromiseResolver = void 0;
|
|
996
1046
|
this.connectPromise = void 0;
|
|
@@ -1099,6 +1149,9 @@ var FluxWebSocketConnection = class {
|
|
|
1099
1149
|
}
|
|
1100
1150
|
return;
|
|
1101
1151
|
}
|
|
1152
|
+
case SUBSCRIBED_NETWORK_CHANNEL_NAME: {
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1102
1155
|
case RPC_REQUEST: {
|
|
1103
1156
|
const payload = JSON.parse(message_.substring(message_.indexOf(":") + 1));
|
|
1104
1157
|
void this.socket.handleMessage(payload, (data) => {
|
|
@@ -1534,22 +1587,26 @@ var FluxAgent = class {
|
|
|
1534
1587
|
}
|
|
1535
1588
|
}
|
|
1536
1589
|
);
|
|
1537
|
-
this.fluxWebSocketConnection
|
|
1538
|
-
this.
|
|
1539
|
-
|
|
1540
|
-
this.
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1590
|
+
if (this.fluxWebSocketConnection) {
|
|
1591
|
+
this.fluxWebSocketConnection.reconnect(ticket);
|
|
1592
|
+
} else {
|
|
1593
|
+
this.fluxWebSocketConnection = createWSConnection(
|
|
1594
|
+
this.id,
|
|
1595
|
+
ticket,
|
|
1596
|
+
this.stateManager,
|
|
1597
|
+
async () => {
|
|
1598
|
+
await this.connect(
|
|
1599
|
+
identification,
|
|
1600
|
+
clientUId
|
|
1601
|
+
);
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
...this.options,
|
|
1605
|
+
domain
|
|
1606
|
+
}
|
|
1607
|
+
);
|
|
1608
|
+
this.fluxClientData.updateWsConnection(this.fluxWebSocketConnection);
|
|
1609
|
+
}
|
|
1553
1610
|
return await this.fluxWebSocketConnection.connectToNetwork();
|
|
1554
1611
|
} catch (error) {
|
|
1555
1612
|
this.stateManager.emitNetworkState("auth-error");
|