@maxtroost/use-websocket 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,15 +1,14 @@
1
- import { Store as e, useStore as t } from "@tanstack/react-store";
2
- import { Store as n } from "@tanstack/store";
3
- import { deepEqual as r } from "fast-equals";
4
- import { createElement as i, useEffect as a, useId as o, useRef as s, useState as c } from "react";
1
+ import { Store as e } from "@tanstack/react-store";
2
+ import { Store as t } from "@tanstack/store";
3
+ import { deepEqual as n } from "fast-equals";
4
+ import { createContext as r, useContext as i, useEffect as a, useId as o, useRef as s, useState as c } from "react";
5
5
  import { useIsomorphicLayoutEffect as l } from "usehooks-ts";
6
- import { closeSnackbar as u, enqueueSnackbar as d } from "notistack";
7
- import { v4 as f } from "uuid";
6
+ import { jsx as u } from "react/jsx-runtime";
8
7
  //#region src/lib/types.ts
9
- var p = /* @__PURE__ */ function(e) {
8
+ var d = /* @__PURE__ */ function(e) {
10
9
  return e[e.UNINSTANTIATED = -1] = "UNINSTANTIATED", e[e.CONNECTING = 0] = "CONNECTING", e[e.OPEN = 1] = "OPEN", e[e.CLOSING = 2] = "CLOSING", e[e.CLOSED = 3] = "CLOSED", e;
11
10
  }({});
12
- function m() {
11
+ function f() {
13
12
  return {
14
13
  message: void 0,
15
14
  subscribed: !1,
@@ -22,19 +21,15 @@ function m() {
22
21
  };
23
22
  }
24
23
  //#endregion
25
- //#region src/lib/websocketStores.ts
26
- var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()), _ = () => {
27
- h.state.forEach((e) => {
28
- e.reconnect();
29
- });
30
- }, v = (e) => new Promise((t) => setTimeout(t, e)), y = {
24
+ //#region src/lib/constants.ts
25
+ var p = {
31
26
  NORMAL_CLOSURE: 1e3,
32
27
  GOING_AWAY: 1001,
33
28
  INTERNAL_ERROR: 1011,
34
29
  SERVICE_RESTART: 1012,
35
30
  TRY_AGAIN_LATER: 1013,
36
31
  ABNORMAL_CLOSURE: 1006
37
- }, b = {
32
+ }, m = {
38
33
  MAX_RETRY_ATTEMPTS: 20,
39
34
  NOTIFICATION_THRESHOLD: 10,
40
35
  TRY_AGAIN_LATER_DELAY_MS: 3e4,
@@ -47,79 +42,40 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
47
42
  FIRST: 5,
48
43
  SECOND: 10
49
44
  }
50
- }, x = {
51
- PRODUCTION_MS: 3e3,
52
- TEST_MS: 10
53
- }, S = { PONG_TIMEOUT_MS: 1e4 }, C = { enabled: !0 }, w = 1e4, T = (e) => e < b.PHASE_THRESHOLDS.FIRST ? b.DELAYS.FIRST_PHASE : e < b.PHASE_THRESHOLDS.SECOND ? b.DELAYS.SECOND_PHASE : b.DELAYS.THIRD_PHASE, E = () => 40 * 1e3, D = (e) => typeof e == "object" && !!e && "uri" in e && typeof e.uri == "string", O = (e) => e ? [
45
+ }, h = 1e3, g = { PONG_TIMEOUT_MS: 1e4 }, _ = { enabled: !0 }, v = {
46
+ enabled: !0,
47
+ pongTimeoutMs: g.PONG_TIMEOUT_MS
48
+ }, y = (e) => new Promise((t) => setTimeout(t, e)), b = (e) => Array.from(e).filter(([, e]) => "uri" in e).map(([, e]) => e.uri), x = (e, t, n) => e < n.first ? t.firstPhase : e < n.second ? t.secondPhase : t.thirdPhase, S = () => 40 * 1e3, C = (e) => typeof e == "object" && !!e && "uri" in e && typeof e.uri == "string", w = (e) => e ? [
54
49
  "error",
55
50
  "conflict",
56
51
  "exception"
57
- ].includes(e) : !1, k = () => typeof window < "u" && window.navigator.onLine, A = (e) => typeof window < "u" && window.navigator.onLine && e !== void 0 && e.readyState === WebSocket.OPEN, j = (e, t, n) => {
58
- t > b.NOTIFICATION_THRESHOLD && d(`trying to reconnect to ${e} in ${n / 1e3} seconds.`, {
59
- key: `${e}-offline`,
60
- variant: "error",
61
- preventDuplicate: !0
62
- });
63
- }, M = (e, t) => {
64
- let n = `${e}-max-retries`;
65
- d(`Connection to ${e} failed after maximum retries.`, {
66
- key: n,
67
- variant: "error",
68
- preventDuplicate: !0,
69
- action: (e) => i("button", {
70
- onClick: () => {
71
- t(), u(e);
72
- },
73
- style: {
74
- marginLeft: 8,
75
- padding: "4px 12px",
76
- background: "rgba(255,255,255,0.2)",
77
- border: "none",
78
- borderRadius: 4,
79
- color: "inherit",
80
- cursor: "pointer",
81
- fontSize: 14,
82
- fontWeight: 500
83
- }
84
- }, "Retry")
85
- });
86
- }, N = (e, t) => {
87
- t > b.NOTIFICATION_THRESHOLD && d(`trying to reconnect to ${e}...`, {
88
- key: `${e}-reconnecting`,
89
- variant: "info",
90
- preventDuplicate: !0
91
- });
92
- }, P = () => JSON.stringify({
52
+ ].includes(e) : !1, T = () => typeof window < "u" && window.navigator.onLine, E = (e) => typeof window < "u" && window.navigator.onLine && e !== void 0 && e.readyState === WebSocket.OPEN, D = () => ({
93
53
  method: "post",
94
54
  uri: "ping",
95
- body: Date.now(),
96
- correlation: f()
97
- }), F = (e) => e?.readyState === WebSocket.OPEN || e?.readyState === WebSocket.CONNECTING, I = (e) => e !== y.NORMAL_CLOSURE, L = class e {
98
- static setCustomLogger(t) {
99
- e._logger = t;
100
- }
101
- constructor(t) {
102
- this._listeners = /* @__PURE__ */ new Map(), this.reconnectTries = 0, this._isReconnecting = !1, this._maxRetriesExceeded = !1, this.cachedMessages = [], this.getSocket = () => this._socket, this.getUriApiByKey = (e) => {
103
- let t = this._listeners.get(e);
104
- if (t && "uri" in t) return t;
105
- }, this.addListener = (e) => (e.setSendToConnection(this.handleSendMessage), this.connect(), this._listeners.set(e.key, e), clearTimeout(this.closeConnectionTimeOut), this._socket?.readyState === WebSocket.OPEN && e.onOpen && e.onOpen(), e), this.removeListener = (e) => {
55
+ body: Date.now()
56
+ }), O = (e) => e?.readyState === WebSocket.OPEN || e?.readyState === WebSocket.CONNECTING, k = (e) => e !== p.NORMAL_CLOSURE, A = class {
57
+ constructor(e, t) {
58
+ this._listeners = /* @__PURE__ */ new Map(), this.reconnectTries = 0, this._isReconnecting = !1, this._maxRetriesExceeded = !1, this.cachedMessages = [], this.getSocket = () => this._socket, this.addListener = (e) => (e.setSendToConnection(this.handleSendMessage), this.connect(), this._listeners.set(e.key, e), clearTimeout(this.closeConnectionTimeOut), this._socket?.readyState === WebSocket.OPEN && e.onOpen && e.onOpen(), e), this.removeListener = (e) => {
106
59
  let t = this._listeners.get(e.key);
107
60
  t && (t.setSendToConnection(null), this._listeners.delete(t.key)), clearTimeout(this.closeConnectionTimeOut), this.scheduleConnectionCleanup();
108
61
  }, this.scheduleConnectionCleanup = () => {
62
+ let { connectionCleanupDelayMs: e } = this._client;
109
63
  this.closeConnectionTimeOut = setTimeout(() => {
110
- this._listeners.size === 0 && this._socket?.close();
111
- }, x.PRODUCTION_MS);
64
+ this._listeners.size === 0 && (this._socket?.close(), this._client.removeConnection(this.url));
65
+ }, e);
112
66
  }, this.replaceUrl = async (e) => {
113
67
  this._url !== e && (this._url = e, await this.teardownAndReconnect());
114
68
  }, this.reconnect = async () => {
115
69
  await this.teardownAndReconnect();
116
70
  }, this.resetRetriesAndReconnect = () => {
117
- this.reconnectTries = 0, this._maxRetriesExceeded = !1, u(`${this._name}-max-retries`), this.connect();
71
+ this.reconnectTries = 0, this._maxRetriesExceeded = !1, this.connect();
118
72
  }, this.connect = () => {
119
- let t = Array.from(this._listeners.values()).some((e) => e.isEnabled);
120
- F(this._socket) || !t || (e._logger?.log?.("info", "ws-connect", {
73
+ let e = Array.from(this._listeners.values()).some((e) => e.isEnabled);
74
+ O(this._socket) || !e || (this._client.connectionEvent?.({
75
+ type: "connect",
121
76
  url: this._url,
122
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri)
77
+ retries: this.reconnectTries,
78
+ uriApis: b(this._listeners)
123
79
  }), this._socket = new WebSocket(this._url), this._socket.addEventListener("close", this.handleClose), this._socket.addEventListener("message", this.handleMessage), this._socket.addEventListener("open", this.handleOpen), this._socket.addEventListener("error", this.handleError));
124
80
  }, this.teardownSocket = () => {
125
81
  this.clearAllTimers(), this.removeListeners(), this._socket?.close(), this._socket = void 0;
@@ -127,106 +83,122 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
127
83
  if (!this._isReconnecting) {
128
84
  this._isReconnecting = !0;
129
85
  try {
130
- this.teardownSocket(), this._listeners.forEach((e) => e.reset()), this.reconnectTries = 0, this._maxRetriesExceeded = !1, u(`${this._name}-max-retries`), await v(1e3), this.connect();
86
+ this.teardownSocket(), this._listeners.forEach((e) => e.reset()), this.reconnectTries = 0, this._maxRetriesExceeded = !1, await y(h), this.connect();
131
87
  } finally {
132
88
  this._isReconnecting = !1;
133
89
  }
134
90
  }
135
91
  }, this.cleanupConnection = () => {
136
- this._listeners.size === 0 && (e._logger?.log?.("info", "ws-closed", {
137
- url: this._url,
138
- subscriptions: this._listeners.size
92
+ this._listeners.size === 0 && (this._client.connectionEvent?.({
93
+ type: "cleanup",
94
+ url: this._url
139
95
  }), this.removeListeners(), this._socket = void 0);
140
96
  }, this.clearAllTimers = () => {
141
97
  clearTimeout(this.pingTimeOut), clearTimeout(this.pongTimeOut), clearTimeout(this.closeConnectionTimeOut);
142
98
  }, this.removeListeners = () => {
143
99
  this._socket?.removeEventListener("message", this.handleMessage), this._socket?.removeEventListener("close", this.handleClose), this._socket?.removeEventListener("open", this.handleOpen), this._socket?.removeEventListener("error", this.handleError), typeof window < "u" && (window.removeEventListener("online", this.handleOnline), window.removeEventListener("online", this.handleOnlineForReconnection), window.removeEventListener("offline", this.handleOffline));
144
- }, this.attemptReconnection = async (t) => {
145
- if (this.reconnectTries >= b.MAX_RETRY_ATTEMPTS) {
146
- this._maxRetriesExceeded = !0, e._logger?.connectionFailed?.(this._url, this.reconnectTries, this._listeners.size), M(this._name, this.resetRetriesAndReconnect);
100
+ }, this.attemptReconnection = async (e) => {
101
+ let { maxRetryAttempts: t, notificationThreshold: n, tryAgainLaterDelayMs: r } = this._client;
102
+ if (this.reconnectTries >= t) {
103
+ this._maxRetriesExceeded = !0, this._client.connectionEvent?.({
104
+ type: "max-retries-exceeded",
105
+ url: this._url,
106
+ retries: this.reconnectTries
107
+ });
147
108
  return;
148
109
  }
149
- if (this.deferReconnectionUntilOnline() || t === y.TRY_AGAIN_LATER && (j(this._name, this.reconnectTries, b.TRY_AGAIN_LATER_DELAY_MS), await v(b.TRY_AGAIN_LATER_DELAY_MS), this.deferReconnectionUntilOnline())) return;
150
- this.reconnectTries++, e._logger?.log?.("info", "ws-reconnect", {
110
+ if (this.deferReconnectionUntilOnline() || e === p.TRY_AGAIN_LATER && (this.reconnectTries > n && this._client.connectionEvent?.({
111
+ type: "reconnecting",
151
112
  url: this._url,
152
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri),
153
113
  retries: this.reconnectTries
154
- });
155
- let n = T(this.reconnectTries);
156
- j(this._name, this.reconnectTries, n), await v(n), !this.deferReconnectionUntilOnline() && (N(this._name, this.reconnectTries), this.connect());
157
- }, this.deferReconnectionUntilOnline = () => k() ? !1 : (typeof window < "u" && window.addEventListener("online", this.handleOnlineForReconnection, { once: !0 }), !0), this.handleClose = async (t) => {
158
- this.clearAllTimers(), e._logger?.log?.("info", "ws-close", {
114
+ }), await y(r), this.deferReconnectionUntilOnline())) return;
115
+ this.reconnectTries++;
116
+ let i = x(this.reconnectTries, this._client.delays, this._client.phaseThresholds);
117
+ this.reconnectTries > n && this._client.connectionEvent?.({
118
+ type: "reconnecting",
119
+ url: this._url,
120
+ retries: this.reconnectTries
121
+ }), await y(i), !this.deferReconnectionUntilOnline() && (this.reconnectTries > n && this._client.connectionEvent?.({
122
+ type: "reconnecting",
123
+ url: this._url,
124
+ retries: this.reconnectTries
125
+ }), this.connect());
126
+ }, this.deferReconnectionUntilOnline = () => T() ? !1 : (typeof window < "u" && window.addEventListener("online", this.handleOnlineForReconnection, { once: !0 }), !0), this.handleClose = async (e) => {
127
+ this.clearAllTimers(), this._client.connectionEvent?.({
128
+ type: "close",
159
129
  url: this._url,
160
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri),
161
- code: t.code,
162
- reason: t.reason,
163
- wasClean: t.wasClean,
164
- online: typeof window < "u" && window.navigator.onLine
130
+ code: e.code,
131
+ reason: e.reason,
132
+ wasClean: e.wasClean,
133
+ subscriptions: this._listeners.size
165
134
  });
166
- let n = I(t.code), r = this._listeners.size > 0;
167
- n && r && await this.attemptReconnection(t.code), this.cleanupConnection();
135
+ let t = k(e.code), n = this._listeners.size > 0;
136
+ t && n && await this.attemptReconnection(e.code), this.cleanupConnection();
168
137
  }, this.handleOpen = () => {
169
- typeof window < "u" && window.addEventListener("offline", this.handleOffline), u(`${this._name}-offline`), u(`${this._name}-reconnecting`), this.reconnectTries > b.NOTIFICATION_THRESHOLD && d(`reconnected to ${this._name}.`, {
170
- key: `${this._name}-online`,
171
- variant: "success",
172
- preventDuplicate: !0
173
- }), this.reconnectTries = 0;
174
- let t = this._socket;
175
- t && (this._listeners.forEach((e) => e.onOpen?.()), e._logger?.log?.("info", "ws-on-open", {
138
+ typeof window < "u" && window.addEventListener("offline", this.handleOffline), this.reconnectTries = 0;
139
+ let e = this._socket;
140
+ e && (this._listeners.forEach((e) => e.onOpen?.()), this._client.connectionEvent?.({
141
+ type: "open",
176
142
  url: this._url,
177
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri)
178
- }), this.cachedMessages.forEach((e) => t.send(this.serializeMessage(e)))), this.cachedMessages = [], this.schedulePing();
179
- }, this.handleMessage = (t) => {
143
+ retries: this.reconnectTries,
144
+ uriApis: b(this._listeners)
145
+ }), this.cachedMessages.forEach((t) => e.send(this.serializeMessage(t)))), this.cachedMessages = [], this._client.heartbeat.enabled && this.schedulePing();
146
+ }, this.handleMessage = (e) => {
180
147
  try {
181
- let n = JSON.parse(t.data);
182
- if (!D(n)) {
183
- e._logger?.log?.("error", "ws-invalid-message", {
148
+ let t = JSON.parse(e.data);
149
+ if (!C(t)) {
150
+ this._client.connectionEvent?.({
151
+ type: "invalid-message",
184
152
  url: this._url,
185
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri),
186
- message: n
187
- }), this._listeners.forEach((e) => e.onError({
153
+ uriApis: b(this._listeners),
154
+ message: t
155
+ }), this._listeners.forEach((t) => t.onError({
188
156
  type: "transport",
189
- event: t
157
+ event: e
190
158
  }));
191
159
  return;
192
160
  }
193
- if (n.uri === "ping") {
194
- this.clearPongTimeout(), this.schedulePing();
161
+ if (t.uri === "ping") {
162
+ this.clearPongTimeout(), this._client.heartbeat.enabled && this.schedulePing();
195
163
  return;
196
164
  }
197
- if (O(n.method)) {
198
- e._logger?.log?.("error", "ws-message-error", {
165
+ if (w(t.method)) {
166
+ this._client.connectionEvent?.({
167
+ type: "message-error",
199
168
  url: this._url,
200
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri),
201
- message: n
202
- }), this.forEachMatchingListener(n.uri, (e) => e.onMessageError({
169
+ uri: t.uri,
170
+ uriApis: b(this._listeners),
171
+ message: t
172
+ }), this.forEachMatchingListener(t.uri, (e) => e.onMessageError({
203
173
  type: "server",
204
- message: n
174
+ message: t
205
175
  }));
206
176
  return;
207
177
  }
208
- this.forEachMatchingListener(n.uri, (e) => {
209
- e.uri === n.uri ? e.onMessage?.(n.body) : e.deliverMessage?.(n.uri, n.body);
178
+ this.forEachMatchingListener(t.uri, (e) => {
179
+ e.uri === t.uri ? e.onMessage?.(t.body) : e.deliverMessage?.(t.uri, t.body);
210
180
  });
211
- } catch (n) {
212
- e._logger?.log?.("error", "ws-message-parse-error", {
181
+ } catch (t) {
182
+ this._client.connectionEvent?.({
183
+ type: "parse-error",
213
184
  url: this._url,
214
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri),
215
- message: t.data,
216
- error: n
217
- }), this._listeners.forEach((e) => e.onError({
185
+ uriApis: b(this._listeners),
186
+ message: e.data,
187
+ error: t
188
+ }), this._listeners.forEach((t) => t.onError({
218
189
  type: "transport",
219
- event: t
190
+ event: e
220
191
  }));
221
192
  }
222
- }, this.handleError = (t) => {
223
- this._listeners.forEach((e) => e.onError({
193
+ }, this.handleError = (e) => {
194
+ this._listeners.forEach((t) => t.onError({
224
195
  type: "transport",
225
- event: t
226
- })), e._logger?.log?.("error", "ws-error", {
196
+ event: e
197
+ })), this._client.connectionEvent?.({
198
+ type: "error",
227
199
  url: this._url,
228
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri),
229
- event: t
200
+ uriApis: b(this._listeners),
201
+ event: e
230
202
  });
231
203
  }, this.handleOnline = () => {
232
204
  typeof window < "u" && window.removeEventListener("online", this.handleOnline), this.connect();
@@ -234,38 +206,43 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
234
206
  typeof window < "u" && window.removeEventListener("online", this.handleOnlineForReconnection), this.reconnectTries--, this.attemptReconnection();
235
207
  }, this.handleOffline = () => {
236
208
  typeof window < "u" && window.removeEventListener("offline", this.handleOffline), this._socket && this._listeners.forEach((e) => e.onClose(new CloseEvent("offline"))), this.teardownSocket(), typeof window < "u" && window.addEventListener("online", this.handleOnline);
237
- }, this.handleSendMessage = (t) => {
209
+ }, this.handleSendMessage = (e) => {
238
210
  if (this._socket?.readyState === WebSocket.OPEN) {
239
- e._logger?.log?.("info", `ws-${t.method}: ${t.uri}`, {
211
+ this._client.connectionEvent?.({
212
+ type: "send-message",
240
213
  url: this._url,
241
- message: t.body
242
- }), this._socket.send(this.serializeMessage(t));
214
+ uri: e.uri,
215
+ body: e.body,
216
+ method: e.method
217
+ }), this._socket.send(this.serializeMessage(e));
243
218
  return;
244
219
  }
245
- t.method !== "subscribe" && this.cachedMessages.push(t), this.connect();
220
+ e.method !== "subscribe" && this.cachedMessages.push(e), this.connect();
246
221
  }, this.sendPing = () => {
247
- A(this._socket) && (this._socket?.send(P()), this.schedulePongTimeout());
222
+ E(this._socket) && (this._socket?.send(this.serializeMessage(D())), this.schedulePongTimeout());
248
223
  }, this.clearPongTimeout = () => {
249
224
  clearTimeout(this.pongTimeOut), this.pongTimeOut = void 0;
250
225
  }, this.schedulePongTimeout = () => {
251
- this.clearPongTimeout(), this.pongTimeOut = setTimeout(() => {
252
- e._logger?.log?.("info", "ws-pong-timeout", {
253
- url: this._url,
254
- uriApis: Array.from(this._listeners).filter(([e, t]) => "uri" in t).map(([e, t]) => t.uri)
226
+ this.clearPongTimeout();
227
+ let e = this._client.heartbeat.pongTimeoutMs;
228
+ this.pongTimeOut = setTimeout(() => {
229
+ this._client.connectionEvent?.({
230
+ type: "pong-timeout",
231
+ url: this._url
255
232
  }), this.teardownSocket(), this.attemptReconnection();
256
- }, S.PONG_TIMEOUT_MS);
233
+ }, e);
257
234
  }, this.schedulePing = () => {
258
235
  this.pingTimeOut = setTimeout(() => {
259
236
  this.sendPing();
260
- }, E());
261
- }, this.serializeMessage = (e) => JSON.stringify({
262
- ...e,
263
- correlation: f()
264
- }), this.forEachMatchingListener = (e, t) => {
237
+ }, S());
238
+ }, this.serializeMessage = (e) => {
239
+ let t = this._client.transformMessagePayload;
240
+ return t && (e = t(e)), JSON.stringify(e);
241
+ }, this.forEachMatchingListener = (e, t) => {
265
242
  this._listeners.forEach((n) => {
266
243
  (n.uri === e || n.hasWaitingUri?.(e)) && t(n);
267
244
  });
268
- }, this._url = t, this._name = new URL(t).pathname;
245
+ }, this._url = e, this._client = t;
269
246
  }
270
247
  get readyState() {
271
248
  return this._socket?.readyState;
@@ -273,9 +250,61 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
273
250
  get url() {
274
251
  return this._url;
275
252
  }
276
- }, R = class {
277
- constructor(e) {
278
- this._sendToConnection = null, this._pendingByUri = /* @__PURE__ */ new Map(), this._pendingMessages = [], this._registeredHooks = /* @__PURE__ */ new Set(), this.hasWaitingUri = (e) => this._pendingByUri.has(e), this.registerHook = (e) => {
253
+ }, j = class {
254
+ constructor({ maxRetryAttempts: t, notificationThreshold: n, tryAgainLaterDelayMs: r, delays: i, phaseThresholds: a, connectionCleanupDelayMs: o, messageResponseTimeoutMs: s, heartbeat: c, transformMessagePayload: l, connectionEvent: u }) {
255
+ this._connections = new e(/* @__PURE__ */ new Map()), this._listeners = new e(/* @__PURE__ */ new Map()), this.reconnectAllConnections = () => {
256
+ this._connections.state.forEach((e) => {
257
+ e.reconnect();
258
+ });
259
+ }, this.addListener = (e) => {
260
+ this._listeners.setState((t) => {
261
+ let n = new Map(t);
262
+ return n.set(e.key, e), n;
263
+ });
264
+ }, this.removeListener = (e) => {
265
+ this._listeners.setState((t) => {
266
+ let n = new Map(t);
267
+ return n.delete(e.key), n;
268
+ });
269
+ }, this.getConnection = (e) => this._connections.state.get(e), this.addConnection = (e, t) => {
270
+ let n = this._connections.state.get(e);
271
+ if (n) return n;
272
+ let r = new A(t, this);
273
+ return this._connections.setState((t) => {
274
+ let n = new Map(t);
275
+ return n.set(e, r), n;
276
+ }), r;
277
+ }, this.removeConnection = (e) => {
278
+ this._connections.setState((t) => {
279
+ let n = new Map(t);
280
+ return n.delete(e), n;
281
+ });
282
+ }, this.maxRetryAttempts = t ?? m.MAX_RETRY_ATTEMPTS, this.notificationThreshold = n ?? m.NOTIFICATION_THRESHOLD, this.tryAgainLaterDelayMs = r ?? m.TRY_AGAIN_LATER_DELAY_MS, this.delays = {
283
+ firstPhase: i?.firstPhase ?? m.DELAYS.FIRST_PHASE,
284
+ secondPhase: i?.secondPhase ?? m.DELAYS.SECOND_PHASE,
285
+ thirdPhase: i?.thirdPhase ?? m.DELAYS.THIRD_PHASE
286
+ }, this.phaseThresholds = {
287
+ first: a?.first ?? m.PHASE_THRESHOLDS.FIRST,
288
+ second: a?.second ?? m.PHASE_THRESHOLDS.SECOND
289
+ }, this.connectionCleanupDelayMs = o ?? 3e3, this.messageResponseTimeoutMs = s ?? 1e4, this.heartbeat = {
290
+ enabled: c?.enabled ?? v.enabled,
291
+ pongTimeoutMs: c?.pongTimeoutMs ?? v.pongTimeoutMs
292
+ }, this.transformMessagePayload = l ?? void 0, this.connectionEvent = u ?? void 0;
293
+ }
294
+ getListener(e, t) {
295
+ let n = this._listeners.state.get(e);
296
+ if (n && n.type === t) return n;
297
+ }
298
+ }, M = r(void 0), N = () => {
299
+ let e = i(M);
300
+ if (!e) throw Error("useWebsocketClient must be used within a WebsocketClientProvider");
301
+ return e;
302
+ }, P = ({ children: e, client: t }) => /* @__PURE__ */ u(M.Provider, {
303
+ value: t,
304
+ children: e
305
+ }), F = class {
306
+ constructor(e, t) {
307
+ this._sendToConnection = null, this._pendingByUri = /* @__PURE__ */ new Map(), this._pendingMessages = [], this._registeredHooks = /* @__PURE__ */ new Set(), this.type = "message", this.hasWaitingUri = (e) => this._pendingByUri.has(e), this.registerHook = (e) => {
279
308
  this._clearHookRemovalTimeout(), this._registeredHooks.add(e);
280
309
  }, this.unregisterHook = (e, t) => {
281
310
  this._registeredHooks.delete(e), this._scheduleHookRemoval(t);
@@ -296,9 +325,9 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
296
325
  this._cancelAllPending(), this._options.onClose?.(e);
297
326
  }, this.reset = () => {
298
327
  this._clearHookRemovalTimeout(), this._cancelAllPending();
299
- }, this._options = {
328
+ }, this._client = t, this._options = {
300
329
  enabled: !0,
301
- responseTimeoutMs: w,
330
+ responseTimeoutMs: t.messageResponseTimeoutMs,
302
331
  ...e
303
332
  };
304
333
  }
@@ -314,7 +343,7 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
314
343
  sendMessage(e, t, n, r) {
315
344
  if (!this.isEnabled) return Promise.reject(/* @__PURE__ */ Error("WebsocketMessageApi is disabled"));
316
345
  this._cancelPendingForUri(e);
317
- let i = r?.timeout ?? this._options.responseTimeoutMs ?? 1e4;
346
+ let i = r?.timeout ?? this._options.responseTimeoutMs ?? this._client.messageResponseTimeoutMs;
318
347
  return new Promise((r, a) => {
319
348
  let o = setTimeout(() => {
320
349
  this._pendingByUri.get(e)?.timeoutId === o && (this._pendingByUri.delete(e), a(/* @__PURE__ */ Error(`WebSocket response timeout for URI: ${e}`)));
@@ -327,8 +356,7 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
327
356
  let s = {
328
357
  uri: e,
329
358
  method: t,
330
- body: n,
331
- correlation: f()
359
+ body: n
332
360
  };
333
361
  this._sendOrQueue(s);
334
362
  });
@@ -338,8 +366,7 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
338
366
  let r = {
339
367
  uri: e,
340
368
  method: t,
341
- body: n,
342
- correlation: f()
369
+ body: n
343
370
  };
344
371
  this._sendOrQueue(r);
345
372
  }
@@ -366,9 +393,9 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
366
393
  clearTimeout(e.timeoutId), e.reject(/* @__PURE__ */ Error("WebSocket connection closed"));
367
394
  }), this._pendingByUri.clear();
368
395
  }
369
- }, z = class {
396
+ }, I = class {
370
397
  constructor(t) {
371
- this._state = new e(m()), this._registeredHooks = /* @__PURE__ */ new Set(), this._sendToConnection = null, this._pendingMessages = [], this.setSendToConnection = (e) => {
398
+ this._state = new e(f()), this._registeredHooks = /* @__PURE__ */ new Set(), this._sendToConnection = null, this._pendingMessages = [], this.type = "subscription", this.setSendToConnection = (e) => {
372
399
  this._sendToConnection = e, e ? this._flushPendingMessages(e) : (this._clearPendingTimeouts(), this._pendingMessages = []);
373
400
  }, this.registerHook = (e) => {
374
401
  this._clearPendingTimeouts(), this._registeredHooks.add(e), this._registeredHooks.size > 1 && console.warn(`the uri ${this.uri} has more than one initiator, multiple initiators could cause unexpected behavior`);
@@ -457,7 +484,7 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
457
484
  pendingSubscription: !1
458
485
  })), this._options.onClose?.(e);
459
486
  }, this._options = {
460
- ...C,
487
+ ..._,
461
488
  ...t
462
489
  };
463
490
  }
@@ -484,13 +511,13 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
484
511
  }
485
512
  set options(e) {
486
513
  let t = {
487
- ...C,
514
+ ..._,
488
515
  ...this._options,
489
516
  ...e
490
517
  };
491
- if (r(this._options, t)) return;
492
- let n = this._options;
493
- this._options = t, this._handleSubscriptionUpdates(n, t), this._handleUnsubscribeOnDisable(n, t);
518
+ if (n(this._options, t)) return;
519
+ let r = this._options;
520
+ this._options = t, this._handleSubscriptionUpdates(r, t), this._handleUnsubscribeOnDisable(r, t);
494
521
  }
495
522
  _clearPendingTimeouts() {
496
523
  this._disconnectTimeout !== void 0 && (clearTimeout(this._disconnectTimeout), this._disconnectTimeout = void 0), this._hookRemovalTimeout !== void 0 && (clearTimeout(this._hookRemovalTimeout), this._hookRemovalTimeout = void 0);
@@ -514,82 +541,70 @@ var h = new e(/* @__PURE__ */ new Map()), g = new e(/* @__PURE__ */ new Map()),
514
541
  this._sendToConnection ? this._sendToConnection(e) : this._pendingMessages.push(e);
515
542
  }
516
543
  _handleSubscriptionUpdates(e, t) {
517
- let n = !r(e.body, t.body), i = !e.enabled && t.enabled;
518
- (n || i) && this.subscribe(t.body);
544
+ let r = !n(e.body, t.body), i = !e.enabled && t.enabled;
545
+ (r || i) && this.subscribe(t.body);
519
546
  }
520
547
  _handleUnsubscribeOnDisable(e, t) {
521
548
  let n = !t.enabled, r = e.enabled;
522
549
  n && r && this._state.state.subscribed && this.unsubscribe();
523
550
  }
524
- }, B = (e, t) => {
525
- let n = V(e);
526
- if (n) return n;
527
- let r = new L(t);
528
- return h.setState((t) => new Map(t).set(e, r)), r;
529
- }, V = (e) => h.state.get(e), H = (e) => {
530
- let t = g.state.get(e);
531
- if (t && "uri" in t) return t;
532
- }, U = (e, t) => {
533
- let n = H(e);
534
- if (n) return n;
535
- let r = new z(t);
536
- return g.setState((t) => new Map(t).set(e, r)), r;
537
- }, W = (e) => {
538
- let t = g.state.get(e);
539
- if (t && "hasWaitingUri" in t) return t;
540
- }, G = (e, t) => {
541
- let n = W(e);
542
- if (n) return n;
543
- let r = new R(t);
544
- return g.setState((t) => new Map(t).set(e, r)), r;
545
- }, K = (e) => {
546
- V(e.url)?.removeListener(e), g.setState((t) => {
547
- let n = new Map(t);
548
- return n.delete(e.key), n;
549
- });
551
+ }, L = (e, t, n) => {
552
+ let r = e.getListener(t, "subscription");
553
+ if (r) return r;
554
+ let i = new I(n);
555
+ return e.addListener(i), i;
556
+ }, R = (e, t, n) => {
557
+ let r = e.getListener(t, "message");
558
+ if (r) return r;
559
+ let i = new F(n, e);
560
+ return e.addListener(i), i;
561
+ }, z = (e, t) => {
562
+ e.getConnection(t.url)?.removeListener(t), e.removeListener(t);
550
563
  };
551
564
  //#endregion
552
565
  //#region src/lib/WebsocketHook.ts
553
- function q(e) {
566
+ function B(e) {
554
567
  let t = s(e);
555
- return r(t.current, e) || (t.current = e), t.current;
568
+ return n(t.current, e) || (t.current = e), t.current;
556
569
  }
557
- function J(e, t, n) {
558
- let r = o();
570
+ function V(e, t, n) {
571
+ let r = o(), i = N();
559
572
  l(() => {
560
- n === !1 ? e.disconnect(() => K(e)) : B(e.url, t).addListener(e);
561
- }, [n, e]), l(() => {
562
- V(t)?.replaceUrl(t);
563
- }, [t, t]), a(() => {
573
+ n === !1 ? e.disconnect(() => z(i, e)) : i.addConnection(e.url, t).addListener(e);
574
+ }, [
575
+ n,
576
+ e,
577
+ i
578
+ ]), l(() => {
579
+ i.getConnection(t)?.replaceUrl(t);
580
+ }, [t, i]), a(() => {
564
581
  let t = r;
565
582
  return n !== !1 && e.registerHook(r), () => {
566
- e.unregisterHook(t, () => K(e));
583
+ e.unregisterHook(t, () => z(i, e));
567
584
  };
568
585
  }, [
586
+ i,
569
587
  n,
570
588
  r,
571
589
  e
572
590
  ]);
573
591
  }
574
- function Y(e) {
575
- let [t] = c(() => U(e.key, e));
576
- J(t, e.url, e.enabled);
577
- let n = q(e);
592
+ function H(e) {
593
+ let t = N(), [n] = c(() => L(t, e.key, e));
594
+ V(n, e.url, e.enabled);
595
+ let r = B(e);
578
596
  return l(() => {
579
- t.options = n;
580
- }, [n, t]), t;
597
+ n.options = r;
598
+ }, [r, n]), n;
581
599
  }
582
- var X = (e) => {
583
- let r = t(g, (t) => {
584
- let n = t.get(e);
585
- if (n && "uri" in n) return n;
586
- }), [i] = c(() => new n(m()));
587
- return r?.store ?? i;
588
- }, Z = (e) => {
589
- let [t] = c(() => G(e.key, e));
590
- return J(t, e.url, e.enabled), t;
600
+ var U = (e) => {
601
+ let n = N().getListener(e, "subscription"), [r] = c(() => new t(f()));
602
+ return n?.store ?? r;
603
+ }, W = (e) => {
604
+ let t = N(), [n] = c(() => R(t, e.key, e));
605
+ return V(n, e.url, e.enabled), n;
591
606
  };
592
607
  //#endregion
593
- export { p as ReadyState, L as WebsocketConnection, R as WebsocketMessageApi, z as WebsocketSubscriptionApi, m as createInitialWebsocketSubscriptionStore, Z as useWebsocketMessage, Y as useWebsocketSubscription, X as useWebsocketSubscriptionByKey, _ as websocketConnectionsReconnect };
608
+ export { d as ReadyState, j as WebsocketClient, P as WebsocketClientProvider, A as WebsocketConnection, F as WebsocketMessageApi, I as WebsocketSubscriptionApi, f as createInitialWebsocketSubscriptionStore, N as useWebsocketClient, W as useWebsocketMessage, H as useWebsocketSubscription, U as useWebsocketSubscriptionByKey };
594
609
 
595
610
  //# sourceMappingURL=index.js.map