@jr200-labs/xstate-nats 0.9.9 → 0.9.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -233,6 +233,7 @@ and request/reply replier.
233
233
  | `xstate.nats.publish` | `SUBJECT.PUBLISH` | `subject`, `payload.bytes` |
234
234
  | `xstate.nats.request` | `SUBJECT.REQUEST` | `subject`, `payload.bytes`, `timeout.ms` |
235
235
  | `xstate.nats.reconnect` | NATS status loop | `reconnect.type` |
236
+ | `xstate.nats.lifecycle` | root machine | `xstate.state`, `xstate.event` |
236
237
  | `xstate.nats.kv.watch` | `KV.SUBSCRIBE` | `bucket`, `key` |
237
238
  | `xstate.nats.kv.entry` | per KV watch entry | `bucket`, `key`, `operation` |
238
239
 
@@ -240,6 +241,29 @@ All error paths record exceptions on the active span, set span status to
240
241
  `ERROR`, and emit a named event (`xstate.nats.error` / `xstate.nats.kv.error`)
241
242
  with a truncated stack.
242
243
 
244
+ ### Lifecycle diagnostics
245
+
246
+ Root machine lifecycle diagnostics are opt-in and separate from raw NATS
247
+ protocol frame logging. Enable them on the connection config:
248
+
249
+ ```ts
250
+ send({
251
+ type: 'CONFIGURE',
252
+ config: {
253
+ opts: { servers: ['wss://example-nats'] },
254
+ diagnostics: { lifecycle: true },
255
+ maxRetries: 3,
256
+ },
257
+ })
258
+ ```
259
+
260
+ When enabled, the root machine emits sanitized `xstate.nats.lifecycle` spans and
261
+ `console.debug('xstate-nats lifecycle', attributes)` breadcrumbs for configure,
262
+ connect, close, manager initialization, and NATS status events. Diagnostics
263
+ include state, event type, server URLs, debug/verbose flags, retry count, auth
264
+ type, and manager readiness flags. They do not include credentials, JWTs, nkeys,
265
+ signatures, passwords, tokens, or raw protocol frames.
266
+
243
267
  ### Enabling tracing
244
268
 
245
269
  `@opentelemetry/api` is a peer dependency — the consumer controls the installed
@@ -2,10 +2,14 @@ import { ConnectionOptions, NatsConnection } from '@nats-io/nats-core';
2
2
  import { ExternalEvents as KvExternalEvents } from './kv';
3
3
  import { ExternalEvents as SubjectExternalEvents } from './subject';
4
4
  import { type AuthConfig } from '../actions/types';
5
+ export interface NatsDiagnosticsConfig {
6
+ lifecycle?: boolean;
7
+ }
5
8
  export interface NatsConnectionConfig {
6
9
  opts: ConnectionOptions;
7
10
  auth?: AuthConfig;
8
11
  maxRetries: number;
12
+ diagnostics?: NatsDiagnosticsConfig;
9
13
  }
10
14
  export interface Context {
11
15
  connection: NatsConnection | null;
@@ -14,6 +18,8 @@ export interface Context {
14
18
  retries: number;
15
19
  subjectManagerReady: boolean;
16
20
  kvManagerReady: boolean;
21
+ configureAfterClose: boolean;
22
+ connectAfterClose: boolean;
17
23
  }
18
24
  export type ExternalEvents = {
19
25
  type: 'CONFIGURE';
@@ -495,10 +501,28 @@ export declare const natsMachine: import("xstate").StateMachine<Context, {
495
501
  }, {
496
502
  type: "doReset";
497
503
  params: import("xstate").NonReducibleUnknown;
504
+ } | {
505
+ type: "configureNats";
506
+ params: import("xstate").NonReducibleUnknown;
507
+ } | {
508
+ type: "configureNatsAfterClose";
509
+ params: import("xstate").NonReducibleUnknown;
510
+ } | {
511
+ type: "reconnectAfterClose";
512
+ params: import("xstate").NonReducibleUnknown;
513
+ } | {
514
+ type: "clearDeferredCloseActions";
515
+ params: import("xstate").NonReducibleUnknown;
498
516
  }, {
499
517
  type: "allManagersReady";
500
518
  params: unknown;
501
- }, never, "error" | "not_configured" | "configured" | "connecting" | "initialise_managers" | "connected" | "closing" | "closed", string, import("xstate").NonReducibleUnknown, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
519
+ } | {
520
+ type: "shouldConnectAfterClose";
521
+ params: unknown;
522
+ } | {
523
+ type: "shouldConfigureAfterClose";
524
+ params: unknown;
525
+ }, never, "error" | "not_configured" | "configured" | "connecting" | "initialise_managers" | "closing" | "connected" | "closed", string, import("xstate").NonReducibleUnknown, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
502
526
  states: {
503
527
  readonly not_configured: {};
504
528
  readonly configured: {};
@@ -1 +1 @@
1
- {"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../src/machines/root.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEtE,OAAO,EAAkB,cAAc,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAA;AACzE,OAAO,EAAuB,cAAc,IAAI,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAExF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAGlD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAA;IACvB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,cAAc,GAAG,IAAI,CAAA;IACjC,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,mBAAmB,EAAE,OAAO,CAAA;IAC5B,cAAc,EAAE,OAAO,CAAA;CACxB;AAYD,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB,qBAAqB,GACrB,gBAAgB,CAAA;AAIpB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAlBZ,WAAW;gBAAc,cAAc;;UACvC,cAAc;;UACd,MAAM;WAAS,KAAK;;UACpB,WAAW;;UACX,OAAO;;UAKP,WAAW;YAAU,oBAAoB;;UACzC,SAAS;;UACT,YAAY;;UACZ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkQjB,CAAA"}
1
+ {"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../src/machines/root.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEtE,OAAO,EAAkB,cAAc,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAA;AACzE,OAAO,EAAuB,cAAc,IAAI,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAExF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAIlD,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAA;IACvB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,qBAAqB,CAAA;CACpC;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,cAAc,GAAG,IAAI,CAAA;IACjC,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,mBAAmB,EAAE,OAAO,CAAA;IAC5B,cAAc,EAAE,OAAO,CAAA;IACvB,mBAAmB,EAAE,OAAO,CAAA;IAC5B,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAYD,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB,qBAAqB,GACrB,gBAAgB,CAAA;AAkDpB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAhEZ,WAAW;gBAAc,cAAc;;UACvC,cAAc;;UACd,MAAM;WAAS,KAAK;;UACpB,WAAW;;UACX,OAAO;;UAKP,WAAW;YAAU,oBAAoB;;UACzC,SAAS;;UACT,YAAY;;UACZ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6bjB,CAAA"}
@@ -2,6 +2,44 @@ import { assign, sendTo, setup } from 'xstate';
2
2
  import { kvManagerLogic } from './kv';
3
3
  import { subjectManagerLogic } from './subject';
4
4
  import { connectToNats, disconnectNats } from '../actions/connection';
5
+ import { withSpan } from '../telemetry';
6
+ function lifecycleDiagnosticsEnabled(context) {
7
+ return Boolean(context.natsConfig?.diagnostics?.lifecycle);
8
+ }
9
+ function serverUrls(config) {
10
+ const servers = config?.opts.servers;
11
+ return Array.isArray(servers) ? servers.join(',') : servers;
12
+ }
13
+ function lifecycleAttributes(context, event, state) {
14
+ return {
15
+ 'xstate.state': state,
16
+ 'xstate.event': event.type,
17
+ 'nats.server.urls': serverUrls(context.natsConfig),
18
+ 'nats.debug': Boolean(context.natsConfig?.opts.debug),
19
+ 'nats.verbose': Boolean(context.natsConfig?.opts.verbose),
20
+ 'nats.max_retries': context.natsConfig?.maxRetries,
21
+ 'nats.auth.type': context.natsConfig?.auth?.type,
22
+ 'nats.has_connection': context.connection !== null,
23
+ 'nats.subject_manager_ready': context.subjectManagerReady,
24
+ 'nats.kv_manager_ready': context.kvManagerReady,
25
+ 'nats.configure_after_close': context.configureAfterClose,
26
+ 'nats.connect_after_close': context.connectAfterClose,
27
+ };
28
+ }
29
+ function recordLifecycle(context, event, state) {
30
+ if (!lifecycleDiagnosticsEnabled(context))
31
+ return;
32
+ const attributes = lifecycleAttributes(context, event, state);
33
+ console.debug('xstate-nats lifecycle', attributes);
34
+ withSpan('xstate.nats.lifecycle', 'xstate.nats.error', attributes, (span) => {
35
+ span.addEvent(`xstate.nats.${state}.${event.type}`, attributes);
36
+ });
37
+ }
38
+ function lifecycleAction(state) {
39
+ return ({ context, event }) => {
40
+ recordLifecycle(context, event, state);
41
+ };
42
+ }
5
43
  export const natsMachine = setup({
6
44
  types: {
7
45
  context: {},
@@ -15,6 +53,43 @@ export const natsMachine = setup({
15
53
  retries: (_) => 0,
16
54
  subjectManagerReady: (_) => false,
17
55
  kvManagerReady: (_) => false,
56
+ configureAfterClose: (_) => false,
57
+ connectAfterClose: (_) => false,
58
+ }),
59
+ configureNats: assign({
60
+ natsConfig: ({ event }) => {
61
+ if (event.type !== 'CONFIGURE') {
62
+ return undefined;
63
+ }
64
+ return event.config;
65
+ },
66
+ connection: (_) => null,
67
+ error: (_) => undefined,
68
+ retries: (_) => 0,
69
+ subjectManagerReady: (_) => false,
70
+ kvManagerReady: (_) => false,
71
+ configureAfterClose: (_) => false,
72
+ connectAfterClose: (_) => false,
73
+ }),
74
+ configureNatsAfterClose: assign({
75
+ natsConfig: ({ event }) => {
76
+ if (event.type !== 'CONFIGURE') {
77
+ return undefined;
78
+ }
79
+ return event.config;
80
+ },
81
+ error: (_) => undefined,
82
+ retries: (_) => 0,
83
+ subjectManagerReady: (_) => false,
84
+ kvManagerReady: (_) => false,
85
+ configureAfterClose: (_) => true,
86
+ }),
87
+ reconnectAfterClose: assign({
88
+ connectAfterClose: (_) => true,
89
+ }),
90
+ clearDeferredCloseActions: assign({
91
+ configureAfterClose: (_) => false,
92
+ connectAfterClose: (_) => false,
18
93
  }),
19
94
  },
20
95
  guards: {
@@ -24,6 +99,12 @@ export const natsMachine = setup({
24
99
  const kvReady = context.kvManagerReady;
25
100
  return hasValidConnection && subjectReady && kvReady;
26
101
  },
102
+ shouldConnectAfterClose: ({ context }) => {
103
+ return context.connectAfterClose && context.natsConfig !== undefined;
104
+ },
105
+ shouldConfigureAfterClose: ({ context }) => {
106
+ return context.configureAfterClose && context.natsConfig !== undefined;
107
+ },
27
108
  },
28
109
  actors: {
29
110
  connectToNats: connectToNats,
@@ -41,6 +122,8 @@ export const natsMachine = setup({
41
122
  retries: 0,
42
123
  subjectManagerReady: false,
43
124
  kvManagerReady: false,
125
+ configureAfterClose: false,
126
+ connectAfterClose: false,
44
127
  },
45
128
  invoke: [
46
129
  { src: 'subject', id: 'subject', systemId: 'subject' },
@@ -50,6 +133,7 @@ export const natsMachine = setup({
50
133
  'NATS_CONNECTION.*': {
51
134
  actions: [
52
135
  ({ context, event }) => {
136
+ recordLifecycle(context, event, 'status');
53
137
  if (context.natsConfig?.opts.debug) {
54
138
  console.log('root received NATS status event', event);
55
139
  }
@@ -62,11 +146,7 @@ export const natsMachine = setup({
62
146
  on: {
63
147
  CONFIGURE: {
64
148
  target: 'configured',
65
- actions: [
66
- assign({
67
- natsConfig: ({ event }) => event.config,
68
- }),
69
- ],
149
+ actions: ['configureNats'],
70
150
  '*': {
71
151
  actions: [
72
152
  ({ event }) => {
@@ -78,9 +158,14 @@ export const natsMachine = setup({
78
158
  },
79
159
  },
80
160
  configured: {
161
+ entry: ['clearDeferredCloseActions'],
81
162
  on: {
163
+ CONFIGURE: {
164
+ actions: ['configureNats', lifecycleAction('configured')],
165
+ },
82
166
  CONNECT: {
83
167
  target: 'connecting',
168
+ actions: lifecycleAction('configured'),
84
169
  },
85
170
  RESET: {
86
171
  target: 'not_configured',
@@ -96,6 +181,17 @@ export const natsMachine = setup({
96
181
  },
97
182
  },
98
183
  connecting: {
184
+ entry: ['clearDeferredCloseActions', lifecycleAction('connecting')],
185
+ on: {
186
+ CONFIGURE: {
187
+ target: 'connecting',
188
+ reenter: true,
189
+ actions: ['configureNats', lifecycleAction('connecting')],
190
+ },
191
+ CONNECT: {
192
+ actions: lifecycleAction('connecting'),
193
+ },
194
+ },
99
195
  invoke: [
100
196
  {
101
197
  src: 'connectToNats',
@@ -106,6 +202,7 @@ export const natsMachine = setup({
106
202
  onDone: {
107
203
  target: 'initialise_managers',
108
204
  actions: [
205
+ lifecycleAction('connecting'),
109
206
  assign({
110
207
  connection: ({ event }) => event.output,
111
208
  retries: (_) => 0,
@@ -114,16 +211,20 @@ export const natsMachine = setup({
114
211
  },
115
212
  onError: {
116
213
  target: 'error',
117
- actions: assign({
118
- error: ({ event }) => event.error,
119
- retries: ({ context }) => context.retries + 1,
120
- }),
214
+ actions: [
215
+ lifecycleAction('connecting'),
216
+ assign({
217
+ error: ({ event }) => event.error,
218
+ retries: ({ context }) => context.retries + 1,
219
+ }),
220
+ ],
121
221
  },
122
222
  },
123
223
  ],
124
224
  },
125
225
  initialise_managers: {
126
226
  entry: [
227
+ lifecycleAction('initialise_managers'),
127
228
  sendTo('subject', ({ context }) => ({
128
229
  type: 'SUBJECT.CONNECT',
129
230
  connection: context.connection,
@@ -131,11 +232,36 @@ export const natsMachine = setup({
131
232
  sendTo('kv', ({ context }) => ({ type: 'KV.CONNECT', connection: context.connection })),
132
233
  ],
133
234
  on: {
235
+ CONFIGURE: {
236
+ target: 'closing',
237
+ actions: [
238
+ 'configureNatsAfterClose',
239
+ 'reconnectAfterClose',
240
+ lifecycleAction('initialise_managers'),
241
+ ],
242
+ },
243
+ CONNECT: {
244
+ actions: lifecycleAction('initialise_managers'),
245
+ },
246
+ DISCONNECT: {
247
+ target: 'closing',
248
+ actions: ['clearDeferredCloseActions', lifecycleAction('initialise_managers')],
249
+ },
250
+ CLOSE: {
251
+ target: 'closing',
252
+ actions: ['clearDeferredCloseActions', lifecycleAction('initialise_managers')],
253
+ },
134
254
  'SUBJECT.CONNECTED': {
135
- actions: [assign({ subjectManagerReady: (_) => true })],
255
+ actions: [
256
+ assign({ subjectManagerReady: (_) => true }),
257
+ lifecycleAction('initialise_managers'),
258
+ ],
136
259
  },
137
260
  'KV.CONNECTED': {
138
- actions: [assign({ kvManagerReady: (_) => true })],
261
+ actions: [
262
+ assign({ kvManagerReady: (_) => true }),
263
+ lifecycleAction('initialise_managers'),
264
+ ],
139
265
  },
140
266
  },
141
267
  always: [
@@ -147,6 +273,8 @@ export const natsMachine = setup({
147
273
  },
148
274
  connected: {
149
275
  entry: [
276
+ 'clearDeferredCloseActions',
277
+ lifecycleAction('connected'),
150
278
  (event) => {
151
279
  if (event.context.natsConfig?.opts.debug) {
152
280
  console.log('CONNECTED', event.context.connection?.getServer());
@@ -154,11 +282,17 @@ export const natsMachine = setup({
154
282
  },
155
283
  ],
156
284
  on: {
285
+ CONFIGURE: {
286
+ target: 'closing',
287
+ actions: ['configureNatsAfterClose', 'reconnectAfterClose', lifecycleAction('connected')],
288
+ },
157
289
  DISCONNECT: {
158
290
  target: 'closing',
291
+ actions: ['clearDeferredCloseActions', lifecycleAction('connected')],
159
292
  },
160
293
  CLOSE: {
161
294
  target: 'closing',
295
+ actions: ['clearDeferredCloseActions', lifecycleAction('connected')],
162
296
  },
163
297
  'SUBJECT.*': {
164
298
  actions: [
@@ -200,31 +334,71 @@ export const natsMachine = setup({
200
334
  console.log('CLOSING', event.context.connection?.getServer());
201
335
  }
202
336
  },
337
+ lifecycleAction('closing'),
203
338
  sendTo('subject', { type: 'SUBJECT.DISCONNECTED' }),
204
339
  sendTo('kv', { type: 'KV.DISCONNECTED' }),
205
340
  ],
206
341
  invoke: {
207
342
  src: 'disconnectNats',
208
343
  input: ({ context }) => ({ connection: context.connection }),
209
- onDone: {
210
- target: 'closed',
211
- },
344
+ onDone: [
345
+ {
346
+ guard: 'shouldConnectAfterClose',
347
+ target: 'connecting',
348
+ actions: lifecycleAction('closing'),
349
+ },
350
+ {
351
+ guard: 'shouldConfigureAfterClose',
352
+ target: 'configured',
353
+ actions: lifecycleAction('closing'),
354
+ },
355
+ {
356
+ target: 'closed',
357
+ actions: lifecycleAction('closing'),
358
+ },
359
+ ],
212
360
  onError: {
213
361
  target: 'error',
214
- actions: assign({
215
- error: ({ event }) => event.error,
216
- }),
362
+ actions: [
363
+ lifecycleAction('closing'),
364
+ assign({
365
+ error: ({ event }) => event.error,
366
+ }),
367
+ ],
368
+ },
369
+ },
370
+ on: {
371
+ CONFIGURE: {
372
+ actions: ['configureNatsAfterClose', lifecycleAction('closing')],
373
+ },
374
+ CONNECT: {
375
+ actions: ['reconnectAfterClose', lifecycleAction('closing')],
217
376
  },
218
377
  },
219
378
  },
220
379
  closed: {
380
+ entry: [
381
+ lifecycleAction('closed'),
382
+ assign({
383
+ connection: (_) => null,
384
+ subjectManagerReady: (_) => false,
385
+ kvManagerReady: (_) => false,
386
+ configureAfterClose: (_) => false,
387
+ connectAfterClose: (_) => false,
388
+ }),
389
+ ],
221
390
  on: {
391
+ CONFIGURE: {
392
+ target: 'configured',
393
+ actions: ['configureNats', lifecycleAction('closed')],
394
+ },
222
395
  RESET: {
223
396
  target: 'not_configured',
224
397
  actions: ['doReset'],
225
398
  },
226
399
  CONNECT: {
227
400
  target: 'connecting',
401
+ actions: lifecycleAction('closed'),
228
402
  },
229
403
  },
230
404
  '*': {
@@ -236,7 +410,12 @@ export const natsMachine = setup({
236
410
  },
237
411
  },
238
412
  error: {
413
+ entry: ['clearDeferredCloseActions', lifecycleAction('error')],
239
414
  on: {
415
+ CONFIGURE: {
416
+ target: 'configured',
417
+ actions: ['configureNats', lifecycleAction('error')],
418
+ },
240
419
  RESET: {
241
420
  target: 'not_configured',
242
421
  actions: ['doReset'],
@@ -1 +1 @@
1
- {"version":3,"file":"root.js","sourceRoot":"","sources":["../../src/machines/root.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"root.js","sourceRoot":"","sources":["../../src/machines/root.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jr200-labs/xstate-nats",
3
- "version": "0.9.9",
3
+ "version": "0.9.11",
4
4
  "description": "XState machine for NATS",
5
5
  "license": "MIT",
6
6
  "author": "Jayshan Raghunandan",
@@ -53,6 +53,40 @@ const mockKvMachine = createMachine({
53
53
  },
54
54
  })
55
55
 
56
+ const slowSubjectMachine = createMachine({
57
+ initial: 'idle',
58
+ states: {
59
+ idle: {
60
+ on: {
61
+ 'SUBJECT.CONNECT': { target: 'connected' },
62
+ 'SUBJECT.DISCONNECTED': { target: 'idle' },
63
+ },
64
+ },
65
+ connected: {
66
+ on: {
67
+ 'SUBJECT.DISCONNECTED': { target: 'idle' },
68
+ },
69
+ },
70
+ },
71
+ })
72
+
73
+ const slowKvMachine = createMachine({
74
+ initial: 'idle',
75
+ states: {
76
+ idle: {
77
+ on: {
78
+ 'KV.CONNECT': { target: 'connected' },
79
+ 'KV.DISCONNECTED': { target: 'idle' },
80
+ },
81
+ },
82
+ connected: {
83
+ on: {
84
+ 'KV.DISCONNECTED': { target: 'idle' },
85
+ },
86
+ },
87
+ },
88
+ })
89
+
56
90
  const mockConnection = {
57
91
  drain: vi.fn().mockResolvedValue(undefined),
58
92
  close: vi.fn().mockResolvedValue(undefined),
@@ -64,6 +98,17 @@ const mockConnection = {
64
98
  }),
65
99
  } as any
66
100
 
101
+ function createDeferred<T>() {
102
+ let resolve!: (value: T) => void
103
+ let reject!: (reason?: unknown) => void
104
+ const promise = new Promise<T>((res, rej) => {
105
+ resolve = res
106
+ reject = rej
107
+ })
108
+
109
+ return { promise, resolve, reject }
110
+ }
111
+
67
112
  function createTestMachine() {
68
113
  return natsMachine.provide({
69
114
  actors: {
@@ -230,6 +275,32 @@ describe('natsMachine', () => {
230
275
  actor.stop()
231
276
  })
232
277
 
278
+ it('should reconfigure from closed state', async () => {
279
+ const actor = createActor(createTestMachine())
280
+ actor.start()
281
+ configureAndConnect(actor)
282
+
283
+ await vi.waitFor(() => {
284
+ expect(actor.getSnapshot().value).toBe('connected')
285
+ })
286
+ actor.send({ type: 'DISCONNECT' })
287
+ await vi.waitFor(() => {
288
+ expect(actor.getSnapshot().value).toBe('closed')
289
+ })
290
+
291
+ actor.send({
292
+ type: 'CONFIGURE',
293
+ config: { opts: { debug: true, servers: ['ws://localhost:4223'] }, maxRetries: 5 },
294
+ })
295
+
296
+ expect(actor.getSnapshot().value).toBe('configured')
297
+ expect(actor.getSnapshot().context.natsConfig).toEqual({
298
+ opts: { debug: true, servers: ['ws://localhost:4223'] },
299
+ maxRetries: 5,
300
+ })
301
+ actor.stop()
302
+ })
303
+
233
304
  it('should reset from closed state', async () => {
234
305
  const actor = createActor(createTestMachine())
235
306
  actor.start()
@@ -293,6 +364,257 @@ describe('natsMachine', () => {
293
364
  actor.stop()
294
365
  })
295
366
 
367
+ it('should reconfigure from error state', async () => {
368
+ const failMachine = natsMachine.provide({
369
+ actors: {
370
+ connectToNats: fromPromise(async () => {
371
+ throw new Error('fail')
372
+ }),
373
+ disconnectNats: fromPromise(async () => {}),
374
+ subject: mockSubjectMachine,
375
+ kv: mockKvMachine,
376
+ },
377
+ })
378
+
379
+ const actor = createActor(failMachine)
380
+ actor.start()
381
+ configureAndConnect(actor)
382
+
383
+ await vi.waitFor(() => {
384
+ expect(actor.getSnapshot().value).toBe('error')
385
+ })
386
+
387
+ actor.send({
388
+ type: 'CONFIGURE',
389
+ config: { opts: { debug: true, servers: ['ws://localhost:4224'] }, maxRetries: 1 },
390
+ })
391
+
392
+ expect(actor.getSnapshot().value).toBe('configured')
393
+ expect(actor.getSnapshot().context.error).toBeUndefined()
394
+ expect(actor.getSnapshot().context.natsConfig).toEqual({
395
+ opts: { debug: true, servers: ['ws://localhost:4224'] },
396
+ maxRetries: 1,
397
+ })
398
+ actor.stop()
399
+ })
400
+
401
+ it('should reconnect when configured while connected', async () => {
402
+ const connectInputs: any[] = []
403
+ const machine = natsMachine.provide({
404
+ actors: {
405
+ connectToNats: fromPromise(async ({ input }) => {
406
+ connectInputs.push(input)
407
+ return mockConnection
408
+ }),
409
+ disconnectNats: fromPromise(async () => {}),
410
+ subject: mockSubjectMachine,
411
+ kv: mockKvMachine,
412
+ },
413
+ })
414
+ const actor = createActor(machine)
415
+ actor.start()
416
+ configureAndConnect(actor)
417
+
418
+ await vi.waitFor(() => {
419
+ expect(actor.getSnapshot().value).toBe('connected')
420
+ })
421
+
422
+ actor.send({
423
+ type: 'CONFIGURE',
424
+ config: { opts: { debug: true, servers: ['ws://localhost:4225'] }, maxRetries: 2 },
425
+ })
426
+
427
+ await vi.waitFor(() => {
428
+ expect(actor.getSnapshot().value).toBe('connected')
429
+ })
430
+ expect(connectInputs).toHaveLength(2)
431
+ expect(connectInputs[1].opts).toEqual({ debug: true, servers: ['ws://localhost:4225'] })
432
+ expect(actor.getSnapshot().context.natsConfig).toEqual({
433
+ opts: { debug: true, servers: ['ws://localhost:4225'] },
434
+ maxRetries: 2,
435
+ })
436
+ actor.stop()
437
+ })
438
+
439
+ it('should apply CONFIGURE and CONNECT sent while closing', async () => {
440
+ const disconnect = createDeferred<void>()
441
+ const connectInputs: any[] = []
442
+ const machine = natsMachine.provide({
443
+ actors: {
444
+ connectToNats: fromPromise(async ({ input }) => {
445
+ connectInputs.push(input)
446
+ return mockConnection
447
+ }),
448
+ disconnectNats: fromPromise(async () => disconnect.promise),
449
+ subject: mockSubjectMachine,
450
+ kv: mockKvMachine,
451
+ },
452
+ })
453
+ const actor = createActor(machine)
454
+ actor.start()
455
+ configureAndConnect(actor)
456
+
457
+ await vi.waitFor(() => {
458
+ expect(actor.getSnapshot().value).toBe('connected')
459
+ })
460
+ actor.send({ type: 'DISCONNECT' })
461
+ expect(actor.getSnapshot().value).toBe('closing')
462
+
463
+ actor.send({
464
+ type: 'CONFIGURE',
465
+ config: { opts: { debug: true, servers: ['ws://localhost:4226'] }, maxRetries: 2 },
466
+ })
467
+ actor.send({ type: 'CONNECT' })
468
+ disconnect.resolve()
469
+
470
+ await vi.waitFor(() => {
471
+ expect(actor.getSnapshot().value).toBe('connected')
472
+ })
473
+ expect(connectInputs).toHaveLength(2)
474
+ expect(connectInputs[1].opts).toEqual({ debug: true, servers: ['ws://localhost:4226'] })
475
+ expect(actor.getSnapshot().context.natsConfig).toEqual({
476
+ opts: { debug: true, servers: ['ws://localhost:4226'] },
477
+ maxRetries: 2,
478
+ })
479
+ actor.stop()
480
+ })
481
+
482
+ it('should emit sanitized lifecycle diagnostics when enabled', async () => {
483
+ const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {})
484
+ const actor = createActor(createTestMachine())
485
+ actor.start()
486
+
487
+ actor.send({
488
+ type: 'CONFIGURE',
489
+ config: {
490
+ opts: { debug: false, servers: ['ws://localhost:4222'], verbose: false },
491
+ auth: { type: 'token', token: 'secret-token' },
492
+ diagnostics: { lifecycle: true },
493
+ maxRetries: 3,
494
+ },
495
+ })
496
+ actor.send({ type: 'CONNECT' })
497
+
498
+ await vi.waitFor(() => {
499
+ expect(actor.getSnapshot().value).toBe('connected')
500
+ })
501
+
502
+ expect(debugSpy).toHaveBeenCalled()
503
+ const lifecycleCalls = debugSpy.mock.calls.filter(
504
+ ([message]) => message === 'xstate-nats lifecycle',
505
+ )
506
+ expect(lifecycleCalls.length).toBeGreaterThan(0)
507
+ expect(lifecycleCalls[0][1]).toMatchObject({
508
+ 'nats.auth.type': 'token',
509
+ 'nats.debug': false,
510
+ 'nats.verbose': false,
511
+ 'nats.max_retries': 3,
512
+ 'nats.server.urls': 'ws://localhost:4222',
513
+ })
514
+ expect(JSON.stringify(lifecycleCalls)).not.toContain('secret-token')
515
+ actor.stop()
516
+ debugSpy.mockRestore()
517
+ })
518
+
519
+ it('should restart an in-flight connection when reconfigured while connecting', async () => {
520
+ const firstConnection = createDeferred<any>()
521
+ const secondConnection = createDeferred<any>()
522
+ const connectInputs: any[] = []
523
+ const machine = natsMachine.provide({
524
+ actors: {
525
+ connectToNats: fromPromise(async ({ input }) => {
526
+ connectInputs.push(input)
527
+ return connectInputs.length === 1 ? firstConnection.promise : secondConnection.promise
528
+ }),
529
+ disconnectNats: fromPromise(async () => {}),
530
+ subject: mockSubjectMachine,
531
+ kv: mockKvMachine,
532
+ },
533
+ })
534
+ const actor = createActor(machine)
535
+ actor.start()
536
+
537
+ actor.send({
538
+ type: 'CONFIGURE',
539
+ config: { opts: { debug: false, servers: ['ws://localhost:4222'] }, maxRetries: 3 },
540
+ })
541
+ actor.send({ type: 'CONNECT' })
542
+ await vi.waitFor(() => {
543
+ expect(actor.getSnapshot().value).toBe('connecting')
544
+ })
545
+
546
+ actor.send({
547
+ type: 'CONFIGURE',
548
+ config: { opts: { debug: true, servers: ['ws://localhost:4227'] }, maxRetries: 2 },
549
+ })
550
+ actor.send({ type: 'CONNECT' })
551
+ await vi.waitFor(() => {
552
+ expect(connectInputs).toHaveLength(2)
553
+ })
554
+
555
+ firstConnection.resolve(mockConnection)
556
+ await new Promise((resolve) => setTimeout(resolve, 0))
557
+ expect(actor.getSnapshot().value).toBe('connecting')
558
+
559
+ secondConnection.resolve(mockConnection)
560
+ await vi.waitFor(() => {
561
+ expect(actor.getSnapshot().value).toBe('connected')
562
+ })
563
+ expect(connectInputs[1].opts).toEqual({ debug: true, servers: ['ws://localhost:4227'] })
564
+ expect(actor.getSnapshot().context.natsConfig).toEqual({
565
+ opts: { debug: true, servers: ['ws://localhost:4227'] },
566
+ maxRetries: 2,
567
+ })
568
+ actor.stop()
569
+ })
570
+
571
+ it('should reconnect with the latest config when reconfigured while managers initialise', async () => {
572
+ const connectInputs: any[] = []
573
+ const disconnects: any[] = []
574
+ const machine = natsMachine.provide({
575
+ actors: {
576
+ connectToNats: fromPromise(async ({ input }) => {
577
+ connectInputs.push(input)
578
+ return mockConnection
579
+ }),
580
+ disconnectNats: fromPromise(async ({ input }: { input: any }) => {
581
+ disconnects.push(input.connection)
582
+ }),
583
+ subject: slowSubjectMachine,
584
+ kv: slowKvMachine,
585
+ },
586
+ })
587
+ const actor = createActor(machine)
588
+ actor.start()
589
+
590
+ actor.send({
591
+ type: 'CONFIGURE',
592
+ config: { opts: { debug: false, servers: ['ws://localhost:4222'] }, maxRetries: 3 },
593
+ })
594
+ actor.send({ type: 'CONNECT' })
595
+ await vi.waitFor(() => {
596
+ expect(actor.getSnapshot().value).toBe('initialise_managers')
597
+ })
598
+
599
+ actor.send({
600
+ type: 'CONFIGURE',
601
+ config: { opts: { debug: true, servers: ['ws://localhost:4228'] }, maxRetries: 2 },
602
+ })
603
+ actor.send({ type: 'CONNECT' })
604
+
605
+ await vi.waitFor(() => {
606
+ expect(connectInputs).toHaveLength(2)
607
+ })
608
+ expect(disconnects).toEqual([mockConnection])
609
+ expect(actor.getSnapshot().value).toBe('initialise_managers')
610
+ expect(connectInputs[1].opts).toEqual({ debug: true, servers: ['ws://localhost:4228'] })
611
+ expect(actor.getSnapshot().context.natsConfig).toEqual({
612
+ opts: { debug: true, servers: ['ws://localhost:4228'] },
613
+ maxRetries: 2,
614
+ })
615
+ actor.stop()
616
+ })
617
+
296
618
  it('should forward SUBJECT.* events when connected', async () => {
297
619
  const actor = createActor(createTestMachine())
298
620
  actor.start()
@@ -5,11 +5,17 @@ import { subjectManagerLogic, ExternalEvents as SubjectExternalEvents } from './
5
5
  import { connectToNats, disconnectNats } from '../actions/connection'
6
6
  import { type AuthConfig } from '../actions/types'
7
7
  import { InternalStatusEvents as NatsStatusEvents } from '../actions/connection'
8
+ import { withSpan } from '../telemetry'
9
+
10
+ export interface NatsDiagnosticsConfig {
11
+ lifecycle?: boolean
12
+ }
8
13
 
9
14
  export interface NatsConnectionConfig {
10
15
  opts: ConnectionOptions
11
16
  auth?: AuthConfig
12
17
  maxRetries: number
18
+ diagnostics?: NatsDiagnosticsConfig
13
19
  }
14
20
 
15
21
  export interface Context {
@@ -19,6 +25,8 @@ export interface Context {
19
25
  retries: number
20
26
  subjectManagerReady: boolean
21
27
  kvManagerReady: boolean
28
+ configureAfterClose: boolean
29
+ connectAfterClose: boolean
22
30
  }
23
31
 
24
32
  // internal events and events from nats connection
@@ -41,6 +49,52 @@ export type ExternalEvents =
41
49
 
42
50
  type Events = InternalEvents | ExternalEvents
43
51
 
52
+ function lifecycleDiagnosticsEnabled(context: Context): boolean {
53
+ return Boolean(context.natsConfig?.diagnostics?.lifecycle)
54
+ }
55
+
56
+ function serverUrls(config: NatsConnectionConfig | undefined): string | undefined {
57
+ const servers = config?.opts.servers
58
+ return Array.isArray(servers) ? servers.join(',') : servers
59
+ }
60
+
61
+ function lifecycleAttributes(
62
+ context: Context,
63
+ event: { type: string },
64
+ state: string,
65
+ ): Record<string, string | number | boolean | undefined> {
66
+ return {
67
+ 'xstate.state': state,
68
+ 'xstate.event': event.type,
69
+ 'nats.server.urls': serverUrls(context.natsConfig),
70
+ 'nats.debug': Boolean(context.natsConfig?.opts.debug),
71
+ 'nats.verbose': Boolean(context.natsConfig?.opts.verbose),
72
+ 'nats.max_retries': context.natsConfig?.maxRetries,
73
+ 'nats.auth.type': context.natsConfig?.auth?.type,
74
+ 'nats.has_connection': context.connection !== null,
75
+ 'nats.subject_manager_ready': context.subjectManagerReady,
76
+ 'nats.kv_manager_ready': context.kvManagerReady,
77
+ 'nats.configure_after_close': context.configureAfterClose,
78
+ 'nats.connect_after_close': context.connectAfterClose,
79
+ }
80
+ }
81
+
82
+ function recordLifecycle(context: Context, event: { type: string }, state: string): void {
83
+ if (!lifecycleDiagnosticsEnabled(context)) return
84
+
85
+ const attributes = lifecycleAttributes(context, event, state)
86
+ console.debug('xstate-nats lifecycle', attributes)
87
+ withSpan('xstate.nats.lifecycle', 'xstate.nats.error', attributes, (span) => {
88
+ span.addEvent(`xstate.nats.${state}.${event.type}`, attributes)
89
+ })
90
+ }
91
+
92
+ function lifecycleAction(state: string) {
93
+ return ({ context, event }: { context: Context; event: { type: string } }) => {
94
+ recordLifecycle(context, event, state)
95
+ }
96
+ }
97
+
44
98
  export const natsMachine = setup({
45
99
  types: {
46
100
  context: {} as Context,
@@ -54,6 +108,43 @@ export const natsMachine = setup({
54
108
  retries: (_) => 0,
55
109
  subjectManagerReady: (_) => false,
56
110
  kvManagerReady: (_) => false,
111
+ configureAfterClose: (_) => false,
112
+ connectAfterClose: (_) => false,
113
+ }),
114
+ configureNats: assign({
115
+ natsConfig: ({ event }) => {
116
+ if (event.type !== 'CONFIGURE') {
117
+ return undefined
118
+ }
119
+ return event.config
120
+ },
121
+ connection: (_) => null,
122
+ error: (_) => undefined,
123
+ retries: (_) => 0,
124
+ subjectManagerReady: (_) => false,
125
+ kvManagerReady: (_) => false,
126
+ configureAfterClose: (_) => false,
127
+ connectAfterClose: (_) => false,
128
+ }),
129
+ configureNatsAfterClose: assign({
130
+ natsConfig: ({ event }) => {
131
+ if (event.type !== 'CONFIGURE') {
132
+ return undefined
133
+ }
134
+ return event.config
135
+ },
136
+ error: (_) => undefined,
137
+ retries: (_) => 0,
138
+ subjectManagerReady: (_) => false,
139
+ kvManagerReady: (_) => false,
140
+ configureAfterClose: (_) => true,
141
+ }),
142
+ reconnectAfterClose: assign({
143
+ connectAfterClose: (_) => true,
144
+ }),
145
+ clearDeferredCloseActions: assign({
146
+ configureAfterClose: (_) => false,
147
+ connectAfterClose: (_) => false,
57
148
  }),
58
149
  },
59
150
  guards: {
@@ -63,6 +154,12 @@ export const natsMachine = setup({
63
154
  const kvReady = context.kvManagerReady
64
155
  return hasValidConnection && subjectReady && kvReady
65
156
  },
157
+ shouldConnectAfterClose: ({ context }) => {
158
+ return context.connectAfterClose && context.natsConfig !== undefined
159
+ },
160
+ shouldConfigureAfterClose: ({ context }) => {
161
+ return context.configureAfterClose && context.natsConfig !== undefined
162
+ },
66
163
  },
67
164
  actors: {
68
165
  connectToNats: connectToNats,
@@ -80,6 +177,8 @@ export const natsMachine = setup({
80
177
  retries: 0,
81
178
  subjectManagerReady: false,
82
179
  kvManagerReady: false,
180
+ configureAfterClose: false,
181
+ connectAfterClose: false,
83
182
  },
84
183
  invoke: [
85
184
  { src: 'subject', id: 'subject', systemId: 'subject' },
@@ -89,6 +188,7 @@ export const natsMachine = setup({
89
188
  'NATS_CONNECTION.*': {
90
189
  actions: [
91
190
  ({ context, event }: { context: Context; event: any }) => {
191
+ recordLifecycle(context, event, 'status')
92
192
  if (context.natsConfig?.opts.debug) {
93
193
  console.log('root received NATS status event', event)
94
194
  }
@@ -101,11 +201,7 @@ export const natsMachine = setup({
101
201
  on: {
102
202
  CONFIGURE: {
103
203
  target: 'configured',
104
- actions: [
105
- assign({
106
- natsConfig: ({ event }) => event.config,
107
- }),
108
- ],
204
+ actions: ['configureNats'],
109
205
  '*': {
110
206
  actions: [
111
207
  ({ event }: { event: any }) => {
@@ -117,9 +213,14 @@ export const natsMachine = setup({
117
213
  },
118
214
  },
119
215
  configured: {
216
+ entry: ['clearDeferredCloseActions'],
120
217
  on: {
218
+ CONFIGURE: {
219
+ actions: ['configureNats', lifecycleAction('configured')],
220
+ },
121
221
  CONNECT: {
122
222
  target: 'connecting',
223
+ actions: lifecycleAction('configured'),
123
224
  },
124
225
  RESET: {
125
226
  target: 'not_configured',
@@ -135,6 +236,17 @@ export const natsMachine = setup({
135
236
  },
136
237
  },
137
238
  connecting: {
239
+ entry: ['clearDeferredCloseActions', lifecycleAction('connecting')],
240
+ on: {
241
+ CONFIGURE: {
242
+ target: 'connecting',
243
+ reenter: true,
244
+ actions: ['configureNats', lifecycleAction('connecting')],
245
+ },
246
+ CONNECT: {
247
+ actions: lifecycleAction('connecting'),
248
+ },
249
+ },
138
250
  invoke: [
139
251
  {
140
252
  src: 'connectToNats',
@@ -145,6 +257,7 @@ export const natsMachine = setup({
145
257
  onDone: {
146
258
  target: 'initialise_managers',
147
259
  actions: [
260
+ lifecycleAction('connecting'),
148
261
  assign({
149
262
  connection: ({ event }) => event.output,
150
263
  retries: (_) => 0,
@@ -153,16 +266,20 @@ export const natsMachine = setup({
153
266
  },
154
267
  onError: {
155
268
  target: 'error',
156
- actions: assign({
157
- error: ({ event }) => event.error as Error,
158
- retries: ({ context }) => context.retries + 1,
159
- }),
269
+ actions: [
270
+ lifecycleAction('connecting'),
271
+ assign({
272
+ error: ({ event }) => event.error as Error,
273
+ retries: ({ context }) => context.retries + 1,
274
+ }),
275
+ ],
160
276
  },
161
277
  },
162
278
  ],
163
279
  },
164
280
  initialise_managers: {
165
281
  entry: [
282
+ lifecycleAction('initialise_managers'),
166
283
  sendTo('subject', ({ context }) => ({
167
284
  type: 'SUBJECT.CONNECT',
168
285
  connection: context.connection!,
@@ -170,11 +287,36 @@ export const natsMachine = setup({
170
287
  sendTo('kv', ({ context }) => ({ type: 'KV.CONNECT', connection: context.connection! })),
171
288
  ],
172
289
  on: {
290
+ CONFIGURE: {
291
+ target: 'closing',
292
+ actions: [
293
+ 'configureNatsAfterClose',
294
+ 'reconnectAfterClose',
295
+ lifecycleAction('initialise_managers'),
296
+ ],
297
+ },
298
+ CONNECT: {
299
+ actions: lifecycleAction('initialise_managers'),
300
+ },
301
+ DISCONNECT: {
302
+ target: 'closing',
303
+ actions: ['clearDeferredCloseActions', lifecycleAction('initialise_managers')],
304
+ },
305
+ CLOSE: {
306
+ target: 'closing',
307
+ actions: ['clearDeferredCloseActions', lifecycleAction('initialise_managers')],
308
+ },
173
309
  'SUBJECT.CONNECTED': {
174
- actions: [assign({ subjectManagerReady: (_) => true })],
310
+ actions: [
311
+ assign({ subjectManagerReady: (_) => true }),
312
+ lifecycleAction('initialise_managers'),
313
+ ],
175
314
  },
176
315
  'KV.CONNECTED': {
177
- actions: [assign({ kvManagerReady: (_) => true })],
316
+ actions: [
317
+ assign({ kvManagerReady: (_) => true }),
318
+ lifecycleAction('initialise_managers'),
319
+ ],
178
320
  },
179
321
  },
180
322
  always: [
@@ -186,6 +328,8 @@ export const natsMachine = setup({
186
328
  },
187
329
  connected: {
188
330
  entry: [
331
+ 'clearDeferredCloseActions',
332
+ lifecycleAction('connected'),
189
333
  (event) => {
190
334
  if (event.context.natsConfig?.opts.debug) {
191
335
  console.log('CONNECTED', event.context.connection?.getServer())
@@ -193,11 +337,17 @@ export const natsMachine = setup({
193
337
  },
194
338
  ],
195
339
  on: {
340
+ CONFIGURE: {
341
+ target: 'closing',
342
+ actions: ['configureNatsAfterClose', 'reconnectAfterClose', lifecycleAction('connected')],
343
+ },
196
344
  DISCONNECT: {
197
345
  target: 'closing',
346
+ actions: ['clearDeferredCloseActions', lifecycleAction('connected')],
198
347
  },
199
348
  CLOSE: {
200
349
  target: 'closing',
350
+ actions: ['clearDeferredCloseActions', lifecycleAction('connected')],
201
351
  },
202
352
  'SUBJECT.*': {
203
353
  actions: [
@@ -242,31 +392,71 @@ export const natsMachine = setup({
242
392
  console.log('CLOSING', event.context.connection?.getServer())
243
393
  }
244
394
  },
395
+ lifecycleAction('closing'),
245
396
  sendTo('subject', { type: 'SUBJECT.DISCONNECTED' }),
246
397
  sendTo('kv', { type: 'KV.DISCONNECTED' }),
247
398
  ],
248
399
  invoke: {
249
400
  src: 'disconnectNats',
250
401
  input: ({ context }) => ({ connection: context.connection }),
251
- onDone: {
252
- target: 'closed',
253
- },
402
+ onDone: [
403
+ {
404
+ guard: 'shouldConnectAfterClose',
405
+ target: 'connecting',
406
+ actions: lifecycleAction('closing'),
407
+ },
408
+ {
409
+ guard: 'shouldConfigureAfterClose',
410
+ target: 'configured',
411
+ actions: lifecycleAction('closing'),
412
+ },
413
+ {
414
+ target: 'closed',
415
+ actions: lifecycleAction('closing'),
416
+ },
417
+ ],
254
418
  onError: {
255
419
  target: 'error',
256
- actions: assign({
257
- error: ({ event }) => event.error as Error,
258
- }),
420
+ actions: [
421
+ lifecycleAction('closing'),
422
+ assign({
423
+ error: ({ event }) => event.error as Error,
424
+ }),
425
+ ],
426
+ },
427
+ },
428
+ on: {
429
+ CONFIGURE: {
430
+ actions: ['configureNatsAfterClose', lifecycleAction('closing')],
431
+ },
432
+ CONNECT: {
433
+ actions: ['reconnectAfterClose', lifecycleAction('closing')],
259
434
  },
260
435
  },
261
436
  },
262
437
  closed: {
438
+ entry: [
439
+ lifecycleAction('closed'),
440
+ assign({
441
+ connection: (_) => null,
442
+ subjectManagerReady: (_) => false,
443
+ kvManagerReady: (_) => false,
444
+ configureAfterClose: (_) => false,
445
+ connectAfterClose: (_) => false,
446
+ }),
447
+ ],
263
448
  on: {
449
+ CONFIGURE: {
450
+ target: 'configured',
451
+ actions: ['configureNats', lifecycleAction('closed')],
452
+ },
264
453
  RESET: {
265
454
  target: 'not_configured',
266
455
  actions: ['doReset'],
267
456
  },
268
457
  CONNECT: {
269
458
  target: 'connecting',
459
+ actions: lifecycleAction('closed'),
270
460
  },
271
461
  },
272
462
  '*': {
@@ -278,7 +468,12 @@ export const natsMachine = setup({
278
468
  },
279
469
  },
280
470
  error: {
471
+ entry: ['clearDeferredCloseActions', lifecycleAction('error')],
281
472
  on: {
473
+ CONFIGURE: {
474
+ target: 'configured',
475
+ actions: ['configureNats', lifecycleAction('error')],
476
+ },
282
477
  RESET: {
283
478
  target: 'not_configured',
284
479
  actions: ['doReset'],