@flamingo-stack/openframe-frontend-core 0.0.555 → 0.0.556

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.
Files changed (113) hide show
  1. package/dist/{chunk-6ER3AYJM.js → chunk-5756Q6UN.js} +3 -3
  2. package/dist/{chunk-E2IPBWGT.js → chunk-5EES5HD4.js} +6 -6
  3. package/dist/{chunk-ODRMPI3Y.js → chunk-5JWLZJK5.js} +2 -2
  4. package/dist/{chunk-CVCQW7WG.js → chunk-5M4PS3XX.js} +3 -3
  5. package/dist/{chunk-6QRKCVYR.cjs → chunk-7Q7GFIFB.cjs} +7 -7
  6. package/dist/{chunk-6QRKCVYR.cjs.map → chunk-7Q7GFIFB.cjs.map} +1 -1
  7. package/dist/{chunk-UXW63WCV.cjs → chunk-BNMKHG2L.cjs} +4 -4
  8. package/dist/{chunk-UXW63WCV.cjs.map → chunk-BNMKHG2L.cjs.map} +1 -1
  9. package/dist/{chunk-SST2YI7S.cjs → chunk-BZKUID4R.cjs} +14 -14
  10. package/dist/{chunk-SST2YI7S.cjs.map → chunk-BZKUID4R.cjs.map} +1 -1
  11. package/dist/{chunk-YAOBDOI5.cjs → chunk-C74PZU6M.cjs} +32 -32
  12. package/dist/{chunk-YAOBDOI5.cjs.map → chunk-C74PZU6M.cjs.map} +1 -1
  13. package/dist/{chunk-P7MSXPGL.js → chunk-CGUSNV6R.js} +8 -8
  14. package/dist/{chunk-N5A4AC2J.cjs → chunk-CRGIXNUE.cjs} +23 -23
  15. package/dist/{chunk-N5A4AC2J.cjs.map → chunk-CRGIXNUE.cjs.map} +1 -1
  16. package/dist/{chunk-Q6RC3YGW.cjs → chunk-DFJ7TWH6.cjs} +3 -3
  17. package/dist/{chunk-Q6RC3YGW.cjs.map → chunk-DFJ7TWH6.cjs.map} +1 -1
  18. package/dist/{chunk-HO3Q7NXJ.js → chunk-FLSEJSTN.js} +2 -2
  19. package/dist/{chunk-UL3WQWTF.js → chunk-FZT7BYNF.js} +2 -2
  20. package/dist/{chunk-XOKRFZBD.cjs → chunk-HOEOGFQM.cjs} +97 -97
  21. package/dist/{chunk-XOKRFZBD.cjs.map → chunk-HOEOGFQM.cjs.map} +1 -1
  22. package/dist/{chunk-MLVF3OXU.cjs → chunk-HYABNMBN.cjs} +76 -76
  23. package/dist/{chunk-MLVF3OXU.cjs.map → chunk-HYABNMBN.cjs.map} +1 -1
  24. package/dist/{chunk-J76LCSR4.cjs → chunk-ICG7JRYT.cjs} +40 -40
  25. package/dist/{chunk-J76LCSR4.cjs.map → chunk-ICG7JRYT.cjs.map} +1 -1
  26. package/dist/{chunk-P22HM2MO.cjs → chunk-JDUPAHJR.cjs} +18 -18
  27. package/dist/{chunk-P22HM2MO.cjs.map → chunk-JDUPAHJR.cjs.map} +1 -1
  28. package/dist/{chunk-B2GEKAAA.js → chunk-JRWOHH7K.js} +2 -2
  29. package/dist/{chunk-TXV444YV.js → chunk-JXJ4FTKN.js} +3 -3
  30. package/dist/{chunk-CU6Q2KQT.cjs → chunk-LZD3VSPS.cjs} +12 -12
  31. package/dist/{chunk-CU6Q2KQT.cjs.map → chunk-LZD3VSPS.cjs.map} +1 -1
  32. package/dist/{chunk-M5TWHFIN.cjs → chunk-Q5SZ2QTZ.cjs} +42 -42
  33. package/dist/{chunk-M5TWHFIN.cjs.map → chunk-Q5SZ2QTZ.cjs.map} +1 -1
  34. package/dist/{chunk-GSONSIWG.js → chunk-R7A7WHXP.js} +60 -35
  35. package/dist/chunk-R7A7WHXP.js.map +1 -0
  36. package/dist/{chunk-E56VNTBV.cjs → chunk-S4LL6QI6.cjs} +147 -147
  37. package/dist/{chunk-E56VNTBV.cjs.map → chunk-S4LL6QI6.cjs.map} +1 -1
  38. package/dist/{chunk-KQKU4VXB.cjs → chunk-STHVHAV4.cjs} +82 -57
  39. package/dist/chunk-STHVHAV4.cjs.map +1 -0
  40. package/dist/{chunk-A7ES3NZK.cjs → chunk-SXMJLNOF.cjs} +3 -3
  41. package/dist/{chunk-A7ES3NZK.cjs.map → chunk-SXMJLNOF.cjs.map} +1 -1
  42. package/dist/{chunk-CTTY5EKH.js → chunk-VF4DCOPD.js} +5 -5
  43. package/dist/{chunk-QTO3WYB2.cjs → chunk-VJTD2DGF.cjs} +3 -3
  44. package/dist/{chunk-QTO3WYB2.cjs.map → chunk-VJTD2DGF.cjs.map} +1 -1
  45. package/dist/{chunk-VGLDA77S.js → chunk-VRX6Y6A7.js} +2 -2
  46. package/dist/{chunk-L36R3G7Z.js → chunk-VXNMOGRP.js} +6 -6
  47. package/dist/{chunk-OR67WC32.js → chunk-WBQ3NOH7.js} +2 -2
  48. package/dist/{chunk-QMQQ37RW.js → chunk-WX5UCLL7.js} +2 -2
  49. package/dist/{chunk-QZ64JOE2.js → chunk-XGBVHQP7.js} +3 -3
  50. package/dist/{chunk-K432ES7N.js → chunk-YM2WHYYK.js} +4 -4
  51. package/dist/{chunk-KXLQITOX.cjs → chunk-Z3R3LOC5.cjs} +5 -5
  52. package/dist/{chunk-KXLQITOX.cjs.map → chunk-Z3R3LOC5.cjs.map} +1 -1
  53. package/dist/components/case-studies/index.cjs +10 -10
  54. package/dist/components/case-studies/index.js +4 -4
  55. package/dist/components/chat/index.cjs +4 -4
  56. package/dist/components/chat/index.js +3 -3
  57. package/dist/components/contact/index.cjs +5 -5
  58. package/dist/components/contact/index.js +4 -4
  59. package/dist/components/docs/index.cjs +7 -7
  60. package/dist/components/docs/index.js +6 -6
  61. package/dist/components/embeds/index.cjs +5 -5
  62. package/dist/components/embeds/index.js +4 -4
  63. package/dist/components/faq/index.cjs +6 -6
  64. package/dist/components/faq/index.js +5 -5
  65. package/dist/components/features/index.cjs +4 -4
  66. package/dist/components/features/index.js +3 -3
  67. package/dist/components/help-center-pages/index.cjs +25 -25
  68. package/dist/components/help-center-pages/index.js +16 -16
  69. package/dist/components/index.cjs +138 -138
  70. package/dist/components/index.js +14 -14
  71. package/dist/components/meeting-scheduler/index.cjs +35 -35
  72. package/dist/components/meeting-scheduler/index.js +5 -5
  73. package/dist/components/navigation/index.cjs +4 -4
  74. package/dist/components/navigation/index.js +3 -3
  75. package/dist/components/onboarding-guides/index.cjs +8 -8
  76. package/dist/components/onboarding-guides/index.js +7 -7
  77. package/dist/components/related-content/index.cjs +6 -6
  78. package/dist/components/related-content/index.js +5 -5
  79. package/dist/components/tickets/index.cjs +8 -8
  80. package/dist/components/tickets/index.js +7 -7
  81. package/dist/components/ui/index.cjs +4 -4
  82. package/dist/components/ui/index.js +3 -3
  83. package/dist/hooks/index.cjs +3 -3
  84. package/dist/hooks/index.js +2 -2
  85. package/dist/index.cjs +4 -4
  86. package/dist/index.js +3 -3
  87. package/dist/nats/index.cjs +2 -2
  88. package/dist/nats/index.js +1 -1
  89. package/dist/nats/nats.d.ts.map +1 -1
  90. package/dist/nats/shared-connection.d.ts +13 -6
  91. package/dist/nats/shared-connection.d.ts.map +1 -1
  92. package/package.json +1 -1
  93. package/src/nats/__tests__/reconnect-lifecycle.test.tsx +814 -0
  94. package/src/nats/nats.ts +56 -13
  95. package/src/nats/shared-connection.ts +132 -36
  96. package/dist/chunk-GSONSIWG.js.map +0 -1
  97. package/dist/chunk-KQKU4VXB.cjs.map +0 -1
  98. /package/dist/{chunk-6ER3AYJM.js.map → chunk-5756Q6UN.js.map} +0 -0
  99. /package/dist/{chunk-E2IPBWGT.js.map → chunk-5EES5HD4.js.map} +0 -0
  100. /package/dist/{chunk-ODRMPI3Y.js.map → chunk-5JWLZJK5.js.map} +0 -0
  101. /package/dist/{chunk-CVCQW7WG.js.map → chunk-5M4PS3XX.js.map} +0 -0
  102. /package/dist/{chunk-P7MSXPGL.js.map → chunk-CGUSNV6R.js.map} +0 -0
  103. /package/dist/{chunk-HO3Q7NXJ.js.map → chunk-FLSEJSTN.js.map} +0 -0
  104. /package/dist/{chunk-UL3WQWTF.js.map → chunk-FZT7BYNF.js.map} +0 -0
  105. /package/dist/{chunk-B2GEKAAA.js.map → chunk-JRWOHH7K.js.map} +0 -0
  106. /package/dist/{chunk-TXV444YV.js.map → chunk-JXJ4FTKN.js.map} +0 -0
  107. /package/dist/{chunk-CTTY5EKH.js.map → chunk-VF4DCOPD.js.map} +0 -0
  108. /package/dist/{chunk-VGLDA77S.js.map → chunk-VRX6Y6A7.js.map} +0 -0
  109. /package/dist/{chunk-L36R3G7Z.js.map → chunk-VXNMOGRP.js.map} +0 -0
  110. /package/dist/{chunk-OR67WC32.js.map → chunk-WBQ3NOH7.js.map} +0 -0
  111. /package/dist/{chunk-QMQQ37RW.js.map → chunk-WX5UCLL7.js.map} +0 -0
  112. /package/dist/{chunk-QZ64JOE2.js.map → chunk-XGBVHQP7.js.map} +0 -0
  113. /package/dist/{chunk-K432ES7N.js.map → chunk-YM2WHYYK.js.map} +0 -0
package/src/nats/nats.ts CHANGED
@@ -3,6 +3,8 @@ import type {
3
3
  Consumer,
4
4
  ConsumerEvents,
5
5
  ConsumerMessages,
6
+ DebugEvents,
7
+ Events,
6
8
  JsMsg,
7
9
  MsgHdrs as NatsHeaders,
8
10
  Msg,
@@ -278,14 +280,58 @@ function mapOptionsToConnectionOptions(
278
280
  }
279
281
  }
280
282
 
281
- function mapNatsTypeToStatus(type: unknown): NatsStatus | null {
282
- const t = String(type).toLowerCase()
283
- if (t.includes('disconnect')) return 'disconnected'
284
- if (t === 'reconnecting') return 'reconnecting'
285
- if (t === 'reconnect' || t.includes('connect')) return 'connected'
286
- if (t.includes('error')) return 'error'
287
- if (t.includes('close')) return 'closed'
288
- return null
283
+ /**
284
+ * Map a nats.ws status event onto our own status vocabulary.
285
+ *
286
+ * Exact enum matches, never substring tests. Substring matching reported
287
+ * `staleConnection` and `client initiated reconnect` as CONNECTED both
288
+ * contain "connect" and neither contains "disconnect" — so the wrapper
289
+ * announced a live connection at the exact moment the client had given up on
290
+ * one. Downstream that is worse than silence: `NatsProvider` reads a
291
+ * `connected` that follows an earlier connection as a RECONNECT and bumps
292
+ * `reconnectionCount`, which every subscriber takes as "the tail came back" —
293
+ * resubscribing against a dying client and refetching persisted history.
294
+ * `staleConnection` is the one an idle mobile app hits routinely: no pong
295
+ * within `pingInterval * maxPingOut`, i.e. after a spell in the background.
296
+ *
297
+ * `StaleConnection` maps to `disconnected` rather than being ignored on the
298
+ * grounds that `Disconnect` follows it anyway — it does not always. nats.ws
299
+ * tears the transport down by draining `bufferedAmount` first, and a
300
+ * black-holed socket (no FIN, which is how a mobile link usually dies) never
301
+ * drains, so `Disconnect` can fail to arrive at all. Reporting it is then the
302
+ * only honest answer available: consumers stop trusting a tail the client has
303
+ * already given up on. It does NOT by itself recover that connection — the
304
+ * retry it arms short-circuits, because a protocol that never closed still
305
+ * reports `isConnected()`. Getting the socket back from that state needs a
306
+ * force-close path the client does not currently expose.
307
+ *
308
+ * The enums arrive as arguments rather than through a module-scope import
309
+ * because `nats.ws` is loaded lazily (see {@link importNats}) to keep this
310
+ * module safe to import from a Next server bundle. A hand-copied literal is
311
+ * what this is undoing, so it is not reintroduced here.
312
+ */
313
+ function mapNatsTypeToStatus(
314
+ type: Events | DebugEvents,
315
+ events: typeof import('nats.ws').Events,
316
+ debugEvents: typeof import('nats.ws').DebugEvents,
317
+ ): NatsStatus | null {
318
+ switch (type) {
319
+ case events.Disconnect:
320
+ return 'disconnected'
321
+ case events.Reconnect:
322
+ return 'connected'
323
+ case events.Error:
324
+ return 'error'
325
+ case debugEvents.Reconnecting:
326
+ case debugEvents.ClientInitiatedReconnect:
327
+ return 'reconnecting'
328
+ case debugEvents.StaleConnection:
329
+ return 'disconnected'
330
+ // Events.Update (cluster gossip), Events.LDM and DebugEvents.PingTimer say
331
+ // nothing about reachability.
332
+ default:
333
+ return null
334
+ }
289
335
  }
290
336
 
291
337
  /**
@@ -372,15 +418,12 @@ export function createNatsClient(options: NatsClientOptions): NatsClient {
372
418
  try {
373
419
  for await (const s of conn.status()) {
374
420
  if (signal.aborted) return
375
- const mapped = mapNatsTypeToStatus((s as any)?.type)
421
+ const mapped = mapNatsTypeToStatus(s.type, nats.Events, nats.DebugEvents)
376
422
  if (mapped) {
377
423
  if (mapped === 'connected' && backoff) {
378
424
  backoff.reset()
379
425
  }
380
- emitStatus({ status: mapped, data: (s as any)?.data })
381
- if (mapped === 'closed') {
382
- nc = null
383
- }
426
+ emitStatus({ status: mapped, data: s.data })
384
427
  }
385
428
  }
386
429
  } catch (e) {
@@ -26,17 +26,24 @@ export interface NatsReconnectionBackoff {
26
26
  export interface SharedConnection {
27
27
  wsUrl: string
28
28
  client: NatsClient
29
- connectPromise: Promise<void> | null
30
29
  refCount: number
31
30
  closeTimer: ReturnType<typeof setTimeout> | null
32
31
  retryTimer: ReturnType<typeof setTimeout> | null
33
32
  /**
34
- * Identity of the consumer driving reconnect. When set, other consumers
35
- * should observe status only and skip their own scheduleRetry — otherwise
36
- * each disconnect triggers multiple concurrent connect() calls racing over
37
- * connectPromise.
33
+ * The lifecycle driving reconnect, held as its own `scheduleRetry`. When set,
34
+ * other consumers observe status only and skip their own scheduleRetry —
35
+ * otherwise every disconnect starts one backoff schedule per attached
36
+ * consumer, all dialling the same connection on their own clocks.
38
37
  */
39
- retryOwner: object | null
38
+ retryOwner: (() => void) | null
39
+ /**
40
+ * The `scheduleRetry` of every lifecycle currently observing this connection,
41
+ * in attach order — the same value that goes into `retryOwner`, so a
42
+ * lifecycle has one identity rather than two. Only the owner drives
43
+ * reconnect, so when it gives the loop up the roster is what a successor is
44
+ * found in; see {@link handOffRetry}.
45
+ */
46
+ retrySchedulers: Set<() => void>
40
47
  }
41
48
 
42
49
  export interface AcquireClientOptions {
@@ -99,11 +106,11 @@ export function acquireClient(url: string, opts?: AcquireClientOptions): SharedC
99
106
  conn = {
100
107
  wsUrl: url,
101
108
  client,
102
- connectPromise: null,
103
109
  refCount: 0,
104
110
  closeTimer: null,
105
111
  retryTimer: null,
106
112
  retryOwner: null,
113
+ retrySchedulers: new Set(),
107
114
  }
108
115
  connections.set(url, conn)
109
116
  }
@@ -146,11 +153,13 @@ export function getSharedConnectionFor(url: string | null | undefined): SharedCo
146
153
 
147
154
  // ---------------------------------------------------------------------------
148
155
  // Connection lifecycle: retry + status loop, shared by NatsProvider and the
149
- // chat hooks. Each consumer that wants to drive reconnect creates an
150
- // ownerToken and calls startConnectionLifecycle(). The first caller to claim
151
- // retryOwner runs the actual retry loop; subsequent claimants observe status
152
- // only. When the owner unmounts and releases retryOwner, the next status
153
- // event lets a surviving consumer pick up ownership opportunistically.
156
+ // chat hooks. Every consumer that wants to observe or drive reconnect calls
157
+ // startConnectionLifecycle(). The first to claim retryOwner runs the actual
158
+ // retry loop; later attachers observe status only. When the owner gives the
159
+ // loop up it is handed to a survivor if the connection still needs one; while
160
+ // the connection is healthy no handoff is needed, because the next status
161
+ // event lets a survivor claim ownership opportunistically inside
162
+ // scheduleRetry.
154
163
  // ---------------------------------------------------------------------------
155
164
 
156
165
  export interface ConnectionLifecycleOptions {
@@ -176,14 +185,30 @@ export interface ConnectionLifecycleHandle {
176
185
 
177
186
  const defaultShouldRetryOn = (status: NatsStatus) => status === 'closed' || status === 'disconnected'
178
187
 
188
+ /**
189
+ * Offer the retry loop to another lifecycle on this connection.
190
+ *
191
+ * A retry is only ever armed from a status event or a failed dial, and a
192
+ * connection that is already down produces neither on its own — so whenever
193
+ * the owner gives the loop up while the connection still needs dialling, a
194
+ * successor has to be pushed rather than left waiting for an event that is not
195
+ * coming.
196
+ *
197
+ * Candidates that cannot service this URL decline inside `scheduleRetry`, so
198
+ * this walks the roster until one actually takes it. Callers must clear any
199
+ * timer of their own first: a successor that claims while a timer is still
200
+ * armed will not arm one, and the departing owner's timer no longer speaks for
201
+ * the connection.
202
+ */
203
+ function handOffRetry(conn: SharedConnection): void {
204
+ for (const takeOver of conn.retrySchedulers) {
205
+ takeOver()
206
+ if (conn.retryOwner) return
207
+ }
208
+ }
209
+
179
210
  export function startConnectionLifecycle(options: ConnectionLifecycleOptions): ConnectionLifecycleHandle {
180
211
  const { conn, wsUrl } = options
181
- // Each lifecycle gets its own identity for retry ownership. The first lifecycle to claim
182
- // an unowned connection drives reconnect; later attachers observe status only until the
183
- // owner releases (see opportunistic claim in scheduleRetry).
184
- const ownerToken = {}
185
- if (!conn.retryOwner) conn.retryOwner = ownerToken
186
-
187
212
  let closed = false
188
213
  let retryAttempt = 0
189
214
 
@@ -195,16 +220,33 @@ export function startConnectionLifecycle(options: ConnectionLifecycleOptions): C
195
220
  }
196
221
  }
197
222
 
223
+ // A lifecycle's identity IS its `scheduleRetry`: that function goes on the
224
+ // connection's roster and, for whichever lifecycle holds the loop, into
225
+ // `retryOwner` — one identity, not two.
226
+ conn.retrySchedulers.add(scheduleRetry)
227
+ if (!conn.retryOwner) conn.retryOwner = scheduleRetry
228
+
198
229
  function scheduleRetry() {
199
230
  if (closed) return
200
231
  if (getSharedConnectionFor(wsUrl) !== conn) return
201
- if (!conn.retryOwner) conn.retryOwner = ownerToken
202
- if (conn.retryOwner !== ownerToken) return
203
-
204
- if (conn.retryTimer) {
205
- clearTimeout(conn.retryTimer)
206
- conn.retryTimer = null
207
- }
232
+ // This lifecycle now wants a different URL, so it must not drive this
233
+ // connection not from its own status events, and not as a handoff
234
+ // successor. Without the guard, two consumers that had both moved on
235
+ // passed ownership back and forth indefinitely, running onBeforeReconnect
236
+ // — a token refresh in the real callers — on every pass and dialling
237
+ // nothing. The armed callback re-checks, because the URL can move between
238
+ // arming and firing.
239
+ if (options.getFreshUrl() !== wsUrl) return
240
+ if (!conn.retryOwner) conn.retryOwner = scheduleRetry
241
+ if (conn.retryOwner !== scheduleRetry) return
242
+
243
+ // One outage can raise more than one status: nats.ws reports
244
+ // `staleConnection` and then, once the transport is down, `disconnect`.
245
+ // Re-arming on the second would spend a backoff tier on the same outage —
246
+ // on the defaults, waiting 2000ms where the caller asked for 1000. The
247
+ // armed timer re-validates everything when it fires, so the first one
248
+ // scheduled for an outage is always the right one to keep.
249
+ if (conn.retryTimer) return
208
250
 
209
251
  const cfg = options.backoff ?? {}
210
252
  const fastRetries = cfg.fastRetries ?? 0
@@ -225,6 +267,16 @@ export function startConnectionLifecycle(options: ConnectionLifecycleOptions): C
225
267
  if (closed) return
226
268
  if (getSharedConnectionFor(wsUrl) !== conn) return
227
269
 
270
+ // Nothing to reconnect. Reached when the dial that was already in flight
271
+ // succeeded while this retry sat in its backoff — a handoff during a
272
+ // healthy first connect is enough to get here — and `onBeforeReconnect`
273
+ // is a token refresh in the real callers, so it must not run on a
274
+ // connection that came back on its own.
275
+ if (conn.client.isConnected()) {
276
+ retryAttempt = 0
277
+ return
278
+ }
279
+
228
280
  try {
229
281
  await options.onBeforeReconnect?.()
230
282
  } catch {
@@ -234,17 +286,33 @@ export function startConnectionLifecycle(options: ConnectionLifecycleOptions): C
234
286
  if (getSharedConnectionFor(wsUrl) !== conn) return
235
287
 
236
288
  const freshUrl = options.getFreshUrl()
237
- if (freshUrl !== wsUrl) return
289
+ if (freshUrl !== wsUrl) {
290
+ // This lifecycle has moved to a different URL, so it must not dial this
291
+ // connection again while holding the loop — that is the dead end the
292
+ // rest of this module exists to avoid. Give the loop up and push it to
293
+ // someone still on this URL.
294
+ if (conn.retryOwner === scheduleRetry) {
295
+ conn.retryOwner = null
296
+ // A status that landed while the refresh above was awaited can have
297
+ // armed a new timer under this ownership. It belongs to a lifecycle
298
+ // that is leaving, and a successor claiming while it is armed would
299
+ // return early believing the loop is covered — then this timer fires,
300
+ // finds someone else owns the loop, and bails without handing on.
301
+ if (conn.retryTimer) {
302
+ clearTimeout(conn.retryTimer)
303
+ conn.retryTimer = null
304
+ }
305
+ handOffRetry(conn)
306
+ }
307
+ return
308
+ }
238
309
 
239
310
  try {
240
- conn.connectPromise = null
241
- conn.connectPromise = conn.client.connect()
242
- await conn.connectPromise
311
+ await conn.client.connect()
243
312
  if (!closed && getSharedConnectionFor(wsUrl) === conn) {
244
313
  retryAttempt = 0
245
314
  }
246
315
  } catch {
247
- conn.connectPromise = null
248
316
  if (!closed && getSharedConnectionFor(wsUrl) === conn) {
249
317
  scheduleRetry()
250
318
  }
@@ -269,12 +337,20 @@ export function startConnectionLifecycle(options: ConnectionLifecycleOptions): C
269
337
  emitSynthetic('connected')
270
338
  }
271
339
 
340
+ // Dial through the client rather than caching a promise on the connection.
341
+ // A `conn.connectPromise` used to be assigned here with `||=` and then left
342
+ // in place after a SUCCESSFUL connect, so it doubled as "this connection has
343
+ // been dialled at some point": a consumer that acquired a still-cached
344
+ // connection whose socket had since died joined that long-settled promise
345
+ // instead of dialling. No connect, no failure, so nothing scheduled a retry,
346
+ // and no status event was coming to arm one either — the connection stayed
347
+ // dead for as long as anything held a reference to it. `NatsClient.connect()`
348
+ // already short-circuits on a live connection and joins its own in-flight
349
+ // dial, so the second copy of that bookkeeping bought nothing.
272
350
  void (async () => {
273
351
  try {
274
- conn.connectPromise ||= conn.client.connect()
275
- await conn.connectPromise
352
+ await conn.client.connect()
276
353
  } catch {
277
- conn.connectPromise = null
278
354
  if (closed) return
279
355
 
280
356
  emitSynthetic('disconnected')
@@ -286,13 +362,33 @@ export function startConnectionLifecycle(options: ConnectionLifecycleOptions): C
286
362
  stop() {
287
363
  closed = true
288
364
  unsubStatus()
365
+ conn.retrySchedulers.delete(scheduleRetry)
366
+
367
+ if (conn.retryOwner !== scheduleRetry) {
368
+ // Not ours to cancel. `retryTimer` lives on the CONNECTION, and
369
+ // clearing it unconditionally cancelled the owner's armed retry — so
370
+ // any consumer merely re-running its effect (an `enabled` toggle, a
371
+ // dialog closing, a route change) during a backoff killed reconnect
372
+ // for everyone. Nothing rescheduled it either, for the reason
373
+ // handOffRetry exists. The connection stayed down for good.
374
+ return
375
+ }
376
+
377
+ conn.retryOwner = null
378
+ const wasRetrying = conn.retryTimer !== null
289
379
  if (conn.retryTimer) {
290
380
  clearTimeout(conn.retryTimer)
291
381
  conn.retryTimer = null
292
382
  }
293
- if (conn.retryOwner === ownerToken) {
294
- conn.retryOwner = null
295
- }
383
+
384
+ // A healthy connection with nothing armed needs no successor: the next
385
+ // disconnect lets a survivor claim opportunistically. `wasRetrying` is
386
+ // read before the clearTimeout above, and the remaining case — the timer
387
+ // already fired and its callback is mid-dial — is caught by the
388
+ // connection not being connected. The successor backs off on its OWN
389
+ // attempt counter, which is zero unless it has driven the loop before.
390
+ if (!wasRetrying && conn.client.isConnected()) return
391
+ handOffRetry(conn)
296
392
  },
297
393
  }
298
394
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/nats/nats.ts","../src/nats/shared-connection.ts","../src/nats/nats-provider.tsx","../src/nats/use-nats-subscription.ts"],"sourcesContent":["import type {\n ConnectionOptions,\n Consumer,\n ConsumerEvents,\n ConsumerMessages,\n JsMsg,\n MsgHdrs as NatsHeaders,\n Msg,\n NatsConnection,\n Subscription,\n} from 'nats.ws'\n\nexport type { JsMsg, Msg, Subscription } from 'nats.ws'\n\nexport type JetStreamDeliverPolicy = 'new' | 'byStartSequence'\n\nexport interface JetStreamOrderedSubscribeOptions {\n streamName: string\n filterSubject: string\n deliverPolicy: JetStreamDeliverPolicy\n /** Required when deliverPolicy === 'byStartSequence'. */\n optStartSeq?: number\n /**\n * Auto-cleanup the ephemeral consumer after this idle time. Defaults to\n * nats.ws's own. Applies to the consumer created first: nats.ws only reads it\n * when the start sequence is the one it was built with, so every consumer it\n * recreates afterwards reverts to the library default.\n */\n inactiveThresholdMs?: number\n /** AbortSignal to tear down the consumer. */\n signal?: AbortSignal\n /**\n * The ordered consumer had to be rebuilt: the server dropped the ephemeral\n * consumer (its inactivity threshold elapsed while the page was suspended or\n * offline), heartbeats were missed, or a sequence gap was detected. nats.ws\n * recreates it from the last delivered sequence, so this is NOT an error —\n * but everything that aged out of the stream while it was gone is\n * unrecoverable from the tail, and no connection event announces it (the\n * WebSocket never dropped). Callers that keep persisted history alongside\n * the live tail must refetch it here, or they keep showing a snapshot from\n * before the gap.\n */\n onRecovered?: () => void\n}\n\nexport interface JetStreamSubscriptionHandle {\n unsubscribe(): void\n}\n\nexport interface NatsClientOptions {\n /**\n * NATS server URL(s), for example:\n * - \"wss://nats.example.com:443\"\n * - [\"wss://nats-1.example.com:443\", \"wss://nats-2.example.com:443\"]\n */\n servers: string | string[]\n\n /**\n * Connection name (shows up in NATS monitoring).\n */\n name?: string\n\n /**\n * Auth options (pick one: token or user/pass).\n */\n token?: string\n user?: string\n pass?: string\n\n /**\n * Reconnect behavior.\n */\n reconnect?: boolean\n maxReconnectAttempts?: number\n reconnectTimeWaitMs?: number\n\n /**\n * Exponential backoff for reconnect delays.\n * When set, uses `reconnectDelayHandler` from nats.ws under the hood,\n * overriding `reconnectTimeWaitMs`.\n */\n exponentialBackoff?: {\n /** Initial delay in ms (default: 1000) */\n initialDelayMs?: number\n /** Maximum delay cap in ms (default: 30000) */\n maxDelayMs?: number\n /** Multiplier per attempt (default: 2) */\n multiplier?: number\n /** Add random jitter 0-50% of delay to prevent thundering herd (default: true) */\n jitter?: boolean\n }\n\n /**\n * Ping behavior (keep-alive).\n */\n pingIntervalMs?: number\n maxPingOut?: number\n\n /**\n * Optional inbox prefix (useful if you want to isolate request/reply inboxes).\n */\n inboxPrefix?: string\n\n /**\n * Connection timeout in milliseconds (maps to `nats.ws` connect option `timeout`).\n * If you see `NatsError: TIMEOUT` during connect, increase this.\n */\n connectTimeoutMs?: number\n}\n\nexport interface NatsSubscribeOptions {\n /**\n * Queue group for load-balancing messages across subscribers.\n */\n queue?: string\n\n /**\n * Auto-unsubscribe after receiving this many messages.\n */\n max?: number\n\n /**\n * Abort signal to stop message iteration and unsubscribe.\n */\n signal?: AbortSignal\n}\n\nexport type NatsHeadersInit = Record<string, string> | NatsHeaders | undefined\n\nexport interface NatsPublishOptions {\n headers?: NatsHeadersInit\n}\n\nexport interface NatsRequestOptions {\n timeoutMs?: number\n headers?: NatsHeadersInit\n}\n\nexport interface NatsSubscriptionHandle {\n readonly subscription: Subscription\n unsubscribe(): void\n}\n\nexport type NatsStatus =\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'reconnecting'\n | 'closed'\n | 'error'\n\nexport interface NatsStatusEvent {\n status: NatsStatus\n data?: unknown\n}\n\nexport interface NatsClient {\n connect(): Promise<void>\n close(): Promise<void>\n\n isConnected(): boolean\n\n publishBytes(subject: string, payload: Uint8Array, options?: NatsPublishOptions): void\n publishString(subject: string, payload: string, options?: NatsPublishOptions): void\n publishJson<T>(subject: string, payload: T, options?: NatsPublishOptions): void\n\n requestBytes(subject: string, payload: Uint8Array, options?: NatsRequestOptions): Promise<Msg>\n requestString(subject: string, payload: string, options?: NatsRequestOptions): Promise<string>\n requestJson<TResponse, TRequest = unknown>(\n subject: string,\n payload: TRequest,\n options?: NatsRequestOptions,\n ): Promise<TResponse>\n\n subscribeBytes(\n subject: string,\n onMessage: (msg: Msg) => void | Promise<void>,\n options?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle\n subscribeString(\n subject: string,\n onMessage: (payload: string, msg: Msg) => void | Promise<void>,\n options?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle\n subscribeJson<T>(\n subject: string,\n onMessage: (payload: T, msg: Msg) => void | Promise<void>,\n options?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle\n\n /**\n * Subscribe to a JetStream subject via an ephemeral OrderedConsumer (no acks).\n * Use `optStartSeq` with `deliverPolicy: 'byStartSequence'` to resume from a known offset,\n * or `deliverPolicy: 'new'` to live-tail.\n */\n subscribeJetStreamOrdered(\n onMessage: (msg: JsMsg) => void | Promise<void>,\n options: JetStreamOrderedSubscribeOptions,\n ): Promise<JetStreamSubscriptionHandle>\n\n onStatus(listener: (event: NatsStatusEvent) => void): () => void\n}\n\nfunction assertClientSide(): void {\n // This wrapper is meant for browser/Tauri usage via WebSockets.\n // Keep it safe to import from Next.js server bundles by throwing only when used.\n if (typeof window === 'undefined') {\n throw new Error('NATS client can only connect from the browser/runtime with WebSocket support (window is undefined).')\n }\n}\n\nasync function importNats(): Promise<typeof import('nats.ws')> {\n // Browser/Tauri only: always use the websocket client (no Node-only deps).\n return await import('nats.ws')\n}\n\nfunction toNatsHeaders(nats: typeof import('nats.ws'), init: NatsHeadersInit): NatsHeaders | undefined {\n if (!init) return undefined\n if (typeof (init as NatsHeaders).get === 'function') return init as NatsHeaders\n\n const h = nats.headers()\n for (const [k, v] of Object.entries(init as Record<string, string>)) {\n if (v !== undefined && v !== null) h.set(k, String(v))\n }\n return h\n}\n\n/** Returns a cryptographically random float in [0, 1). */\nfunction cryptoRandom(): number {\n const buf = new Uint32Array(1)\n crypto.getRandomValues(buf)\n return buf[0] / (0xffffffff + 1)\n}\n\ninterface ExponentialBackoffHandle {\n handler: () => number\n reset: () => void\n}\n\nfunction createExponentialBackoffHandler(opts: NonNullable<NatsClientOptions['exponentialBackoff']>): ExponentialBackoffHandle {\n const initialDelay = opts.initialDelayMs ?? 1000\n const maxDelay = opts.maxDelayMs ?? 30_000\n const multiplier = opts.multiplier ?? 2\n const jitter = opts.jitter ?? true\n\n let attempt = 0\n\n return {\n handler: (): number => {\n const delay = Math.min(initialDelay * multiplier ** attempt, maxDelay)\n attempt++\n return jitter ? delay * (0.5 + cryptoRandom() * 0.5) : delay\n },\n reset: () => {\n attempt = 0\n },\n }\n}\n\nfunction mapOptionsToConnectionOptions(\n opts: NatsClientOptions,\n backoff?: ExponentialBackoffHandle,\n): ConnectionOptions {\n return {\n servers: opts.servers,\n name: opts.name,\n token: opts.token,\n user: opts.user,\n pass: opts.pass,\n timeout: opts.connectTimeoutMs ?? 15000,\n reconnect: opts.reconnect ?? true,\n maxReconnectAttempts: opts.maxReconnectAttempts,\n reconnectTimeWait: opts.reconnectTimeWaitMs,\n reconnectDelayHandler: backoff?.handler,\n pingInterval: opts.pingIntervalMs,\n maxPingOut: opts.maxPingOut,\n inboxPrefix: opts.inboxPrefix,\n }\n}\n\nfunction mapNatsTypeToStatus(type: unknown): NatsStatus | null {\n const t = String(type).toLowerCase()\n if (t.includes('disconnect')) return 'disconnected'\n if (t === 'reconnecting') return 'reconnecting'\n if (t === 'reconnect' || t.includes('connect')) return 'connected'\n if (t.includes('error')) return 'error'\n if (t.includes('close')) return 'closed'\n return null\n}\n\n/**\n * Report an ordered consumer rebuilding itself.\n *\n * nats.ws announces this on the message iterator's status channel and nowhere\n * else — the iterator keeps yielding, the WebSocket never drops, and nothing\n * consumes that channel unless someone asks for it. That silence is what lets a\n * tail resume after a suspended page having permanently missed whatever expired\n * from the stream meanwhile: the recreation resumes from the last delivered\n * sequence, so the gap is invisible from the tail alone.\n *\n * `recreatedEvent` is nats.ws's own enum value rather than a literal of ours: a\n * copy that drifted from the library would kill this signal silently, which is\n * the failure mode the signal exists to prevent.\n *\n * The status channel is closed along with the iterator, which ends this loop.\n */\nfunction watchForRecovery(\n iter: ConsumerMessages,\n recreatedEvent: ConsumerEvents.OrderedConsumerRecreated,\n onRecovered?: () => void,\n): void {\n if (!onRecovered) return\n void (async () => {\n try {\n const status = await iter.status()\n for await (const event of status) {\n if (event.type !== recreatedEvent) continue\n try {\n onRecovered()\n } catch (e) {\n // A caller that throws must not take the watch down with it — this\n // loop is the only thing reporting recoveries for this subscription.\n console.warn('[nats] onRecovered threw:', e)\n }\n }\n } catch {\n // Status ends with the subscription — nothing left to report.\n }\n })()\n}\n\nexport function createNatsClient(options: NatsClientOptions): NatsClient {\n let nc: NatsConnection | null = null\n let statusLoopAbort: AbortController | null = null\n let connectInFlight: Promise<void> | null = null\n\n const backoff = options.exponentialBackoff\n ? createExponentialBackoffHandler(options.exponentialBackoff)\n : undefined\n\n const statusListeners = new Set<(event: NatsStatusEvent) => void>()\n\n function emitStatus(event: NatsStatusEvent) {\n for (const listener of statusListeners) {\n try {\n listener(event)\n } catch {\n // ignore listener failures\n }\n }\n }\n\n async function connect(): Promise<void> {\n if (nc && !nc.isClosed()) return\n if (connectInFlight) return connectInFlight\n assertClientSide()\n\n connectInFlight = (async () => {\n try {\n emitStatus({ status: 'connecting' })\n\n const nats = await importNats()\n const conn = await nats.connect(mapOptionsToConnectionOptions(options, backoff))\n nc = conn\n\n emitStatus({ status: 'connected' })\n\n statusLoopAbort = new AbortController()\n const signal = statusLoopAbort.signal\n\n ;(async () => {\n try {\n for await (const s of conn.status()) {\n if (signal.aborted) return\n const mapped = mapNatsTypeToStatus((s as any)?.type)\n if (mapped) {\n if (mapped === 'connected' && backoff) {\n backoff.reset()\n }\n emitStatus({ status: mapped, data: (s as any)?.data })\n if (mapped === 'closed') {\n nc = null\n }\n }\n }\n } catch (e) {\n if (!signal.aborted) {\n emitStatus({ status: 'error', data: e })\n \n if (nc === conn && conn.isClosed()) {\n nc = null\n emitStatus({ status: 'closed' })\n }\n }\n }\n })().catch(() => {\n // ignore\n })\n } finally {\n connectInFlight = null\n }\n })()\n\n return connectInFlight\n }\n\n async function close(): Promise<void> {\n const conn = nc\n nc = null\n\n if (statusLoopAbort) {\n try {\n statusLoopAbort.abort()\n } catch {\n // ignore\n }\n statusLoopAbort = null\n }\n\n if (!conn) return\n try {\n await conn.drain()\n } finally {\n try {\n await conn.close()\n } finally {\n emitStatus({ status: 'closed' })\n }\n }\n }\n\n function requireConnection(): NatsConnection {\n if (!nc) throw new Error('NATS is not connected. Call client.connect() first.')\n return nc\n }\n\n function isConnected(): boolean {\n return Boolean(nc) && !nc!.isClosed()\n }\n\n function publishBytes(subject: string, payload: Uint8Array, opts?: NatsPublishOptions): void {\n const conn = requireConnection()\n ;(async () => {\n const nats = await importNats()\n conn.publish(subject, payload, { headers: toNatsHeaders(nats, opts?.headers) })\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n }\n\n function publishString(subject: string, payload: string, opts?: NatsPublishOptions): void {\n ;(async () => {\n const nats = await importNats()\n const sc = nats.StringCodec()\n publishBytes(subject, sc.encode(payload), opts)\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n }\n\n function publishJson<T>(subject: string, payload: T, opts?: NatsPublishOptions): void {\n ;(async () => {\n const nats = await importNats()\n const jc = nats.JSONCodec<T>()\n publishBytes(subject, jc.encode(payload), opts)\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n }\n\n async function requestBytes(subject: string, payload: Uint8Array, opts?: NatsRequestOptions): Promise<Msg> {\n const conn = requireConnection()\n const nats = await importNats()\n const msg = await conn.request(subject, payload, {\n timeout: opts?.timeoutMs ?? 2000,\n headers: toNatsHeaders(nats, opts?.headers),\n })\n return msg\n }\n\n async function requestString(subject: string, payload: string, opts?: NatsRequestOptions): Promise<string> {\n const nats = await importNats()\n const sc = nats.StringCodec()\n const msg = await requestBytes(subject, sc.encode(payload), opts)\n return sc.decode(msg.data)\n }\n\n async function requestJson<TResponse, TRequest = unknown>(\n subject: string,\n payload: TRequest,\n opts?: NatsRequestOptions,\n ): Promise<TResponse> {\n const nats = await importNats()\n const reqCodec = nats.JSONCodec<TRequest>()\n const resCodec = nats.JSONCodec<TResponse>()\n const msg = await requestBytes(subject, reqCodec.encode(payload), opts)\n return resCodec.decode(msg.data)\n }\n\n function subscribeBytes(\n subject: string,\n onMessage: (msg: Msg) => void | Promise<void>,\n opts?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle {\n const conn = requireConnection()\n const sub = conn.subscribe(subject, { queue: opts?.queue })\n if (typeof opts?.max === 'number') sub.unsubscribe(opts.max)\n\n const abortController = new AbortController()\n const signal = opts?.signal ?? abortController.signal\n\n ;(async () => {\n try {\n for await (const msg of sub) {\n if (signal.aborted) break\n await onMessage(msg)\n }\n } catch (e) {\n emitStatus({ status: 'error', data: e })\n } finally {\n try {\n sub.unsubscribe()\n } catch {\n // ignore\n }\n }\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n\n return {\n subscription: sub,\n unsubscribe() {\n try {\n abortController.abort()\n } catch {\n // ignore\n }\n try {\n sub.unsubscribe()\n } catch {\n // ignore\n }\n },\n }\n }\n\n function subscribeString(\n subject: string,\n onMessage: (payload: string, msg: Msg) => void | Promise<void>,\n opts?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle {\n return subscribeBytes(\n subject,\n async (msg) => {\n const nats = await importNats()\n const sc = nats.StringCodec()\n await onMessage(sc.decode(msg.data), msg)\n },\n opts,\n )\n }\n\n function subscribeJson<T>(\n subject: string,\n onMessage: (payload: T, msg: Msg) => void | Promise<void>,\n opts?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle {\n return subscribeBytes(\n subject,\n async (msg) => {\n const nats = await importNats()\n const jc = nats.JSONCodec<T>()\n await onMessage(jc.decode(msg.data), msg)\n },\n opts,\n )\n }\n\n async function subscribeJetStreamOrdered(\n onMessage: (msg: JsMsg) => void | Promise<void>,\n opts: JetStreamOrderedSubscribeOptions,\n ): Promise<JetStreamSubscriptionHandle> {\n const conn = requireConnection()\n if (opts.signal?.aborted) {\n return { unsubscribe() {} }\n }\n\n const nats = await importNats()\n if (opts.signal?.aborted) {\n return { unsubscribe() {} }\n }\n\n const js = conn.jetstream()\n const consumer: Consumer = await js.consumers.get(opts.streamName, {\n filterSubjects: opts.filterSubject,\n deliver_policy: nats.DeliverPolicy.StartSequence,\n opt_start_seq: opts.optStartSeq ?? 0,\n // Milliseconds, NOT nanoseconds: nats.ws runs this through its own\n // `nanos()` before it reaches the server. Pre-converting here multiplied\n // it by 1e6 twice, putting the threshold ~9.5 years out — so the ephemeral\n // consumer never expired. Two consequences, both silent: every reconnect\n // and dialog switch orphaned a consumer server-side, and a client that\n // stopped pulling never got the `consumer deleted` that drives the ordered\n // consumer's self-repair. Undefined stays undefined so nats.ws applies its\n // own default rather than a copy of it.\n inactive_threshold: opts.inactiveThresholdMs,\n })\n\n const iterRef: { current: ConsumerMessages | null } = { current: null }\n let closed = false\n\n const onAbort = () => {\n void teardown()\n }\n opts.signal?.addEventListener('abort', onAbort, { once: true })\n\n async function teardown(): Promise<void> {\n if (closed) return\n closed = true\n opts.signal?.removeEventListener('abort', onAbort)\n const iter = iterRef.current\n iterRef.current = null\n if (iter) {\n try {\n await iter.close()\n } catch {\n // ignore\n }\n }\n }\n\n if (opts.signal?.aborted) {\n void teardown()\n return { unsubscribe() {} }\n }\n\n ;(async () => {\n try {\n const iter = await consumer.consume()\n if (closed) {\n try {\n await iter.close()\n } catch {\n // ignore\n }\n return\n }\n iterRef.current = iter\n watchForRecovery(iter, nats.ConsumerEvents.OrderedConsumerRecreated, opts.onRecovered)\n for await (const msg of iter) {\n if (closed) break\n try {\n await onMessage(msg)\n } catch (e) {\n emitStatus({ status: 'error', data: e })\n }\n }\n } catch (e) {\n if (!closed) emitStatus({ status: 'error', data: e })\n }\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n\n return {\n unsubscribe() {\n void teardown()\n },\n }\n }\n\n function onStatus(listener: (event: NatsStatusEvent) => void): () => void {\n statusListeners.add(listener)\n return () => statusListeners.delete(listener)\n }\n\n return {\n connect,\n close,\n isConnected,\n publishBytes,\n publishString,\n publishJson,\n requestBytes,\n requestString,\n requestJson,\n subscribeBytes,\n subscribeString,\n subscribeJson,\n subscribeJetStreamOrdered,\n onStatus,\n }\n}\n","import { createNatsClient, type NatsClient, type NatsStatus, type NatsStatusEvent } from './nats'\n\nexport const NATS_DEFAULTS = {\n SHARED_CLOSE_DELAY_MS: 3000,\n CONNECT_TIMEOUT_MS: 10_000,\n PING_INTERVAL_MS: 30_000,\n MAX_PING_OUT: 3,\n RETRY_INITIAL_DELAY_MS: 1000,\n RETRY_MAX_DELAY_MS: 30_000,\n RETRY_MULTIPLIER: 2,\n} as const\n\nexport interface NatsReconnectionBackoff {\n /** Number of fast retries before exponential phase kicks in. Default: 0. */\n fastRetries?: number\n /** Delay used during the fast-retry phase. Default: RETRY_INITIAL_DELAY_MS. */\n fastRetryDelayMs?: number\n /** Base delay for the exponential phase. Default: RETRY_INITIAL_DELAY_MS. */\n initialDelayMs?: number\n /** Upper cap on any single retry delay. Default: RETRY_MAX_DELAY_MS. */\n maxDelayMs?: number\n /** Per-attempt multiplier during exponential phase. Default: RETRY_MULTIPLIER. */\n multiplier?: number\n}\n\nexport interface SharedConnection {\n wsUrl: string\n client: NatsClient\n connectPromise: Promise<void> | null\n refCount: number\n closeTimer: ReturnType<typeof setTimeout> | null\n retryTimer: ReturnType<typeof setTimeout> | null\n /**\n * Identity of the consumer driving reconnect. When set, other consumers\n * should observe status only and skip their own scheduleRetry — otherwise\n * each disconnect triggers multiple concurrent connect() calls racing over\n * connectPromise.\n */\n retryOwner: object | null\n}\n\nexport interface AcquireClientOptions {\n name?: string\n user?: string\n pass?: string\n connectTimeoutMs?: number\n pingIntervalMs?: number\n maxPingOut?: number\n}\n\nexport interface ReleaseClientOptions {\n delayMs?: number\n}\n\n// One shared connection PER URL. The previous single-slot implementation\n// force-closed whatever was connected the moment any consumer acquired a\n// DIFFERENT URL — even with live refs on it. With two chat surfaces on\n// distinct endpoints (`/ws/nats` client chat vs `/ws/nats-api` dashboard)\n// mounted at once, each acquire killed the other's socket, and the loser's\n// retry loop self-cancelled (connection identity mismatch) leaving a dead\n// subscription that silently received nothing.\nconst connections = new Map<string, SharedConnection>()\n\n/** Legacy accessor from the single-slot era: returns the first live shared\n * connection, or null. With MULTIPLE URLs connected (e.g. `/ws/nats` client\n * chat + `/ws/nats-api` dashboard mounted together) \"first\" is whichever\n * surface acquired first — an arbitrary, mount-order-dependent answer.\n * Prefer `getSharedConnectionFor(url)`; this stays only for external\n * registry-pinned consumers of the old single-connection API. */\nexport function getSharedConnection(): SharedConnection | null {\n const first = connections.values().next()\n return first.done ? null : first.value\n}\n\nexport function acquireClient(url: string, opts?: AcquireClientOptions): SharedConnection {\n let conn = connections.get(url)\n\n if (!conn) {\n const {\n name = 'openframe-frontend',\n user = 'machine',\n pass = '',\n connectTimeoutMs = NATS_DEFAULTS.CONNECT_TIMEOUT_MS,\n pingIntervalMs = NATS_DEFAULTS.PING_INTERVAL_MS,\n maxPingOut = NATS_DEFAULTS.MAX_PING_OUT,\n } = opts ?? {}\n\n const client = createNatsClient({\n servers: url,\n name,\n user,\n pass,\n connectTimeoutMs,\n reconnect: false,\n pingIntervalMs,\n maxPingOut,\n })\n\n conn = {\n wsUrl: url,\n client,\n connectPromise: null,\n refCount: 0,\n closeTimer: null,\n retryTimer: null,\n retryOwner: null,\n }\n connections.set(url, conn)\n }\n\n conn.refCount += 1\n if (conn.closeTimer) {\n clearTimeout(conn.closeTimer)\n conn.closeTimer = null\n }\n return conn\n}\n\nexport function releaseClient(url: string, opts?: ReleaseClientOptions): void {\n const conn = connections.get(url)\n if (!conn) return\n\n conn.refCount = Math.max(0, conn.refCount - 1)\n if (conn.refCount > 0) return\n\n const delay = opts?.delayMs ?? NATS_DEFAULTS.SHARED_CLOSE_DELAY_MS\n conn.closeTimer = setTimeout(() => {\n conn.closeTimer = null\n // A new acquire may have raced in during the grace period.\n if (conn.refCount > 0) return\n if (connections.get(url) === conn) {\n connections.delete(url)\n }\n if (conn.retryTimer) {\n clearTimeout(conn.retryTimer)\n conn.retryTimer = null\n }\n void conn.client.close().catch(() => {})\n }, delay)\n}\n\nexport function getSharedConnectionFor(url: string | null | undefined): SharedConnection | null {\n if (!url) return null\n return connections.get(url) ?? null\n}\n\n// ---------------------------------------------------------------------------\n// Connection lifecycle: retry + status loop, shared by NatsProvider and the\n// chat hooks. Each consumer that wants to drive reconnect creates an\n// ownerToken and calls startConnectionLifecycle(). The first caller to claim\n// retryOwner runs the actual retry loop; subsequent claimants observe status\n// only. When the owner unmounts and releases retryOwner, the next status\n// event lets a surviving consumer pick up ownership opportunistically.\n// ---------------------------------------------------------------------------\n\nexport interface ConnectionLifecycleOptions {\n conn: SharedConnection\n wsUrl: string\n onBeforeReconnect?: () => Promise<void> | void\n backoff?: NatsReconnectionBackoff\n getFreshUrl: () => string | null\n /** Called on every status change (after closed-guard). */\n onStatusChange?: (status: NatsStatus, evt: NatsStatusEvent) => void\n /**\n * Decide which statuses should trigger a retry attempt. Defaults to closed +\n * disconnected. Override to skip 'error' (JetStream protocol errors that\n * don't close the WS) or include it.\n */\n shouldRetryOn?: (status: NatsStatus) => boolean\n}\n\nexport interface ConnectionLifecycleHandle {\n /** Stop observing status, clear any pending retry, release ownership if held. */\n stop(): void\n}\n\nconst defaultShouldRetryOn = (status: NatsStatus) => status === 'closed' || status === 'disconnected'\n\nexport function startConnectionLifecycle(options: ConnectionLifecycleOptions): ConnectionLifecycleHandle {\n const { conn, wsUrl } = options\n // Each lifecycle gets its own identity for retry ownership. The first lifecycle to claim\n // an unowned connection drives reconnect; later attachers observe status only until the\n // owner releases (see opportunistic claim in scheduleRetry).\n const ownerToken = {}\n if (!conn.retryOwner) conn.retryOwner = ownerToken\n\n let closed = false\n let retryAttempt = 0\n\n function emitSynthetic(status: NatsStatus) {\n if (closed) return\n options.onStatusChange?.(status, { status })\n if (status === 'connected') {\n retryAttempt = 0\n }\n }\n\n function scheduleRetry() {\n if (closed) return\n if (getSharedConnectionFor(wsUrl) !== conn) return\n if (!conn.retryOwner) conn.retryOwner = ownerToken\n if (conn.retryOwner !== ownerToken) return\n\n if (conn.retryTimer) {\n clearTimeout(conn.retryTimer)\n conn.retryTimer = null\n }\n\n const cfg = options.backoff ?? {}\n const fastRetries = cfg.fastRetries ?? 0\n const fastDelay = cfg.fastRetryDelayMs ?? NATS_DEFAULTS.RETRY_INITIAL_DELAY_MS\n const baseDelay = cfg.initialDelayMs ?? NATS_DEFAULTS.RETRY_INITIAL_DELAY_MS\n const maxDelay = cfg.maxDelayMs ?? NATS_DEFAULTS.RETRY_MAX_DELAY_MS\n const multiplier = cfg.multiplier ?? NATS_DEFAULTS.RETRY_MULTIPLIER\n\n const delay =\n retryAttempt < fastRetries\n ? fastDelay\n : Math.min(baseDelay * multiplier ** (retryAttempt - fastRetries), maxDelay)\n const jitteredDelay = delay * (0.5 + Math.random() * 0.5)\n retryAttempt++\n\n conn.retryTimer = setTimeout(async () => {\n conn.retryTimer = null\n if (closed) return\n if (getSharedConnectionFor(wsUrl) !== conn) return\n\n try {\n await options.onBeforeReconnect?.()\n } catch {\n // continue regardless of token-refresh outcome\n }\n if (closed) return\n if (getSharedConnectionFor(wsUrl) !== conn) return\n\n const freshUrl = options.getFreshUrl()\n if (freshUrl !== wsUrl) return\n\n try {\n conn.connectPromise = null\n conn.connectPromise = conn.client.connect()\n await conn.connectPromise\n if (!closed && getSharedConnectionFor(wsUrl) === conn) {\n retryAttempt = 0\n }\n } catch {\n conn.connectPromise = null\n if (!closed && getSharedConnectionFor(wsUrl) === conn) {\n scheduleRetry()\n }\n }\n }, jitteredDelay)\n }\n\n const shouldRetryOn = options.shouldRetryOn ?? defaultShouldRetryOn\n\n const unsubStatus = conn.client.onStatus((evt) => {\n if (closed) return\n options.onStatusChange?.(evt.status, evt)\n if (evt.status === 'connected') {\n retryAttempt = 0\n }\n if (shouldRetryOn(evt.status)) {\n scheduleRetry()\n }\n })\n\n if (conn.client.isConnected()) {\n emitSynthetic('connected')\n }\n\n void (async () => {\n try {\n conn.connectPromise ||= conn.client.connect()\n await conn.connectPromise\n } catch {\n conn.connectPromise = null\n if (closed) return\n\n emitSynthetic('disconnected')\n scheduleRetry()\n }\n })()\n\n return {\n stop() {\n closed = true\n unsubStatus()\n if (conn.retryTimer) {\n clearTimeout(conn.retryTimer)\n conn.retryTimer = null\n }\n if (conn.retryOwner === ownerToken) {\n conn.retryOwner = null\n }\n },\n }\n}\n","'use client'\n\nimport * as React from 'react'\nimport type { NatsClient, NatsStatus } from './nats'\nimport {\n acquireClient,\n releaseClient,\n startConnectionLifecycle,\n type AcquireClientOptions,\n type NatsReconnectionBackoff,\n} from './shared-connection'\n\nexport type { NatsReconnectionBackoff } from './shared-connection'\n\nexport interface NatsProviderProps {\n children: React.ReactNode\n /** Return the current NATS WebSocket URL (or null when not yet available, e.g. unauthenticated). */\n getWsUrl: () => string | null\n /** Called before each reconnect attempt. */\n onBeforeReconnect?: () => Promise<void> | void\n clientConfig?: AcquireClientOptions\n reconnectionBackoff?: NatsReconnectionBackoff\n /**\n * Bump this to force re-evaluating `getWsUrl()` (e.g. when auth state flips).\n * Provider does not subscribe to external auth state by itself.\n */\n urlRevision?: unknown\n}\n\nexport interface NatsContextValue {\n client: NatsClient | null\n status: NatsStatus\n isReady: boolean\n reconnectionCount: number\n}\n\nconst NatsContext = React.createContext<NatsContextValue | null>(null)\n\nexport function NatsProvider({\n children,\n getWsUrl,\n onBeforeReconnect,\n clientConfig,\n reconnectionBackoff,\n urlRevision,\n}: NatsProviderProps) {\n const [client, setClient] = React.useState<NatsClient | null>(null)\n const [status, setStatus] = React.useState<NatsStatus>('closed')\n const [reconnectionCount, setReconnectionCount] = React.useState(0)\n\n const getWsUrlRef = React.useRef(getWsUrl)\n React.useEffect(() => {\n getWsUrlRef.current = getWsUrl\n }, [getWsUrl])\n\n const onBeforeReconnectRef = React.useRef(onBeforeReconnect)\n React.useEffect(() => {\n onBeforeReconnectRef.current = onBeforeReconnect\n }, [onBeforeReconnect])\n\n const reconnectionBackoffRef = React.useRef(reconnectionBackoff)\n React.useEffect(() => {\n reconnectionBackoffRef.current = reconnectionBackoff\n }, [reconnectionBackoff])\n\n const clientConfigRef = React.useRef(clientConfig)\n React.useEffect(() => {\n clientConfigRef.current = clientConfig\n }, [clientConfig])\n\n const heldUrlRef = React.useRef<string | null>(null)\n const hadConnectionBeforeRef = React.useRef(false)\n\n React.useEffect(() => {\n const wsUrl = getWsUrlRef.current()\n\n if (!wsUrl) {\n if (heldUrlRef.current) {\n releaseClient(heldUrlRef.current)\n heldUrlRef.current = null\n setClient(null)\n setStatus('closed')\n }\n return\n }\n\n if (heldUrlRef.current && heldUrlRef.current !== wsUrl) {\n releaseClient(heldUrlRef.current)\n heldUrlRef.current = null\n }\n\n const conn = acquireClient(wsUrl, clientConfigRef.current)\n heldUrlRef.current = wsUrl\n setClient(conn.client)\n setStatus(conn.client.isConnected() ? 'connected' : 'connecting')\n\n const lifecycle = startConnectionLifecycle({\n conn,\n wsUrl,\n onBeforeReconnect: () => onBeforeReconnectRef.current?.(),\n backoff: reconnectionBackoffRef.current,\n getFreshUrl: () => getWsUrlRef.current(),\n onStatusChange: (newStatus) => {\n if (newStatus === 'error') return\n setStatus(newStatus)\n if (newStatus === 'connected') {\n if (hadConnectionBeforeRef.current) {\n setReconnectionCount((c) => c + 1)\n }\n hadConnectionBeforeRef.current = true\n }\n },\n })\n\n return () => {\n lifecycle.stop()\n if (heldUrlRef.current) {\n releaseClient(heldUrlRef.current)\n heldUrlRef.current = null\n }\n setClient(null)\n setStatus('closed')\n }\n }, [urlRevision])\n\n const value = React.useMemo<NatsContextValue>(\n () => ({\n client,\n status,\n isReady: status === 'connected' && client !== null,\n reconnectionCount,\n }),\n [client, status, reconnectionCount],\n )\n\n return <NatsContext.Provider value={value}>{children}</NatsContext.Provider>\n}\n\nexport function useNats(): NatsContextValue {\n const ctx = React.useContext(NatsContext)\n if (!ctx) throw new Error('useNats must be used inside <NatsProvider>')\n return ctx\n}\n\nexport function useOptionalNats(): NatsContextValue | null {\n return React.useContext(NatsContext)\n}\n","'use client'\n\nimport * as React from 'react'\nimport type { JsMsg, Msg, NatsSubscribeOptions } from './nats'\nimport { useOptionalNats } from './nats-provider'\n\nexport interface UseNatsSubscriptionOptions extends NatsSubscribeOptions {\n enabled?: boolean\n}\n\nexport interface UseNatsSubscriptionReturn {\n isSubscribed: boolean\n isReady: boolean\n}\n\n/**\n * Subscribe to a NATS subject using the shared connection from <NatsProvider>.\n * Automatically (re)subscribes when the connection becomes ready, when the\n * subject changes, and after reconnections.\n */\nexport function useNatsSubscription(\n subject: string | null,\n onMessage: (msg: Msg) => void | Promise<void>,\n options?: UseNatsSubscriptionOptions,\n): UseNatsSubscriptionReturn {\n const nats = useOptionalNats()\n const handlerRef = React.useRef(onMessage)\n React.useEffect(() => {\n handlerRef.current = onMessage\n }, [onMessage])\n\n const [isSubscribed, setIsSubscribed] = React.useState(false)\n\n const enabled = options?.enabled !== false\n const queue = options?.queue\n const max = options?.max\n const reconnectionCount = nats?.reconnectionCount ?? 0\n const isReady = !!nats?.isReady\n const client = nats?.client ?? null\n\n React.useEffect(() => {\n if (!client || !isReady || !subject || !enabled) {\n setIsSubscribed(false)\n return\n }\n\n const sub = client.subscribeBytes(\n subject,\n (msg) => handlerRef.current(msg),\n { queue, max },\n )\n setIsSubscribed(true)\n\n return () => {\n setIsSubscribed(false)\n try {\n sub.unsubscribe()\n } catch {\n // ignore\n }\n }\n // reconnectionCount intentionally in deps: re-subscribe after reconnect\n }, [client, isReady, subject, enabled, queue, max, reconnectionCount])\n\n return { isSubscribed, isReady }\n}\n\nexport type UseNatsJsonSubscriptionOptions = UseNatsSubscriptionOptions\n\nexport function useNatsJsonSubscription<T = unknown>(\n subject: string | null,\n onPayload: (payload: T, msg: Msg) => void | Promise<void>,\n options?: UseNatsJsonSubscriptionOptions,\n): UseNatsSubscriptionReturn {\n const handlerRef = React.useRef(onPayload)\n React.useEffect(() => {\n handlerRef.current = onPayload\n }, [onPayload])\n\n const decoderRef = React.useRef<TextDecoder | null>(null)\n if (!decoderRef.current && typeof TextDecoder !== 'undefined') {\n decoderRef.current = new TextDecoder()\n }\n\n const wrapped = React.useCallback(async (msg: Msg) => {\n const decoder = decoderRef.current\n if (!decoder) return\n try {\n const parsed = JSON.parse(decoder.decode(msg.data)) as T\n await handlerRef.current(parsed, msg)\n } catch {\n // ignore malformed payloads\n }\n }, [])\n\n return useNatsSubscription(subject, wrapped, options)\n}\n\nexport type NatsJsMsg = JsMsg\n"],"mappings":"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","names":["React"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-KQKU4VXB.cjs","../src/nats/nats.ts","../src/nats/shared-connection.ts","../src/nats/nats-provider.tsx","../src/nats/use-nats-subscription.ts"],"names":[],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-KQKU4VXB.cjs","sourcesContent":[null,"import type {\n ConnectionOptions,\n Consumer,\n ConsumerEvents,\n ConsumerMessages,\n JsMsg,\n MsgHdrs as NatsHeaders,\n Msg,\n NatsConnection,\n Subscription,\n} from 'nats.ws'\n\nexport type { JsMsg, Msg, Subscription } from 'nats.ws'\n\nexport type JetStreamDeliverPolicy = 'new' | 'byStartSequence'\n\nexport interface JetStreamOrderedSubscribeOptions {\n streamName: string\n filterSubject: string\n deliverPolicy: JetStreamDeliverPolicy\n /** Required when deliverPolicy === 'byStartSequence'. */\n optStartSeq?: number\n /**\n * Auto-cleanup the ephemeral consumer after this idle time. Defaults to\n * nats.ws's own. Applies to the consumer created first: nats.ws only reads it\n * when the start sequence is the one it was built with, so every consumer it\n * recreates afterwards reverts to the library default.\n */\n inactiveThresholdMs?: number\n /** AbortSignal to tear down the consumer. */\n signal?: AbortSignal\n /**\n * The ordered consumer had to be rebuilt: the server dropped the ephemeral\n * consumer (its inactivity threshold elapsed while the page was suspended or\n * offline), heartbeats were missed, or a sequence gap was detected. nats.ws\n * recreates it from the last delivered sequence, so this is NOT an error —\n * but everything that aged out of the stream while it was gone is\n * unrecoverable from the tail, and no connection event announces it (the\n * WebSocket never dropped). Callers that keep persisted history alongside\n * the live tail must refetch it here, or they keep showing a snapshot from\n * before the gap.\n */\n onRecovered?: () => void\n}\n\nexport interface JetStreamSubscriptionHandle {\n unsubscribe(): void\n}\n\nexport interface NatsClientOptions {\n /**\n * NATS server URL(s), for example:\n * - \"wss://nats.example.com:443\"\n * - [\"wss://nats-1.example.com:443\", \"wss://nats-2.example.com:443\"]\n */\n servers: string | string[]\n\n /**\n * Connection name (shows up in NATS monitoring).\n */\n name?: string\n\n /**\n * Auth options (pick one: token or user/pass).\n */\n token?: string\n user?: string\n pass?: string\n\n /**\n * Reconnect behavior.\n */\n reconnect?: boolean\n maxReconnectAttempts?: number\n reconnectTimeWaitMs?: number\n\n /**\n * Exponential backoff for reconnect delays.\n * When set, uses `reconnectDelayHandler` from nats.ws under the hood,\n * overriding `reconnectTimeWaitMs`.\n */\n exponentialBackoff?: {\n /** Initial delay in ms (default: 1000) */\n initialDelayMs?: number\n /** Maximum delay cap in ms (default: 30000) */\n maxDelayMs?: number\n /** Multiplier per attempt (default: 2) */\n multiplier?: number\n /** Add random jitter 0-50% of delay to prevent thundering herd (default: true) */\n jitter?: boolean\n }\n\n /**\n * Ping behavior (keep-alive).\n */\n pingIntervalMs?: number\n maxPingOut?: number\n\n /**\n * Optional inbox prefix (useful if you want to isolate request/reply inboxes).\n */\n inboxPrefix?: string\n\n /**\n * Connection timeout in milliseconds (maps to `nats.ws` connect option `timeout`).\n * If you see `NatsError: TIMEOUT` during connect, increase this.\n */\n connectTimeoutMs?: number\n}\n\nexport interface NatsSubscribeOptions {\n /**\n * Queue group for load-balancing messages across subscribers.\n */\n queue?: string\n\n /**\n * Auto-unsubscribe after receiving this many messages.\n */\n max?: number\n\n /**\n * Abort signal to stop message iteration and unsubscribe.\n */\n signal?: AbortSignal\n}\n\nexport type NatsHeadersInit = Record<string, string> | NatsHeaders | undefined\n\nexport interface NatsPublishOptions {\n headers?: NatsHeadersInit\n}\n\nexport interface NatsRequestOptions {\n timeoutMs?: number\n headers?: NatsHeadersInit\n}\n\nexport interface NatsSubscriptionHandle {\n readonly subscription: Subscription\n unsubscribe(): void\n}\n\nexport type NatsStatus =\n | 'connecting'\n | 'connected'\n | 'disconnected'\n | 'reconnecting'\n | 'closed'\n | 'error'\n\nexport interface NatsStatusEvent {\n status: NatsStatus\n data?: unknown\n}\n\nexport interface NatsClient {\n connect(): Promise<void>\n close(): Promise<void>\n\n isConnected(): boolean\n\n publishBytes(subject: string, payload: Uint8Array, options?: NatsPublishOptions): void\n publishString(subject: string, payload: string, options?: NatsPublishOptions): void\n publishJson<T>(subject: string, payload: T, options?: NatsPublishOptions): void\n\n requestBytes(subject: string, payload: Uint8Array, options?: NatsRequestOptions): Promise<Msg>\n requestString(subject: string, payload: string, options?: NatsRequestOptions): Promise<string>\n requestJson<TResponse, TRequest = unknown>(\n subject: string,\n payload: TRequest,\n options?: NatsRequestOptions,\n ): Promise<TResponse>\n\n subscribeBytes(\n subject: string,\n onMessage: (msg: Msg) => void | Promise<void>,\n options?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle\n subscribeString(\n subject: string,\n onMessage: (payload: string, msg: Msg) => void | Promise<void>,\n options?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle\n subscribeJson<T>(\n subject: string,\n onMessage: (payload: T, msg: Msg) => void | Promise<void>,\n options?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle\n\n /**\n * Subscribe to a JetStream subject via an ephemeral OrderedConsumer (no acks).\n * Use `optStartSeq` with `deliverPolicy: 'byStartSequence'` to resume from a known offset,\n * or `deliverPolicy: 'new'` to live-tail.\n */\n subscribeJetStreamOrdered(\n onMessage: (msg: JsMsg) => void | Promise<void>,\n options: JetStreamOrderedSubscribeOptions,\n ): Promise<JetStreamSubscriptionHandle>\n\n onStatus(listener: (event: NatsStatusEvent) => void): () => void\n}\n\nfunction assertClientSide(): void {\n // This wrapper is meant for browser/Tauri usage via WebSockets.\n // Keep it safe to import from Next.js server bundles by throwing only when used.\n if (typeof window === 'undefined') {\n throw new Error('NATS client can only connect from the browser/runtime with WebSocket support (window is undefined).')\n }\n}\n\nasync function importNats(): Promise<typeof import('nats.ws')> {\n // Browser/Tauri only: always use the websocket client (no Node-only deps).\n return await import('nats.ws')\n}\n\nfunction toNatsHeaders(nats: typeof import('nats.ws'), init: NatsHeadersInit): NatsHeaders | undefined {\n if (!init) return undefined\n if (typeof (init as NatsHeaders).get === 'function') return init as NatsHeaders\n\n const h = nats.headers()\n for (const [k, v] of Object.entries(init as Record<string, string>)) {\n if (v !== undefined && v !== null) h.set(k, String(v))\n }\n return h\n}\n\n/** Returns a cryptographically random float in [0, 1). */\nfunction cryptoRandom(): number {\n const buf = new Uint32Array(1)\n crypto.getRandomValues(buf)\n return buf[0] / (0xffffffff + 1)\n}\n\ninterface ExponentialBackoffHandle {\n handler: () => number\n reset: () => void\n}\n\nfunction createExponentialBackoffHandler(opts: NonNullable<NatsClientOptions['exponentialBackoff']>): ExponentialBackoffHandle {\n const initialDelay = opts.initialDelayMs ?? 1000\n const maxDelay = opts.maxDelayMs ?? 30_000\n const multiplier = opts.multiplier ?? 2\n const jitter = opts.jitter ?? true\n\n let attempt = 0\n\n return {\n handler: (): number => {\n const delay = Math.min(initialDelay * multiplier ** attempt, maxDelay)\n attempt++\n return jitter ? delay * (0.5 + cryptoRandom() * 0.5) : delay\n },\n reset: () => {\n attempt = 0\n },\n }\n}\n\nfunction mapOptionsToConnectionOptions(\n opts: NatsClientOptions,\n backoff?: ExponentialBackoffHandle,\n): ConnectionOptions {\n return {\n servers: opts.servers,\n name: opts.name,\n token: opts.token,\n user: opts.user,\n pass: opts.pass,\n timeout: opts.connectTimeoutMs ?? 15000,\n reconnect: opts.reconnect ?? true,\n maxReconnectAttempts: opts.maxReconnectAttempts,\n reconnectTimeWait: opts.reconnectTimeWaitMs,\n reconnectDelayHandler: backoff?.handler,\n pingInterval: opts.pingIntervalMs,\n maxPingOut: opts.maxPingOut,\n inboxPrefix: opts.inboxPrefix,\n }\n}\n\nfunction mapNatsTypeToStatus(type: unknown): NatsStatus | null {\n const t = String(type).toLowerCase()\n if (t.includes('disconnect')) return 'disconnected'\n if (t === 'reconnecting') return 'reconnecting'\n if (t === 'reconnect' || t.includes('connect')) return 'connected'\n if (t.includes('error')) return 'error'\n if (t.includes('close')) return 'closed'\n return null\n}\n\n/**\n * Report an ordered consumer rebuilding itself.\n *\n * nats.ws announces this on the message iterator's status channel and nowhere\n * else — the iterator keeps yielding, the WebSocket never drops, and nothing\n * consumes that channel unless someone asks for it. That silence is what lets a\n * tail resume after a suspended page having permanently missed whatever expired\n * from the stream meanwhile: the recreation resumes from the last delivered\n * sequence, so the gap is invisible from the tail alone.\n *\n * `recreatedEvent` is nats.ws's own enum value rather than a literal of ours: a\n * copy that drifted from the library would kill this signal silently, which is\n * the failure mode the signal exists to prevent.\n *\n * The status channel is closed along with the iterator, which ends this loop.\n */\nfunction watchForRecovery(\n iter: ConsumerMessages,\n recreatedEvent: ConsumerEvents.OrderedConsumerRecreated,\n onRecovered?: () => void,\n): void {\n if (!onRecovered) return\n void (async () => {\n try {\n const status = await iter.status()\n for await (const event of status) {\n if (event.type !== recreatedEvent) continue\n try {\n onRecovered()\n } catch (e) {\n // A caller that throws must not take the watch down with it — this\n // loop is the only thing reporting recoveries for this subscription.\n console.warn('[nats] onRecovered threw:', e)\n }\n }\n } catch {\n // Status ends with the subscription — nothing left to report.\n }\n })()\n}\n\nexport function createNatsClient(options: NatsClientOptions): NatsClient {\n let nc: NatsConnection | null = null\n let statusLoopAbort: AbortController | null = null\n let connectInFlight: Promise<void> | null = null\n\n const backoff = options.exponentialBackoff\n ? createExponentialBackoffHandler(options.exponentialBackoff)\n : undefined\n\n const statusListeners = new Set<(event: NatsStatusEvent) => void>()\n\n function emitStatus(event: NatsStatusEvent) {\n for (const listener of statusListeners) {\n try {\n listener(event)\n } catch {\n // ignore listener failures\n }\n }\n }\n\n async function connect(): Promise<void> {\n if (nc && !nc.isClosed()) return\n if (connectInFlight) return connectInFlight\n assertClientSide()\n\n connectInFlight = (async () => {\n try {\n emitStatus({ status: 'connecting' })\n\n const nats = await importNats()\n const conn = await nats.connect(mapOptionsToConnectionOptions(options, backoff))\n nc = conn\n\n emitStatus({ status: 'connected' })\n\n statusLoopAbort = new AbortController()\n const signal = statusLoopAbort.signal\n\n ;(async () => {\n try {\n for await (const s of conn.status()) {\n if (signal.aborted) return\n const mapped = mapNatsTypeToStatus((s as any)?.type)\n if (mapped) {\n if (mapped === 'connected' && backoff) {\n backoff.reset()\n }\n emitStatus({ status: mapped, data: (s as any)?.data })\n if (mapped === 'closed') {\n nc = null\n }\n }\n }\n } catch (e) {\n if (!signal.aborted) {\n emitStatus({ status: 'error', data: e })\n \n if (nc === conn && conn.isClosed()) {\n nc = null\n emitStatus({ status: 'closed' })\n }\n }\n }\n })().catch(() => {\n // ignore\n })\n } finally {\n connectInFlight = null\n }\n })()\n\n return connectInFlight\n }\n\n async function close(): Promise<void> {\n const conn = nc\n nc = null\n\n if (statusLoopAbort) {\n try {\n statusLoopAbort.abort()\n } catch {\n // ignore\n }\n statusLoopAbort = null\n }\n\n if (!conn) return\n try {\n await conn.drain()\n } finally {\n try {\n await conn.close()\n } finally {\n emitStatus({ status: 'closed' })\n }\n }\n }\n\n function requireConnection(): NatsConnection {\n if (!nc) throw new Error('NATS is not connected. Call client.connect() first.')\n return nc\n }\n\n function isConnected(): boolean {\n return Boolean(nc) && !nc!.isClosed()\n }\n\n function publishBytes(subject: string, payload: Uint8Array, opts?: NatsPublishOptions): void {\n const conn = requireConnection()\n ;(async () => {\n const nats = await importNats()\n conn.publish(subject, payload, { headers: toNatsHeaders(nats, opts?.headers) })\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n }\n\n function publishString(subject: string, payload: string, opts?: NatsPublishOptions): void {\n ;(async () => {\n const nats = await importNats()\n const sc = nats.StringCodec()\n publishBytes(subject, sc.encode(payload), opts)\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n }\n\n function publishJson<T>(subject: string, payload: T, opts?: NatsPublishOptions): void {\n ;(async () => {\n const nats = await importNats()\n const jc = nats.JSONCodec<T>()\n publishBytes(subject, jc.encode(payload), opts)\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n }\n\n async function requestBytes(subject: string, payload: Uint8Array, opts?: NatsRequestOptions): Promise<Msg> {\n const conn = requireConnection()\n const nats = await importNats()\n const msg = await conn.request(subject, payload, {\n timeout: opts?.timeoutMs ?? 2000,\n headers: toNatsHeaders(nats, opts?.headers),\n })\n return msg\n }\n\n async function requestString(subject: string, payload: string, opts?: NatsRequestOptions): Promise<string> {\n const nats = await importNats()\n const sc = nats.StringCodec()\n const msg = await requestBytes(subject, sc.encode(payload), opts)\n return sc.decode(msg.data)\n }\n\n async function requestJson<TResponse, TRequest = unknown>(\n subject: string,\n payload: TRequest,\n opts?: NatsRequestOptions,\n ): Promise<TResponse> {\n const nats = await importNats()\n const reqCodec = nats.JSONCodec<TRequest>()\n const resCodec = nats.JSONCodec<TResponse>()\n const msg = await requestBytes(subject, reqCodec.encode(payload), opts)\n return resCodec.decode(msg.data)\n }\n\n function subscribeBytes(\n subject: string,\n onMessage: (msg: Msg) => void | Promise<void>,\n opts?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle {\n const conn = requireConnection()\n const sub = conn.subscribe(subject, { queue: opts?.queue })\n if (typeof opts?.max === 'number') sub.unsubscribe(opts.max)\n\n const abortController = new AbortController()\n const signal = opts?.signal ?? abortController.signal\n\n ;(async () => {\n try {\n for await (const msg of sub) {\n if (signal.aborted) break\n await onMessage(msg)\n }\n } catch (e) {\n emitStatus({ status: 'error', data: e })\n } finally {\n try {\n sub.unsubscribe()\n } catch {\n // ignore\n }\n }\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n\n return {\n subscription: sub,\n unsubscribe() {\n try {\n abortController.abort()\n } catch {\n // ignore\n }\n try {\n sub.unsubscribe()\n } catch {\n // ignore\n }\n },\n }\n }\n\n function subscribeString(\n subject: string,\n onMessage: (payload: string, msg: Msg) => void | Promise<void>,\n opts?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle {\n return subscribeBytes(\n subject,\n async (msg) => {\n const nats = await importNats()\n const sc = nats.StringCodec()\n await onMessage(sc.decode(msg.data), msg)\n },\n opts,\n )\n }\n\n function subscribeJson<T>(\n subject: string,\n onMessage: (payload: T, msg: Msg) => void | Promise<void>,\n opts?: NatsSubscribeOptions,\n ): NatsSubscriptionHandle {\n return subscribeBytes(\n subject,\n async (msg) => {\n const nats = await importNats()\n const jc = nats.JSONCodec<T>()\n await onMessage(jc.decode(msg.data), msg)\n },\n opts,\n )\n }\n\n async function subscribeJetStreamOrdered(\n onMessage: (msg: JsMsg) => void | Promise<void>,\n opts: JetStreamOrderedSubscribeOptions,\n ): Promise<JetStreamSubscriptionHandle> {\n const conn = requireConnection()\n if (opts.signal?.aborted) {\n return { unsubscribe() {} }\n }\n\n const nats = await importNats()\n if (opts.signal?.aborted) {\n return { unsubscribe() {} }\n }\n\n const js = conn.jetstream()\n const consumer: Consumer = await js.consumers.get(opts.streamName, {\n filterSubjects: opts.filterSubject,\n deliver_policy: nats.DeliverPolicy.StartSequence,\n opt_start_seq: opts.optStartSeq ?? 0,\n // Milliseconds, NOT nanoseconds: nats.ws runs this through its own\n // `nanos()` before it reaches the server. Pre-converting here multiplied\n // it by 1e6 twice, putting the threshold ~9.5 years out — so the ephemeral\n // consumer never expired. Two consequences, both silent: every reconnect\n // and dialog switch orphaned a consumer server-side, and a client that\n // stopped pulling never got the `consumer deleted` that drives the ordered\n // consumer's self-repair. Undefined stays undefined so nats.ws applies its\n // own default rather than a copy of it.\n inactive_threshold: opts.inactiveThresholdMs,\n })\n\n const iterRef: { current: ConsumerMessages | null } = { current: null }\n let closed = false\n\n const onAbort = () => {\n void teardown()\n }\n opts.signal?.addEventListener('abort', onAbort, { once: true })\n\n async function teardown(): Promise<void> {\n if (closed) return\n closed = true\n opts.signal?.removeEventListener('abort', onAbort)\n const iter = iterRef.current\n iterRef.current = null\n if (iter) {\n try {\n await iter.close()\n } catch {\n // ignore\n }\n }\n }\n\n if (opts.signal?.aborted) {\n void teardown()\n return { unsubscribe() {} }\n }\n\n ;(async () => {\n try {\n const iter = await consumer.consume()\n if (closed) {\n try {\n await iter.close()\n } catch {\n // ignore\n }\n return\n }\n iterRef.current = iter\n watchForRecovery(iter, nats.ConsumerEvents.OrderedConsumerRecreated, opts.onRecovered)\n for await (const msg of iter) {\n if (closed) break\n try {\n await onMessage(msg)\n } catch (e) {\n emitStatus({ status: 'error', data: e })\n }\n }\n } catch (e) {\n if (!closed) emitStatus({ status: 'error', data: e })\n }\n })().catch((e) => emitStatus({ status: 'error', data: e }))\n\n return {\n unsubscribe() {\n void teardown()\n },\n }\n }\n\n function onStatus(listener: (event: NatsStatusEvent) => void): () => void {\n statusListeners.add(listener)\n return () => statusListeners.delete(listener)\n }\n\n return {\n connect,\n close,\n isConnected,\n publishBytes,\n publishString,\n publishJson,\n requestBytes,\n requestString,\n requestJson,\n subscribeBytes,\n subscribeString,\n subscribeJson,\n subscribeJetStreamOrdered,\n onStatus,\n }\n}\n","import { createNatsClient, type NatsClient, type NatsStatus, type NatsStatusEvent } from './nats'\n\nexport const NATS_DEFAULTS = {\n SHARED_CLOSE_DELAY_MS: 3000,\n CONNECT_TIMEOUT_MS: 10_000,\n PING_INTERVAL_MS: 30_000,\n MAX_PING_OUT: 3,\n RETRY_INITIAL_DELAY_MS: 1000,\n RETRY_MAX_DELAY_MS: 30_000,\n RETRY_MULTIPLIER: 2,\n} as const\n\nexport interface NatsReconnectionBackoff {\n /** Number of fast retries before exponential phase kicks in. Default: 0. */\n fastRetries?: number\n /** Delay used during the fast-retry phase. Default: RETRY_INITIAL_DELAY_MS. */\n fastRetryDelayMs?: number\n /** Base delay for the exponential phase. Default: RETRY_INITIAL_DELAY_MS. */\n initialDelayMs?: number\n /** Upper cap on any single retry delay. Default: RETRY_MAX_DELAY_MS. */\n maxDelayMs?: number\n /** Per-attempt multiplier during exponential phase. Default: RETRY_MULTIPLIER. */\n multiplier?: number\n}\n\nexport interface SharedConnection {\n wsUrl: string\n client: NatsClient\n connectPromise: Promise<void> | null\n refCount: number\n closeTimer: ReturnType<typeof setTimeout> | null\n retryTimer: ReturnType<typeof setTimeout> | null\n /**\n * Identity of the consumer driving reconnect. When set, other consumers\n * should observe status only and skip their own scheduleRetry — otherwise\n * each disconnect triggers multiple concurrent connect() calls racing over\n * connectPromise.\n */\n retryOwner: object | null\n}\n\nexport interface AcquireClientOptions {\n name?: string\n user?: string\n pass?: string\n connectTimeoutMs?: number\n pingIntervalMs?: number\n maxPingOut?: number\n}\n\nexport interface ReleaseClientOptions {\n delayMs?: number\n}\n\n// One shared connection PER URL. The previous single-slot implementation\n// force-closed whatever was connected the moment any consumer acquired a\n// DIFFERENT URL — even with live refs on it. With two chat surfaces on\n// distinct endpoints (`/ws/nats` client chat vs `/ws/nats-api` dashboard)\n// mounted at once, each acquire killed the other's socket, and the loser's\n// retry loop self-cancelled (connection identity mismatch) leaving a dead\n// subscription that silently received nothing.\nconst connections = new Map<string, SharedConnection>()\n\n/** Legacy accessor from the single-slot era: returns the first live shared\n * connection, or null. With MULTIPLE URLs connected (e.g. `/ws/nats` client\n * chat + `/ws/nats-api` dashboard mounted together) \"first\" is whichever\n * surface acquired first — an arbitrary, mount-order-dependent answer.\n * Prefer `getSharedConnectionFor(url)`; this stays only for external\n * registry-pinned consumers of the old single-connection API. */\nexport function getSharedConnection(): SharedConnection | null {\n const first = connections.values().next()\n return first.done ? null : first.value\n}\n\nexport function acquireClient(url: string, opts?: AcquireClientOptions): SharedConnection {\n let conn = connections.get(url)\n\n if (!conn) {\n const {\n name = 'openframe-frontend',\n user = 'machine',\n pass = '',\n connectTimeoutMs = NATS_DEFAULTS.CONNECT_TIMEOUT_MS,\n pingIntervalMs = NATS_DEFAULTS.PING_INTERVAL_MS,\n maxPingOut = NATS_DEFAULTS.MAX_PING_OUT,\n } = opts ?? {}\n\n const client = createNatsClient({\n servers: url,\n name,\n user,\n pass,\n connectTimeoutMs,\n reconnect: false,\n pingIntervalMs,\n maxPingOut,\n })\n\n conn = {\n wsUrl: url,\n client,\n connectPromise: null,\n refCount: 0,\n closeTimer: null,\n retryTimer: null,\n retryOwner: null,\n }\n connections.set(url, conn)\n }\n\n conn.refCount += 1\n if (conn.closeTimer) {\n clearTimeout(conn.closeTimer)\n conn.closeTimer = null\n }\n return conn\n}\n\nexport function releaseClient(url: string, opts?: ReleaseClientOptions): void {\n const conn = connections.get(url)\n if (!conn) return\n\n conn.refCount = Math.max(0, conn.refCount - 1)\n if (conn.refCount > 0) return\n\n const delay = opts?.delayMs ?? NATS_DEFAULTS.SHARED_CLOSE_DELAY_MS\n conn.closeTimer = setTimeout(() => {\n conn.closeTimer = null\n // A new acquire may have raced in during the grace period.\n if (conn.refCount > 0) return\n if (connections.get(url) === conn) {\n connections.delete(url)\n }\n if (conn.retryTimer) {\n clearTimeout(conn.retryTimer)\n conn.retryTimer = null\n }\n void conn.client.close().catch(() => {})\n }, delay)\n}\n\nexport function getSharedConnectionFor(url: string | null | undefined): SharedConnection | null {\n if (!url) return null\n return connections.get(url) ?? null\n}\n\n// ---------------------------------------------------------------------------\n// Connection lifecycle: retry + status loop, shared by NatsProvider and the\n// chat hooks. Each consumer that wants to drive reconnect creates an\n// ownerToken and calls startConnectionLifecycle(). The first caller to claim\n// retryOwner runs the actual retry loop; subsequent claimants observe status\n// only. When the owner unmounts and releases retryOwner, the next status\n// event lets a surviving consumer pick up ownership opportunistically.\n// ---------------------------------------------------------------------------\n\nexport interface ConnectionLifecycleOptions {\n conn: SharedConnection\n wsUrl: string\n onBeforeReconnect?: () => Promise<void> | void\n backoff?: NatsReconnectionBackoff\n getFreshUrl: () => string | null\n /** Called on every status change (after closed-guard). */\n onStatusChange?: (status: NatsStatus, evt: NatsStatusEvent) => void\n /**\n * Decide which statuses should trigger a retry attempt. Defaults to closed +\n * disconnected. Override to skip 'error' (JetStream protocol errors that\n * don't close the WS) or include it.\n */\n shouldRetryOn?: (status: NatsStatus) => boolean\n}\n\nexport interface ConnectionLifecycleHandle {\n /** Stop observing status, clear any pending retry, release ownership if held. */\n stop(): void\n}\n\nconst defaultShouldRetryOn = (status: NatsStatus) => status === 'closed' || status === 'disconnected'\n\nexport function startConnectionLifecycle(options: ConnectionLifecycleOptions): ConnectionLifecycleHandle {\n const { conn, wsUrl } = options\n // Each lifecycle gets its own identity for retry ownership. The first lifecycle to claim\n // an unowned connection drives reconnect; later attachers observe status only until the\n // owner releases (see opportunistic claim in scheduleRetry).\n const ownerToken = {}\n if (!conn.retryOwner) conn.retryOwner = ownerToken\n\n let closed = false\n let retryAttempt = 0\n\n function emitSynthetic(status: NatsStatus) {\n if (closed) return\n options.onStatusChange?.(status, { status })\n if (status === 'connected') {\n retryAttempt = 0\n }\n }\n\n function scheduleRetry() {\n if (closed) return\n if (getSharedConnectionFor(wsUrl) !== conn) return\n if (!conn.retryOwner) conn.retryOwner = ownerToken\n if (conn.retryOwner !== ownerToken) return\n\n if (conn.retryTimer) {\n clearTimeout(conn.retryTimer)\n conn.retryTimer = null\n }\n\n const cfg = options.backoff ?? {}\n const fastRetries = cfg.fastRetries ?? 0\n const fastDelay = cfg.fastRetryDelayMs ?? NATS_DEFAULTS.RETRY_INITIAL_DELAY_MS\n const baseDelay = cfg.initialDelayMs ?? NATS_DEFAULTS.RETRY_INITIAL_DELAY_MS\n const maxDelay = cfg.maxDelayMs ?? NATS_DEFAULTS.RETRY_MAX_DELAY_MS\n const multiplier = cfg.multiplier ?? NATS_DEFAULTS.RETRY_MULTIPLIER\n\n const delay =\n retryAttempt < fastRetries\n ? fastDelay\n : Math.min(baseDelay * multiplier ** (retryAttempt - fastRetries), maxDelay)\n const jitteredDelay = delay * (0.5 + Math.random() * 0.5)\n retryAttempt++\n\n conn.retryTimer = setTimeout(async () => {\n conn.retryTimer = null\n if (closed) return\n if (getSharedConnectionFor(wsUrl) !== conn) return\n\n try {\n await options.onBeforeReconnect?.()\n } catch {\n // continue regardless of token-refresh outcome\n }\n if (closed) return\n if (getSharedConnectionFor(wsUrl) !== conn) return\n\n const freshUrl = options.getFreshUrl()\n if (freshUrl !== wsUrl) return\n\n try {\n conn.connectPromise = null\n conn.connectPromise = conn.client.connect()\n await conn.connectPromise\n if (!closed && getSharedConnectionFor(wsUrl) === conn) {\n retryAttempt = 0\n }\n } catch {\n conn.connectPromise = null\n if (!closed && getSharedConnectionFor(wsUrl) === conn) {\n scheduleRetry()\n }\n }\n }, jitteredDelay)\n }\n\n const shouldRetryOn = options.shouldRetryOn ?? defaultShouldRetryOn\n\n const unsubStatus = conn.client.onStatus((evt) => {\n if (closed) return\n options.onStatusChange?.(evt.status, evt)\n if (evt.status === 'connected') {\n retryAttempt = 0\n }\n if (shouldRetryOn(evt.status)) {\n scheduleRetry()\n }\n })\n\n if (conn.client.isConnected()) {\n emitSynthetic('connected')\n }\n\n void (async () => {\n try {\n conn.connectPromise ||= conn.client.connect()\n await conn.connectPromise\n } catch {\n conn.connectPromise = null\n if (closed) return\n\n emitSynthetic('disconnected')\n scheduleRetry()\n }\n })()\n\n return {\n stop() {\n closed = true\n unsubStatus()\n if (conn.retryTimer) {\n clearTimeout(conn.retryTimer)\n conn.retryTimer = null\n }\n if (conn.retryOwner === ownerToken) {\n conn.retryOwner = null\n }\n },\n }\n}\n","'use client'\n\nimport * as React from 'react'\nimport type { NatsClient, NatsStatus } from './nats'\nimport {\n acquireClient,\n releaseClient,\n startConnectionLifecycle,\n type AcquireClientOptions,\n type NatsReconnectionBackoff,\n} from './shared-connection'\n\nexport type { NatsReconnectionBackoff } from './shared-connection'\n\nexport interface NatsProviderProps {\n children: React.ReactNode\n /** Return the current NATS WebSocket URL (or null when not yet available, e.g. unauthenticated). */\n getWsUrl: () => string | null\n /** Called before each reconnect attempt. */\n onBeforeReconnect?: () => Promise<void> | void\n clientConfig?: AcquireClientOptions\n reconnectionBackoff?: NatsReconnectionBackoff\n /**\n * Bump this to force re-evaluating `getWsUrl()` (e.g. when auth state flips).\n * Provider does not subscribe to external auth state by itself.\n */\n urlRevision?: unknown\n}\n\nexport interface NatsContextValue {\n client: NatsClient | null\n status: NatsStatus\n isReady: boolean\n reconnectionCount: number\n}\n\nconst NatsContext = React.createContext<NatsContextValue | null>(null)\n\nexport function NatsProvider({\n children,\n getWsUrl,\n onBeforeReconnect,\n clientConfig,\n reconnectionBackoff,\n urlRevision,\n}: NatsProviderProps) {\n const [client, setClient] = React.useState<NatsClient | null>(null)\n const [status, setStatus] = React.useState<NatsStatus>('closed')\n const [reconnectionCount, setReconnectionCount] = React.useState(0)\n\n const getWsUrlRef = React.useRef(getWsUrl)\n React.useEffect(() => {\n getWsUrlRef.current = getWsUrl\n }, [getWsUrl])\n\n const onBeforeReconnectRef = React.useRef(onBeforeReconnect)\n React.useEffect(() => {\n onBeforeReconnectRef.current = onBeforeReconnect\n }, [onBeforeReconnect])\n\n const reconnectionBackoffRef = React.useRef(reconnectionBackoff)\n React.useEffect(() => {\n reconnectionBackoffRef.current = reconnectionBackoff\n }, [reconnectionBackoff])\n\n const clientConfigRef = React.useRef(clientConfig)\n React.useEffect(() => {\n clientConfigRef.current = clientConfig\n }, [clientConfig])\n\n const heldUrlRef = React.useRef<string | null>(null)\n const hadConnectionBeforeRef = React.useRef(false)\n\n React.useEffect(() => {\n const wsUrl = getWsUrlRef.current()\n\n if (!wsUrl) {\n if (heldUrlRef.current) {\n releaseClient(heldUrlRef.current)\n heldUrlRef.current = null\n setClient(null)\n setStatus('closed')\n }\n return\n }\n\n if (heldUrlRef.current && heldUrlRef.current !== wsUrl) {\n releaseClient(heldUrlRef.current)\n heldUrlRef.current = null\n }\n\n const conn = acquireClient(wsUrl, clientConfigRef.current)\n heldUrlRef.current = wsUrl\n setClient(conn.client)\n setStatus(conn.client.isConnected() ? 'connected' : 'connecting')\n\n const lifecycle = startConnectionLifecycle({\n conn,\n wsUrl,\n onBeforeReconnect: () => onBeforeReconnectRef.current?.(),\n backoff: reconnectionBackoffRef.current,\n getFreshUrl: () => getWsUrlRef.current(),\n onStatusChange: (newStatus) => {\n if (newStatus === 'error') return\n setStatus(newStatus)\n if (newStatus === 'connected') {\n if (hadConnectionBeforeRef.current) {\n setReconnectionCount((c) => c + 1)\n }\n hadConnectionBeforeRef.current = true\n }\n },\n })\n\n return () => {\n lifecycle.stop()\n if (heldUrlRef.current) {\n releaseClient(heldUrlRef.current)\n heldUrlRef.current = null\n }\n setClient(null)\n setStatus('closed')\n }\n }, [urlRevision])\n\n const value = React.useMemo<NatsContextValue>(\n () => ({\n client,\n status,\n isReady: status === 'connected' && client !== null,\n reconnectionCount,\n }),\n [client, status, reconnectionCount],\n )\n\n return <NatsContext.Provider value={value}>{children}</NatsContext.Provider>\n}\n\nexport function useNats(): NatsContextValue {\n const ctx = React.useContext(NatsContext)\n if (!ctx) throw new Error('useNats must be used inside <NatsProvider>')\n return ctx\n}\n\nexport function useOptionalNats(): NatsContextValue | null {\n return React.useContext(NatsContext)\n}\n","'use client'\n\nimport * as React from 'react'\nimport type { JsMsg, Msg, NatsSubscribeOptions } from './nats'\nimport { useOptionalNats } from './nats-provider'\n\nexport interface UseNatsSubscriptionOptions extends NatsSubscribeOptions {\n enabled?: boolean\n}\n\nexport interface UseNatsSubscriptionReturn {\n isSubscribed: boolean\n isReady: boolean\n}\n\n/**\n * Subscribe to a NATS subject using the shared connection from <NatsProvider>.\n * Automatically (re)subscribes when the connection becomes ready, when the\n * subject changes, and after reconnections.\n */\nexport function useNatsSubscription(\n subject: string | null,\n onMessage: (msg: Msg) => void | Promise<void>,\n options?: UseNatsSubscriptionOptions,\n): UseNatsSubscriptionReturn {\n const nats = useOptionalNats()\n const handlerRef = React.useRef(onMessage)\n React.useEffect(() => {\n handlerRef.current = onMessage\n }, [onMessage])\n\n const [isSubscribed, setIsSubscribed] = React.useState(false)\n\n const enabled = options?.enabled !== false\n const queue = options?.queue\n const max = options?.max\n const reconnectionCount = nats?.reconnectionCount ?? 0\n const isReady = !!nats?.isReady\n const client = nats?.client ?? null\n\n React.useEffect(() => {\n if (!client || !isReady || !subject || !enabled) {\n setIsSubscribed(false)\n return\n }\n\n const sub = client.subscribeBytes(\n subject,\n (msg) => handlerRef.current(msg),\n { queue, max },\n )\n setIsSubscribed(true)\n\n return () => {\n setIsSubscribed(false)\n try {\n sub.unsubscribe()\n } catch {\n // ignore\n }\n }\n // reconnectionCount intentionally in deps: re-subscribe after reconnect\n }, [client, isReady, subject, enabled, queue, max, reconnectionCount])\n\n return { isSubscribed, isReady }\n}\n\nexport type UseNatsJsonSubscriptionOptions = UseNatsSubscriptionOptions\n\nexport function useNatsJsonSubscription<T = unknown>(\n subject: string | null,\n onPayload: (payload: T, msg: Msg) => void | Promise<void>,\n options?: UseNatsJsonSubscriptionOptions,\n): UseNatsSubscriptionReturn {\n const handlerRef = React.useRef(onPayload)\n React.useEffect(() => {\n handlerRef.current = onPayload\n }, [onPayload])\n\n const decoderRef = React.useRef<TextDecoder | null>(null)\n if (!decoderRef.current && typeof TextDecoder !== 'undefined') {\n decoderRef.current = new TextDecoder()\n }\n\n const wrapped = React.useCallback(async (msg: Msg) => {\n const decoder = decoderRef.current\n if (!decoder) return\n try {\n const parsed = JSON.parse(decoder.decode(msg.data)) as T\n await handlerRef.current(parsed, msg)\n } catch {\n // ignore malformed payloads\n }\n }, [])\n\n return useNatsSubscription(subject, wrapped, options)\n}\n\nexport type NatsJsMsg = JsMsg\n"]}