@flamingo-stack/openframe-frontend-core 0.0.212 → 0.0.213

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 (91) hide show
  1. package/dist/{chunk-ZFBLC5GV.cjs → chunk-35XIT2CF.cjs} +17 -17
  2. package/dist/{chunk-ZFBLC5GV.cjs.map → chunk-35XIT2CF.cjs.map} +1 -1
  3. package/dist/{chunk-QKFBZLIR.js → chunk-3JWIJJ44.js} +2 -2
  4. package/dist/chunk-CZR7ARBA.js +698 -0
  5. package/dist/chunk-CZR7ARBA.js.map +1 -0
  6. package/dist/{chunk-UYQOPC57.js → chunk-HICZPTRR.js} +4 -351
  7. package/dist/chunk-HICZPTRR.js.map +1 -0
  8. package/dist/{chunk-5BNWGK6D.js → chunk-IK2X5YJU.js} +3 -3
  9. package/dist/{chunk-VTUIMMHO.cjs → chunk-OTKJASSX.cjs} +26 -26
  10. package/dist/{chunk-VTUIMMHO.cjs.map → chunk-OTKJASSX.cjs.map} +1 -1
  11. package/dist/chunk-OZ3GH6OQ.cjs +698 -0
  12. package/dist/chunk-OZ3GH6OQ.cjs.map +1 -0
  13. package/dist/{chunk-EH3RWVF3.cjs → chunk-WT5JV2GS.cjs} +8 -355
  14. package/dist/chunk-WT5JV2GS.cjs.map +1 -0
  15. package/dist/{chunk-WI76ZUBE.cjs → chunk-ZDF6F7ED.cjs} +544 -678
  16. package/dist/chunk-ZDF6F7ED.cjs.map +1 -0
  17. package/dist/{chunk-3E5ANY55.js → chunk-ZTJVRSN5.js} +409 -543
  18. package/dist/{chunk-3E5ANY55.js.map → chunk-ZTJVRSN5.js.map} +1 -1
  19. package/dist/components/chat/hooks/use-jetstream-dialog-subscription.d.ts.map +1 -1
  20. package/dist/components/chat/hooks/use-nats-dialog-subscription.d.ts +0 -9
  21. package/dist/components/chat/hooks/use-nats-dialog-subscription.d.ts.map +1 -1
  22. package/dist/components/chat/index.cjs +5 -4
  23. package/dist/components/chat/index.cjs.map +1 -1
  24. package/dist/components/chat/index.js +4 -3
  25. package/dist/components/contact/index.cjs +6 -5
  26. package/dist/components/contact/index.cjs.map +1 -1
  27. package/dist/components/contact/index.js +5 -4
  28. package/dist/components/features/index.cjs +5 -4
  29. package/dist/components/features/index.cjs.map +1 -1
  30. package/dist/components/features/index.js +4 -3
  31. package/dist/components/features/notifications/index.d.ts +2 -2
  32. package/dist/components/features/notifications/index.d.ts.map +1 -1
  33. package/dist/components/features/notifications/notifications-context.d.ts +16 -1
  34. package/dist/components/features/notifications/notifications-context.d.ts.map +1 -1
  35. package/dist/components/features/notifications/types.d.ts +4 -0
  36. package/dist/components/features/notifications/types.d.ts.map +1 -1
  37. package/dist/components/index.cjs +55 -54
  38. package/dist/components/index.cjs.map +1 -1
  39. package/dist/components/index.js +7 -6
  40. package/dist/components/index.js.map +1 -1
  41. package/dist/components/navigation/app-header.d.ts.map +1 -1
  42. package/dist/components/navigation/index.cjs +5 -4
  43. package/dist/components/navigation/index.cjs.map +1 -1
  44. package/dist/components/navigation/index.js +4 -3
  45. package/dist/components/tickets/index.cjs +66 -65
  46. package/dist/components/tickets/index.cjs.map +1 -1
  47. package/dist/components/tickets/index.js +6 -5
  48. package/dist/components/tickets/index.js.map +1 -1
  49. package/dist/components/ui/index.cjs +5 -4
  50. package/dist/components/ui/index.cjs.map +1 -1
  51. package/dist/components/ui/index.js +4 -3
  52. package/dist/embed-shims/index.cjs +3 -3
  53. package/dist/embed-shims/index.cjs.map +1 -1
  54. package/dist/embed-shims/index.js +4 -4
  55. package/dist/hooks/index.cjs +3 -2
  56. package/dist/hooks/index.cjs.map +1 -1
  57. package/dist/hooks/index.js +2 -1
  58. package/dist/index.cjs +5 -4
  59. package/dist/index.cjs.map +1 -1
  60. package/dist/index.js +4 -3
  61. package/dist/nats/index.cjs +28 -346
  62. package/dist/nats/index.cjs.map +1 -1
  63. package/dist/nats/index.d.ts +3 -0
  64. package/dist/nats/index.d.ts.map +1 -1
  65. package/dist/nats/index.js +30 -346
  66. package/dist/nats/index.js.map +1 -1
  67. package/dist/nats/nats-provider.d.ts +28 -0
  68. package/dist/nats/nats-provider.d.ts.map +1 -0
  69. package/dist/nats/nats.d.ts +1 -0
  70. package/dist/nats/nats.d.ts.map +1 -1
  71. package/dist/nats/shared-connection.d.ts +73 -0
  72. package/dist/nats/shared-connection.d.ts.map +1 -0
  73. package/dist/nats/use-nats-subscription.d.ts +18 -0
  74. package/dist/nats/use-nats-subscription.d.ts.map +1 -0
  75. package/package.json +1 -1
  76. package/src/components/chat/hooks/use-jetstream-dialog-subscription.ts +60 -207
  77. package/src/components/chat/hooks/use-nats-dialog-subscription.ts +71 -214
  78. package/src/components/features/notifications/index.ts +2 -1
  79. package/src/components/features/notifications/notifications-context.tsx +104 -6
  80. package/src/components/features/notifications/types.ts +5 -0
  81. package/src/components/navigation/app-header.tsx +7 -9
  82. package/src/nats/index.ts +3 -0
  83. package/src/nats/nats-provider.tsx +146 -0
  84. package/src/nats/nats.ts +2 -0
  85. package/src/nats/shared-connection.ts +285 -0
  86. package/src/nats/use-nats-subscription.ts +99 -0
  87. package/dist/chunk-EH3RWVF3.cjs.map +0 -1
  88. package/dist/chunk-UYQOPC57.js.map +0 -1
  89. package/dist/chunk-WI76ZUBE.cjs.map +0 -1
  90. /package/dist/{chunk-QKFBZLIR.js.map → chunk-3JWIJJ44.js.map} +0 -0
  91. /package/dist/{chunk-5BNWGK6D.js.map → chunk-IK2X5YJU.js.map} +0 -0
@@ -0,0 +1,698 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+
3
+ // src/nats/nats.ts
4
+ function assertClientSide() {
5
+ if (typeof window === "undefined") {
6
+ throw new Error("NATS client can only connect from the browser/runtime with WebSocket support (window is undefined).");
7
+ }
8
+ }
9
+ async function importNats() {
10
+ return await Promise.resolve().then(() => _interopRequireWildcard(require("nats.ws")));
11
+ }
12
+ function toNatsHeaders(nats, init) {
13
+ if (!init) return void 0;
14
+ if (typeof init.get === "function") return init;
15
+ const h = nats.headers();
16
+ for (const [k, v] of Object.entries(init)) {
17
+ if (v !== void 0 && v !== null) h.set(k, String(v));
18
+ }
19
+ return h;
20
+ }
21
+ function cryptoRandom() {
22
+ const buf = new Uint32Array(1);
23
+ crypto.getRandomValues(buf);
24
+ return buf[0] / (4294967295 + 1);
25
+ }
26
+ function createExponentialBackoffHandler(opts) {
27
+ const initialDelay = _nullishCoalesce(opts.initialDelayMs, () => ( 1e3));
28
+ const maxDelay = _nullishCoalesce(opts.maxDelayMs, () => ( 3e4));
29
+ const multiplier = _nullishCoalesce(opts.multiplier, () => ( 2));
30
+ const jitter = _nullishCoalesce(opts.jitter, () => ( true));
31
+ let attempt = 0;
32
+ return {
33
+ handler: () => {
34
+ const delay = Math.min(initialDelay * multiplier ** attempt, maxDelay);
35
+ attempt++;
36
+ return jitter ? delay * (0.5 + cryptoRandom() * 0.5) : delay;
37
+ },
38
+ reset: () => {
39
+ attempt = 0;
40
+ }
41
+ };
42
+ }
43
+ function mapOptionsToConnectionOptions(opts, backoff) {
44
+ return {
45
+ servers: opts.servers,
46
+ name: opts.name,
47
+ token: opts.token,
48
+ user: opts.user,
49
+ pass: opts.pass,
50
+ timeout: _nullishCoalesce(opts.connectTimeoutMs, () => ( 15e3)),
51
+ reconnect: _nullishCoalesce(opts.reconnect, () => ( true)),
52
+ maxReconnectAttempts: opts.maxReconnectAttempts,
53
+ reconnectTimeWait: opts.reconnectTimeWaitMs,
54
+ reconnectDelayHandler: _optionalChain([backoff, 'optionalAccess', _ => _.handler]),
55
+ pingInterval: opts.pingIntervalMs,
56
+ maxPingOut: opts.maxPingOut,
57
+ inboxPrefix: opts.inboxPrefix
58
+ };
59
+ }
60
+ function mapNatsTypeToStatus(type) {
61
+ const t = String(type).toLowerCase();
62
+ if (t.includes("disconnect")) return "disconnected";
63
+ if (t === "reconnecting") return "reconnecting";
64
+ if (t === "reconnect" || t.includes("connect")) return "connected";
65
+ if (t.includes("error")) return "error";
66
+ if (t.includes("close")) return "closed";
67
+ return null;
68
+ }
69
+ function createNatsClient(options) {
70
+ let nc = null;
71
+ let statusLoopAbort = null;
72
+ let connectInFlight = null;
73
+ const backoff = options.exponentialBackoff ? createExponentialBackoffHandler(options.exponentialBackoff) : void 0;
74
+ const statusListeners = /* @__PURE__ */ new Set();
75
+ function emitStatus(event) {
76
+ for (const listener of statusListeners) {
77
+ try {
78
+ listener(event);
79
+ } catch (e2) {
80
+ }
81
+ }
82
+ }
83
+ async function connect() {
84
+ if (nc && !nc.isClosed()) return;
85
+ if (connectInFlight) return connectInFlight;
86
+ assertClientSide();
87
+ connectInFlight = (async () => {
88
+ try {
89
+ emitStatus({ status: "connecting" });
90
+ const nats = await importNats();
91
+ const conn = await nats.connect(mapOptionsToConnectionOptions(options, backoff));
92
+ nc = conn;
93
+ emitStatus({ status: "connected" });
94
+ statusLoopAbort = new AbortController();
95
+ const signal = statusLoopAbort.signal;
96
+ (async () => {
97
+ try {
98
+ for await (const s of conn.status()) {
99
+ if (signal.aborted) return;
100
+ const mapped = mapNatsTypeToStatus(_optionalChain([s, 'optionalAccess', _2 => _2.type]));
101
+ if (mapped) {
102
+ if (mapped === "connected" && backoff) {
103
+ backoff.reset();
104
+ }
105
+ emitStatus({ status: mapped, data: _optionalChain([s, 'optionalAccess', _3 => _3.data]) });
106
+ if (mapped === "closed") {
107
+ nc = null;
108
+ }
109
+ }
110
+ }
111
+ } catch (e) {
112
+ if (!signal.aborted) {
113
+ emitStatus({ status: "error", data: e });
114
+ nc = null;
115
+ }
116
+ }
117
+ })().catch(() => {
118
+ });
119
+ } finally {
120
+ connectInFlight = null;
121
+ }
122
+ })();
123
+ return connectInFlight;
124
+ }
125
+ async function close() {
126
+ const conn = nc;
127
+ nc = null;
128
+ if (statusLoopAbort) {
129
+ try {
130
+ statusLoopAbort.abort();
131
+ } catch (e3) {
132
+ }
133
+ statusLoopAbort = null;
134
+ }
135
+ if (!conn) return;
136
+ try {
137
+ await conn.drain();
138
+ } finally {
139
+ try {
140
+ await conn.close();
141
+ } finally {
142
+ emitStatus({ status: "closed" });
143
+ }
144
+ }
145
+ }
146
+ function requireConnection() {
147
+ if (!nc) throw new Error("NATS is not connected. Call client.connect() first.");
148
+ return nc;
149
+ }
150
+ function isConnected() {
151
+ return Boolean(nc) && !nc.isClosed();
152
+ }
153
+ function publishBytes(subject, payload, opts) {
154
+ const conn = requireConnection();
155
+ (async () => {
156
+ const nats = await importNats();
157
+ conn.publish(subject, payload, { headers: toNatsHeaders(nats, _optionalChain([opts, 'optionalAccess', _4 => _4.headers])) });
158
+ })().catch((e) => emitStatus({ status: "error", data: e }));
159
+ }
160
+ function publishString(subject, payload, opts) {
161
+ ;
162
+ (async () => {
163
+ const nats = await importNats();
164
+ const sc = nats.StringCodec();
165
+ publishBytes(subject, sc.encode(payload), opts);
166
+ })().catch((e) => emitStatus({ status: "error", data: e }));
167
+ }
168
+ function publishJson(subject, payload, opts) {
169
+ ;
170
+ (async () => {
171
+ const nats = await importNats();
172
+ const jc = nats.JSONCodec();
173
+ publishBytes(subject, jc.encode(payload), opts);
174
+ })().catch((e) => emitStatus({ status: "error", data: e }));
175
+ }
176
+ async function requestBytes(subject, payload, opts) {
177
+ const conn = requireConnection();
178
+ const nats = await importNats();
179
+ const msg = await conn.request(subject, payload, {
180
+ timeout: _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _5 => _5.timeoutMs]), () => ( 2e3)),
181
+ headers: toNatsHeaders(nats, _optionalChain([opts, 'optionalAccess', _6 => _6.headers]))
182
+ });
183
+ return msg;
184
+ }
185
+ async function requestString(subject, payload, opts) {
186
+ const nats = await importNats();
187
+ const sc = nats.StringCodec();
188
+ const msg = await requestBytes(subject, sc.encode(payload), opts);
189
+ return sc.decode(msg.data);
190
+ }
191
+ async function requestJson(subject, payload, opts) {
192
+ const nats = await importNats();
193
+ const reqCodec = nats.JSONCodec();
194
+ const resCodec = nats.JSONCodec();
195
+ const msg = await requestBytes(subject, reqCodec.encode(payload), opts);
196
+ return resCodec.decode(msg.data);
197
+ }
198
+ function subscribeBytes(subject, onMessage, opts) {
199
+ const conn = requireConnection();
200
+ const sub = conn.subscribe(subject, { queue: _optionalChain([opts, 'optionalAccess', _7 => _7.queue]) });
201
+ if (typeof _optionalChain([opts, 'optionalAccess', _8 => _8.max]) === "number") sub.unsubscribe(opts.max);
202
+ const abortController = new AbortController();
203
+ const signal = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _9 => _9.signal]), () => ( abortController.signal));
204
+ (async () => {
205
+ try {
206
+ for await (const msg of sub) {
207
+ if (signal.aborted) break;
208
+ await onMessage(msg);
209
+ }
210
+ } catch (e) {
211
+ emitStatus({ status: "error", data: e });
212
+ } finally {
213
+ try {
214
+ sub.unsubscribe();
215
+ } catch (e4) {
216
+ }
217
+ }
218
+ })().catch((e) => emitStatus({ status: "error", data: e }));
219
+ return {
220
+ subscription: sub,
221
+ unsubscribe() {
222
+ try {
223
+ abortController.abort();
224
+ } catch (e5) {
225
+ }
226
+ try {
227
+ sub.unsubscribe();
228
+ } catch (e6) {
229
+ }
230
+ }
231
+ };
232
+ }
233
+ function subscribeString(subject, onMessage, opts) {
234
+ return subscribeBytes(
235
+ subject,
236
+ async (msg) => {
237
+ const nats = await importNats();
238
+ const sc = nats.StringCodec();
239
+ await onMessage(sc.decode(msg.data), msg);
240
+ },
241
+ opts
242
+ );
243
+ }
244
+ function subscribeJson(subject, onMessage, opts) {
245
+ return subscribeBytes(
246
+ subject,
247
+ async (msg) => {
248
+ const nats = await importNats();
249
+ const jc = nats.JSONCodec();
250
+ await onMessage(jc.decode(msg.data), msg);
251
+ },
252
+ opts
253
+ );
254
+ }
255
+ async function subscribeJetStreamOrdered(onMessage, opts) {
256
+ const conn = requireConnection();
257
+ if (_optionalChain([opts, 'access', _10 => _10.signal, 'optionalAccess', _11 => _11.aborted])) {
258
+ return { unsubscribe() {
259
+ } };
260
+ }
261
+ const nats = await importNats();
262
+ if (_optionalChain([opts, 'access', _12 => _12.signal, 'optionalAccess', _13 => _13.aborted])) {
263
+ return { unsubscribe() {
264
+ } };
265
+ }
266
+ const inactiveThresholdNs = (_nullishCoalesce(opts.inactiveThresholdMs, () => ( 5 * 6e4))) * 1e6;
267
+ const js = conn.jetstream();
268
+ const consumer = await js.consumers.get(opts.streamName, {
269
+ filterSubjects: opts.filterSubject,
270
+ deliver_policy: nats.DeliverPolicy.StartSequence,
271
+ opt_start_seq: _nullishCoalesce(opts.optStartSeq, () => ( 0)),
272
+ inactive_threshold: inactiveThresholdNs
273
+ });
274
+ const iterRef = { current: null };
275
+ let closed = false;
276
+ const onAbort = () => {
277
+ void teardown();
278
+ };
279
+ _optionalChain([opts, 'access', _14 => _14.signal, 'optionalAccess', _15 => _15.addEventListener, 'call', _16 => _16("abort", onAbort, { once: true })]);
280
+ async function teardown() {
281
+ if (closed) return;
282
+ closed = true;
283
+ _optionalChain([opts, 'access', _17 => _17.signal, 'optionalAccess', _18 => _18.removeEventListener, 'call', _19 => _19("abort", onAbort)]);
284
+ const iter = iterRef.current;
285
+ iterRef.current = null;
286
+ if (iter) {
287
+ try {
288
+ await iter.close();
289
+ } catch (e7) {
290
+ }
291
+ }
292
+ }
293
+ if (_optionalChain([opts, 'access', _20 => _20.signal, 'optionalAccess', _21 => _21.aborted])) {
294
+ void teardown();
295
+ return { unsubscribe() {
296
+ } };
297
+ }
298
+ ;
299
+ (async () => {
300
+ try {
301
+ const iter = await consumer.consume();
302
+ if (closed) {
303
+ try {
304
+ await iter.close();
305
+ } catch (e8) {
306
+ }
307
+ return;
308
+ }
309
+ iterRef.current = iter;
310
+ for await (const msg of iter) {
311
+ if (closed) break;
312
+ try {
313
+ await onMessage(msg);
314
+ } catch (e) {
315
+ emitStatus({ status: "error", data: e });
316
+ }
317
+ }
318
+ } catch (e) {
319
+ if (!closed) emitStatus({ status: "error", data: e });
320
+ }
321
+ })().catch((e) => emitStatus({ status: "error", data: e }));
322
+ return {
323
+ unsubscribe() {
324
+ void teardown();
325
+ }
326
+ };
327
+ }
328
+ function onStatus(listener) {
329
+ statusListeners.add(listener);
330
+ return () => statusListeners.delete(listener);
331
+ }
332
+ return {
333
+ connect,
334
+ close,
335
+ isConnected,
336
+ publishBytes,
337
+ publishString,
338
+ publishJson,
339
+ requestBytes,
340
+ requestString,
341
+ requestJson,
342
+ subscribeBytes,
343
+ subscribeString,
344
+ subscribeJson,
345
+ subscribeJetStreamOrdered,
346
+ onStatus
347
+ };
348
+ }
349
+
350
+ // src/nats/shared-connection.ts
351
+ var NATS_DEFAULTS = {
352
+ SHARED_CLOSE_DELAY_MS: 3e3,
353
+ CONNECT_TIMEOUT_MS: 1e4,
354
+ PING_INTERVAL_MS: 3e4,
355
+ MAX_PING_OUT: 3,
356
+ RETRY_INITIAL_DELAY_MS: 1e3,
357
+ RETRY_MAX_DELAY_MS: 3e4,
358
+ RETRY_MULTIPLIER: 2
359
+ };
360
+ var shared = null;
361
+ function getSharedConnection() {
362
+ return shared;
363
+ }
364
+ function acquireClient(url, opts) {
365
+ if (_optionalChain([shared, 'optionalAccess', _22 => _22.wsUrl]) !== url) {
366
+ if (shared) {
367
+ if (shared.closeTimer) clearTimeout(shared.closeTimer);
368
+ const old = shared;
369
+ shared = null;
370
+ void old.client.close().catch(() => {
371
+ });
372
+ }
373
+ const {
374
+ name = "openframe-frontend",
375
+ user = "machine",
376
+ pass = "",
377
+ connectTimeoutMs = NATS_DEFAULTS.CONNECT_TIMEOUT_MS,
378
+ pingIntervalMs = NATS_DEFAULTS.PING_INTERVAL_MS,
379
+ maxPingOut = NATS_DEFAULTS.MAX_PING_OUT
380
+ } = _nullishCoalesce(opts, () => ( {}));
381
+ const client = createNatsClient({
382
+ servers: url,
383
+ name,
384
+ user,
385
+ pass,
386
+ connectTimeoutMs,
387
+ reconnect: false,
388
+ pingIntervalMs,
389
+ maxPingOut
390
+ });
391
+ shared = {
392
+ wsUrl: url,
393
+ client,
394
+ connectPromise: null,
395
+ refCount: 0,
396
+ closeTimer: null,
397
+ retryTimer: null,
398
+ retryOwner: null
399
+ };
400
+ }
401
+ shared.refCount += 1;
402
+ if (shared.closeTimer) {
403
+ clearTimeout(shared.closeTimer);
404
+ shared.closeTimer = null;
405
+ }
406
+ return shared;
407
+ }
408
+ function releaseClient(url, opts) {
409
+ if (!shared || shared.wsUrl !== url) return;
410
+ shared.refCount = Math.max(0, shared.refCount - 1);
411
+ if (shared.refCount > 0) return;
412
+ const delay = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _23 => _23.delayMs]), () => ( NATS_DEFAULTS.SHARED_CLOSE_DELAY_MS));
413
+ shared.closeTimer = setTimeout(() => {
414
+ const s = shared;
415
+ shared = null;
416
+ if (s) {
417
+ if (s.retryTimer) {
418
+ clearTimeout(s.retryTimer);
419
+ s.retryTimer = null;
420
+ }
421
+ void s.client.close().catch(() => {
422
+ });
423
+ }
424
+ }, delay);
425
+ }
426
+ function getSharedConnectionFor(url) {
427
+ if (!url) return null;
428
+ return shared && shared.wsUrl === url ? shared : null;
429
+ }
430
+ var defaultShouldRetryOn = (status) => status === "closed" || status === "disconnected";
431
+ function startConnectionLifecycle(options) {
432
+ const { conn, wsUrl } = options;
433
+ const ownerToken = {};
434
+ if (!conn.retryOwner) conn.retryOwner = ownerToken;
435
+ let closed = false;
436
+ let retryAttempt = 0;
437
+ function emitSynthetic(status) {
438
+ if (closed) return;
439
+ _optionalChain([options, 'access', _24 => _24.onStatusChange, 'optionalCall', _25 => _25(status, { status })]);
440
+ if (status === "connected") {
441
+ retryAttempt = 0;
442
+ }
443
+ }
444
+ function scheduleRetry() {
445
+ if (closed) return;
446
+ if (getSharedConnectionFor(wsUrl) !== conn) return;
447
+ if (!conn.retryOwner) conn.retryOwner = ownerToken;
448
+ if (conn.retryOwner !== ownerToken) return;
449
+ if (conn.retryTimer) {
450
+ clearTimeout(conn.retryTimer);
451
+ conn.retryTimer = null;
452
+ }
453
+ const cfg = _nullishCoalesce(options.backoff, () => ( {}));
454
+ const fastRetries = _nullishCoalesce(cfg.fastRetries, () => ( 0));
455
+ const fastDelay = _nullishCoalesce(cfg.fastRetryDelayMs, () => ( NATS_DEFAULTS.RETRY_INITIAL_DELAY_MS));
456
+ const baseDelay = _nullishCoalesce(cfg.initialDelayMs, () => ( NATS_DEFAULTS.RETRY_INITIAL_DELAY_MS));
457
+ const maxDelay = _nullishCoalesce(cfg.maxDelayMs, () => ( NATS_DEFAULTS.RETRY_MAX_DELAY_MS));
458
+ const multiplier = _nullishCoalesce(cfg.multiplier, () => ( NATS_DEFAULTS.RETRY_MULTIPLIER));
459
+ const delay = retryAttempt < fastRetries ? fastDelay : Math.min(baseDelay * multiplier ** (retryAttempt - fastRetries), maxDelay);
460
+ const jitteredDelay = delay * (0.5 + Math.random() * 0.5);
461
+ retryAttempt++;
462
+ conn.retryTimer = setTimeout(async () => {
463
+ conn.retryTimer = null;
464
+ if (closed) return;
465
+ if (getSharedConnectionFor(wsUrl) !== conn) return;
466
+ try {
467
+ await _optionalChain([options, 'access', _26 => _26.onBeforeReconnect, 'optionalCall', _27 => _27()]);
468
+ } catch (e9) {
469
+ }
470
+ if (closed) return;
471
+ if (getSharedConnectionFor(wsUrl) !== conn) return;
472
+ const freshUrl = options.getFreshUrl();
473
+ if (freshUrl !== wsUrl) return;
474
+ try {
475
+ conn.connectPromise = null;
476
+ conn.connectPromise = conn.client.connect();
477
+ await conn.connectPromise;
478
+ if (!closed && getSharedConnectionFor(wsUrl) === conn) {
479
+ retryAttempt = 0;
480
+ }
481
+ } catch (e10) {
482
+ conn.connectPromise = null;
483
+ if (!closed && getSharedConnectionFor(wsUrl) === conn) {
484
+ scheduleRetry();
485
+ }
486
+ }
487
+ }, jitteredDelay);
488
+ }
489
+ const shouldRetryOn = _nullishCoalesce(options.shouldRetryOn, () => ( defaultShouldRetryOn));
490
+ const unsubStatus = conn.client.onStatus((evt) => {
491
+ if (closed) return;
492
+ _optionalChain([options, 'access', _28 => _28.onStatusChange, 'optionalCall', _29 => _29(evt.status, evt)]);
493
+ if (evt.status === "connected") {
494
+ retryAttempt = 0;
495
+ }
496
+ if (shouldRetryOn(evt.status)) {
497
+ scheduleRetry();
498
+ }
499
+ });
500
+ if (conn.client.isConnected()) {
501
+ emitSynthetic("connected");
502
+ }
503
+ void (async () => {
504
+ try {
505
+ conn.connectPromise || (conn.connectPromise = conn.client.connect());
506
+ await conn.connectPromise;
507
+ } catch (e11) {
508
+ conn.connectPromise = null;
509
+ if (closed) return;
510
+ emitSynthetic("disconnected");
511
+ scheduleRetry();
512
+ }
513
+ })();
514
+ return {
515
+ stop() {
516
+ closed = true;
517
+ unsubStatus();
518
+ if (conn.retryTimer) {
519
+ clearTimeout(conn.retryTimer);
520
+ conn.retryTimer = null;
521
+ }
522
+ if (conn.retryOwner === ownerToken) {
523
+ conn.retryOwner = null;
524
+ }
525
+ }
526
+ };
527
+ }
528
+
529
+ // src/nats/nats-provider.tsx
530
+ var _react = require('react'); var React = _interopRequireWildcard(_react); var React2 = _interopRequireWildcard(_react);
531
+ var _jsxruntime = require('react/jsx-runtime');
532
+ var NatsContext = React.createContext(null);
533
+ function NatsProvider({
534
+ children,
535
+ getWsUrl,
536
+ onBeforeReconnect,
537
+ clientConfig,
538
+ reconnectionBackoff,
539
+ urlRevision
540
+ }) {
541
+ const [client, setClient] = React.useState(null);
542
+ const [status, setStatus] = React.useState("closed");
543
+ const [reconnectionCount, setReconnectionCount] = React.useState(0);
544
+ const getWsUrlRef = React.useRef(getWsUrl);
545
+ React.useEffect(() => {
546
+ getWsUrlRef.current = getWsUrl;
547
+ }, [getWsUrl]);
548
+ const onBeforeReconnectRef = React.useRef(onBeforeReconnect);
549
+ React.useEffect(() => {
550
+ onBeforeReconnectRef.current = onBeforeReconnect;
551
+ }, [onBeforeReconnect]);
552
+ const reconnectionBackoffRef = React.useRef(reconnectionBackoff);
553
+ React.useEffect(() => {
554
+ reconnectionBackoffRef.current = reconnectionBackoff;
555
+ }, [reconnectionBackoff]);
556
+ const clientConfigRef = React.useRef(clientConfig);
557
+ React.useEffect(() => {
558
+ clientConfigRef.current = clientConfig;
559
+ }, [clientConfig]);
560
+ const heldUrlRef = React.useRef(null);
561
+ const hadConnectionBeforeRef = React.useRef(false);
562
+ React.useEffect(() => {
563
+ const wsUrl = getWsUrlRef.current();
564
+ if (!wsUrl) {
565
+ if (heldUrlRef.current) {
566
+ releaseClient(heldUrlRef.current);
567
+ heldUrlRef.current = null;
568
+ setClient(null);
569
+ setStatus("closed");
570
+ }
571
+ return;
572
+ }
573
+ if (heldUrlRef.current && heldUrlRef.current !== wsUrl) {
574
+ releaseClient(heldUrlRef.current);
575
+ heldUrlRef.current = null;
576
+ }
577
+ const conn = acquireClient(wsUrl, clientConfigRef.current);
578
+ heldUrlRef.current = wsUrl;
579
+ setClient(conn.client);
580
+ setStatus(conn.client.isConnected() ? "connected" : "connecting");
581
+ const lifecycle = startConnectionLifecycle({
582
+ conn,
583
+ wsUrl,
584
+ onBeforeReconnect: () => _optionalChain([onBeforeReconnectRef, 'access', _30 => _30.current, 'optionalCall', _31 => _31()]),
585
+ backoff: reconnectionBackoffRef.current,
586
+ getFreshUrl: () => getWsUrlRef.current(),
587
+ onStatusChange: (newStatus) => {
588
+ setStatus(newStatus);
589
+ if (newStatus === "connected") {
590
+ if (hadConnectionBeforeRef.current) {
591
+ setReconnectionCount((c) => c + 1);
592
+ }
593
+ hadConnectionBeforeRef.current = true;
594
+ }
595
+ }
596
+ });
597
+ return () => {
598
+ lifecycle.stop();
599
+ if (heldUrlRef.current) {
600
+ releaseClient(heldUrlRef.current);
601
+ heldUrlRef.current = null;
602
+ }
603
+ setClient(null);
604
+ setStatus("closed");
605
+ };
606
+ }, [urlRevision]);
607
+ const value = React.useMemo(
608
+ () => ({
609
+ client,
610
+ status,
611
+ isReady: status === "connected" && client !== null,
612
+ reconnectionCount
613
+ }),
614
+ [client, status, reconnectionCount]
615
+ );
616
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, NatsContext.Provider, { value, children });
617
+ }
618
+ function useNats() {
619
+ const ctx = React.useContext(NatsContext);
620
+ if (!ctx) throw new Error("useNats must be used inside <NatsProvider>");
621
+ return ctx;
622
+ }
623
+ function useOptionalNats() {
624
+ return React.useContext(NatsContext);
625
+ }
626
+
627
+ // src/nats/use-nats-subscription.ts
628
+
629
+ function useNatsSubscription(subject, onMessage, options) {
630
+ const nats = useOptionalNats();
631
+ const handlerRef = React2.useRef(onMessage);
632
+ React2.useEffect(() => {
633
+ handlerRef.current = onMessage;
634
+ }, [onMessage]);
635
+ const [isSubscribed, setIsSubscribed] = React2.useState(false);
636
+ const enabled = _optionalChain([options, 'optionalAccess', _32 => _32.enabled]) !== false;
637
+ const queue = _optionalChain([options, 'optionalAccess', _33 => _33.queue]);
638
+ const max = _optionalChain([options, 'optionalAccess', _34 => _34.max]);
639
+ const reconnectionCount = _nullishCoalesce(_optionalChain([nats, 'optionalAccess', _35 => _35.reconnectionCount]), () => ( 0));
640
+ const isReady = !!_optionalChain([nats, 'optionalAccess', _36 => _36.isReady]);
641
+ const client = _nullishCoalesce(_optionalChain([nats, 'optionalAccess', _37 => _37.client]), () => ( null));
642
+ React2.useEffect(() => {
643
+ if (!client || !isReady || !subject || !enabled) {
644
+ setIsSubscribed(false);
645
+ return;
646
+ }
647
+ const sub = client.subscribeBytes(
648
+ subject,
649
+ (msg) => handlerRef.current(msg),
650
+ { queue, max }
651
+ );
652
+ setIsSubscribed(true);
653
+ return () => {
654
+ setIsSubscribed(false);
655
+ try {
656
+ sub.unsubscribe();
657
+ } catch (e12) {
658
+ }
659
+ };
660
+ }, [client, isReady, subject, enabled, queue, max, reconnectionCount]);
661
+ return { isSubscribed, isReady };
662
+ }
663
+ function useNatsJsonSubscription(subject, onPayload, options) {
664
+ const handlerRef = React2.useRef(onPayload);
665
+ React2.useEffect(() => {
666
+ handlerRef.current = onPayload;
667
+ }, [onPayload]);
668
+ const decoderRef = React2.useRef(null);
669
+ if (!decoderRef.current && typeof TextDecoder !== "undefined") {
670
+ decoderRef.current = new TextDecoder();
671
+ }
672
+ const wrapped = React2.useCallback(async (msg) => {
673
+ const decoder = decoderRef.current;
674
+ if (!decoder) return;
675
+ try {
676
+ const parsed = JSON.parse(decoder.decode(msg.data));
677
+ await handlerRef.current(parsed, msg);
678
+ } catch (e13) {
679
+ }
680
+ }, []);
681
+ return useNatsSubscription(subject, wrapped, options);
682
+ }
683
+
684
+
685
+
686
+
687
+
688
+
689
+
690
+
691
+
692
+
693
+
694
+
695
+
696
+
697
+ exports.createNatsClient = createNatsClient; exports.NATS_DEFAULTS = NATS_DEFAULTS; exports.getSharedConnection = getSharedConnection; exports.acquireClient = acquireClient; exports.releaseClient = releaseClient; exports.getSharedConnectionFor = getSharedConnectionFor; exports.startConnectionLifecycle = startConnectionLifecycle; exports.NatsProvider = NatsProvider; exports.useNats = useNats; exports.useOptionalNats = useOptionalNats; exports.useNatsSubscription = useNatsSubscription; exports.useNatsJsonSubscription = useNatsJsonSubscription;
698
+ //# sourceMappingURL=chunk-OZ3GH6OQ.cjs.map