@crossdelta/cloudevents 0.6.2 → 0.6.4

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/dist/index.cjs CHANGED
@@ -1,14 +1,40 @@
1
1
  'use strict';
2
2
 
3
3
  var cloudevents = require('cloudevents');
4
+ var pluralizeLib = require('pluralize');
4
5
  var fs = require('fs');
5
6
  var path = require('path');
7
+ var flowcore = require('@crossdelta/flowcore');
6
8
  var url = require('url');
7
9
  var glob = require('glob');
8
10
  var zod = require('zod');
9
11
  var nats = require('nats');
10
12
 
11
13
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
14
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
+
16
+ function _interopNamespace(e) {
17
+ if (e && e.__esModule) return e;
18
+ var n = Object.create(null);
19
+ if (e) {
20
+ Object.keys(e).forEach(function (k) {
21
+ if (k !== 'default') {
22
+ var d = Object.getOwnPropertyDescriptor(e, k);
23
+ Object.defineProperty(n, k, d.get ? d : {
24
+ enumerable: true,
25
+ get: function () { return e[k]; }
26
+ });
27
+ }
28
+ });
29
+ }
30
+ n.default = e;
31
+ return Object.freeze(n);
32
+ }
33
+
34
+ var pluralizeLib__default = /*#__PURE__*/_interopDefault(pluralizeLib);
35
+ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
36
+ var path__namespace = /*#__PURE__*/_interopNamespace(path);
37
+
12
38
  var __defProp = Object.defineProperty;
13
39
  var __getOwnPropNames = Object.getOwnPropertyNames;
14
40
  var __esm = (fn, res) => function __init() {
@@ -20,9 +46,26 @@ var __export = (target, all) => {
20
46
  };
21
47
 
22
48
  // src/infrastructure/errors.ts
23
- var handleErrorWithContext, createValidationError, createCloudEventParseError;
49
+ var ValidationError, CloudEventParseError, handleErrorWithContext, createValidationError, createCloudEventParseError;
24
50
  var init_errors = __esm({
25
51
  "src/infrastructure/errors.ts"() {
52
+ ValidationError = class extends Error {
53
+ constructor(eventType, details) {
54
+ super(`Validation failed for event type: ${eventType}`);
55
+ this.eventType = eventType;
56
+ this.details = details;
57
+ this.name = "ValidationError";
58
+ }
59
+ type = "ValidationError";
60
+ };
61
+ CloudEventParseError = class extends Error {
62
+ constructor(message, cause) {
63
+ super(message);
64
+ this.cause = cause;
65
+ this.name = "CloudEventParseError";
66
+ }
67
+ type = "CloudEventParseError";
68
+ };
26
69
  handleErrorWithContext = (error, context, additionalInfo) => {
27
70
  const errorInfo = {
28
71
  message: error.message,
@@ -35,17 +78,8 @@ var init_errors = __esm({
35
78
  console.error("[Error Handler]", JSON.stringify(errorInfo, null, 2));
36
79
  return errorInfo;
37
80
  };
38
- createValidationError = (eventType, details) => ({
39
- type: "ValidationError",
40
- eventType,
41
- message: `Validation failed for event type: ${eventType}`,
42
- details
43
- });
44
- createCloudEventParseError = (message, cause) => ({
45
- type: "CloudEventParseError",
46
- message,
47
- cause
48
- });
81
+ createValidationError = (eventType, details) => new ValidationError(eventType, details);
82
+ createCloudEventParseError = (message, cause) => new CloudEventParseError(message, cause);
49
83
  }
50
84
  });
51
85
 
@@ -219,46 +253,842 @@ var init_raw_event = __esm({
219
253
  };
220
254
  }
221
255
  });
256
+ exports.pluralize = void 0; exports.singularize = void 0;
257
+ var init_pluralize = __esm({
258
+ "src/utils/pluralize.ts"() {
259
+ exports.pluralize = (word) => pluralizeLib__default.default.plural(word);
260
+ exports.singularize = (word) => pluralizeLib__default.default.singular(word);
261
+ }
262
+ });
222
263
 
223
- // src/adapters/cloudevents/cloudevents.ts
224
- init_infrastructure();
225
- var hasCloudEventHeaders = (headers) => Object.keys(headers).some((key) => key.toLowerCase().startsWith("ce-"));
226
- var isRecord = (value) => typeof value === "object" && value !== null;
227
- var parseEventFromContext = async (context) => {
228
- try {
229
- const headers = context.req.header();
230
- const rawBody = await context.req.text();
231
- let parsedBody;
232
- if (rawBody?.length) {
264
+ // src/utils/index.ts
265
+ var init_utils = __esm({
266
+ "src/utils/index.ts"() {
267
+ init_pluralize();
268
+ }
269
+ });
270
+
271
+ // src/domain/naming.ts
272
+ exports.toKebabCase = void 0; exports.toPascalCase = void 0; exports.validateEventType = void 0; exports.isValidEventType = void 0; exports.deriveEventNames = void 0; exports.getContractPaths = void 0; exports.getHandlerPath = void 0; exports.getStreamName = void 0; exports.parseEventTypeFromHandler = void 0; exports.parseEventTypeFromContract = void 0; exports.normalizeSubject = void 0;
273
+ var init_naming = __esm({
274
+ "src/domain/naming.ts"() {
275
+ init_utils();
276
+ exports.toKebabCase = (str) => str.replace(/\./g, "-").toLowerCase();
277
+ exports.toPascalCase = (str) => str.split(/[-.]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
278
+ exports.validateEventType = (eventType) => {
279
+ const errors = [];
280
+ if (!eventType) {
281
+ errors.push("Event type is required");
282
+ return { valid: false, errors };
283
+ }
284
+ if (!eventType.includes(".")) {
285
+ errors.push("Event type must include a namespace separator (e.g., order.created)");
286
+ }
287
+ if (eventType !== eventType.toLowerCase()) {
288
+ errors.push("Event type must be lowercase");
289
+ }
290
+ if (eventType.startsWith(".") || eventType.endsWith(".")) {
291
+ errors.push("Event type must not start or end with a dot");
292
+ }
293
+ if (eventType.includes("..")) {
294
+ errors.push("Event type must not contain consecutive dots");
295
+ }
296
+ const validChars = /^[a-z0-9.-]+$/;
297
+ if (!validChars.test(eventType)) {
298
+ errors.push("Event type must only contain lowercase letters, numbers, dots, and dashes");
299
+ }
300
+ return {
301
+ valid: errors.length === 0,
302
+ errors
303
+ };
304
+ };
305
+ exports.isValidEventType = (eventType) => exports.validateEventType(eventType).valid;
306
+ exports.deriveEventNames = (eventType) => {
307
+ const parts = eventType.split(".");
308
+ const namespace = parts[0];
309
+ const action = parts.slice(1).join("-");
310
+ const kebab = exports.toKebabCase(eventType);
311
+ const pascal = exports.toPascalCase(eventType);
312
+ const pluralNamespace = exports.pluralize(namespace);
313
+ const pluralPascal = exports.toPascalCase(`${pluralNamespace}.${action}`);
314
+ return {
315
+ eventType,
316
+ kebab,
317
+ pascal,
318
+ schemaName: `${pascal}Schema`,
319
+ typeName: `${pascal}Data`,
320
+ contractName: `${pluralPascal}Contract`,
321
+ handlerFile: `${kebab}.handler.ts`,
322
+ streamName: pluralNamespace.toUpperCase(),
323
+ domain: pluralNamespace.toLowerCase(),
324
+ action,
325
+ namespace
326
+ };
327
+ };
328
+ exports.getContractPaths = (eventType) => {
329
+ const { domain, action } = exports.deriveEventNames(eventType);
330
+ return {
331
+ relativePath: `events/${domain}/${action}.ts`,
332
+ folder: domain,
333
+ filename: action
334
+ };
335
+ };
336
+ exports.getHandlerPath = (eventType) => {
337
+ const { handlerFile } = exports.deriveEventNames(eventType);
338
+ return `events/${handlerFile}`;
339
+ };
340
+ exports.getStreamName = (eventType) => exports.deriveEventNames(eventType).streamName;
341
+ exports.parseEventTypeFromHandler = (filename) => {
342
+ const match = filename.match(/^(.+)\.handler\.ts$/);
343
+ if (!match) return null;
344
+ const kebab = match[1];
345
+ const parts = kebab.split("-");
346
+ if (parts.length < 2) return null;
347
+ const action = parts.at(-1);
348
+ if (!action) return null;
349
+ const namespace = parts.slice(0, -1).join("-");
350
+ return `${namespace}.${action}`;
351
+ };
352
+ exports.parseEventTypeFromContract = (path2) => {
353
+ const cleanPath = path2.replace(/^events\//, "");
354
+ const match = cleanPath.match(/^([^/]+)\/(.+)\.ts$/);
355
+ if (!match) return null;
356
+ const [, folder, filename] = match;
357
+ const namespace = exports.singularize(folder);
358
+ return `${namespace}.${filename}`;
359
+ };
360
+ exports.normalizeSubject = (eventType) => {
361
+ const { domain, action } = exports.deriveEventNames(eventType);
362
+ return `${domain}.${action}`;
363
+ };
364
+ }
365
+ });
366
+
367
+ // src/effects/types.ts
368
+ exports.streamWired = void 0; exports.contractCreated = void 0; exports.handlerCreated = void 0;
369
+ var init_types = __esm({
370
+ "src/effects/types.ts"() {
371
+ exports.streamWired = (stream, servicePath) => ({
372
+ kind: "stream.wired",
373
+ stream,
374
+ servicePath
375
+ });
376
+ exports.contractCreated = (path2, eventType) => ({
377
+ kind: "contract.created",
378
+ path: path2,
379
+ eventType
380
+ });
381
+ exports.handlerCreated = (path2, eventType, servicePath) => ({
382
+ kind: "handler.created",
383
+ path: path2,
384
+ eventType,
385
+ servicePath
386
+ });
387
+ }
388
+ });
389
+
390
+ // src/effects/index.ts
391
+ var init_effects = __esm({
392
+ "src/effects/index.ts"() {
393
+ init_types();
394
+ }
395
+ });
396
+ var createNodeFileSystem; exports.createMemoryFileSystem = void 0;
397
+ var init_types2 = __esm({
398
+ "src/generators/types.ts"() {
399
+ createNodeFileSystem = () => {
400
+ return {
401
+ readFile: (filePath) => {
402
+ try {
403
+ return fs__namespace.readFileSync(filePath, "utf-8");
404
+ } catch {
405
+ return null;
406
+ }
407
+ },
408
+ writeFile: (filePath, content) => {
409
+ const dir = path__namespace.dirname(filePath);
410
+ if (!fs__namespace.existsSync(dir)) {
411
+ fs__namespace.mkdirSync(dir, { recursive: true });
412
+ }
413
+ fs__namespace.writeFileSync(filePath, content, "utf-8");
414
+ },
415
+ exists: (filePath) => fs__namespace.existsSync(filePath),
416
+ mkdir: (dirPath) => fs__namespace.mkdirSync(dirPath, { recursive: true })
417
+ };
418
+ };
419
+ exports.createMemoryFileSystem = (initialFiles = {}) => {
420
+ const files = { ...initialFiles };
421
+ return {
422
+ files,
423
+ readFile: (path2) => files[path2] ?? null,
424
+ writeFile: (path2, content) => {
425
+ files[path2] = content;
426
+ },
427
+ exists: (path2) => path2 in files,
428
+ mkdir: () => {
429
+ }
430
+ };
431
+ };
432
+ }
433
+ });
434
+ var fieldTypeToZod, generateSchemaFields; exports.generateContractContent = void 0; exports.getContractFilePath = void 0; exports.generateContract = void 0;
435
+ var init_contract = __esm({
436
+ "src/generators/contract.ts"() {
437
+ init_naming();
438
+ init_types2();
439
+ fieldTypeToZod = (type, optional) => {
440
+ const baseTypes = {
441
+ string: "z.string()",
442
+ number: "z.number()",
443
+ boolean: "z.boolean()",
444
+ date: "z.string().datetime()",
445
+ datetime: "z.string().datetime()",
446
+ array: "z.array(z.unknown())",
447
+ object: "z.record(z.unknown())"
448
+ };
449
+ const base = baseTypes[type];
450
+ return optional ? `${base}.optional()` : base;
451
+ };
452
+ generateSchemaFields = (fields) => {
453
+ if (!fields || fields.length === 0) {
454
+ return ` id: z.string(),
455
+ createdAt: z.string(),`;
456
+ }
457
+ return fields.map((field) => ` ${field.name}: ${fieldTypeToZod(field.type, field.optional)},`).join("\n");
458
+ };
459
+ exports.generateContractContent = (options) => {
460
+ const { eventType, fields } = options;
461
+ const names = exports.deriveEventNames(eventType);
462
+ const schemaFields = generateSchemaFields(fields);
463
+ const schemaBody = schemaFields ? `{
464
+ ${schemaFields}
465
+ }` : "{}";
466
+ return `import { createContract } from '@crossdelta/cloudevents'
467
+ import { z } from 'zod'
468
+
469
+ export const ${names.schemaName} = z.object(${schemaBody})
470
+
471
+ export const ${names.contractName} = createContract({
472
+ type: '${eventType}',
473
+ channel: { stream: '${names.streamName}' },
474
+ schema: ${names.schemaName},
475
+ })
476
+
477
+ export type ${names.typeName} = z.infer<typeof ${names.contractName}.schema>
478
+ `;
479
+ };
480
+ exports.getContractFilePath = (eventType, basePath) => {
481
+ const paths = exports.getContractPaths(eventType);
482
+ return `${basePath}/${paths.relativePath}`;
483
+ };
484
+ exports.generateContract = (options, fs2 = createNodeFileSystem()) => {
485
+ const filePath = exports.getContractFilePath(options.eventType, options.basePath);
486
+ const content = exports.generateContractContent(options);
487
+ const exists = fs2.exists(filePath);
488
+ if (!exists) {
489
+ fs2.writeFile(filePath, content);
490
+ return flowcore.change.created(filePath);
491
+ }
492
+ if (options.force) {
493
+ fs2.writeFile(filePath, content);
494
+ return flowcore.change.updated(filePath);
495
+ }
496
+ return flowcore.change.skipped("File already exists");
497
+ };
498
+ }
499
+ });
500
+
501
+ // src/generators/exports.ts
502
+ var hasExport, addExportToIndex, ensureDomainExport;
503
+ var init_exports = __esm({
504
+ "src/generators/exports.ts"() {
505
+ init_types2();
506
+ hasExport = (content, exportPath) => {
507
+ const patterns = [
508
+ new RegExp(`^\\s*export \\* from ['"]${exportPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}['"]`, "m"),
509
+ new RegExp(`^\\s*export \\* from ['"]${exportPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.ts['"]`, "m")
510
+ ];
511
+ return patterns.some((p) => p.test(content));
512
+ };
513
+ addExportToIndex = (options, fs2 = createNodeFileSystem()) => {
514
+ const { indexPath, exportPath, force } = options;
515
+ if (!fs2.exists(indexPath)) {
516
+ fs2.writeFile(indexPath, `export * from '${exportPath}'
517
+ `);
518
+ return { added: true, path: indexPath };
519
+ }
520
+ const content = fs2.readFile(indexPath);
521
+ if (!content) {
522
+ fs2.writeFile(indexPath, `export * from '${exportPath}'
523
+ `);
524
+ return { added: true, path: indexPath };
525
+ }
526
+ if (!force && hasExport(content, exportPath)) {
527
+ return { added: false, path: indexPath, alreadyExists: true };
528
+ }
529
+ const commentedExport = new RegExp(`//\\s*export \\* from ['"]${exportPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}['"]`);
530
+ let newContent;
531
+ if (commentedExport.test(content)) {
532
+ newContent = content.replace(commentedExport, `export * from '${exportPath}'`);
533
+ } else {
534
+ const trimmed = content.trimEnd();
535
+ newContent = trimmed.length > 0 ? `${trimmed}
536
+ export * from '${exportPath}'
537
+ ` : `export * from '${exportPath}'
538
+ `;
539
+ }
540
+ fs2.writeFile(indexPath, newContent);
541
+ return { added: true, path: indexPath };
542
+ };
543
+ ensureDomainExport = (options, fs2 = createNodeFileSystem()) => {
544
+ const results = [];
545
+ const { contractsBasePath, domain, eventFile } = options;
546
+ const eventsIndexPath = `${contractsBasePath}/events/index.ts`;
547
+ const domainExportResult = addExportToIndex(
548
+ {
549
+ indexPath: eventsIndexPath,
550
+ exportPath: `./${domain}`
551
+ },
552
+ fs2
553
+ );
554
+ results.push(domainExportResult);
555
+ const domainIndexPath = `${contractsBasePath}/events/${domain}/index.ts`;
556
+ const eventExportResult = addExportToIndex(
557
+ {
558
+ indexPath: domainIndexPath,
559
+ exportPath: `./${eventFile}`
560
+ },
561
+ fs2
562
+ );
563
+ results.push(eventExportResult);
564
+ const mainIndexPath = `${contractsBasePath}/index.ts`;
565
+ const mainExportResult = addExportToIndex(
566
+ {
567
+ indexPath: mainIndexPath,
568
+ exportPath: "./events"
569
+ },
570
+ fs2
571
+ );
572
+ results.push(mainExportResult);
573
+ return results;
574
+ };
575
+ }
576
+ });
577
+ exports.generateEventHandlerContent = void 0; exports.getHandlerFilePath = void 0; exports.generateEventHandler = void 0;
578
+ var init_handler = __esm({
579
+ "src/generators/handler.ts"() {
580
+ init_naming();
581
+ init_types2();
582
+ exports.generateEventHandlerContent = (options) => {
583
+ const { eventType, contractsPackage = "@crossdelta/contracts" } = options;
584
+ const names = exports.deriveEventNames(eventType);
585
+ return `import { handleEvent } from '@crossdelta/cloudevents'
586
+ import { ${names.contractName}, type ${names.typeName} } from '${contractsPackage}'
587
+
588
+ export default handleEvent(${names.contractName}, async (data: ${names.typeName}) => {
589
+ // TODO: Implement event handling logic
590
+ console.log('Received ${eventType}:', data)
591
+ })
592
+ `;
593
+ };
594
+ exports.getHandlerFilePath = (eventType, basePath) => {
595
+ const handlerPath = exports.getHandlerPath(eventType);
596
+ return `${basePath}/${handlerPath}`;
597
+ };
598
+ exports.generateEventHandler = (options, fs2 = createNodeFileSystem()) => {
599
+ const filePath = exports.getHandlerFilePath(options.eventType, options.basePath);
600
+ const content = exports.generateEventHandlerContent(options);
601
+ const exists = fs2.exists(filePath);
602
+ if (!exists) {
603
+ fs2.writeFile(filePath, content);
604
+ return flowcore.change.created(filePath);
605
+ }
606
+ if (options.force) {
607
+ fs2.writeFile(filePath, content);
608
+ return flowcore.change.updated(filePath);
609
+ }
610
+ return flowcore.change.skipped("File already exists");
611
+ };
612
+ }
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;
615
+ var init_mock = __esm({
616
+ "src/generators/mock.ts"() {
617
+ init_naming();
618
+ init_types2();
619
+ fakerInstance = null;
620
+ fakerLoadAttempted = false;
621
+ tryLoadFaker = async () => {
622
+ if (fakerLoadAttempted) return fakerInstance;
623
+ fakerLoadAttempted = true;
233
624
  try {
234
- parsedBody = JSON.parse(rawBody);
625
+ const { faker } = await import('@faker-js/faker');
626
+ fakerInstance = faker;
627
+ return faker;
235
628
  } catch {
236
- parsedBody = void 0;
629
+ return null;
237
630
  }
238
- }
239
- const bodyObject = isRecord(parsedBody) ? parsedBody : void 0;
240
- if (bodyObject && "specversion" in bodyObject) {
241
- const { parseStructuredMode: parseStructuredMode2 } = await Promise.resolve().then(() => (init_structured_mode(), structured_mode_exports));
242
- return parseStructuredMode2(bodyObject);
243
- }
244
- if (bodyObject && "message" in bodyObject) {
245
- const { parsePubSubMessage: parsePubSubMessage2 } = await Promise.resolve().then(() => (init_pubsub(), pubsub_exports));
246
- return await parsePubSubMessage2(bodyObject, headers);
247
- }
248
- if (hasCloudEventHeaders(headers)) {
249
- const { parseBinaryMode: parseBinaryMode2 } = await Promise.resolve().then(() => (init_binary_mode(), binary_mode_exports));
250
- return await parseBinaryMode2(headers, rawBody);
251
- }
252
- const { parseRawEvent: parseRawEvent2 } = await Promise.resolve().then(() => (init_raw_event(), raw_event_exports));
253
- if (bodyObject) {
254
- return parseRawEvent2(bodyObject);
255
- }
256
- return parseRawEvent2({ raw: rawBody });
257
- } catch (error) {
258
- logger.error("Failed to parse event:", error);
259
- throw new Error(`Failed to parse CloudEvent: ${error instanceof Error ? error.message : "Unknown error"}`);
631
+ };
632
+ getFaker = () => fakerInstance;
633
+ exports.initFaker = async () => {
634
+ const faker = await tryLoadFaker();
635
+ return faker !== null;
636
+ };
637
+ createFieldGenerators = () => [
638
+ { pattern: "email", generate: () => "user@example.com", fakerGenerate: () => getFaker()?.internet.email(), hint: "email" },
639
+ { pattern: "id", generate: () => crypto.randomUUID(), fakerGenerate: () => getFaker()?.string.uuid(), hint: "uuid" },
640
+ { pattern: "firstname", generate: () => "John", fakerGenerate: () => getFaker()?.person.firstName(), hint: "firstName" },
641
+ { pattern: "lastname", generate: () => "Doe", fakerGenerate: () => getFaker()?.person.lastName(), hint: "lastName" },
642
+ { pattern: "name", generate: () => "John Doe", fakerGenerate: () => getFaker()?.person.fullName(), hint: "fullName" },
643
+ { pattern: "phone", generate: () => "+1-555-123-4567", fakerGenerate: () => getFaker()?.phone.number(), hint: "phoneNumber" },
644
+ { pattern: "address", generate: () => "123 Main St", fakerGenerate: () => getFaker()?.location.streetAddress(), hint: "streetAddress" },
645
+ { pattern: "street", generate: () => "123 Main St", fakerGenerate: () => getFaker()?.location.streetAddress(), hint: "streetAddress" },
646
+ { pattern: "city", generate: () => "New York", fakerGenerate: () => getFaker()?.location.city(), hint: "city" },
647
+ { pattern: "country", generate: () => "USA", fakerGenerate: () => getFaker()?.location.country(), hint: "country" },
648
+ { pattern: "price", generate: () => 99.99, fakerGenerate: () => getFaker()?.number.float({ min: 10, max: 1e3, fractionDigits: 2 }), hint: "price" },
649
+ { pattern: "amount", generate: () => 99.99, fakerGenerate: () => getFaker()?.number.float({ min: 10, max: 1e3, fractionDigits: 2 }), hint: "price" },
650
+ { pattern: "total", generate: () => 99.99, fakerGenerate: () => getFaker()?.number.float({ min: 10, max: 1e3, fractionDigits: 2 }), hint: "price" },
651
+ { pattern: "quantity", generate: () => 1, fakerGenerate: () => getFaker()?.number.int({ min: 1, max: 10 }), hint: "quantity" },
652
+ { pattern: "date", generate: () => (/* @__PURE__ */ new Date()).toISOString(), fakerGenerate: () => getFaker()?.date.recent().toISOString(), hint: "date" },
653
+ { pattern: "createdat", generate: () => (/* @__PURE__ */ new Date()).toISOString(), fakerGenerate: () => getFaker()?.date.recent().toISOString(), hint: "date" },
654
+ { pattern: "updatedat", generate: () => (/* @__PURE__ */ new Date()).toISOString(), fakerGenerate: () => getFaker()?.date.recent().toISOString(), hint: "date" }
655
+ ];
656
+ generateByFieldName = (fieldName, useFaker = false) => {
657
+ const generators = createFieldGenerators();
658
+ const lowerField = fieldName.toLowerCase();
659
+ const matched = generators.find((g) => lowerField.includes(g.pattern));
660
+ if (!matched) return null;
661
+ const value = (useFaker ? matched.fakerGenerate?.() : void 0) ?? matched.generate();
662
+ return { value, hint: matched.hint };
663
+ };
664
+ generateByFormat = (format, useFaker = false) => {
665
+ const faker = getFaker();
666
+ const formatGenerators = {
667
+ email: {
668
+ static: () => "user@example.com",
669
+ faker: faker ? () => faker.internet.email() : void 0
670
+ },
671
+ datetime: {
672
+ static: () => (/* @__PURE__ */ new Date()).toISOString(),
673
+ faker: faker ? () => faker.date.recent().toISOString() : void 0
674
+ },
675
+ url: {
676
+ static: () => "https://example.com",
677
+ faker: faker ? () => faker.internet.url() : void 0
678
+ },
679
+ uuid: {
680
+ static: () => crypto.randomUUID(),
681
+ faker: faker ? () => faker.string.uuid() : void 0
682
+ },
683
+ date: {
684
+ static: () => (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
685
+ faker: faker ? () => faker.date.recent().toISOString().split("T")[0] : void 0
686
+ },
687
+ time: {
688
+ static: () => (/* @__PURE__ */ new Date()).toISOString().split("T")[1]?.split(".")[0],
689
+ faker: faker ? () => faker.date.recent().toISOString().split("T")[1]?.split(".")[0] : void 0
690
+ }
691
+ };
692
+ const gen = formatGenerators[format];
693
+ if (!gen) return "example";
694
+ return useFaker && gen.faker ? gen.faker() : gen.static();
695
+ };
696
+ generateByZodType = (zodType, useFaker = false) => {
697
+ const faker = getFaker();
698
+ const typeGenerators = {
699
+ string: {
700
+ static: () => "example",
701
+ faker: faker ? () => faker.lorem.word() : void 0
702
+ },
703
+ number: {
704
+ static: () => 42,
705
+ faker: faker ? () => faker.number.int({ min: 1, max: 100 }) : void 0
706
+ },
707
+ boolean: {
708
+ static: () => true,
709
+ faker: faker ? () => faker.datatype.boolean() : void 0
710
+ }
711
+ };
712
+ const gen = typeGenerators[zodType];
713
+ if (!gen) return void 0;
714
+ return useFaker && gen.faker ? gen.faker() : gen.static();
715
+ };
716
+ generateMockValue = (type) => {
717
+ const mockValues = {
718
+ string: "'mock-string'",
719
+ number: "42",
720
+ boolean: "true",
721
+ date: "new Date().toISOString()",
722
+ datetime: "new Date().toISOString()",
723
+ array: "[]",
724
+ object: "{}"
725
+ };
726
+ return mockValues[type];
727
+ };
728
+ generateMockFields = (fields) => {
729
+ if (!fields || fields.length === 0) {
730
+ return ` id: 'mock-id',
731
+ createdAt: new Date().toISOString(),`;
732
+ }
733
+ return fields.filter((field) => !field.optional).map((field) => ` ${field.name}: ${generateMockValue(field.type)},`).join("\n");
734
+ };
735
+ exports.generateMockContent = (options) => {
736
+ const { eventType, fields } = options;
737
+ const names = exports.deriveEventNames(eventType);
738
+ return `import type { ${names.typeName} } from '../${names.domain}/${names.action}'
739
+
740
+ export const mock${names.pascal}: ${names.typeName} = {
741
+ ${generateMockFields(fields)}
742
+ }
743
+
744
+ export const create${names.pascal}Mock = (overrides: Partial<${names.typeName}> = {}): ${names.typeName} => ({
745
+ ...mock${names.pascal},
746
+ ...overrides,
747
+ })
748
+ `;
749
+ };
750
+ exports.getMockFilePath = (eventType, basePath) => {
751
+ const names = exports.deriveEventNames(eventType);
752
+ return `${basePath}/${names.kebab}.mock.ts`;
753
+ };
754
+ exports.generateMock = (options, fs2 = createNodeFileSystem()) => {
755
+ const filePath = exports.getMockFilePath(options.eventType, options.basePath);
756
+ const content = exports.generateMockContent(options);
757
+ const exists = fs2.exists(filePath);
758
+ if (!exists) {
759
+ fs2.writeFile(filePath, content);
760
+ return flowcore.change.created(filePath);
761
+ }
762
+ if (options.force) {
763
+ fs2.writeFile(filePath, content);
764
+ return flowcore.change.updated(filePath);
765
+ }
766
+ return flowcore.change.skipped("File already exists");
767
+ };
768
+ generateDefaultMockFields = (useFaker) => ({
769
+ data: {
770
+ id: (useFaker ? getFaker()?.string.uuid() : void 0) ?? crypto.randomUUID(),
771
+ createdAt: (useFaker ? getFaker()?.date.recent().toISOString() : void 0) ?? (/* @__PURE__ */ new Date()).toISOString()
772
+ },
773
+ faker: { id: "uuid", createdAt: "date" }
774
+ });
775
+ processMockField = (field, useFaker, data, fakerHints) => {
776
+ const byName = generateByFieldName(field.name, useFaker);
777
+ if (byName) {
778
+ data[field.name] = byName.value;
779
+ if (byName.hint) fakerHints[field.name] = byName.hint;
780
+ } else {
781
+ data[field.name] = generateByZodType(field.type, useFaker) ?? "example";
782
+ }
783
+ };
784
+ generateJsonMockData = (options = {}) => {
785
+ const { fields, useFaker = false } = options;
786
+ if (!fields || fields.length === 0) {
787
+ return generateDefaultMockFields(useFaker);
788
+ }
789
+ const data = {};
790
+ const fakerHints = {};
791
+ for (const field of fields) {
792
+ if (!field.optional) processMockField(field, useFaker, data, fakerHints);
793
+ }
794
+ return { data, faker: fakerHints };
795
+ };
796
+ parseSchemaFromSource = (schemaBody, useFaker = false) => {
797
+ const data = {};
798
+ const fakerHints = {};
799
+ const fieldRegex = /(\w+):\s*z\.(\w+)\(/g;
800
+ const matches = Array.from(schemaBody.matchAll(fieldRegex));
801
+ for (const [, fieldName, zodType] of matches) {
802
+ if (zodType === "array" || zodType === "object") continue;
803
+ const byName = generateByFieldName(fieldName, useFaker);
804
+ if (byName) {
805
+ data[fieldName] = byName.value;
806
+ if (byName.hint) fakerHints[fieldName] = byName.hint;
807
+ } else {
808
+ data[fieldName] = generateByZodType(zodType, useFaker) ?? "example";
809
+ }
810
+ }
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
+ };
819
+ exports.getJsonMockPath = (eventType, contractsPath) => {
820
+ const names = exports.deriveEventNames(eventType);
821
+ return `${contractsPath}/events/${names.domain}/${names.action}.mock.json`;
822
+ };
823
+ exports.jsonMockExists = (eventType, contractsPath, fs2 = createNodeFileSystem()) => fs2.exists(exports.getJsonMockPath(eventType, contractsPath));
824
+ exports.loadJsonMock = (eventType, contractsPath, fs2 = createNodeFileSystem()) => {
825
+ const mockPath = exports.getJsonMockPath(eventType, contractsPath);
826
+ const content = fs2.readFile(mockPath);
827
+ if (!content) return null;
828
+ try {
829
+ return JSON.parse(content);
830
+ } catch {
831
+ return null;
832
+ }
833
+ };
834
+ exports.generateJsonMock = (options, fs2 = createNodeFileSystem()) => {
835
+ const { eventType, contractsPath, fields, force, useFaker = false } = options;
836
+ const mockPath = exports.getJsonMockPath(eventType, contractsPath);
837
+ const exists = fs2.exists(mockPath);
838
+ const { data, faker: fakerHints } = generateJsonMockData({ fields, useFaker });
839
+ const mockData = {
840
+ eventName: eventType,
841
+ description: `Mock data for ${eventType} event`,
842
+ data
843
+ };
844
+ if (Object.keys(fakerHints).length > 0) {
845
+ mockData.faker = fakerHints;
846
+ }
847
+ const content = JSON.stringify(mockData, null, 2);
848
+ if (!exists) {
849
+ fs2.writeFile(mockPath, content);
850
+ return flowcore.change.created(mockPath);
851
+ }
852
+ if (force) {
853
+ fs2.writeFile(mockPath, content);
854
+ return flowcore.change.updated(mockPath);
855
+ }
856
+ return flowcore.change.skipped("File already exists");
857
+ };
858
+ exports.generateJsonMockFromContract = (eventType, contractsPath, options = {}, fs2 = createNodeFileSystem()) => {
859
+ const { useFaker = false } = options;
860
+ const names = exports.deriveEventNames(eventType);
861
+ const contractPath = `${contractsPath}/events/${names.domain}/${names.action}.ts`;
862
+ const contractContent = fs2.readFile(contractPath);
863
+ if (!contractContent) return null;
864
+ const schemaMatch = contractContent.match(/export const \w+Schema\s*=\s*z\.object\(\s*\{([\s\S]*?)\}\s*\)/m);
865
+ if (!schemaMatch) return null;
866
+ const { data, faker: fakerHints } = parseSchemaFromSource(schemaMatch[1], useFaker);
867
+ const mockPath = exports.getJsonMockPath(eventType, contractsPath);
868
+ const mockData = {
869
+ eventName: eventType,
870
+ description: `Mock data for ${eventType} event`,
871
+ data
872
+ };
873
+ if (Object.keys(fakerHints).length > 0) {
874
+ mockData.faker = fakerHints;
875
+ }
876
+ const content = JSON.stringify(mockData, null, 2);
877
+ fs2.writeFile(mockPath, content);
878
+ return flowcore.change.created(mockPath);
879
+ };
260
880
  }
261
- };
881
+ });
882
+
883
+ // src/generators/index.ts
884
+ var generators_exports = {};
885
+ __export(generators_exports, {
886
+ addExportToIndex: () => addExportToIndex,
887
+ createMemoryFileSystem: () => exports.createMemoryFileSystem,
888
+ createNodeFileSystem: () => createNodeFileSystem,
889
+ ensureDomainExport: () => ensureDomainExport,
890
+ generateContract: () => exports.generateContract,
891
+ generateContractContent: () => exports.generateContractContent,
892
+ generateEventHandler: () => exports.generateEventHandler,
893
+ generateEventHandlerContent: () => exports.generateEventHandlerContent,
894
+ generateJsonMock: () => exports.generateJsonMock,
895
+ generateJsonMockFromContract: () => exports.generateJsonMockFromContract,
896
+ generateMock: () => exports.generateMock,
897
+ generateMockContent: () => exports.generateMockContent,
898
+ getContractFilePath: () => exports.getContractFilePath,
899
+ getHandlerFilePath: () => exports.getHandlerFilePath,
900
+ getJsonMockPath: () => exports.getJsonMockPath,
901
+ getMockFilePath: () => exports.getMockFilePath,
902
+ initFaker: () => exports.initFaker,
903
+ jsonMockExists: () => exports.jsonMockExists,
904
+ loadJsonMock: () => exports.loadJsonMock
905
+ });
906
+ var init_generators = __esm({
907
+ "src/generators/index.ts"() {
908
+ init_contract();
909
+ init_exports();
910
+ init_handler();
911
+ init_mock();
912
+ init_types2();
913
+ }
914
+ });
915
+
916
+ // src/flows/create-event.flow.ts
917
+ var create_event_flow_exports = {};
918
+ __export(create_event_flow_exports, {
919
+ createEventFlowSteps: () => exports.createEventFlowSteps,
920
+ parseFieldsInput: () => exports.parseFieldsInput
921
+ });
922
+ var parseField; exports.parseFieldsInput = void 0; var generateContractTask, addExportsTask, generateMockTask, generateHandlerTask, flow, isInvalidEventType, getEventTypeErrorMessage, ensureInfraStep, ensureGenerationStep, eventTypeStep, validateEventTypeStep, schemaFieldsStep, serviceSelectionStep, generateFilesStep, printSummary, printSummaryStep; exports.createEventFlowSteps = void 0;
923
+ var init_create_event_flow = __esm({
924
+ "src/flows/create-event.flow.ts"() {
925
+ init_naming();
926
+ init_effects();
927
+ init_generators();
928
+ parseField = (field) => {
929
+ const [nameWithOptional, type = "string"] = field.split(":").map((s) => s.trim());
930
+ const optional = nameWithOptional.endsWith("?");
931
+ const name = optional ? nameWithOptional.slice(0, -1) : nameWithOptional;
932
+ return { name, type, optional };
933
+ };
934
+ exports.parseFieldsInput = (input2) => input2.trim() === "" ? [] : input2.split(",").map((f) => f.trim()).filter(Boolean).map(parseField);
935
+ generateContractTask = (ctx) => {
936
+ const generation = flowcore.initGenerationContext(ctx);
937
+ const result = exports.generateContract(
938
+ {
939
+ eventType: ctx.eventType,
940
+ basePath: ctx.config.contractsPath,
941
+ fields: ctx.fields ?? [],
942
+ force: ctx.force ?? false
943
+ },
944
+ ctx._fs
945
+ );
946
+ flowcore.trackChange(result).record(generation.artifacts, "Contract").onCreated((path2) => {
947
+ generation.addEffect(exports.contractCreated(path2, ctx.eventType));
948
+ });
949
+ };
950
+ addExportsTask = (ctx) => {
951
+ const names = exports.deriveEventNames(ctx.eventType);
952
+ ensureDomainExport(
953
+ {
954
+ contractsBasePath: ctx.config.contractsPath,
955
+ domain: names.domain,
956
+ eventFile: names.action
957
+ },
958
+ ctx._fs
959
+ );
960
+ };
961
+ generateMockTask = (ctx) => {
962
+ const generation = flowcore.initGenerationContext(ctx);
963
+ const result = exports.generateJsonMock(
964
+ {
965
+ eventType: ctx.eventType,
966
+ contractsPath: ctx.config.contractsPath,
967
+ fields: ctx.fields ?? [],
968
+ force: ctx.force ?? false
969
+ },
970
+ ctx._fs
971
+ );
972
+ flowcore.trackChange(result).record(generation.artifacts, "Mock");
973
+ };
974
+ generateHandlerTask = (ctx) => {
975
+ if (!ctx.servicePath) return;
976
+ const generation = flowcore.initGenerationContext(ctx);
977
+ const names = exports.deriveEventNames(ctx.eventType);
978
+ const handlerBasePath = ctx.servicePath.endsWith("/src") ? ctx.servicePath : `${ctx.servicePath}/src`;
979
+ const result = exports.generateEventHandler(
980
+ {
981
+ eventType: ctx.eventType,
982
+ basePath: handlerBasePath,
983
+ contractsPackage: ctx.config.contractsPackage ?? "",
984
+ force: ctx.force ?? false
985
+ },
986
+ ctx._fs
987
+ );
988
+ flowcore.trackChange(result).record(generation.artifacts, "Handler").onCreated((path2) => {
989
+ if (ctx.servicePath) {
990
+ generation.addEffect(exports.handlerCreated(path2, ctx.eventType, ctx.servicePath));
991
+ generation.addEffect(exports.streamWired(names.streamName, ctx.servicePath));
992
+ }
993
+ });
994
+ };
995
+ flow = flowcore.createFlow();
996
+ isInvalidEventType = (ctx) => !exports.isValidEventType(ctx.eventType);
997
+ getEventTypeErrorMessage = (ctx) => `Invalid event type: ${exports.validateEventType(ctx.eventType).errors.join(", ")}`;
998
+ ensureInfraStep = flow.ensure("_fs", (ctx) => ctx.config.fs ?? createNodeFileSystem()).build();
999
+ ensureGenerationStep = flow.ensure("_generation", () => flowcore.createGenerationResult()).build();
1000
+ eventTypeStep = flow.input("eventType").prompt({
1001
+ title: "Event Type",
1002
+ message: "Enter event type (e.g., order.created):"
1003
+ }).validateBy(exports.validateEventType).skipIfSet().build();
1004
+ validateEventTypeStep = flow.abortIf(isInvalidEventType, getEventTypeErrorMessage).build();
1005
+ schemaFieldsStep = flowcore.input("fieldsInput").prompt({
1006
+ title: "Schema Fields",
1007
+ message: "Schema fields (e.g., orderId:string,total:number) or leave empty:"
1008
+ }).mapTo("fields", exports.parseFieldsInput).skipWhen((ctx) => ctx.fields !== void 0).build();
1009
+ serviceSelectionStep = flow.select("servicePath").title("Service Selection").prompt("Select service to create handler in:").choicesFrom((ctx) => (ctx.availableServices ?? []).map((s) => ({ name: s, value: s }))).optional("Skip handler creation").skipIfSet().build();
1010
+ generateFilesStep = flow.task("Generate files").steps([generateContractTask, addExportsTask, generateMockTask, generateHandlerTask]).produces("fields", "_generation").build();
1011
+ printSummary = (ctx) => {
1012
+ flowcore.printGenerationSummary(flowcore.initGenerationContext(ctx));
1013
+ };
1014
+ printSummaryStep = flow.task("Print summary").steps([printSummary]).build();
1015
+ exports.createEventFlowSteps = [
1016
+ ensureInfraStep,
1017
+ ensureGenerationStep,
1018
+ eventTypeStep,
1019
+ validateEventTypeStep,
1020
+ schemaFieldsStep,
1021
+ serviceSelectionStep,
1022
+ generateFilesStep,
1023
+ printSummaryStep
1024
+ ];
1025
+ }
1026
+ });
1027
+
1028
+ // src/flows/list-events.flow.ts
1029
+ var list_events_flow_exports = {};
1030
+ __export(list_events_flow_exports, {
1031
+ discoverEventTypes: () => exports.discoverEventTypes,
1032
+ listEventsFlowSteps: () => exports.listEventsFlowSteps
1033
+ });
1034
+ var isContractFile, makeRelativePath, safeReadDir, safeStat, processEntry, findContractFiles, parseEventType, matchesPattern; exports.discoverEventTypes = void 0; var flow2; exports.listEventsFlowSteps = void 0;
1035
+ var init_list_events_flow = __esm({
1036
+ "src/flows/list-events.flow.ts"() {
1037
+ init_naming();
1038
+ isContractFile = (filename) => filename.endsWith(".ts") && !filename.endsWith(".test.ts") && filename !== "index.ts";
1039
+ makeRelativePath = (contractsPath, fullPath) => fullPath.replace(`${contractsPath}/`, "").replace(/\\/g, "/");
1040
+ safeReadDir = (dir) => {
1041
+ try {
1042
+ return fs.readdirSync(dir);
1043
+ } catch {
1044
+ return [];
1045
+ }
1046
+ };
1047
+ safeStat = (path2) => {
1048
+ try {
1049
+ const stat = fs.statSync(path2);
1050
+ return { isDirectory: stat.isDirectory() };
1051
+ } catch {
1052
+ return null;
1053
+ }
1054
+ };
1055
+ processEntry = (dir, entry, contractsPath) => {
1056
+ const fullPath = path.join(dir, entry);
1057
+ const stat = safeStat(fullPath);
1058
+ if (!stat) return [];
1059
+ if (stat.isDirectory) {
1060
+ return findContractFiles(fullPath, contractsPath);
1061
+ }
1062
+ if (isContractFile(entry)) {
1063
+ return [makeRelativePath(contractsPath, fullPath)];
1064
+ }
1065
+ return [];
1066
+ };
1067
+ findContractFiles = (dir, contractsPath) => safeReadDir(dir).flatMap((entry) => processEntry(dir, entry, contractsPath));
1068
+ parseEventType = (filePath) => exports.parseEventTypeFromContract(filePath);
1069
+ matchesPattern = (pattern) => (eventType) => !pattern || pattern.trim() === "" || eventType.includes(pattern);
1070
+ exports.discoverEventTypes = (contractsPath, pattern) => {
1071
+ const eventsDir = path.join(contractsPath, "events");
1072
+ if (!fs.existsSync(eventsDir)) {
1073
+ return [];
1074
+ }
1075
+ return findContractFiles(eventsDir, contractsPath).map(parseEventType).filter((eventType) => eventType !== null).filter(matchesPattern(pattern)).sort();
1076
+ };
1077
+ flow2 = flowcore.createFlow();
1078
+ exports.listEventsFlowSteps = [
1079
+ flow2.input("pattern").prompt({
1080
+ title: "Filter Pattern",
1081
+ message: "Filter by pattern (leave empty for all):"
1082
+ }).skipWhen((ctx) => ctx.pattern != null).build(),
1083
+ flow2.task("Discover events").steps([
1084
+ (ctx) => {
1085
+ const filterPattern = ctx.pattern && ctx.pattern.trim() !== "" ? ctx.pattern : void 0;
1086
+ ctx.eventTypes = exports.discoverEventTypes(ctx.config.contractsPath, filterPattern);
1087
+ }
1088
+ ]).produces("eventTypes").build()
1089
+ ];
1090
+ }
1091
+ });
262
1092
 
263
1093
  // src/domain/contract-helper.ts
264
1094
  function createContract(options) {
@@ -272,162 +1102,173 @@ function createContract(options) {
272
1102
  channel: resolvedChannel
273
1103
  };
274
1104
  }
275
-
276
- // src/domain/discovery.ts
277
- init_infrastructure();
1105
+ var init_contract_helper = __esm({
1106
+ "src/domain/contract-helper.ts"() {
1107
+ }
1108
+ });
278
1109
 
279
1110
  // src/domain/validation.ts
280
- var hasShape = (schema) => "shape" in schema && schema.shape !== null && schema.shape !== void 0 && typeof schema.shape === "object";
281
- var hasTypeField = (shape) => "type" in shape && shape.type !== null && shape.type !== void 0 && typeof shape.type === "object" && "value" in shape.type;
282
- var extractTypeValue = (typeField) => typeof typeField.value === "string" ? typeField.value : void 0;
283
- var safeExtractType = (schema) => {
284
- if (!hasShape(schema)) return void 0;
285
- if (!hasTypeField(schema.shape)) return void 0;
286
- return extractTypeValue(schema.shape.type);
287
- };
288
1111
  function isValidHandler(value) {
289
1112
  if (typeof value !== "function") return false;
290
1113
  const handler = value;
291
1114
  return !!(handler.__eventarcMetadata || handler.prototype?.handle);
292
1115
  }
293
- var extractTypeFromSchema = (schema) => {
294
- try {
295
- return safeExtractType(schema);
296
- } catch {
297
- return void 0;
298
- }
299
- };
300
-
301
- // src/domain/discovery.ts
302
- var getSearchDirectories = () => {
303
- const directories = /* @__PURE__ */ new Set();
304
- directories.add(process.cwd());
305
- try {
306
- const currentDir = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
307
- directories.add(currentDir);
308
- if (currentDir.includes("/dist/")) {
309
- const pkgRoot = currentDir.split("/dist/")[0];
310
- if (pkgRoot) directories.add(pkgRoot);
311
- }
312
- } catch {
313
- }
314
- return [...directories].filter((dir) => fs.existsSync(dir));
315
- };
316
- var loadHandlers = async (filePath, filter) => {
317
- try {
318
- if (!fs.existsSync(filePath)) {
319
- return [];
320
- }
321
- const module = await import(filePath);
322
- return Object.entries(module).filter(([name, handler]) => isValidHandler(handler) && (!filter || filter(name, handler))).map(([name, handler]) => {
323
- const HandlerClass = handler;
324
- const hasNoMeaningfulName = !HandlerClass.name || HandlerClass.name === "" || HandlerClass.name === "HandlerClass";
325
- const isNamedExport = name !== "default";
326
- if (hasNoMeaningfulName && isNamedExport) {
327
- return Object.defineProperty(HandlerClass, "name", { value: name, configurable: true });
328
- }
329
- return HandlerClass;
330
- });
331
- } catch (error) {
332
- logger?.warn(`Failed to load ${filePath}`);
333
- logger?.warn(`Error type: ${typeof error}`);
334
- logger?.warn(`Error constructor: ${error?.constructor?.name}`);
335
- if (error instanceof Error) {
336
- logger?.warn(`Error message: ${error.message}`);
337
- if (error.stack) {
338
- logger?.warn(`Stack trace:
339
- ${error.stack}`);
340
- }
341
- } else {
342
- logger?.warn(`Error value: ${String(error)}`);
1116
+ var hasShape, hasTypeField, extractTypeValue, safeExtractType; exports.extractTypeFromSchema = void 0;
1117
+ var init_validation = __esm({
1118
+ "src/domain/validation.ts"() {
1119
+ hasShape = (schema) => "shape" in schema && schema.shape !== null && schema.shape !== void 0 && typeof schema.shape === "object";
1120
+ hasTypeField = (shape) => "type" in shape && shape.type !== null && shape.type !== void 0 && typeof shape.type === "object" && "value" in shape.type;
1121
+ extractTypeValue = (typeField) => typeof typeField.value === "string" ? typeField.value : void 0;
1122
+ safeExtractType = (schema) => {
1123
+ if (!hasShape(schema)) return void 0;
1124
+ if (!hasTypeField(schema.shape)) return void 0;
1125
+ return extractTypeValue(schema.shape.type);
1126
+ };
1127
+ exports.extractTypeFromSchema = (schema) => {
343
1128
  try {
344
- logger?.warn(`Error JSON: ${JSON.stringify(error, null, 2)}`);
1129
+ return safeExtractType(schema);
345
1130
  } catch {
346
- logger?.warn("(Error is not JSON-serializable)");
1131
+ return void 0;
347
1132
  }
348
- }
349
- return [];
350
- }
351
- };
352
- var deduplicateHandlers = (handlers) => handlers.reduce((acc, handler) => {
353
- const existing = acc.find((h) => h.name === handler.name);
354
- if (!existing) {
355
- acc.push(handler);
356
- }
357
- return acc;
358
- }, []);
359
- var EXTENSION_FALLBACKS = ["js", "mjs", "cjs"];
360
- var expandPatternVariants = (pattern, preferCompiled) => {
361
- if (!/\.tsx?\b/.test(pattern)) {
362
- return [pattern];
363
- }
364
- const basePattern = pattern;
365
- const compiledVariants = EXTENSION_FALLBACKS.map((ext) => basePattern.replace(/\.tsx?\b/g, `.${ext}`));
366
- const ordered = preferCompiled ? [...compiledVariants, basePattern] : [basePattern, ...compiledVariants];
367
- return [...new Set(ordered)];
368
- };
369
- var shouldScanDirectory = (basePath, variant) => {
370
- if (!fs.existsSync(basePath)) {
371
- return false;
372
- }
373
- const dirPrefix = variant.match(/^([^*{[]+)\//)?.[1];
374
- if (dirPrefix) {
375
- const fullDirPath = path.join(basePath, dirPrefix);
376
- return fs.existsSync(fullDirPath);
1133
+ };
377
1134
  }
378
- return true;
379
- };
380
- var discoverFiles = async (pattern, basePath, preferCompiled) => {
381
- const isTestPattern = pattern.startsWith("test/");
382
- const prefixedPattern = isTestPattern ? pattern : `{src,dist,build,lib,out}/${pattern}`;
383
- const patterns = preferCompiled ? [prefixedPattern, pattern] : [pattern, prefixedPattern];
384
- const allFiles = [];
385
- for (const globPattern of patterns) {
386
- const variants = expandPatternVariants(globPattern, preferCompiled);
387
- for (const variant of variants) {
1135
+ });
1136
+ var getSearchDirectories, loadHandlers, deduplicateHandlers, EXTENSION_FALLBACKS, expandPatternVariants, shouldScanDirectory, discoverFiles, discoverHandlers;
1137
+ var init_discovery = __esm({
1138
+ "src/domain/discovery.ts"() {
1139
+ init_infrastructure();
1140
+ init_validation();
1141
+ getSearchDirectories = () => {
1142
+ const directories = /* @__PURE__ */ new Set();
1143
+ directories.add(process.cwd());
388
1144
  try {
389
- if (!shouldScanDirectory(basePath, variant)) {
390
- continue;
1145
+ const currentDir = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
1146
+ directories.add(currentDir);
1147
+ if (currentDir.includes("/dist/")) {
1148
+ const pkgRoot = currentDir.split("/dist/")[0];
1149
+ if (pkgRoot) directories.add(pkgRoot);
391
1150
  }
392
- const files = await glob.glob(variant, {
393
- cwd: basePath,
394
- absolute: true,
395
- nodir: true,
396
- windowsPathsNoEscape: true
397
- });
398
- const existingFiles = files.filter((f) => fs.existsSync(f));
399
- allFiles.push(...existingFiles);
400
1151
  } catch {
401
1152
  }
402
- }
403
- }
404
- return [...new Set(allFiles)];
405
- };
406
- var discoverHandlers = async (pattern, options = {}) => {
407
- const { filter } = options;
408
- const searchDirectories = getSearchDirectories();
409
- const preferCompiled = searchDirectories.some((dir) => dir.includes("/dist/") || dir.includes("\\dist\\"));
410
- try {
411
- const uniqueFiles = /* @__PURE__ */ new Set();
412
- for (const basePath of searchDirectories) {
413
- const discoveredFiles = await discoverFiles(pattern, basePath, preferCompiled);
414
- for (const file of discoveredFiles) {
415
- uniqueFiles.add(file);
1153
+ return [...directories].filter((dir) => fs.existsSync(dir));
1154
+ };
1155
+ loadHandlers = async (filePath, filter) => {
1156
+ try {
1157
+ if (!fs.existsSync(filePath)) {
1158
+ return [];
1159
+ }
1160
+ const module = await import(filePath);
1161
+ return Object.entries(module).filter(([name, handler]) => isValidHandler(handler) && (!filter || filter(name, handler))).map(([name, handler]) => {
1162
+ const HandlerClass = handler;
1163
+ const hasNoMeaningfulName = !HandlerClass.name || HandlerClass.name === "" || HandlerClass.name === "HandlerClass";
1164
+ const isNamedExport = name !== "default";
1165
+ if (hasNoMeaningfulName && isNamedExport) {
1166
+ return Object.defineProperty(HandlerClass, "name", { value: name, configurable: true });
1167
+ }
1168
+ return HandlerClass;
1169
+ });
1170
+ } catch (error) {
1171
+ logger?.warn(`Failed to load ${filePath}`);
1172
+ logger?.warn(`Error type: ${typeof error}`);
1173
+ logger?.warn(`Error constructor: ${error?.constructor?.name}`);
1174
+ if (error instanceof Error) {
1175
+ logger?.warn(`Error message: ${error.message}`);
1176
+ if (error.stack) {
1177
+ logger?.warn(`Stack trace:
1178
+ ${error.stack}`);
1179
+ }
1180
+ } else {
1181
+ logger?.warn(`Error value: ${String(error)}`);
1182
+ try {
1183
+ logger?.warn(`Error JSON: ${JSON.stringify(error, null, 2)}`);
1184
+ } catch {
1185
+ logger?.warn("(Error is not JSON-serializable)");
1186
+ }
1187
+ }
1188
+ return [];
416
1189
  }
417
- }
418
- if (uniqueFiles.size === 0) {
419
- logger.warn(`No files found matching pattern: ${pattern}`);
420
- return [];
421
- }
422
- const handlers = await Promise.all([...uniqueFiles].map((file) => loadHandlers(file, filter)));
423
- const flatHandlers = handlers.flat();
424
- const uniqueHandlers = deduplicateHandlers(flatHandlers);
425
- return uniqueHandlers;
426
- } catch (error) {
427
- logger.error("Discovery failed:", error);
428
- return [];
1190
+ };
1191
+ deduplicateHandlers = (handlers) => handlers.reduce((acc, handler) => {
1192
+ const existing = acc.find((h) => h.name === handler.name);
1193
+ if (!existing) {
1194
+ acc.push(handler);
1195
+ }
1196
+ return acc;
1197
+ }, []);
1198
+ EXTENSION_FALLBACKS = ["js", "mjs", "cjs"];
1199
+ expandPatternVariants = (pattern, preferCompiled) => {
1200
+ if (!/\.tsx?\b/.test(pattern)) {
1201
+ return [pattern];
1202
+ }
1203
+ const basePattern = pattern;
1204
+ const compiledVariants = EXTENSION_FALLBACKS.map((ext) => basePattern.replace(/\.tsx?\b/g, `.${ext}`));
1205
+ const ordered = preferCompiled ? [...compiledVariants, basePattern] : [basePattern, ...compiledVariants];
1206
+ return [...new Set(ordered)];
1207
+ };
1208
+ shouldScanDirectory = (basePath, variant) => {
1209
+ if (!fs.existsSync(basePath)) {
1210
+ return false;
1211
+ }
1212
+ const dirPrefix = variant.match(/^([^*{[]+)\//)?.[1];
1213
+ if (dirPrefix) {
1214
+ const fullDirPath = path.join(basePath, dirPrefix);
1215
+ return fs.existsSync(fullDirPath);
1216
+ }
1217
+ return true;
1218
+ };
1219
+ discoverFiles = async (pattern, basePath, preferCompiled) => {
1220
+ const isTestPattern = pattern.startsWith("test/");
1221
+ const prefixedPattern = isTestPattern ? pattern : `{src,dist,build,lib,out}/${pattern}`;
1222
+ const patterns = preferCompiled ? [prefixedPattern, pattern] : [pattern, prefixedPattern];
1223
+ const allFiles = [];
1224
+ for (const globPattern of patterns) {
1225
+ const variants = expandPatternVariants(globPattern, preferCompiled);
1226
+ for (const variant of variants) {
1227
+ try {
1228
+ if (!shouldScanDirectory(basePath, variant)) {
1229
+ continue;
1230
+ }
1231
+ const files = await glob.glob(variant, {
1232
+ cwd: basePath,
1233
+ absolute: true,
1234
+ nodir: true,
1235
+ windowsPathsNoEscape: true
1236
+ });
1237
+ const existingFiles = files.filter((f) => fs.existsSync(f));
1238
+ allFiles.push(...existingFiles);
1239
+ } catch {
1240
+ }
1241
+ }
1242
+ }
1243
+ return [...new Set(allFiles)];
1244
+ };
1245
+ discoverHandlers = async (pattern, options = {}) => {
1246
+ const { filter } = options;
1247
+ const searchDirectories = getSearchDirectories();
1248
+ const preferCompiled = searchDirectories.some((dir) => dir.includes("/dist/") || dir.includes("\\dist\\"));
1249
+ try {
1250
+ const uniqueFiles = /* @__PURE__ */ new Set();
1251
+ for (const basePath of searchDirectories) {
1252
+ const discoveredFiles = await discoverFiles(pattern, basePath, preferCompiled);
1253
+ for (const file of discoveredFiles) {
1254
+ uniqueFiles.add(file);
1255
+ }
1256
+ }
1257
+ if (uniqueFiles.size === 0) {
1258
+ logger.warn(`No files found matching pattern: ${pattern}`);
1259
+ return [];
1260
+ }
1261
+ const handlers = await Promise.all([...uniqueFiles].map((file) => loadHandlers(file, filter)));
1262
+ const flatHandlers = handlers.flat();
1263
+ const uniqueHandlers = deduplicateHandlers(flatHandlers);
1264
+ return uniqueHandlers;
1265
+ } catch (error) {
1266
+ logger.error("Discovery failed:", error);
1267
+ return [];
1268
+ }
1269
+ };
429
1270
  }
430
- };
1271
+ });
431
1272
  function extractFromValueGetter(typeField) {
432
1273
  if ("value" in typeField && typeof typeField.value === "string") {
433
1274
  return typeField.value;
@@ -521,160 +1362,353 @@ function handleEvent(schemaOrOptions, handler, eventType) {
521
1362
  function eventSchema(schema) {
522
1363
  return zod.z.object(schema);
523
1364
  }
524
-
525
- // src/middlewares/cloudevents-middleware.ts
526
- init_infrastructure();
527
-
528
- // src/processing/dlq-safe.ts
529
- init_infrastructure();
530
- init_infrastructure();
531
-
532
- // src/utils/pluralize.ts
533
- var pluralize = (word) => {
534
- if (word.endsWith("y") && !["a", "e", "i", "o", "u"].includes(word[word.length - 2])) {
535
- return `${word.slice(0, -1)}ies`;
1365
+ var init_handler_factory = __esm({
1366
+ "src/domain/handler-factory.ts"() {
536
1367
  }
537
- if (word.endsWith("s") || word.endsWith("sh") || word.endsWith("ch") || word.endsWith("x")) {
538
- return `${word}es`;
539
- }
540
- return `${word}s`;
541
- };
542
- var singularize = (word) => {
543
- if (word.endsWith("ies")) {
544
- return `${word.slice(0, -3)}y`;
545
- }
546
- if (word.endsWith("xes") || word.endsWith("shes") || word.endsWith("ches") || word.endsWith("ses")) {
547
- return word.slice(0, -2);
548
- }
549
- if (word.endsWith("s")) {
550
- return word.slice(0, -1);
1368
+ });
1369
+
1370
+ // src/domain/index.ts
1371
+ var init_domain = __esm({
1372
+ "src/domain/index.ts"() {
1373
+ init_contract_helper();
1374
+ init_discovery();
1375
+ init_handler_factory();
1376
+ init_naming();
1377
+ init_validation();
551
1378
  }
552
- return word;
553
- };
1379
+ });
554
1380
 
555
1381
  // src/publishing/nats.publisher.ts
556
- var sc = nats.StringCodec();
557
- var natsConnectionPromise = null;
558
- var deriveSubjectFromEventType = (eventType) => {
559
- const parts = eventType.split(".");
560
- if (parts.length < 2) return eventType;
561
- const domain = parts[0];
562
- const action = parts.slice(1).join(".");
563
- const pluralDomain = pluralize(domain);
564
- return `${pluralDomain}.${action}`;
565
- };
566
- var getNatsConnection = async (servers) => {
567
- if (!natsConnectionPromise) {
568
- const url = servers ?? process.env.NATS_URL ?? "nats://localhost:4222";
569
- natsConnectionPromise = nats.connect({ servers: url }).then((connection) => {
570
- logger.debug(`[NATS] connected to ${url}`);
571
- return connection;
572
- }).catch((error) => {
573
- logger.error("[NATS] connection error", error);
574
- natsConnectionPromise = null;
575
- throw error;
576
- });
1382
+ var nats_publisher_exports = {};
1383
+ __export(nats_publisher_exports, {
1384
+ __resetNatsPublisher: () => exports.__resetNatsPublisher,
1385
+ closeConnection: () => exports.closeConnection,
1386
+ deriveStreamFromType: () => exports.deriveStreamFromType,
1387
+ deriveSubjectFromType: () => exports.deriveSubjectFromType,
1388
+ publish: () => exports.publish,
1389
+ publishNatsEvent: () => exports.publishNatsEvent,
1390
+ publishNatsRawEvent: () => exports.publishNatsRawEvent
1391
+ });
1392
+ var sc, natsConnectionPromise, deriveSubjectFromEventType, getNatsConnection; exports.closeConnection = 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;
1393
+ var init_nats_publisher = __esm({
1394
+ "src/publishing/nats.publisher.ts"() {
1395
+ init_domain();
1396
+ init_infrastructure();
1397
+ init_utils();
1398
+ sc = nats.StringCodec();
1399
+ natsConnectionPromise = null;
1400
+ deriveSubjectFromEventType = (eventType) => {
1401
+ const parts = eventType.split(".");
1402
+ if (parts.length < 2) return eventType;
1403
+ const domain = parts[0];
1404
+ const action = parts.slice(1).join(".");
1405
+ const pluralDomain = exports.pluralize(domain);
1406
+ return `${pluralDomain}.${action}`;
1407
+ };
1408
+ getNatsConnection = async (servers) => {
1409
+ if (!natsConnectionPromise) {
1410
+ const url = servers ?? process.env.NATS_URL ?? "nats://localhost:4222";
1411
+ natsConnectionPromise = nats.connect({ servers: url }).then((connection) => {
1412
+ logger.debug(`[NATS] connected to ${url}`);
1413
+ return connection;
1414
+ }).catch((error) => {
1415
+ logger.error("[NATS] connection error", error);
1416
+ natsConnectionPromise = null;
1417
+ throw error;
1418
+ });
1419
+ }
1420
+ return natsConnectionPromise;
1421
+ };
1422
+ exports.closeConnection = async () => {
1423
+ if (natsConnectionPromise) {
1424
+ try {
1425
+ const nc = await natsConnectionPromise;
1426
+ if (nc && typeof nc.drain === "function") {
1427
+ await nc.drain();
1428
+ logger.debug("[NATS] connection closed");
1429
+ }
1430
+ } catch {
1431
+ } finally {
1432
+ natsConnectionPromise = null;
1433
+ }
1434
+ }
1435
+ };
1436
+ exports.__resetNatsPublisher = async () => {
1437
+ await exports.closeConnection();
1438
+ };
1439
+ exports.deriveSubjectFromType = (eventType, config) => {
1440
+ if (!config?.typeToSubjectMap) {
1441
+ return config?.defaultSubjectPrefix ? `${config.defaultSubjectPrefix}.${eventType}` : eventType;
1442
+ }
1443
+ const sortedPrefixes = Object.keys(config.typeToSubjectMap).sort((a, b) => b.length - a.length);
1444
+ for (const prefix of sortedPrefixes) {
1445
+ if (eventType.startsWith(prefix)) {
1446
+ const suffix = eventType.slice(prefix.length);
1447
+ const mappedPrefix = config.typeToSubjectMap[prefix];
1448
+ const cleanSuffix = suffix.startsWith(".") ? suffix.slice(1) : suffix;
1449
+ return cleanSuffix ? `${mappedPrefix}.${cleanSuffix}` : mappedPrefix;
1450
+ }
1451
+ }
1452
+ return config.defaultSubjectPrefix ? `${config.defaultSubjectPrefix}.${eventType}` : eventType;
1453
+ };
1454
+ exports.deriveStreamFromType = (eventType, config) => {
1455
+ if (!config?.typeToStreamMap) return void 0;
1456
+ const sortedPrefixes = Object.keys(config.typeToStreamMap).sort((a, b) => b.length - a.length);
1457
+ for (const prefix of sortedPrefixes) {
1458
+ if (eventType.startsWith(prefix)) {
1459
+ return config.typeToStreamMap[prefix];
1460
+ }
1461
+ }
1462
+ return void 0;
1463
+ };
1464
+ exports.publishNatsRawEvent = async (subjectName, eventType, eventData, options) => {
1465
+ const cloudEvent = {
1466
+ specversion: "1.0",
1467
+ type: eventType,
1468
+ source: options?.source || "hono-service",
1469
+ id: crypto.randomUUID(),
1470
+ time: (/* @__PURE__ */ new Date()).toISOString(),
1471
+ datacontenttype: "application/json",
1472
+ data: eventData,
1473
+ ...options?.subject && { subject: options.subject },
1474
+ ...options?.tenantId && { tenantid: options.tenantId }
1475
+ };
1476
+ const data = JSON.stringify(cloudEvent);
1477
+ const nc = await getNatsConnection(options?.servers);
1478
+ nc.publish(subjectName, sc.encode(data));
1479
+ logger.debug(`Published CloudEvent ${eventType} to NATS subject ${subjectName} (id=${cloudEvent.id})`);
1480
+ if (options?.closeAfterPublish) {
1481
+ await exports.closeConnection();
1482
+ }
1483
+ return cloudEvent.id;
1484
+ };
1485
+ exports.publishNatsEvent = async (subjectName, schema, eventData, options) => {
1486
+ const eventType = exports.extractTypeFromSchema(schema);
1487
+ if (!eventType) {
1488
+ throw new Error("Could not extract event type from schema. Make sure your schema has proper metadata.");
1489
+ }
1490
+ const validationResult = schema.safeParse(eventData);
1491
+ if (!validationResult.success) {
1492
+ const validationDetails = validationResult.error.issues.map((issue) => ({
1493
+ code: issue.code,
1494
+ message: issue.message,
1495
+ path: issue.path.filter((p) => typeof p !== "symbol"),
1496
+ expected: "expected" in issue ? String(issue.expected) : void 0,
1497
+ received: "received" in issue ? String(issue.received) : void 0
1498
+ }));
1499
+ const handlerValidationError = {
1500
+ handlerName: `NatsPublisher:${eventType}`,
1501
+ validationErrors: validationDetails
1502
+ };
1503
+ throw createValidationError(eventType, [handlerValidationError]);
1504
+ }
1505
+ return exports.publishNatsRawEvent(subjectName, eventType, validationResult.data, options);
1506
+ };
1507
+ exports.publish = async (eventTypeOrContract, eventData, options) => {
1508
+ const eventType = typeof eventTypeOrContract === "string" ? eventTypeOrContract : eventTypeOrContract.type;
1509
+ const natsSubject = typeof eventTypeOrContract === "string" ? deriveSubjectFromEventType(eventTypeOrContract) : eventTypeOrContract.channel?.subject ?? eventTypeOrContract.type;
1510
+ return exports.publishNatsRawEvent(natsSubject, eventType, eventData, options);
1511
+ };
577
1512
  }
578
- return natsConnectionPromise;
579
- };
580
- var deriveSubjectFromType = (eventType, config) => {
581
- if (!config?.typeToSubjectMap) {
582
- return config?.defaultSubjectPrefix ? `${config.defaultSubjectPrefix}.${eventType}` : eventType;
583
- }
584
- const sortedPrefixes = Object.keys(config.typeToSubjectMap).sort((a, b) => b.length - a.length);
585
- for (const prefix of sortedPrefixes) {
586
- if (eventType.startsWith(prefix)) {
587
- const suffix = eventType.slice(prefix.length);
588
- const mappedPrefix = config.typeToSubjectMap[prefix];
589
- const cleanSuffix = suffix.startsWith(".") ? suffix.slice(1) : suffix;
590
- return cleanSuffix ? `${mappedPrefix}.${cleanSuffix}` : mappedPrefix;
591
- }
1513
+ });
1514
+
1515
+ // src/flows/publish-event.flow.ts
1516
+ var publish_event_flow_exports = {};
1517
+ __export(publish_event_flow_exports, {
1518
+ parseDataInput: () => exports.parseDataInput,
1519
+ publishEventFlowSteps: () => exports.publishEventFlowSteps
1520
+ });
1521
+ exports.parseDataInput = void 0; var loadDataFromInput, publishToNats, hasExplicitData, isInvalidEventType2, getEventTypeErrorMessage2, flow3; exports.publishEventFlowSteps = void 0;
1522
+ var init_publish_event_flow = __esm({
1523
+ "src/flows/publish-event.flow.ts"() {
1524
+ init_naming();
1525
+ init_generators();
1526
+ exports.parseDataInput = (input2) => {
1527
+ if (!input2.trim()) return {};
1528
+ try {
1529
+ return JSON.parse(input2);
1530
+ } catch {
1531
+ return null;
1532
+ }
1533
+ };
1534
+ loadDataFromInput = async (ctx) => {
1535
+ if (ctx.dataInput !== void 0 && ctx.dataInput.trim() !== "") {
1536
+ const parsed = exports.parseDataInput(ctx.dataInput);
1537
+ if (parsed === null) {
1538
+ throw new Error("Invalid JSON data");
1539
+ }
1540
+ ctx.data = parsed;
1541
+ return;
1542
+ }
1543
+ const { loadJsonMock: loadJsonMock2 } = await Promise.resolve().then(() => (init_generators(), generators_exports));
1544
+ const mock = loadJsonMock2(ctx.eventType, ctx.config.contractsPath);
1545
+ if (mock?.data) {
1546
+ ctx.data = mock.data;
1547
+ ctx.usedMock = true;
1548
+ return;
1549
+ }
1550
+ ctx.data = {};
1551
+ };
1552
+ publishToNats = async (ctx) => {
1553
+ const { publish: publish2 } = await Promise.resolve().then(() => (init_nats_publisher(), nats_publisher_exports));
1554
+ await publish2(ctx.eventType, ctx.data ?? {}, {
1555
+ source: "pf-cli",
1556
+ closeAfterPublish: true
1557
+ });
1558
+ ctx.published = true;
1559
+ const mockHint = ctx.usedMock ? " (using mock data)" : "";
1560
+ console.log(`\u2705 Published ${ctx.eventType}${mockHint}`);
1561
+ };
1562
+ hasExplicitData = (ctx) => ctx.data !== void 0 || exports.jsonMockExists(ctx.eventType, ctx.config.contractsPath);
1563
+ isInvalidEventType2 = (ctx) => !exports.isValidEventType(ctx.eventType);
1564
+ getEventTypeErrorMessage2 = (ctx) => `Invalid event type: ${exports.validateEventType(ctx.eventType).errors.join(", ")}`;
1565
+ flow3 = flowcore.createFlow();
1566
+ exports.publishEventFlowSteps = [
1567
+ flow3.input("eventType").prompt({
1568
+ title: "Event Type",
1569
+ message: "Event type to publish (e.g., order.created):"
1570
+ }).validateBy(exports.validateEventType).skipIfSet().build(),
1571
+ flow3.abortIf(isInvalidEventType2, getEventTypeErrorMessage2).build(),
1572
+ flow3.input("dataInput").prompt({
1573
+ title: "Event Data",
1574
+ message: "Event data as JSON (or leave empty for mock data):"
1575
+ }).skipWhen(hasExplicitData).build(),
1576
+ flow3.task("Publish event").steps([
1577
+ loadDataFromInput,
1578
+ publishToNats
1579
+ ]).produces("data", "published", "usedMock").build()
1580
+ ];
592
1581
  }
593
- return config.defaultSubjectPrefix ? `${config.defaultSubjectPrefix}.${eventType}` : eventType;
594
- };
595
- var deriveStreamFromType = (eventType, config) => {
596
- if (!config?.typeToStreamMap) return void 0;
597
- const sortedPrefixes = Object.keys(config.typeToStreamMap).sort((a, b) => b.length - a.length);
598
- for (const prefix of sortedPrefixes) {
599
- if (eventType.startsWith(prefix)) {
600
- return config.typeToStreamMap[prefix];
1582
+ });
1583
+
1584
+ // src/adapters/cloudevents/cloudevents.ts
1585
+ init_infrastructure();
1586
+ var hasCloudEventHeaders = (headers) => Object.keys(headers).some((key) => key.toLowerCase().startsWith("ce-"));
1587
+ var isRecord = (value) => typeof value === "object" && value !== null;
1588
+ var parseEventFromContext = async (context) => {
1589
+ try {
1590
+ const headers = context.req.header();
1591
+ const rawBody = await context.req.text();
1592
+ let parsedBody;
1593
+ if (rawBody?.length) {
1594
+ try {
1595
+ parsedBody = JSON.parse(rawBody);
1596
+ } catch {
1597
+ parsedBody = void 0;
1598
+ }
601
1599
  }
1600
+ const bodyObject = isRecord(parsedBody) ? parsedBody : void 0;
1601
+ if (bodyObject && "specversion" in bodyObject) {
1602
+ const { parseStructuredMode: parseStructuredMode2 } = await Promise.resolve().then(() => (init_structured_mode(), structured_mode_exports));
1603
+ return parseStructuredMode2(bodyObject);
1604
+ }
1605
+ if (bodyObject && "message" in bodyObject) {
1606
+ const { parsePubSubMessage: parsePubSubMessage2 } = await Promise.resolve().then(() => (init_pubsub(), pubsub_exports));
1607
+ return await parsePubSubMessage2(bodyObject, headers);
1608
+ }
1609
+ if (hasCloudEventHeaders(headers)) {
1610
+ const { parseBinaryMode: parseBinaryMode2 } = await Promise.resolve().then(() => (init_binary_mode(), binary_mode_exports));
1611
+ return await parseBinaryMode2(headers, rawBody);
1612
+ }
1613
+ const { parseRawEvent: parseRawEvent2 } = await Promise.resolve().then(() => (init_raw_event(), raw_event_exports));
1614
+ if (bodyObject) {
1615
+ return parseRawEvent2(bodyObject);
1616
+ }
1617
+ return parseRawEvent2({ raw: rawBody });
1618
+ } catch (error) {
1619
+ logger.error("Failed to parse event:", error);
1620
+ throw new Error(`Failed to parse CloudEvent: ${error instanceof Error ? error.message : "Unknown error"}`);
602
1621
  }
603
- return void 0;
604
1622
  };
605
- var publishNatsRawEvent = async (subjectName, eventType, eventData, options) => {
606
- const cloudEvent = {
607
- specversion: "1.0",
608
- type: eventType,
609
- source: options?.source || "hono-service",
610
- id: crypto.randomUUID(),
611
- time: (/* @__PURE__ */ new Date()).toISOString(),
612
- datacontenttype: "application/json",
613
- data: eventData,
614
- ...options?.subject && { subject: options.subject },
615
- ...options?.tenantId && { tenantid: options.tenantId }
1623
+
1624
+ // src/flows/index.ts
1625
+ init_create_event_flow();
1626
+ init_list_events_flow();
1627
+ init_publish_event_flow();
1628
+
1629
+ // src/api.ts
1630
+ var createEvent = async (eventType, options = {}) => {
1631
+ const { fields, service, contractsPath, mocksPath, force } = options;
1632
+ const result = await flowcore.runFlow(exports.createEventFlowSteps, {
1633
+ initialContext: {
1634
+ eventType,
1635
+ fields: typeof fields === "string" ? exports.parseFieldsInput(fields) : fields,
1636
+ servicePath: service,
1637
+ availableServices: [],
1638
+ // No services in simple API
1639
+ force,
1640
+ config: {
1641
+ contractsPath: contractsPath ?? "packages/contracts/src",
1642
+ mocksPath
1643
+ }
1644
+ },
1645
+ inputs: {},
1646
+ // Non-interactive mode
1647
+ exitOnError: true
1648
+ });
1649
+ if (!result.success) {
1650
+ throw new Error(result.abortReason ?? "Failed to create event");
1651
+ }
1652
+ return {
1653
+ created: result.context._generation?.created ?? [],
1654
+ skipped: result.context._generation?.skipped ?? [],
1655
+ effects: result.context._generation?.effects ?? []
616
1656
  };
617
- const data = JSON.stringify(cloudEvent);
618
- const nc = await getNatsConnection(options?.servers);
619
- nc.publish(subjectName, sc.encode(data));
620
- logger.debug(`Published CloudEvent ${eventType} to NATS subject ${subjectName} (id=${cloudEvent.id})`);
621
- return cloudEvent.id;
622
1657
  };
623
- var publishNatsEvent = async (subjectName, schema, eventData, options) => {
624
- const eventType = extractTypeFromSchema(schema);
625
- if (!eventType) {
626
- throw new Error("Could not extract event type from schema. Make sure your schema has proper metadata.");
627
- }
628
- const validationResult = schema.safeParse(eventData);
629
- if (!validationResult.success) {
630
- const validationDetails = validationResult.error.issues.map((issue) => ({
631
- code: issue.code,
632
- message: issue.message,
633
- path: issue.path.filter((p) => typeof p !== "symbol"),
634
- expected: "expected" in issue ? String(issue.expected) : void 0,
635
- received: "received" in issue ? String(issue.received) : void 0
636
- }));
637
- const handlerValidationError = {
638
- handlerName: `NatsPublisher:${eventType}`,
639
- validationErrors: validationDetails
640
- };
641
- throw createValidationError(eventType, [handlerValidationError]);
1658
+ var listEvents = async (options = {}) => {
1659
+ const { pattern, contractsPath } = options;
1660
+ const result = await flowcore.runFlow(exports.listEventsFlowSteps, {
1661
+ initialContext: {
1662
+ pattern: pattern ?? "",
1663
+ config: {
1664
+ contractsPath: contractsPath ?? "packages/contracts/src"
1665
+ }
1666
+ },
1667
+ exitOnError: true
1668
+ });
1669
+ if (!result.success) {
1670
+ throw new Error(result.abortReason ?? "Failed to list events");
642
1671
  }
643
- return publishNatsRawEvent(subjectName, eventType, validationResult.data, options);
1672
+ return result.context.eventTypes ?? [];
644
1673
  };
645
- var publish = async (eventTypeOrContract, eventData, options) => {
646
- const eventType = typeof eventTypeOrContract === "string" ? eventTypeOrContract : eventTypeOrContract.type;
647
- const natsSubject = typeof eventTypeOrContract === "string" ? deriveSubjectFromEventType(eventTypeOrContract) : eventTypeOrContract.channel?.subject ?? eventTypeOrContract.type;
648
- return publishNatsRawEvent(natsSubject, eventType, eventData, options);
649
- };
650
- var __resetNatsPublisher = () => {
651
- natsConnectionPromise = null;
1674
+ var publishEvent = async (eventType, data, options = {}) => {
1675
+ const { natsUrl, contractsPath } = options;
1676
+ const result = await flowcore.runFlow(exports.publishEventFlowSteps, {
1677
+ initialContext: {
1678
+ eventType,
1679
+ data,
1680
+ config: {
1681
+ contractsPath: contractsPath ?? "packages/contracts/src",
1682
+ natsUrl: natsUrl ?? "nats://localhost:4222"
1683
+ },
1684
+ published: false
1685
+ },
1686
+ exitOnError: true
1687
+ });
1688
+ if (!result.success) {
1689
+ throw new Error(result.abortReason ?? "Failed to publish event");
1690
+ }
1691
+ return { success: true };
652
1692
  };
653
1693
 
1694
+ // src/index.ts
1695
+ init_domain();
1696
+ init_naming();
1697
+ init_effects();
1698
+ init_generators();
1699
+
1700
+ // src/middlewares/cloudevents-middleware.ts
1701
+ init_infrastructure();
1702
+
1703
+ // src/processing/dlq-safe.ts
1704
+ init_infrastructure();
1705
+
1706
+ // src/publishing/index.ts
1707
+ init_nats_publisher();
1708
+
654
1709
  // src/publishing/pubsub.publisher.ts
1710
+ init_domain();
655
1711
  init_infrastructure();
656
- async function publishEvent(topicName, schema, eventData, options) {
657
- const eventType = extractTypeFromSchema(schema);
658
- if (!eventType) {
659
- throw new Error("Could not extract event type from schema. Make sure your schema has proper metadata.");
660
- }
661
- const validationResult = schema.safeParse(eventData);
662
- if (!validationResult.success) {
663
- const validationDetails = validationResult.error.issues.map((issue) => ({
664
- code: issue.code,
665
- message: issue.message,
666
- path: issue.path.filter((p) => typeof p !== "symbol"),
667
- expected: "expected" in issue ? String(issue.expected) : void 0,
668
- received: "received" in issue ? String(issue.received) : void 0
669
- }));
670
- const handlerValidationError = {
671
- handlerName: `Publisher:${eventType}`,
672
- validationErrors: validationDetails
673
- };
674
- throw createValidationError(eventType, [handlerValidationError]);
675
- }
676
- return publishRawEvent(topicName, eventType, validationResult.data, options);
677
- }
678
1712
  async function publishRawEvent(topicName, eventType, eventData, options) {
679
1713
  const { PubSub } = await import('@google-cloud/pubsub');
680
1714
  const pubsub = new PubSub({
@@ -793,6 +1827,7 @@ var createProcessingContext = (eventType, eventData, context, originalCloudEvent
793
1827
  });
794
1828
 
795
1829
  // src/processing/handler-cache.ts
1830
+ init_domain();
796
1831
  init_logging();
797
1832
  var createEmptyCache = () => /* @__PURE__ */ new Map();
798
1833
  var createEmptyMessageIds = () => /* @__PURE__ */ new Set();
@@ -814,7 +1849,7 @@ var processHandler = (HandlerClass) => {
814
1849
  const metadata = HandlerClass.__eventarcMetadata;
815
1850
  if (!metadata) return null;
816
1851
  const instance = new HandlerClass();
817
- const eventType = metadata.declaredType || extractTypeFromSchema(metadata.schema);
1852
+ const eventType = metadata.declaredType || exports.extractTypeFromSchema(metadata.schema);
818
1853
  if (!eventType) return null;
819
1854
  return {
820
1855
  type: eventType,
@@ -1116,6 +2151,142 @@ function cloudEvents(options = {}) {
1116
2151
  };
1117
2152
  }
1118
2153
 
2154
+ // package.json
2155
+ var package_default = {
2156
+ name: "@crossdelta/cloudevents",
2157
+ version: "0.6.4",
2158
+ description: "CloudEvents toolkit for TypeScript - Zod validation, handler discovery, NATS JetStream"};
2159
+
2160
+ // src/plugin.ts
2161
+ var createAddCommand = (config) => ({
2162
+ name: "add",
2163
+ description: "Add a new event contract, handler, and mock",
2164
+ args: [{ name: "eventType", description: "Event type (e.g., order.created)", required: false }],
2165
+ options: [
2166
+ { flags: "-s, --service <path>", description: "Service path for handler" },
2167
+ { flags: "-f, --fields <fields>", description: "Schema fields (e.g., orderId:string,total:number)" },
2168
+ { flags: "--force", description: "Overwrite existing files", default: false }
2169
+ ],
2170
+ run: async (args, opts) => {
2171
+ const { runFlow: runFlow2 } = await import('@crossdelta/flowcore');
2172
+ const { createEventFlowSteps: createEventFlowSteps2, parseFieldsInput: parseFieldsInput2 } = await Promise.resolve().then(() => (init_create_event_flow(), create_event_flow_exports));
2173
+ const result = await runFlow2(createEventFlowSteps2, {
2174
+ initialContext: {
2175
+ eventType: args.eventType,
2176
+ fields: opts.fields ? parseFieldsInput2(opts.fields) : void 0,
2177
+ servicePath: opts.service,
2178
+ availableServices: config.availableServices,
2179
+ force: opts.force,
2180
+ config: {
2181
+ contractsPath: config.contractsPath,
2182
+ contractsPackage: config.contractsPackage,
2183
+ mocksPath: config.mocksPath
2184
+ }
2185
+ },
2186
+ exitOnError: true
2187
+ });
2188
+ if (!result.success) {
2189
+ throw new Error(result.abortReason ?? "Unknown error");
2190
+ }
2191
+ return { effects: result.context._generation?.effects ?? [] };
2192
+ }
2193
+ });
2194
+ var createListCommand = (config) => ({
2195
+ name: "list",
2196
+ description: "List event types in the workspace",
2197
+ args: [],
2198
+ options: [{ flags: "-p, --pattern <pattern>", description: "Filter by pattern" }],
2199
+ run: async (_args, opts) => {
2200
+ const { runFlow: runFlow2 } = await import('@crossdelta/flowcore');
2201
+ const { listEventsFlowSteps: listEventsFlowSteps2 } = await Promise.resolve().then(() => (init_list_events_flow(), list_events_flow_exports));
2202
+ const pattern = opts.pattern !== void 0 ? opts.pattern : "";
2203
+ const result = await runFlow2(listEventsFlowSteps2, {
2204
+ initialContext: {
2205
+ pattern,
2206
+ config: { contractsPath: config.contractsPath }
2207
+ },
2208
+ exitOnError: true
2209
+ });
2210
+ if (!result.success) {
2211
+ throw new Error(result.abortReason ?? "Unknown error");
2212
+ }
2213
+ const eventTypes = result.context.eventTypes ?? [];
2214
+ const output = eventTypes.length > 0 ? `
2215
+ Event types:
2216
+ ${eventTypes.map((e) => ` \u2022 ${e}`).join("\n")}` : "\n\u2139\uFE0F No event types found";
2217
+ return { effects: [], output };
2218
+ }
2219
+ });
2220
+ var createPublishCommand = (config) => ({
2221
+ name: "publish",
2222
+ description: "Publish an event to NATS",
2223
+ args: [{ name: "eventType", description: "Event type to publish", required: true }],
2224
+ options: [{ flags: "-d, --data <json>", description: "Event data as JSON" }],
2225
+ run: async (args, opts) => {
2226
+ const { runFlow: runFlow2 } = await import('@crossdelta/flowcore');
2227
+ const { publishEventFlowSteps: publishEventFlowSteps2, parseDataInput: parseDataInput2 } = await Promise.resolve().then(() => (init_publish_event_flow(), publish_event_flow_exports));
2228
+ const data = opts.data ? parseDataInput2(opts.data) ?? void 0 : void 0;
2229
+ const result = await runFlow2(publishEventFlowSteps2, {
2230
+ initialContext: {
2231
+ eventType: args.eventType,
2232
+ data,
2233
+ config: { contractsPath: config.contractsPath, natsUrl: config.natsUrl },
2234
+ published: false
2235
+ },
2236
+ exitOnError: true
2237
+ });
2238
+ if (!result.success) {
2239
+ throw new Error(result.abortReason ?? "Unknown error");
2240
+ }
2241
+ return { effects: [] };
2242
+ }
2243
+ });
2244
+ var createFlows = () => [
2245
+ {
2246
+ name: "create-event",
2247
+ description: "Interactive flow for creating event artifacts",
2248
+ getSteps: async () => {
2249
+ const { createEventFlowSteps: createEventFlowSteps2 } = await Promise.resolve().then(() => (init_create_event_flow(), create_event_flow_exports));
2250
+ return createEventFlowSteps2;
2251
+ }
2252
+ },
2253
+ {
2254
+ name: "list-events",
2255
+ description: "Interactive flow for listing events",
2256
+ getSteps: async () => {
2257
+ const { listEventsFlowSteps: listEventsFlowSteps2 } = await Promise.resolve().then(() => (init_list_events_flow(), list_events_flow_exports));
2258
+ return listEventsFlowSteps2;
2259
+ }
2260
+ },
2261
+ {
2262
+ name: "publish-event",
2263
+ description: "Interactive flow for publishing events",
2264
+ getSteps: async () => {
2265
+ const { publishEventFlowSteps: publishEventFlowSteps2 } = await Promise.resolve().then(() => (init_publish_event_flow(), publish_event_flow_exports));
2266
+ return publishEventFlowSteps2;
2267
+ }
2268
+ }
2269
+ ];
2270
+ var createPfPlugin = (options = {}) => {
2271
+ const config = {
2272
+ contractsPath: options.contractsPath ?? "packages/contracts/src",
2273
+ contractsPackage: options.contractsPackage,
2274
+ mocksPath: options.mocksPath,
2275
+ availableServices: options.availableServices ?? [],
2276
+ natsUrl: options.natsUrl ?? "nats://localhost:4222"
2277
+ };
2278
+ return {
2279
+ name: package_default.name.replace("@crossdelta/", ""),
2280
+ version: package_default.version,
2281
+ description: package_default.description,
2282
+ commands: [createAddCommand(config), createListCommand(config), createPublishCommand(config)],
2283
+ flows: createFlows(),
2284
+ setup: (context) => {
2285
+ context.logger.debug("cloudevents plugin loaded");
2286
+ }
2287
+ };
2288
+ };
2289
+
1119
2290
  // src/transports/nats/base-message-processor.ts
1120
2291
  function extractTenantId(ce) {
1121
2292
  const extensions = ce;
@@ -1139,11 +2310,7 @@ function createBaseMessageProcessor(deps) {
1139
2310
  const findHandler = (event) => processedHandlers.find(
1140
2311
  (handler) => handler.type === event.eventType && (!handler.match || handler.match(event))
1141
2312
  );
1142
- const handleMissingHandler = async (context, eventType) => {
1143
- logger2.warn(`[${name}] no handler for event type: ${eventType}`);
1144
- if (dlqEnabled) {
1145
- await quarantineMessage(context, "no_handler", options, new Error(`No handler for event type ${eventType}`));
1146
- }
2313
+ const handleMissingHandler = async (_context, _eventType) => {
1147
2314
  return { handled: true, shouldAck: true };
1148
2315
  };
1149
2316
  const handleValidationFailure = async (validationResult, handler, context) => {
@@ -1217,6 +2384,9 @@ function createBaseMessageProcessor(deps) {
1217
2384
  handleUnhandledError
1218
2385
  };
1219
2386
  }
2387
+
2388
+ // src/transports/nats/jetstream-consumer.ts
2389
+ init_domain();
1220
2390
  init_logging();
1221
2391
 
1222
2392
  // src/transports/nats/jetstream-message-processor.ts
@@ -1498,6 +2668,9 @@ async function consumeJetStreamStreams(options) {
1498
2668
  }
1499
2669
  var ensureJetStreams = ensureJetStreamStreams;
1500
2670
  var consumeJetStreams = consumeJetStreamStreams;
2671
+
2672
+ // src/transports/nats/nats-consumer.ts
2673
+ init_domain();
1501
2674
  init_logging();
1502
2675
 
1503
2676
  // src/transports/nats/nats-message-processor.ts
@@ -1590,7 +2763,9 @@ async function consumeNatsEvents(options) {
1590
2763
  return sub;
1591
2764
  }
1592
2765
 
1593
- exports.__resetNatsPublisher = __resetNatsPublisher;
2766
+ // src/index.ts
2767
+ init_utils();
2768
+
1594
2769
  exports.checkAndMarkProcessed = checkAndMarkProcessed;
1595
2770
  exports.clearHandlerCache = clearHandlerCache;
1596
2771
  exports.cloudEvents = cloudEvents;
@@ -1599,22 +2774,17 @@ exports.consumeJetStreamStreams = consumeJetStreamStreams;
1599
2774
  exports.consumeJetStreams = consumeJetStreams;
1600
2775
  exports.consumeNatsEvents = consumeNatsEvents;
1601
2776
  exports.createContract = createContract;
2777
+ exports.createEvent = createEvent;
1602
2778
  exports.createInMemoryIdempotencyStore = createInMemoryIdempotencyStore;
1603
- exports.deriveStreamFromType = deriveStreamFromType;
1604
- exports.deriveSubjectFromType = deriveSubjectFromType;
2779
+ exports.createPfPlugin = createPfPlugin;
1605
2780
  exports.ensureJetStreamStream = ensureJetStreamStream;
1606
2781
  exports.ensureJetStreamStreams = ensureJetStreamStreams;
1607
2782
  exports.ensureJetStreams = ensureJetStreams;
1608
2783
  exports.eventSchema = eventSchema;
1609
- exports.extractTypeFromSchema = extractTypeFromSchema;
1610
2784
  exports.getDefaultIdempotencyStore = getDefaultIdempotencyStore;
1611
2785
  exports.handleEvent = handleEvent;
2786
+ exports.listEvents = listEvents;
1612
2787
  exports.parseEventFromContext = parseEventFromContext;
1613
- exports.pluralize = pluralize;
1614
- exports.publish = publish;
1615
2788
  exports.publishEvent = publishEvent;
1616
- exports.publishNatsEvent = publishNatsEvent;
1617
- exports.publishNatsRawEvent = publishNatsRawEvent;
1618
2789
  exports.publishRawEvent = publishRawEvent;
1619
2790
  exports.resetDefaultIdempotencyStore = resetDefaultIdempotencyStore;
1620
- exports.singularize = singularize;