@crossdelta/cloudevents 0.7.7 → 0.7.9

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
@@ -130,7 +130,7 @@ Drop a `*.handler.ts` file anywhere — it's auto-registered:
130
130
  import { z } from 'zod'
131
131
 
132
132
  const UserSignupSchema = z.object({
133
- email: z.string().email(),
133
+ email: z.email(),
134
134
  name: z.string(),
135
135
  })
136
136
 
@@ -483,6 +483,38 @@ export default handleEvent({
483
483
 
484
484
  </details>
485
485
 
486
+ <details>
487
+ <summary><b>Wildcard Handler (Catch-All)</b></summary>
488
+
489
+ Use `type: '*'` to create a handler that processes **all** events, regardless of type. Useful for audit logging, metrics collection, or event replay.
490
+
491
+ ```typescript
492
+ import { handleEvent } from '@crossdelta/cloudevents'
493
+ import { z } from 'zod'
494
+
495
+ export default handleEvent(
496
+ {
497
+ type: '*',
498
+ schema: z.record(z.string(), z.unknown()),
499
+ },
500
+ async (data, context) => {
501
+ await persistAuditEvent({
502
+ eventType: context.eventType,
503
+ source: context.source,
504
+ data,
505
+ })
506
+ },
507
+ )
508
+ ```
509
+
510
+ **Routing behavior:**
511
+ - Specific handlers (`type: 'order.created'`) always take priority
512
+ - The wildcard handler runs only when no specific handler matches
513
+ - Only one wildcard handler per consumer is recommended
514
+ - Works with both JetStream and NATS Core consumers
515
+
516
+ </details>
517
+
486
518
  <details>
487
519
  <summary><b>Custom Matching</b></summary>
488
520
 
@@ -557,7 +589,7 @@ app.use('/events', cloudEvents({ discover: 'src/events/**/*.handler.ts' }))
557
589
 
558
590
  | Function | Purpose |
559
591
  |----------|---------|
560
- | `handleEvent(options, handler)` | Create a handler |
592
+ | `handleEvent(options, handler)` | Create a handler (supports `type: '*'` wildcard) |
561
593
  | `createContract(options)` | Create shared event contract |
562
594
  | `ensureJetStreams(options)` | Create/update JetStream streams |
563
595
  | `consumeJetStreams(options)` | Consume from multiple streams |
package/bin/cli.js CHANGED
@@ -161,8 +161,8 @@ var init_contract = __esm({
161
161
  string: "z.string()",
162
162
  number: "z.number()",
163
163
  boolean: "z.boolean()",
164
- date: "z.string().datetime()",
165
- datetime: "z.string().datetime()",
164
+ date: "z.iso.datetime()",
165
+ datetime: "z.iso.datetime()",
166
166
  array: "z.array(z.unknown())",
167
167
  object: "z.record(z.unknown())"
168
168
  };
@@ -331,7 +331,7 @@ export default handleEvent(${names.contractName}, async (data: ${names.typeName}
331
331
  };
332
332
  }
333
333
  });
334
- var fakerInstance, fakerLoadAttempted, tryLoadFaker, getFaker, initFaker, createFieldGenerators, generateByFieldName, generateByFormat, generateByZodType, generateMockValue, generateMockFields, generateMockContent, getMockFilePath, generateMock, generateDefaultMockFields, processMockField, generateJsonMockData, parseSchemaFromSource, getJsonMockPath, jsonMockExists, loadJsonMock, generateJsonMock, generateJsonMockFromContract;
334
+ var fakerInstance, fakerLoadAttempted, tryLoadFaker, getFaker, initFaker, createFieldGenerators, generateByFieldName, generateByFormat, generateByZodType, generateMockValue, generateMockFields, generateMockContent, getMockFilePath, generateMock, generateDefaultMockFields, processMockField, generateJsonMockData, applyFormatMatches, datetimeHint, parseSchemaFromSource, getJsonMockPath, jsonMockExists, loadJsonMock, generateJsonMock, generateJsonMockFromContract;
335
335
  var init_mock = __esm({
336
336
  "src/generators/mock.ts"() {
337
337
  init_naming();
@@ -513,28 +513,32 @@ export const create${names.pascal}Mock = (overrides: Partial<${names.typeName}>
513
513
  }
514
514
  return { data, faker: fakerHints };
515
515
  };
516
+ applyFormatMatches = (regex, schemaBody, useFaker, accumulator, hintMapper = (m) => m) => {
517
+ for (const [, fieldName, method] of schemaBody.matchAll(regex)) {
518
+ if (!(fieldName in accumulator.data)) {
519
+ accumulator.data[fieldName] = generateByFormat(method, useFaker);
520
+ accumulator.faker[fieldName] = hintMapper(method);
521
+ }
522
+ }
523
+ };
524
+ datetimeHint = (method) => method === "datetime" ? "date" : method;
516
525
  parseSchemaFromSource = (schemaBody, useFaker = false) => {
517
- const data = {};
518
- const fakerHints = {};
526
+ const accumulator = { data: {}, faker: {} };
519
527
  const fieldRegex = /(\w+):\s*z\.(\w+)\(/g;
520
- const matches = Array.from(schemaBody.matchAll(fieldRegex));
521
- for (const [, fieldName, zodType] of matches) {
528
+ for (const [, fieldName, zodType] of schemaBody.matchAll(fieldRegex)) {
522
529
  if (zodType === "array" || zodType === "object") continue;
523
530
  const byName = generateByFieldName(fieldName, useFaker);
524
531
  if (byName) {
525
- data[fieldName] = byName.value;
526
- if (byName.hint) fakerHints[fieldName] = byName.hint;
532
+ accumulator.data[fieldName] = byName.value;
533
+ if (byName.hint) accumulator.faker[fieldName] = byName.hint;
527
534
  } else {
528
- data[fieldName] = generateByZodType(zodType, useFaker) ?? "example";
535
+ accumulator.data[fieldName] = generateByZodType(zodType, useFaker) ?? "example";
529
536
  }
530
537
  }
531
- const chainedRegex = /(\w+):\s*z\.string\(\)\.(datetime|email|url|uuid)\(\)/g;
532
- const chainedMatches = Array.from(schemaBody.matchAll(chainedRegex));
533
- for (const [, fieldName, method] of chainedMatches) {
534
- data[fieldName] = generateByFormat(method, useFaker);
535
- fakerHints[fieldName] = method === "datetime" ? "date" : method;
536
- }
537
- return { data, faker: fakerHints };
538
+ applyFormatMatches(/(\w+):\s*z\.string\(\)\.(datetime|email|url|uuid)\(\)/g, schemaBody, useFaker, accumulator, datetimeHint);
539
+ applyFormatMatches(/(\w+):\s*z\.(uuid|email|url)\(\)/g, schemaBody, useFaker, accumulator);
540
+ applyFormatMatches(/(\w+):\s*z\.iso\.(datetime|date)\(\)/g, schemaBody, useFaker, accumulator, datetimeHint);
541
+ return accumulator;
538
542
  };
539
543
  getJsonMockPath = (eventType, contractsPath) => {
540
544
  const names = deriveEventNames(eventType);
package/dist/index.cjs CHANGED
@@ -441,8 +441,8 @@ var init_contract = __esm({
441
441
  string: "z.string()",
442
442
  number: "z.number()",
443
443
  boolean: "z.boolean()",
444
- date: "z.string().datetime()",
445
- datetime: "z.string().datetime()",
444
+ date: "z.iso.datetime()",
445
+ datetime: "z.iso.datetime()",
446
446
  array: "z.array(z.unknown())",
447
447
  object: "z.record(z.unknown())"
448
448
  };
@@ -611,7 +611,7 @@ export default handleEvent(${names.contractName}, async (data: ${names.typeName}
611
611
  };
612
612
  }
613
613
  });
614
- var fakerInstance, fakerLoadAttempted, tryLoadFaker, getFaker; exports.initFaker = void 0; var createFieldGenerators, generateByFieldName, generateByFormat, generateByZodType, generateMockValue, generateMockFields; exports.generateMockContent = void 0; exports.getMockFilePath = void 0; exports.generateMock = void 0; var generateDefaultMockFields, processMockField, generateJsonMockData, parseSchemaFromSource; exports.getJsonMockPath = void 0; exports.jsonMockExists = void 0; exports.loadJsonMock = void 0; exports.generateJsonMock = void 0; exports.generateJsonMockFromContract = void 0;
614
+ var fakerInstance, fakerLoadAttempted, tryLoadFaker, getFaker; exports.initFaker = void 0; var createFieldGenerators, generateByFieldName, generateByFormat, generateByZodType, generateMockValue, generateMockFields; exports.generateMockContent = void 0; exports.getMockFilePath = void 0; exports.generateMock = void 0; var generateDefaultMockFields, processMockField, generateJsonMockData, applyFormatMatches, datetimeHint, parseSchemaFromSource; exports.getJsonMockPath = void 0; exports.jsonMockExists = void 0; exports.loadJsonMock = void 0; exports.generateJsonMock = void 0; exports.generateJsonMockFromContract = void 0;
615
615
  var init_mock = __esm({
616
616
  "src/generators/mock.ts"() {
617
617
  init_naming();
@@ -793,28 +793,32 @@ export const create${names.pascal}Mock = (overrides: Partial<${names.typeName}>
793
793
  }
794
794
  return { data, faker: fakerHints };
795
795
  };
796
+ applyFormatMatches = (regex, schemaBody, useFaker, accumulator, hintMapper = (m) => m) => {
797
+ for (const [, fieldName, method] of schemaBody.matchAll(regex)) {
798
+ if (!(fieldName in accumulator.data)) {
799
+ accumulator.data[fieldName] = generateByFormat(method, useFaker);
800
+ accumulator.faker[fieldName] = hintMapper(method);
801
+ }
802
+ }
803
+ };
804
+ datetimeHint = (method) => method === "datetime" ? "date" : method;
796
805
  parseSchemaFromSource = (schemaBody, useFaker = false) => {
797
- const data = {};
798
- const fakerHints = {};
806
+ const accumulator = { data: {}, faker: {} };
799
807
  const fieldRegex = /(\w+):\s*z\.(\w+)\(/g;
800
- const matches = Array.from(schemaBody.matchAll(fieldRegex));
801
- for (const [, fieldName, zodType] of matches) {
808
+ for (const [, fieldName, zodType] of schemaBody.matchAll(fieldRegex)) {
802
809
  if (zodType === "array" || zodType === "object") continue;
803
810
  const byName = generateByFieldName(fieldName, useFaker);
804
811
  if (byName) {
805
- data[fieldName] = byName.value;
806
- if (byName.hint) fakerHints[fieldName] = byName.hint;
812
+ accumulator.data[fieldName] = byName.value;
813
+ if (byName.hint) accumulator.faker[fieldName] = byName.hint;
807
814
  } else {
808
- data[fieldName] = generateByZodType(zodType, useFaker) ?? "example";
815
+ accumulator.data[fieldName] = generateByZodType(zodType, useFaker) ?? "example";
809
816
  }
810
817
  }
811
- const chainedRegex = /(\w+):\s*z\.string\(\)\.(datetime|email|url|uuid)\(\)/g;
812
- const chainedMatches = Array.from(schemaBody.matchAll(chainedRegex));
813
- for (const [, fieldName, method] of chainedMatches) {
814
- data[fieldName] = generateByFormat(method, useFaker);
815
- fakerHints[fieldName] = method === "datetime" ? "date" : method;
816
- }
817
- return { data, faker: fakerHints };
818
+ applyFormatMatches(/(\w+):\s*z\.string\(\)\.(datetime|email|url|uuid)\(\)/g, schemaBody, useFaker, accumulator, datetimeHint);
819
+ applyFormatMatches(/(\w+):\s*z\.(uuid|email|url)\(\)/g, schemaBody, useFaker, accumulator);
820
+ applyFormatMatches(/(\w+):\s*z\.iso\.(datetime|date)\(\)/g, schemaBody, useFaker, accumulator, datetimeHint);
821
+ return accumulator;
818
822
  };
819
823
  exports.getJsonMockPath = (eventType, contractsPath) => {
820
824
  const names = exports.deriveEventNames(eventType);
@@ -2193,7 +2197,7 @@ function cloudEvents(options = {}) {
2193
2197
  // package.json
2194
2198
  var package_default = {
2195
2199
  name: "@crossdelta/cloudevents",
2196
- version: "0.7.7",
2200
+ version: "0.7.9",
2197
2201
  description: "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream & Core"};
2198
2202
 
2199
2203
  // src/plugin.ts
@@ -2348,6 +2352,8 @@ function createBaseMessageProcessor(deps) {
2348
2352
  };
2349
2353
  const findHandler = (event) => processedHandlers.find(
2350
2354
  (handler) => handler.type === event.eventType && (!handler.match || handler.match(event))
2355
+ ) ?? processedHandlers.find(
2356
+ (handler) => handler.type === "*" && (!handler.match || handler.match(event))
2351
2357
  );
2352
2358
  const handleMissingHandler = async (_context, _eventType) => {
2353
2359
  return { handled: true, shouldAck: true };
package/dist/index.js CHANGED
@@ -416,8 +416,8 @@ var init_contract = __esm({
416
416
  string: "z.string()",
417
417
  number: "z.number()",
418
418
  boolean: "z.boolean()",
419
- date: "z.string().datetime()",
420
- datetime: "z.string().datetime()",
419
+ date: "z.iso.datetime()",
420
+ datetime: "z.iso.datetime()",
421
421
  array: "z.array(z.unknown())",
422
422
  object: "z.record(z.unknown())"
423
423
  };
@@ -586,7 +586,7 @@ export default handleEvent(${names.contractName}, async (data: ${names.typeName}
586
586
  };
587
587
  }
588
588
  });
589
- var fakerInstance, fakerLoadAttempted, tryLoadFaker, getFaker, initFaker, createFieldGenerators, generateByFieldName, generateByFormat, generateByZodType, generateMockValue, generateMockFields, generateMockContent, getMockFilePath, generateMock, generateDefaultMockFields, processMockField, generateJsonMockData, parseSchemaFromSource, getJsonMockPath, jsonMockExists, loadJsonMock, generateJsonMock, generateJsonMockFromContract;
589
+ var fakerInstance, fakerLoadAttempted, tryLoadFaker, getFaker, initFaker, createFieldGenerators, generateByFieldName, generateByFormat, generateByZodType, generateMockValue, generateMockFields, generateMockContent, getMockFilePath, generateMock, generateDefaultMockFields, processMockField, generateJsonMockData, applyFormatMatches, datetimeHint, parseSchemaFromSource, getJsonMockPath, jsonMockExists, loadJsonMock, generateJsonMock, generateJsonMockFromContract;
590
590
  var init_mock = __esm({
591
591
  "src/generators/mock.ts"() {
592
592
  init_naming();
@@ -768,28 +768,32 @@ export const create${names.pascal}Mock = (overrides: Partial<${names.typeName}>
768
768
  }
769
769
  return { data, faker: fakerHints };
770
770
  };
771
+ applyFormatMatches = (regex, schemaBody, useFaker, accumulator, hintMapper = (m) => m) => {
772
+ for (const [, fieldName, method] of schemaBody.matchAll(regex)) {
773
+ if (!(fieldName in accumulator.data)) {
774
+ accumulator.data[fieldName] = generateByFormat(method, useFaker);
775
+ accumulator.faker[fieldName] = hintMapper(method);
776
+ }
777
+ }
778
+ };
779
+ datetimeHint = (method) => method === "datetime" ? "date" : method;
771
780
  parseSchemaFromSource = (schemaBody, useFaker = false) => {
772
- const data = {};
773
- const fakerHints = {};
781
+ const accumulator = { data: {}, faker: {} };
774
782
  const fieldRegex = /(\w+):\s*z\.(\w+)\(/g;
775
- const matches = Array.from(schemaBody.matchAll(fieldRegex));
776
- for (const [, fieldName, zodType] of matches) {
783
+ for (const [, fieldName, zodType] of schemaBody.matchAll(fieldRegex)) {
777
784
  if (zodType === "array" || zodType === "object") continue;
778
785
  const byName = generateByFieldName(fieldName, useFaker);
779
786
  if (byName) {
780
- data[fieldName] = byName.value;
781
- if (byName.hint) fakerHints[fieldName] = byName.hint;
787
+ accumulator.data[fieldName] = byName.value;
788
+ if (byName.hint) accumulator.faker[fieldName] = byName.hint;
782
789
  } else {
783
- data[fieldName] = generateByZodType(zodType, useFaker) ?? "example";
790
+ accumulator.data[fieldName] = generateByZodType(zodType, useFaker) ?? "example";
784
791
  }
785
792
  }
786
- const chainedRegex = /(\w+):\s*z\.string\(\)\.(datetime|email|url|uuid)\(\)/g;
787
- const chainedMatches = Array.from(schemaBody.matchAll(chainedRegex));
788
- for (const [, fieldName, method] of chainedMatches) {
789
- data[fieldName] = generateByFormat(method, useFaker);
790
- fakerHints[fieldName] = method === "datetime" ? "date" : method;
791
- }
792
- return { data, faker: fakerHints };
793
+ applyFormatMatches(/(\w+):\s*z\.string\(\)\.(datetime|email|url|uuid)\(\)/g, schemaBody, useFaker, accumulator, datetimeHint);
794
+ applyFormatMatches(/(\w+):\s*z\.(uuid|email|url)\(\)/g, schemaBody, useFaker, accumulator);
795
+ applyFormatMatches(/(\w+):\s*z\.iso\.(datetime|date)\(\)/g, schemaBody, useFaker, accumulator, datetimeHint);
796
+ return accumulator;
793
797
  };
794
798
  getJsonMockPath = (eventType, contractsPath) => {
795
799
  const names = deriveEventNames(eventType);
@@ -2168,7 +2172,7 @@ function cloudEvents(options = {}) {
2168
2172
  // package.json
2169
2173
  var package_default = {
2170
2174
  name: "@crossdelta/cloudevents",
2171
- version: "0.7.7",
2175
+ version: "0.7.9",
2172
2176
  description: "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream & Core"};
2173
2177
 
2174
2178
  // src/plugin.ts
@@ -2323,6 +2327,8 @@ function createBaseMessageProcessor(deps) {
2323
2327
  };
2324
2328
  const findHandler = (event) => processedHandlers.find(
2325
2329
  (handler) => handler.type === event.eventType && (!handler.match || handler.match(event))
2330
+ ) ?? processedHandlers.find(
2331
+ (handler) => handler.type === "*" && (!handler.match || handler.match(event))
2326
2332
  );
2327
2333
  const handleMissingHandler = async (_context, _eventType) => {
2328
2334
  return { handled: true, shouldAck: true };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossdelta/cloudevents",
3
- "version": "0.7.7",
3
+ "version": "0.7.9",
4
4
  "description": "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream & Core",
5
5
  "author": "crossdelta",
6
6
  "license": "MIT",