@crossdelta/cloudevents 0.1.4 → 0.1.6

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.
@@ -29,9 +29,15 @@ const loadHandlers = async (filePath, filter) => {
29
29
  .filter(([name, handler]) => isValidHandler(handler) && (!filter || filter(name, handler)))
30
30
  .map(([name, handler]) => {
31
31
  const HandlerClass = handler;
32
- return HandlerClass.name !== name
33
- ? Object.defineProperty(HandlerClass, 'name', { value: name, configurable: true })
34
- : HandlerClass;
32
+ // Only override with export name if:
33
+ // 1. Export is named (not 'default')
34
+ // 2. Handler has no meaningful name (empty or generic class names)
35
+ const hasNoMeaningfulName = !HandlerClass.name || HandlerClass.name === '' || HandlerClass.name === 'HandlerClass';
36
+ const isNamedExport = name !== 'default';
37
+ if (hasNoMeaningfulName && isNamedExport) {
38
+ return Object.defineProperty(HandlerClass, 'name', { value: name, configurable: true });
39
+ }
40
+ return HandlerClass;
35
41
  });
36
42
  }
37
43
  catch (error) {
@@ -35,8 +35,12 @@ export function handleEvent(schemaOrOptions, handler, eventType) {
35
35
  if (!finalEventType) {
36
36
  finalEventType = 'unknown.event';
37
37
  }
38
- // Create handler class with proper naming
39
- const handlerName = `${finalEventType.replace(/[^a-zA-Z0-9]/g, '')}Handler`;
38
+ // Create handler class with proper naming (e.g., "orderboss.orders.created" → "OrdersCreatedHandler")
39
+ const handlerName = finalEventType
40
+ .split('.')
41
+ .slice(-2) // Take last 2 segments (e.g., ["orders", "created"])
42
+ .map(s => s.charAt(0).toUpperCase() + s.slice(1)) // Capitalize
43
+ .join('') + 'Handler';
40
44
  const HandlerClass = class extends Object {
41
45
  static __eventarcMetadata = {
42
46
  schema,
@@ -4,6 +4,28 @@ import { logger } from '../../infrastructure/logging';
4
4
  import { processHandler } from '../../processing/handler-cache';
5
5
  import { createNatsMessageProcessor } from './nats-message-processor';
6
6
  const sc = StringCodec();
7
+ // Use globalThis to persist across hot-reloads
8
+ const CONSUMER_REGISTRY_KEY = '__crossdelta_nats_consumers__';
9
+ function getConsumerRegistry() {
10
+ if (!globalThis[CONSUMER_REGISTRY_KEY]) {
11
+ ;
12
+ globalThis[CONSUMER_REGISTRY_KEY] = new Map();
13
+ }
14
+ return globalThis[CONSUMER_REGISTRY_KEY];
15
+ }
16
+ /**
17
+ * Cleanup function to close a consumer by name
18
+ */
19
+ async function cleanupConsumer(name) {
20
+ const registry = getConsumerRegistry();
21
+ const consumer = registry.get(name);
22
+ if (consumer) {
23
+ logger.info(`[${name}] cleaning up subscription...`);
24
+ consumer.subscription.unsubscribe();
25
+ await consumer.connection.drain();
26
+ registry.delete(name);
27
+ }
28
+ }
7
29
  /**
8
30
  * Connects to NATS, discovers matching event handlers, and processes incoming CloudEvents.
9
31
  *
@@ -17,6 +39,8 @@ export async function consumeNatsEvents(options) {
17
39
  const servers = options.servers ?? process.env.NATS_URL ?? 'nats://localhost:4222';
18
40
  const subject = options.subject;
19
41
  const name = options.consumerName ?? `nats-consumer:${subject}`;
42
+ // Cleanup existing consumer with same name (handles hot-reload)
43
+ await cleanupConsumer(name);
20
44
  // 1) Discover handler classes from *.event.ts files
21
45
  const handlerConstructors = await discoverHandlers(options.discover);
22
46
  const processedHandlers = handlerConstructors
@@ -32,6 +56,8 @@ export async function consumeNatsEvents(options) {
32
56
  // 3) Subscribe to the subject
33
57
  const sub = nc.subscribe(subject);
34
58
  logger.info(`[${name}] subscribed to subject: ${subject}`);
59
+ // Track this consumer for cleanup
60
+ getConsumerRegistry().set(name, { subscription: sub, connection: nc });
35
61
  const dlqEnabled = Boolean(options.quarantineTopic || options.errorTopic);
36
62
  const { handleMessage, handleUnhandledProcessingError } = createNatsMessageProcessor({
37
63
  name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossdelta/cloudevents",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "CloudEvents toolkit for TypeScript - handler discovery, DLQ-safe processing, NATS streaming",
5
5
  "author": "crossdelta",
6
6
  "license": "MIT",
@@ -27,6 +27,10 @@
27
27
  ".": {
28
28
  "import": "./dist/src/index.js",
29
29
  "types": "./dist/src/index.d.ts"
30
+ },
31
+ "./transports/nats": {
32
+ "import": "./dist/src/transports/nats/index.js",
33
+ "types": "./dist/src/transports/nats/index.d.ts"
30
34
  }
31
35
  },
32
36
  "publishConfig": {