@crossdelta/cloudevents 0.7.11 → 0.7.13

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
@@ -596,7 +596,9 @@ app.use('/events', cloudEvents({ discover: 'src/events/**/*.handler.ts' }))
596
596
  | `consumeNatsEvents(options)` | Consume fire-and-forget |
597
597
  | `publish(type, data)` | Publish event (fire-and-forget) |
598
598
  | `request(type, data, opts?)` | Publish event and await reply (Request-Reply) |
599
- | `isNatsConnected()` | Check if NATS connection is live (for health checks) |
599
+ | `isNatsConnected()` | Check if NATS publisher connection is live (for health checks) |
600
+ | `isConsumerConnected()` | Check if any NATS consumer connection is live (for readiness probes) |
601
+ | `configureNatsPublisher(config)` | Set connection options for the publisher singleton |
600
602
  | `closeConnection()` | Drain and close the NATS connection (for CLI tools) |
601
603
  ---
602
604
 
package/bin/cli.js CHANGED
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import { existsSync, readdirSync, statSync } from 'fs';
5
5
  import * as path from 'path';
6
6
  import { join } from 'path';
7
- import { createFlow, createGenerationResult, input, initGenerationContext, trackChange, printGenerationSummary, change, runFlow } from '@crossdelta/flowcore';
7
+ import { createFlow, createGenerationResult, input, initGenerationContext, trackChange, printGenerationSummary, runFlow, change } from '@crossdelta/flowcore';
8
8
  import 'url';
9
9
  import 'glob';
10
10
  import 'zod';
@@ -738,6 +738,7 @@ var nats_publisher_exports = {};
738
738
  __export(nats_publisher_exports, {
739
739
  __resetNatsPublisher: () => __resetNatsPublisher,
740
740
  closeConnection: () => closeConnection,
741
+ configureNatsPublisher: () => configureNatsPublisher,
741
742
  connectNats: () => connectNats,
742
743
  deriveStreamFromType: () => deriveStreamFromType,
743
744
  deriveSubjectFromType: () => deriveSubjectFromType,
@@ -747,7 +748,7 @@ __export(nats_publisher_exports, {
747
748
  publishNatsRawEvent: () => publishNatsRawEvent,
748
749
  request: () => request
749
750
  });
750
- var sc, natsConnectionPromise, deriveSubjectFromEventType, getNatsConnection, closeConnection, connectNats, isNatsConnected, __resetNatsPublisher, deriveSubjectFromType, deriveStreamFromType, publishNatsRawEvent, publishNatsEvent, publish, DEFAULT_REQUEST_TIMEOUT, request;
751
+ var sc, natsConnectionPromise, deriveSubjectFromEventType, connectionConfig, configureNatsPublisher, getNatsConnection, closeConnection, connectNats, isNatsConnected, __resetNatsPublisher, deriveSubjectFromType, deriveStreamFromType, publishNatsRawEvent, publishNatsEvent, publish, DEFAULT_REQUEST_TIMEOUT, request;
751
752
  var init_nats_publisher = __esm({
752
753
  "src/publishing/nats.publisher.ts"() {
753
754
  init_domain();
@@ -763,10 +764,17 @@ var init_nats_publisher = __esm({
763
764
  const pluralDomain = pluralize(domain);
764
765
  return `${pluralDomain}.${action}`;
765
766
  };
767
+ configureNatsPublisher = (config) => {
768
+ connectionConfig = config;
769
+ };
766
770
  getNatsConnection = async (servers) => {
767
771
  if (!natsConnectionPromise) {
768
772
  const url = servers ?? process.env.NATS_URL ?? "nats://localhost:4222";
769
- natsConnectionPromise = connect({ servers: url }).then((connection) => {
773
+ natsConnectionPromise = connect({
774
+ servers: url,
775
+ waitOnFirstConnect: connectionConfig?.waitOnFirstConnect ?? false,
776
+ maxReconnectAttempts: connectionConfig?.maxReconnectAttempts ?? -1
777
+ }).then((connection) => {
770
778
  logger.debug(`[NATS] connected to ${url}`);
771
779
  return connection;
772
780
  }).catch((error) => {
@@ -805,6 +813,7 @@ var init_nats_publisher = __esm({
805
813
  };
806
814
  __resetNatsPublisher = async () => {
807
815
  await closeConnection();
816
+ connectionConfig = void 0;
808
817
  };
809
818
  deriveSubjectFromType = (eventType, config) => {
810
819
  if (!config?.typeToSubjectMap) {
package/dist/index.cjs CHANGED
@@ -1372,6 +1372,7 @@ var nats_publisher_exports = {};
1372
1372
  __export(nats_publisher_exports, {
1373
1373
  __resetNatsPublisher: () => exports.__resetNatsPublisher,
1374
1374
  closeConnection: () => exports.closeConnection,
1375
+ configureNatsPublisher: () => exports.configureNatsPublisher,
1375
1376
  connectNats: () => exports.connectNats,
1376
1377
  deriveStreamFromType: () => exports.deriveStreamFromType,
1377
1378
  deriveSubjectFromType: () => exports.deriveSubjectFromType,
@@ -1381,7 +1382,7 @@ __export(nats_publisher_exports, {
1381
1382
  publishNatsRawEvent: () => exports.publishNatsRawEvent,
1382
1383
  request: () => exports.request
1383
1384
  });
1384
- var sc, natsConnectionPromise, deriveSubjectFromEventType, getNatsConnection; exports.closeConnection = void 0; exports.connectNats = void 0; exports.isNatsConnected = void 0; exports.__resetNatsPublisher = void 0; exports.deriveSubjectFromType = void 0; exports.deriveStreamFromType = void 0; exports.publishNatsRawEvent = void 0; exports.publishNatsEvent = void 0; exports.publish = void 0; var DEFAULT_REQUEST_TIMEOUT; exports.request = void 0;
1385
+ var sc, natsConnectionPromise, deriveSubjectFromEventType, connectionConfig; exports.configureNatsPublisher = void 0; var getNatsConnection; exports.closeConnection = void 0; exports.connectNats = void 0; exports.isNatsConnected = void 0; exports.__resetNatsPublisher = void 0; exports.deriveSubjectFromType = void 0; exports.deriveStreamFromType = void 0; exports.publishNatsRawEvent = void 0; exports.publishNatsEvent = void 0; exports.publish = void 0; var DEFAULT_REQUEST_TIMEOUT; exports.request = void 0;
1385
1386
  var init_nats_publisher = __esm({
1386
1387
  "src/publishing/nats.publisher.ts"() {
1387
1388
  init_domain();
@@ -1397,10 +1398,17 @@ var init_nats_publisher = __esm({
1397
1398
  const pluralDomain = exports.pluralize(domain);
1398
1399
  return `${pluralDomain}.${action}`;
1399
1400
  };
1401
+ exports.configureNatsPublisher = (config) => {
1402
+ connectionConfig = config;
1403
+ };
1400
1404
  getNatsConnection = async (servers) => {
1401
1405
  if (!natsConnectionPromise) {
1402
1406
  const url = servers ?? process.env.NATS_URL ?? "nats://localhost:4222";
1403
- natsConnectionPromise = nats.connect({ servers: url }).then((connection) => {
1407
+ natsConnectionPromise = nats.connect({
1408
+ servers: url,
1409
+ waitOnFirstConnect: connectionConfig?.waitOnFirstConnect ?? false,
1410
+ maxReconnectAttempts: connectionConfig?.maxReconnectAttempts ?? -1
1411
+ }).then((connection) => {
1404
1412
  logger.debug(`[NATS] connected to ${url}`);
1405
1413
  return connection;
1406
1414
  }).catch((error) => {
@@ -1439,6 +1447,7 @@ var init_nats_publisher = __esm({
1439
1447
  };
1440
1448
  exports.__resetNatsPublisher = async () => {
1441
1449
  await exports.closeConnection();
1450
+ connectionConfig = void 0;
1442
1451
  };
1443
1452
  exports.deriveSubjectFromType = (eventType, config) => {
1444
1453
  if (!config?.typeToSubjectMap) {
@@ -2182,7 +2191,7 @@ function cloudEvents(options = {}) {
2182
2191
  // package.json
2183
2192
  var package_default = {
2184
2193
  name: "@crossdelta/cloudevents",
2185
- version: "0.7.11",
2194
+ version: "0.7.13",
2186
2195
  description: "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream & Core"};
2187
2196
 
2188
2197
  // src/plugin.ts
@@ -2415,6 +2424,44 @@ function createBaseMessageProcessor(deps) {
2415
2424
  };
2416
2425
  }
2417
2426
 
2427
+ // src/transports/nats/connection.ts
2428
+ var LONG_LIVED_DEFAULTS = {
2429
+ waitOnFirstConnect: true,
2430
+ maxReconnectAttempts: -1
2431
+ };
2432
+ var SHORT_LIVED_DEFAULTS = {
2433
+ waitOnFirstConnect: true,
2434
+ maxReconnectAttempts: 10
2435
+ };
2436
+ var buildConnectOptions = (config, mode) => {
2437
+ const defaults = mode === "long-lived" ? LONG_LIVED_DEFAULTS : SHORT_LIVED_DEFAULTS;
2438
+ return {
2439
+ waitOnFirstConnect: config?.waitOnFirstConnect ?? defaults.waitOnFirstConnect,
2440
+ maxReconnectAttempts: config?.maxReconnectAttempts ?? defaults.maxReconnectAttempts
2441
+ };
2442
+ };
2443
+ var CONNECTION_REGISTRY_KEY = "__crossdelta_nats_connections__";
2444
+ var getConnectionRegistry = () => {
2445
+ if (!globalThis[CONNECTION_REGISTRY_KEY]) {
2446
+ globalThis[CONNECTION_REGISTRY_KEY] = /* @__PURE__ */ new Map();
2447
+ }
2448
+ return globalThis[CONNECTION_REGISTRY_KEY];
2449
+ };
2450
+ var registerConnection = (name, connection) => {
2451
+ getConnectionRegistry().set(name, connection);
2452
+ };
2453
+ var unregisterConnection = (name) => {
2454
+ getConnectionRegistry().delete(name);
2455
+ };
2456
+ var isConsumerConnected = () => {
2457
+ const registry = getConnectionRegistry();
2458
+ if (registry.size === 0) return false;
2459
+ for (const connection of registry.values()) {
2460
+ if (!connection.isClosed() && !connection.isDraining()) return true;
2461
+ }
2462
+ return false;
2463
+ };
2464
+
2418
2465
  // src/transports/nats/jetstream-consumer.ts
2419
2466
  init_domain();
2420
2467
  init_logging();
@@ -2473,7 +2520,8 @@ async function ensureJetStreamStream(options) {
2473
2520
  const pass = options.pass ?? process.env.NATS_PASSWORD;
2474
2521
  const nc = await nats.connect({
2475
2522
  servers,
2476
- ...user && pass ? { user, pass } : {}
2523
+ ...user && pass ? { user, pass } : {},
2524
+ ...buildConnectOptions(options.connection, "short-lived")
2477
2525
  });
2478
2526
  try {
2479
2527
  const jsm = await nc.jetstreamManager();
@@ -2514,7 +2562,8 @@ async function ensureJetStreamStreams(options) {
2514
2562
  const pass = options.pass ?? process.env.NATS_PASSWORD;
2515
2563
  const nc = await nats.connect({
2516
2564
  servers,
2517
- ...user && pass ? { user, pass } : {}
2565
+ ...user && pass ? { user, pass } : {},
2566
+ ...buildConnectOptions(options.connection, "short-lived")
2518
2567
  });
2519
2568
  try {
2520
2569
  const jsm = await nc.jetstreamManager();
@@ -2566,8 +2615,10 @@ async function consumeJetStreamEvents(options) {
2566
2615
  logger.info(`[${name}] discovered ${processedHandlers.length} handler(s): ${handlerNames}`);
2567
2616
  const nc = await nats.connect({
2568
2617
  servers,
2569
- ...user && pass ? { user, pass } : {}
2618
+ ...user && pass ? { user, pass } : {},
2619
+ ...buildConnectOptions(options.connection, "long-lived")
2570
2620
  });
2621
+ registerConnection(name, nc);
2571
2622
  logger.info(`[${name}] connected to NATS: ${servers}${user ? " (authenticated)" : ""}`);
2572
2623
  const jsm = await nc.jetstreamManager();
2573
2624
  const js = nc.jetstream();
@@ -2634,8 +2685,10 @@ async function consumeJetStreamStreams(options) {
2634
2685
  logger.info(`[${name}] discovered ${processedHandlers.length} handler(s): ${handlerNames}`);
2635
2686
  const nc = await nats.connect({
2636
2687
  servers,
2637
- ...user && pass ? { user, pass } : {}
2688
+ ...user && pass ? { user, pass } : {},
2689
+ ...buildConnectOptions(options.connection, "long-lived")
2638
2690
  });
2691
+ registerConnection(name, nc);
2639
2692
  logger.info(`[${name}] connected to NATS: ${servers}${user ? " (authenticated)" : ""}`);
2640
2693
  const jsm = await nc.jetstreamManager();
2641
2694
  const js = nc.jetstream();
@@ -2762,6 +2815,7 @@ async function cleanupConsumer(name) {
2762
2815
  consumer.subscription.unsubscribe();
2763
2816
  await consumer.connection.drain();
2764
2817
  registry.delete(name);
2818
+ unregisterConnection(name);
2765
2819
  }
2766
2820
  }
2767
2821
  async function consumeNatsEvents(options) {
@@ -2777,12 +2831,14 @@ async function consumeNatsEvents(options) {
2777
2831
  logger.info(`[${name}] discovered ${processedHandlers.length} handler(s): ${handlerNames}`);
2778
2832
  const nc = await nats.connect({
2779
2833
  servers,
2780
- ...user && pass ? { user, pass } : {}
2834
+ ...user && pass ? { user, pass } : {},
2835
+ ...buildConnectOptions(options.connection, "long-lived")
2781
2836
  });
2782
2837
  logger.info(`[${name}] connected to NATS: ${servers}${user ? " (authenticated)" : ""}`);
2783
2838
  const sub = nc.subscribe(subject, { queue: name });
2784
2839
  logger.info(`[${name}] subscribed to subject: ${subject} (queue: ${name})`);
2785
2840
  getConsumerRegistry().set(name, { subscription: sub, connection: nc });
2841
+ registerConnection(name, nc);
2786
2842
  const dlqEnabled = Boolean(options.quarantineTopic || options.errorTopic);
2787
2843
  const { handleMessage, handleUnhandledProcessingError } = createNatsMessageProcessor({
2788
2844
  name,
@@ -2824,6 +2880,7 @@ exports.ensureJetStreams = ensureJetStreams;
2824
2880
  exports.eventSchema = eventSchema;
2825
2881
  exports.getDefaultIdempotencyStore = getDefaultIdempotencyStore;
2826
2882
  exports.handleEvent = handleEvent;
2883
+ exports.isConsumerConnected = isConsumerConnected;
2827
2884
  exports.listEvents = listEvents;
2828
2885
  exports.parseEventFromContext = parseEventFromContext;
2829
2886
  exports.publishEvent = publishEvent;
package/dist/index.d.cts CHANGED
@@ -1298,6 +1298,18 @@ interface CloudEventsPfPluginOptions {
1298
1298
  }
1299
1299
  declare const createPfPlugin: (options?: CloudEventsPfPluginOptions) => PfPlugin;
1300
1300
 
1301
+ interface NatsConnectionConfig {
1302
+ /** Retry the initial connection instead of failing immediately. @default true */
1303
+ waitOnFirstConnect?: boolean;
1304
+ /** Maximum reconnect attempts (-1 = unlimited). @default -1 */
1305
+ maxReconnectAttempts?: number;
1306
+ }
1307
+ /**
1308
+ * Returns true if at least one registered consumer connection is alive.
1309
+ * Returns false if no consumers are registered or all are closed/draining.
1310
+ */
1311
+ declare const isConsumerConnected: () => boolean;
1312
+
1301
1313
  interface RequestNatsEventOptions {
1302
1314
  servers?: string;
1303
1315
  source?: string;
@@ -1314,6 +1326,11 @@ interface PublishNatsEventOptions {
1314
1326
  /** Close connection after publishing (for CLI tools) */
1315
1327
  closeAfterPublish?: boolean;
1316
1328
  }
1329
+ /**
1330
+ * Configure connection defaults for the publisher singleton.
1331
+ * Call before any publish/request to override defaults.
1332
+ */
1333
+ declare const configureNatsPublisher: (config: NatsConnectionConfig) => void;
1317
1334
  /**
1318
1335
  * Close the NATS connection and reset state
1319
1336
  */
@@ -1408,6 +1425,8 @@ interface JetStreamStreamOptions {
1408
1425
  subjects: string[];
1409
1426
  /** Stream configuration */
1410
1427
  config?: StreamConfig;
1428
+ /** NATS connection tuning */
1429
+ connection?: NatsConnectionConfig;
1411
1430
  }
1412
1431
  /**
1413
1432
  * Stream definition for batch operations
@@ -1432,6 +1451,8 @@ interface JetStreamStreamsOptions {
1432
1451
  pass?: string;
1433
1452
  /** Array of stream definitions */
1434
1453
  streams: StreamDefinition[];
1454
+ /** NATS connection tuning */
1455
+ connection?: NatsConnectionConfig;
1435
1456
  }
1436
1457
  /**
1437
1458
  * JetStream consumer configuration
@@ -1487,6 +1508,8 @@ interface JetStreamConsumerOptions extends Pick<CloudEventsOptions, 'quarantineT
1487
1508
  * @default 86400000 (24 hours)
1488
1509
  */
1489
1510
  idempotencyTtl?: number;
1511
+ /** NATS connection tuning */
1512
+ connection?: NatsConnectionConfig;
1490
1513
  }
1491
1514
  /**
1492
1515
  * Ensures a JetStream stream exists with the given configuration.
@@ -1570,6 +1593,8 @@ interface JetStreamStreamsConsumerOptions extends Pick<CloudEventsOptions, 'quar
1570
1593
  idempotencyStore?: IdempotencyStore | false;
1571
1594
  /** TTL for idempotency records in milliseconds @default 86400000 */
1572
1595
  idempotencyTtl?: number;
1596
+ /** NATS connection tuning */
1597
+ connection?: NatsConnectionConfig;
1573
1598
  }
1574
1599
  /**
1575
1600
  * Consume CloudEvents from multiple JetStream streams with a single connection.
@@ -1619,6 +1644,8 @@ interface NatsConsumerOptions extends Pick<CloudEventsOptions, 'quarantineTopic'
1619
1644
  user?: string;
1620
1645
  /** NATS password for authentication (defaults to NATS_PASSWORD env var) */
1621
1646
  pass?: string;
1647
+ /** NATS connection tuning */
1648
+ connection?: NatsConnectionConfig;
1622
1649
  }
1623
1650
  /**
1624
1651
  * Connects to NATS, discovers matching event handlers, and processes incoming CloudEvents.
@@ -1631,4 +1658,4 @@ interface NatsConsumerOptions extends Pick<CloudEventsOptions, 'quarantineTopic'
1631
1658
  */
1632
1659
  declare function consumeNatsEvents(options: NatsConsumerOptions): Promise<Subscription>;
1633
1660
 
1634
- export { type ChannelConfig, type ChannelMetadata, type CloudEventsPfPluginOptions, type ContractCreatedEffect, type ContractPaths, type CreateEventContext, type CreateEventOptions, type DomainEffect, type EnrichedEvent, type EventContext, type EventNames, type EventTypeValidation, type FileSystem, type HandleEventOptions, type HandlerCreatedEffect, type IdempotencyStore, type InferEventData, type JetStreamConsumerOptions, type JetStreamStreamOptions, type JetStreamStreamsConsumerOptions, type JetStreamStreamsOptions, type ListEventsContext, type NatsRequestResponse, type PublishEventContext, type PublishEventOptions, type PublishNatsEventOptions, type RequestNatsEventOptions, type RoutingConfig, type SchemaField, type StreamConfig, type StreamDefinition, type StreamWiredEffect, __resetNatsPublisher, checkAndMarkProcessed, clearHandlerCache, closeConnection, cloudEvents, connectNats, consumeJetStreamEvents, consumeJetStreamStreams, consumeJetStreams, consumeNatsEvents, contractCreated, createContract, createEvent, createEventFlowSteps, createInMemoryIdempotencyStore, createMemoryFileSystem, createPfPlugin, deriveEventNames, deriveStreamFromType, deriveSubjectFromType, discoverEventTypes, ensureJetStreamStream, ensureJetStreamStreams, ensureJetStreams, eventSchema, extractTypeFromSchema, generateContract, generateContractContent, generateEventHandler, generateEventHandlerContent, generateJsonMock, generateJsonMockFromContract, generateMock, generateMockContent, getContractFilePath, getContractPaths, getDefaultIdempotencyStore, getHandlerFilePath, getHandlerPath, getJsonMockPath, getMockFilePath, getStreamName, handleEvent, handlerCreated, initFaker, isNatsConnected, isValidEventType, jsonMockExists, listEvents, listEventsFlowSteps, loadJsonMock, normalizeSubject, parseDataInput, parseEventFromContext, parseEventTypeFromContract, parseEventTypeFromHandler, parseFieldsInput, pluralize, publish, publishEvent, publishEventFlowSteps, publishNatsEvent, publishNatsRawEvent, publishRawEvent, request, resetDefaultIdempotencyStore, singularize, streamWired, toKebabCase, toPascalCase, validateEventType };
1661
+ export { type ChannelConfig, type ChannelMetadata, type CloudEventsPfPluginOptions, type ContractCreatedEffect, type ContractPaths, type CreateEventContext, type CreateEventOptions, type DomainEffect, type EnrichedEvent, type EventContext, type EventNames, type EventTypeValidation, type FileSystem, type HandleEventOptions, type HandlerCreatedEffect, type IdempotencyStore, type InferEventData, type JetStreamConsumerOptions, type JetStreamStreamOptions, type JetStreamStreamsConsumerOptions, type JetStreamStreamsOptions, type ListEventsContext, type NatsConnectionConfig, type NatsRequestResponse, type PublishEventContext, type PublishEventOptions, type PublishNatsEventOptions, type RequestNatsEventOptions, type RoutingConfig, type SchemaField, type StreamConfig, type StreamDefinition, type StreamWiredEffect, __resetNatsPublisher, checkAndMarkProcessed, clearHandlerCache, closeConnection, cloudEvents, configureNatsPublisher, connectNats, consumeJetStreamEvents, consumeJetStreamStreams, consumeJetStreams, consumeNatsEvents, contractCreated, createContract, createEvent, createEventFlowSteps, createInMemoryIdempotencyStore, createMemoryFileSystem, createPfPlugin, deriveEventNames, deriveStreamFromType, deriveSubjectFromType, discoverEventTypes, ensureJetStreamStream, ensureJetStreamStreams, ensureJetStreams, eventSchema, extractTypeFromSchema, generateContract, generateContractContent, generateEventHandler, generateEventHandlerContent, generateJsonMock, generateJsonMockFromContract, generateMock, generateMockContent, getContractFilePath, getContractPaths, getDefaultIdempotencyStore, getHandlerFilePath, getHandlerPath, getJsonMockPath, getMockFilePath, getStreamName, handleEvent, handlerCreated, initFaker, isConsumerConnected, isNatsConnected, isValidEventType, jsonMockExists, listEvents, listEventsFlowSteps, loadJsonMock, normalizeSubject, parseDataInput, parseEventFromContext, parseEventTypeFromContract, parseEventTypeFromHandler, parseFieldsInput, pluralize, publish, publishEvent, publishEventFlowSteps, publishNatsEvent, publishNatsRawEvent, publishRawEvent, request, resetDefaultIdempotencyStore, singularize, streamWired, toKebabCase, toPascalCase, validateEventType };
package/dist/index.d.ts CHANGED
@@ -1298,6 +1298,18 @@ interface CloudEventsPfPluginOptions {
1298
1298
  }
1299
1299
  declare const createPfPlugin: (options?: CloudEventsPfPluginOptions) => PfPlugin;
1300
1300
 
1301
+ interface NatsConnectionConfig {
1302
+ /** Retry the initial connection instead of failing immediately. @default true */
1303
+ waitOnFirstConnect?: boolean;
1304
+ /** Maximum reconnect attempts (-1 = unlimited). @default -1 */
1305
+ maxReconnectAttempts?: number;
1306
+ }
1307
+ /**
1308
+ * Returns true if at least one registered consumer connection is alive.
1309
+ * Returns false if no consumers are registered or all are closed/draining.
1310
+ */
1311
+ declare const isConsumerConnected: () => boolean;
1312
+
1301
1313
  interface RequestNatsEventOptions {
1302
1314
  servers?: string;
1303
1315
  source?: string;
@@ -1314,6 +1326,11 @@ interface PublishNatsEventOptions {
1314
1326
  /** Close connection after publishing (for CLI tools) */
1315
1327
  closeAfterPublish?: boolean;
1316
1328
  }
1329
+ /**
1330
+ * Configure connection defaults for the publisher singleton.
1331
+ * Call before any publish/request to override defaults.
1332
+ */
1333
+ declare const configureNatsPublisher: (config: NatsConnectionConfig) => void;
1317
1334
  /**
1318
1335
  * Close the NATS connection and reset state
1319
1336
  */
@@ -1408,6 +1425,8 @@ interface JetStreamStreamOptions {
1408
1425
  subjects: string[];
1409
1426
  /** Stream configuration */
1410
1427
  config?: StreamConfig;
1428
+ /** NATS connection tuning */
1429
+ connection?: NatsConnectionConfig;
1411
1430
  }
1412
1431
  /**
1413
1432
  * Stream definition for batch operations
@@ -1432,6 +1451,8 @@ interface JetStreamStreamsOptions {
1432
1451
  pass?: string;
1433
1452
  /** Array of stream definitions */
1434
1453
  streams: StreamDefinition[];
1454
+ /** NATS connection tuning */
1455
+ connection?: NatsConnectionConfig;
1435
1456
  }
1436
1457
  /**
1437
1458
  * JetStream consumer configuration
@@ -1487,6 +1508,8 @@ interface JetStreamConsumerOptions extends Pick<CloudEventsOptions, 'quarantineT
1487
1508
  * @default 86400000 (24 hours)
1488
1509
  */
1489
1510
  idempotencyTtl?: number;
1511
+ /** NATS connection tuning */
1512
+ connection?: NatsConnectionConfig;
1490
1513
  }
1491
1514
  /**
1492
1515
  * Ensures a JetStream stream exists with the given configuration.
@@ -1570,6 +1593,8 @@ interface JetStreamStreamsConsumerOptions extends Pick<CloudEventsOptions, 'quar
1570
1593
  idempotencyStore?: IdempotencyStore | false;
1571
1594
  /** TTL for idempotency records in milliseconds @default 86400000 */
1572
1595
  idempotencyTtl?: number;
1596
+ /** NATS connection tuning */
1597
+ connection?: NatsConnectionConfig;
1573
1598
  }
1574
1599
  /**
1575
1600
  * Consume CloudEvents from multiple JetStream streams with a single connection.
@@ -1619,6 +1644,8 @@ interface NatsConsumerOptions extends Pick<CloudEventsOptions, 'quarantineTopic'
1619
1644
  user?: string;
1620
1645
  /** NATS password for authentication (defaults to NATS_PASSWORD env var) */
1621
1646
  pass?: string;
1647
+ /** NATS connection tuning */
1648
+ connection?: NatsConnectionConfig;
1622
1649
  }
1623
1650
  /**
1624
1651
  * Connects to NATS, discovers matching event handlers, and processes incoming CloudEvents.
@@ -1631,4 +1658,4 @@ interface NatsConsumerOptions extends Pick<CloudEventsOptions, 'quarantineTopic'
1631
1658
  */
1632
1659
  declare function consumeNatsEvents(options: NatsConsumerOptions): Promise<Subscription>;
1633
1660
 
1634
- export { type ChannelConfig, type ChannelMetadata, type CloudEventsPfPluginOptions, type ContractCreatedEffect, type ContractPaths, type CreateEventContext, type CreateEventOptions, type DomainEffect, type EnrichedEvent, type EventContext, type EventNames, type EventTypeValidation, type FileSystem, type HandleEventOptions, type HandlerCreatedEffect, type IdempotencyStore, type InferEventData, type JetStreamConsumerOptions, type JetStreamStreamOptions, type JetStreamStreamsConsumerOptions, type JetStreamStreamsOptions, type ListEventsContext, type NatsRequestResponse, type PublishEventContext, type PublishEventOptions, type PublishNatsEventOptions, type RequestNatsEventOptions, type RoutingConfig, type SchemaField, type StreamConfig, type StreamDefinition, type StreamWiredEffect, __resetNatsPublisher, checkAndMarkProcessed, clearHandlerCache, closeConnection, cloudEvents, connectNats, consumeJetStreamEvents, consumeJetStreamStreams, consumeJetStreams, consumeNatsEvents, contractCreated, createContract, createEvent, createEventFlowSteps, createInMemoryIdempotencyStore, createMemoryFileSystem, createPfPlugin, deriveEventNames, deriveStreamFromType, deriveSubjectFromType, discoverEventTypes, ensureJetStreamStream, ensureJetStreamStreams, ensureJetStreams, eventSchema, extractTypeFromSchema, generateContract, generateContractContent, generateEventHandler, generateEventHandlerContent, generateJsonMock, generateJsonMockFromContract, generateMock, generateMockContent, getContractFilePath, getContractPaths, getDefaultIdempotencyStore, getHandlerFilePath, getHandlerPath, getJsonMockPath, getMockFilePath, getStreamName, handleEvent, handlerCreated, initFaker, isNatsConnected, isValidEventType, jsonMockExists, listEvents, listEventsFlowSteps, loadJsonMock, normalizeSubject, parseDataInput, parseEventFromContext, parseEventTypeFromContract, parseEventTypeFromHandler, parseFieldsInput, pluralize, publish, publishEvent, publishEventFlowSteps, publishNatsEvent, publishNatsRawEvent, publishRawEvent, request, resetDefaultIdempotencyStore, singularize, streamWired, toKebabCase, toPascalCase, validateEventType };
1661
+ export { type ChannelConfig, type ChannelMetadata, type CloudEventsPfPluginOptions, type ContractCreatedEffect, type ContractPaths, type CreateEventContext, type CreateEventOptions, type DomainEffect, type EnrichedEvent, type EventContext, type EventNames, type EventTypeValidation, type FileSystem, type HandleEventOptions, type HandlerCreatedEffect, type IdempotencyStore, type InferEventData, type JetStreamConsumerOptions, type JetStreamStreamOptions, type JetStreamStreamsConsumerOptions, type JetStreamStreamsOptions, type ListEventsContext, type NatsConnectionConfig, type NatsRequestResponse, type PublishEventContext, type PublishEventOptions, type PublishNatsEventOptions, type RequestNatsEventOptions, type RoutingConfig, type SchemaField, type StreamConfig, type StreamDefinition, type StreamWiredEffect, __resetNatsPublisher, checkAndMarkProcessed, clearHandlerCache, closeConnection, cloudEvents, configureNatsPublisher, connectNats, consumeJetStreamEvents, consumeJetStreamStreams, consumeJetStreams, consumeNatsEvents, contractCreated, createContract, createEvent, createEventFlowSteps, createInMemoryIdempotencyStore, createMemoryFileSystem, createPfPlugin, deriveEventNames, deriveStreamFromType, deriveSubjectFromType, discoverEventTypes, ensureJetStreamStream, ensureJetStreamStreams, ensureJetStreams, eventSchema, extractTypeFromSchema, generateContract, generateContractContent, generateEventHandler, generateEventHandlerContent, generateJsonMock, generateJsonMockFromContract, generateMock, generateMockContent, getContractFilePath, getContractPaths, getDefaultIdempotencyStore, getHandlerFilePath, getHandlerPath, getJsonMockPath, getMockFilePath, getStreamName, handleEvent, handlerCreated, initFaker, isConsumerConnected, isNatsConnected, isValidEventType, jsonMockExists, listEvents, listEventsFlowSteps, loadJsonMock, normalizeSubject, parseDataInput, parseEventFromContext, parseEventTypeFromContract, parseEventTypeFromHandler, parseFieldsInput, pluralize, publish, publishEvent, publishEventFlowSteps, publishNatsEvent, publishNatsRawEvent, publishRawEvent, request, resetDefaultIdempotencyStore, singularize, streamWired, toKebabCase, toPascalCase, validateEventType };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import { existsSync, readdirSync, statSync } from 'fs';
5
5
  import * as path from 'path';
6
6
  import { join, dirname } from 'path';
7
- import { createFlow, createGenerationResult, input, initGenerationContext, trackChange, printGenerationSummary, change, runFlow } from '@crossdelta/flowcore';
7
+ import { createFlow, createGenerationResult, input, initGenerationContext, trackChange, printGenerationSummary, runFlow, change } from '@crossdelta/flowcore';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { glob } from 'glob';
10
10
  import { z } from 'zod';
@@ -1347,6 +1347,7 @@ var nats_publisher_exports = {};
1347
1347
  __export(nats_publisher_exports, {
1348
1348
  __resetNatsPublisher: () => __resetNatsPublisher,
1349
1349
  closeConnection: () => closeConnection,
1350
+ configureNatsPublisher: () => configureNatsPublisher,
1350
1351
  connectNats: () => connectNats,
1351
1352
  deriveStreamFromType: () => deriveStreamFromType,
1352
1353
  deriveSubjectFromType: () => deriveSubjectFromType,
@@ -1356,7 +1357,7 @@ __export(nats_publisher_exports, {
1356
1357
  publishNatsRawEvent: () => publishNatsRawEvent,
1357
1358
  request: () => request
1358
1359
  });
1359
- var sc, natsConnectionPromise, deriveSubjectFromEventType, getNatsConnection, closeConnection, connectNats, isNatsConnected, __resetNatsPublisher, deriveSubjectFromType, deriveStreamFromType, publishNatsRawEvent, publishNatsEvent, publish, DEFAULT_REQUEST_TIMEOUT, request;
1360
+ var sc, natsConnectionPromise, deriveSubjectFromEventType, connectionConfig, configureNatsPublisher, getNatsConnection, closeConnection, connectNats, isNatsConnected, __resetNatsPublisher, deriveSubjectFromType, deriveStreamFromType, publishNatsRawEvent, publishNatsEvent, publish, DEFAULT_REQUEST_TIMEOUT, request;
1360
1361
  var init_nats_publisher = __esm({
1361
1362
  "src/publishing/nats.publisher.ts"() {
1362
1363
  init_domain();
@@ -1372,10 +1373,17 @@ var init_nats_publisher = __esm({
1372
1373
  const pluralDomain = pluralize(domain);
1373
1374
  return `${pluralDomain}.${action}`;
1374
1375
  };
1376
+ configureNatsPublisher = (config) => {
1377
+ connectionConfig = config;
1378
+ };
1375
1379
  getNatsConnection = async (servers) => {
1376
1380
  if (!natsConnectionPromise) {
1377
1381
  const url = servers ?? process.env.NATS_URL ?? "nats://localhost:4222";
1378
- natsConnectionPromise = connect({ servers: url }).then((connection) => {
1382
+ natsConnectionPromise = connect({
1383
+ servers: url,
1384
+ waitOnFirstConnect: connectionConfig?.waitOnFirstConnect ?? false,
1385
+ maxReconnectAttempts: connectionConfig?.maxReconnectAttempts ?? -1
1386
+ }).then((connection) => {
1379
1387
  logger.debug(`[NATS] connected to ${url}`);
1380
1388
  return connection;
1381
1389
  }).catch((error) => {
@@ -1414,6 +1422,7 @@ var init_nats_publisher = __esm({
1414
1422
  };
1415
1423
  __resetNatsPublisher = async () => {
1416
1424
  await closeConnection();
1425
+ connectionConfig = void 0;
1417
1426
  };
1418
1427
  deriveSubjectFromType = (eventType, config) => {
1419
1428
  if (!config?.typeToSubjectMap) {
@@ -2157,7 +2166,7 @@ function cloudEvents(options = {}) {
2157
2166
  // package.json
2158
2167
  var package_default = {
2159
2168
  name: "@crossdelta/cloudevents",
2160
- version: "0.7.11",
2169
+ version: "0.7.13",
2161
2170
  description: "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream & Core"};
2162
2171
 
2163
2172
  // src/plugin.ts
@@ -2390,6 +2399,44 @@ function createBaseMessageProcessor(deps) {
2390
2399
  };
2391
2400
  }
2392
2401
 
2402
+ // src/transports/nats/connection.ts
2403
+ var LONG_LIVED_DEFAULTS = {
2404
+ waitOnFirstConnect: true,
2405
+ maxReconnectAttempts: -1
2406
+ };
2407
+ var SHORT_LIVED_DEFAULTS = {
2408
+ waitOnFirstConnect: true,
2409
+ maxReconnectAttempts: 10
2410
+ };
2411
+ var buildConnectOptions = (config, mode) => {
2412
+ const defaults = mode === "long-lived" ? LONG_LIVED_DEFAULTS : SHORT_LIVED_DEFAULTS;
2413
+ return {
2414
+ waitOnFirstConnect: config?.waitOnFirstConnect ?? defaults.waitOnFirstConnect,
2415
+ maxReconnectAttempts: config?.maxReconnectAttempts ?? defaults.maxReconnectAttempts
2416
+ };
2417
+ };
2418
+ var CONNECTION_REGISTRY_KEY = "__crossdelta_nats_connections__";
2419
+ var getConnectionRegistry = () => {
2420
+ if (!globalThis[CONNECTION_REGISTRY_KEY]) {
2421
+ globalThis[CONNECTION_REGISTRY_KEY] = /* @__PURE__ */ new Map();
2422
+ }
2423
+ return globalThis[CONNECTION_REGISTRY_KEY];
2424
+ };
2425
+ var registerConnection = (name, connection) => {
2426
+ getConnectionRegistry().set(name, connection);
2427
+ };
2428
+ var unregisterConnection = (name) => {
2429
+ getConnectionRegistry().delete(name);
2430
+ };
2431
+ var isConsumerConnected = () => {
2432
+ const registry = getConnectionRegistry();
2433
+ if (registry.size === 0) return false;
2434
+ for (const connection of registry.values()) {
2435
+ if (!connection.isClosed() && !connection.isDraining()) return true;
2436
+ }
2437
+ return false;
2438
+ };
2439
+
2393
2440
  // src/transports/nats/jetstream-consumer.ts
2394
2441
  init_domain();
2395
2442
  init_logging();
@@ -2448,7 +2495,8 @@ async function ensureJetStreamStream(options) {
2448
2495
  const pass = options.pass ?? process.env.NATS_PASSWORD;
2449
2496
  const nc = await connect({
2450
2497
  servers,
2451
- ...user && pass ? { user, pass } : {}
2498
+ ...user && pass ? { user, pass } : {},
2499
+ ...buildConnectOptions(options.connection, "short-lived")
2452
2500
  });
2453
2501
  try {
2454
2502
  const jsm = await nc.jetstreamManager();
@@ -2489,7 +2537,8 @@ async function ensureJetStreamStreams(options) {
2489
2537
  const pass = options.pass ?? process.env.NATS_PASSWORD;
2490
2538
  const nc = await connect({
2491
2539
  servers,
2492
- ...user && pass ? { user, pass } : {}
2540
+ ...user && pass ? { user, pass } : {},
2541
+ ...buildConnectOptions(options.connection, "short-lived")
2493
2542
  });
2494
2543
  try {
2495
2544
  const jsm = await nc.jetstreamManager();
@@ -2541,8 +2590,10 @@ async function consumeJetStreamEvents(options) {
2541
2590
  logger.info(`[${name}] discovered ${processedHandlers.length} handler(s): ${handlerNames}`);
2542
2591
  const nc = await connect({
2543
2592
  servers,
2544
- ...user && pass ? { user, pass } : {}
2593
+ ...user && pass ? { user, pass } : {},
2594
+ ...buildConnectOptions(options.connection, "long-lived")
2545
2595
  });
2596
+ registerConnection(name, nc);
2546
2597
  logger.info(`[${name}] connected to NATS: ${servers}${user ? " (authenticated)" : ""}`);
2547
2598
  const jsm = await nc.jetstreamManager();
2548
2599
  const js = nc.jetstream();
@@ -2609,8 +2660,10 @@ async function consumeJetStreamStreams(options) {
2609
2660
  logger.info(`[${name}] discovered ${processedHandlers.length} handler(s): ${handlerNames}`);
2610
2661
  const nc = await connect({
2611
2662
  servers,
2612
- ...user && pass ? { user, pass } : {}
2663
+ ...user && pass ? { user, pass } : {},
2664
+ ...buildConnectOptions(options.connection, "long-lived")
2613
2665
  });
2666
+ registerConnection(name, nc);
2614
2667
  logger.info(`[${name}] connected to NATS: ${servers}${user ? " (authenticated)" : ""}`);
2615
2668
  const jsm = await nc.jetstreamManager();
2616
2669
  const js = nc.jetstream();
@@ -2737,6 +2790,7 @@ async function cleanupConsumer(name) {
2737
2790
  consumer.subscription.unsubscribe();
2738
2791
  await consumer.connection.drain();
2739
2792
  registry.delete(name);
2793
+ unregisterConnection(name);
2740
2794
  }
2741
2795
  }
2742
2796
  async function consumeNatsEvents(options) {
@@ -2752,12 +2806,14 @@ async function consumeNatsEvents(options) {
2752
2806
  logger.info(`[${name}] discovered ${processedHandlers.length} handler(s): ${handlerNames}`);
2753
2807
  const nc = await connect({
2754
2808
  servers,
2755
- ...user && pass ? { user, pass } : {}
2809
+ ...user && pass ? { user, pass } : {},
2810
+ ...buildConnectOptions(options.connection, "long-lived")
2756
2811
  });
2757
2812
  logger.info(`[${name}] connected to NATS: ${servers}${user ? " (authenticated)" : ""}`);
2758
2813
  const sub = nc.subscribe(subject, { queue: name });
2759
2814
  logger.info(`[${name}] subscribed to subject: ${subject} (queue: ${name})`);
2760
2815
  getConsumerRegistry().set(name, { subscription: sub, connection: nc });
2816
+ registerConnection(name, nc);
2761
2817
  const dlqEnabled = Boolean(options.quarantineTopic || options.errorTopic);
2762
2818
  const { handleMessage, handleUnhandledProcessingError } = createNatsMessageProcessor({
2763
2819
  name,
@@ -2782,4 +2838,4 @@ async function consumeNatsEvents(options) {
2782
2838
  // src/index.ts
2783
2839
  init_utils();
2784
2840
 
2785
- export { __resetNatsPublisher, checkAndMarkProcessed, clearHandlerCache, closeConnection, cloudEvents, connectNats, consumeJetStreamEvents, consumeJetStreamStreams, consumeJetStreams, consumeNatsEvents, contractCreated, createContract, createEvent, createEventFlowSteps, createInMemoryIdempotencyStore, createMemoryFileSystem, createPfPlugin, deriveEventNames, deriveStreamFromType, deriveSubjectFromType, discoverEventTypes, ensureJetStreamStream, ensureJetStreamStreams, ensureJetStreams, eventSchema, extractTypeFromSchema, generateContract, generateContractContent, generateEventHandler, generateEventHandlerContent, generateJsonMock, generateJsonMockFromContract, generateMock, generateMockContent, getContractFilePath, getContractPaths, getDefaultIdempotencyStore, getHandlerFilePath, getHandlerPath, getJsonMockPath, getMockFilePath, getStreamName, handleEvent, handlerCreated, initFaker, isNatsConnected, isValidEventType, jsonMockExists, listEvents, listEventsFlowSteps, loadJsonMock, normalizeSubject, parseDataInput, parseEventFromContext, parseEventTypeFromContract, parseEventTypeFromHandler, parseFieldsInput, pluralize, publish, publishEvent, publishEventFlowSteps, publishNatsEvent, publishNatsRawEvent, publishRawEvent, request, resetDefaultIdempotencyStore, singularize, streamWired, toKebabCase, toPascalCase, validateEventType };
2841
+ export { __resetNatsPublisher, checkAndMarkProcessed, clearHandlerCache, closeConnection, cloudEvents, configureNatsPublisher, connectNats, consumeJetStreamEvents, consumeJetStreamStreams, consumeJetStreams, consumeNatsEvents, contractCreated, createContract, createEvent, createEventFlowSteps, createInMemoryIdempotencyStore, createMemoryFileSystem, createPfPlugin, deriveEventNames, deriveStreamFromType, deriveSubjectFromType, discoverEventTypes, ensureJetStreamStream, ensureJetStreamStreams, ensureJetStreams, eventSchema, extractTypeFromSchema, generateContract, generateContractContent, generateEventHandler, generateEventHandlerContent, generateJsonMock, generateJsonMockFromContract, generateMock, generateMockContent, getContractFilePath, getContractPaths, getDefaultIdempotencyStore, getHandlerFilePath, getHandlerPath, getJsonMockPath, getMockFilePath, getStreamName, handleEvent, handlerCreated, initFaker, isConsumerConnected, isNatsConnected, isValidEventType, jsonMockExists, listEvents, listEventsFlowSteps, loadJsonMock, normalizeSubject, parseDataInput, parseEventFromContext, parseEventTypeFromContract, parseEventTypeFromHandler, parseFieldsInput, pluralize, publish, publishEvent, publishEventFlowSteps, publishNatsEvent, publishNatsRawEvent, publishRawEvent, request, resetDefaultIdempotencyStore, singularize, streamWired, toKebabCase, toPascalCase, validateEventType };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossdelta/cloudevents",
3
- "version": "0.7.11",
3
+ "version": "0.7.13",
4
4
  "description": "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream & Core",
5
5
  "author": "crossdelta",
6
6
  "license": "MIT",