@pattern-stack/codegen 0.14.1 → 0.14.2

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.
@@ -6273,8 +6273,8 @@ async function generateScopeEntityType(opts) {
6273
6273
  }
6274
6274
 
6275
6275
  // src/cli/shared/subsystem-barrel-generator.ts
6276
- import fs5 from "fs";
6277
- import path8 from "path";
6276
+ import fs6 from "fs";
6277
+ import path9 from "path";
6278
6278
 
6279
6279
  // src/cli/shared/subsystem-detect.ts
6280
6280
  import fs4 from "fs";
@@ -6541,274 +6541,16 @@ function resolveSubsystemsRoot(ctx, overrideTarget) {
6541
6541
  return resolveSubsystemsRootFromConfig(ctx.cwd, ctx.config);
6542
6542
  }
6543
6543
 
6544
- // src/cli/shared/subsystem-barrel-generator.ts
6545
- function quoteOpts(opts) {
6546
- const entries = Object.entries(opts).filter(([, v]) => v !== void 0);
6547
- if (entries.length === 0) return "";
6548
- return "{ " + entries.map(([k, v]) => `${k}: ${typeof v === "string" ? `'${v}'` : String(v)}`).join(", ") + " }";
6549
- }
6550
- function jsonToTs(value) {
6551
- if (value === null || value === void 0) return "undefined";
6552
- if (typeof value === "string") return `'${value.replace(/'/g, "\\'")}'`;
6553
- if (typeof value === "number" || typeof value === "boolean") return String(value);
6554
- if (Array.isArray(value)) return `[${value.map(jsonToTs).join(", ")}]`;
6555
- if (typeof value === "object") {
6556
- const entries = Object.entries(value).filter(
6557
- ([, v]) => v !== void 0
6558
- );
6559
- return `{ ${entries.map(([k, v]) => `${k}: ${jsonToTs(v)}`).join(", ")} }`;
6560
- }
6561
- return "undefined";
6562
- }
6563
- function quoteBullmqDomainOpts(input) {
6564
- const { backend, multiTenant, bullExt } = input;
6565
- if (backend !== "bullmq" || !bullExt) {
6566
- return quoteOpts({ backend, multiTenant });
6567
- }
6568
- const parts = [`backend: 'bullmq'`];
6569
- if (multiTenant) parts.push(`multiTenant: true`);
6570
- parts.push(`extensions: { bullmq: ${jsonToTs(bullExt)} }`);
6571
- return `{ ${parts.join(", ")} }`;
6572
- }
6573
- var COMPOSERS = {
6574
- events: ({ moduleImport, cfg }) => {
6575
- const backend = cfg?.backend ?? "drizzle";
6576
- const multiTenant = Boolean(cfg?.multi_tenant);
6577
- return {
6578
- imports: [
6579
- `import { EventsModule } from '${moduleImport("events", "events.module")}';`
6580
- ],
6581
- calls: [
6582
- ` EventsModule.forRoot(${quoteOpts({ backend, multiTenant })}),`
6583
- ]
6584
- };
6585
- },
6586
- jobs: ({ moduleImport, cfg }) => {
6587
- const backend = cfg?.backend ?? "drizzle";
6588
- const multiTenant = Boolean(cfg?.multi_tenant);
6589
- const workerMode = (cfg?.worker_mode ?? "standalone").trim();
6590
- const imports = [
6591
- `import { JobsDomainModule } from '${moduleImport("jobs", "jobs-domain.module")}';`
6592
- ];
6593
- const bullExt = backend === "bullmq" ? cfg?.extensions?.bullmq : void 0;
6594
- const domainOpts = quoteBullmqDomainOpts({ backend, multiTenant, bullExt });
6595
- const calls = [` JobsDomainModule.forRoot(${domainOpts}),`];
6596
- if (workerMode === "embedded") {
6597
- imports.push(
6598
- `import { JobWorkerModule } from '${moduleImport("jobs", "job-worker.module")}';`
6599
- );
6600
- const workerOpts = backend === "bullmq" ? `{ mode: 'embedded', backend: 'bullmq'${bullExt ? `, domainModuleExtensions: { bullmq: ${jsonToTs(bullExt)} }` : ""} }` : `{ mode: 'embedded' }`;
6601
- calls.push(` JobWorkerModule.forRoot(${workerOpts}),`);
6602
- }
6603
- return { imports, calls };
6604
- },
6605
- bridge: ({ moduleImport, cfg }) => {
6606
- const backend = cfg?.backend ?? "drizzle";
6607
- const multiTenant = Boolean(cfg?.multi_tenant);
6608
- return {
6609
- imports: [
6610
- `import { BridgeModule } from '${moduleImport("bridge", "bridge.module")}';`
6611
- ],
6612
- calls: [
6613
- ` BridgeModule.forRoot(${quoteOpts({ backend, multiTenant })}),`
6614
- ]
6615
- };
6616
- },
6617
- integration: ({ moduleImport, cfg }) => {
6618
- const backend = cfg?.backend ?? "drizzle";
6619
- const multiTenant = Boolean(cfg?.multi_tenant);
6620
- return {
6621
- imports: [
6622
- `import { IntegrationModule } from '${moduleImport("integration", "integration.module")}';`
6623
- ],
6624
- calls: [
6625
- ` IntegrationModule.forRoot(${quoteOpts({ backend, multiTenant })}),`
6626
- ]
6627
- };
6628
- }
6629
- };
6630
- var PACKAGE2 = "@pattern-stack/codegen";
6631
- function makeModuleImport(mode, subsystemsRel) {
6632
- if (mode === "vendored") {
6633
- return (subsystem, moduleBasename) => `${subsystemsRel}/${subsystem}/${moduleBasename}`;
6634
- }
6635
- return (subsystem) => subsystem === "events" ? `${PACKAGE2}/subsystems` : `${PACKAGE2}/runtime/subsystems/${subsystem}/index`;
6636
- }
6637
- var COMPOSABLE_ORDER = ["events", "jobs", "bridge", "integration"];
6638
- var HEADER3 = `// AUTO-GENERATED by @pattern-stack/codegen. DO NOT EDIT.
6639
- // Subsystem composition barrel \u2014 reflects \`subsystems.install\` in
6640
- // codegen.config.yaml and the per-subsystem option blocks
6641
- // (\`events:\`, \`jobs:\`, \`bridge:\`, \`integration:\`).
6642
- //
6643
- // Wire into AppModule once:
6644
- //
6645
- // import { SUBSYSTEM_MODULES } from './generated/subsystems';
6646
- // @Module({ imports: [DatabaseModule, ...SUBSYSTEM_MODULES, ...GENERATED_MODULES] })
6647
- //
6648
- // Regenerated by every \`codegen entity new\` / \`codegen subsystem install\`.
6649
-
6650
- `;
6651
- function buildSubsystemBarrel(installed, config, subsystemsRel, mode = "vendored") {
6652
- const moduleImport = makeModuleImport(mode, subsystemsRel);
6653
- const actable = installed.filter((i) => i.status !== "incomplete");
6654
- const installedNames = new Set(actable.map((i) => i.name));
6655
- const emitted = [];
6656
- const skipped = [];
6657
- const allImports = [`import type { DynamicModule } from '@nestjs/common';`];
6658
- const allCalls = [];
6659
- for (const name of COMPOSABLE_ORDER) {
6660
- if (!installedNames.has(name)) continue;
6661
- const composer = COMPOSERS[name];
6662
- if (!composer) {
6663
- skipped.push(name);
6664
- continue;
6665
- }
6666
- const cfg = config?.[name] ?? void 0;
6667
- const out = composer({ moduleImport, cfg });
6668
- allImports.push(...out.imports);
6669
- allCalls.push(...out.calls);
6670
- emitted.push(name);
6671
- }
6672
- for (const inst of actable) {
6673
- if (!COMPOSABLE_ORDER.includes(inst.name) && !COMPOSERS[inst.name]) {
6674
- skipped.push(inst.name);
6675
- }
6676
- }
6677
- const exportLine = allCalls.length === 0 ? `export const SUBSYSTEM_MODULES: DynamicModule[] = [];
6678
- ` : `export const SUBSYSTEM_MODULES: DynamicModule[] = [
6679
- ${allCalls.join("\n")}
6680
- ];
6681
- `;
6682
- const body = allImports.join("\n") + "\n\n" + exportLine;
6683
- return { content: HEADER3 + body, emitted, skipped };
6684
- }
6685
- async function regenerateSubsystemBarrel(opts) {
6686
- const { ctx, dryRun = false } = opts;
6687
- const generatedDir = opts.generatedDir ?? resolveGeneratedDir(ctx);
6688
- const mode = resolveRuntimeMode(ctx.config);
6689
- const installed = mode === "package" ? configuredInstalledSubsystems(
6690
- ctx.config
6691
- ) : await detectInstalledSubsystems(ctx);
6692
- const subsystemsAbs = resolveSubsystemsRoot(ctx);
6693
- const barrelAbs = path8.resolve(generatedDir, "subsystems.ts");
6694
- let subsystemsRel = path8.relative(path8.dirname(barrelAbs), subsystemsAbs).split(path8.sep).join("/");
6695
- if (!subsystemsRel.startsWith(".")) subsystemsRel = "./" + subsystemsRel;
6696
- const { content, emitted, skipped } = buildSubsystemBarrel(
6697
- installed,
6698
- ctx.config,
6699
- subsystemsRel,
6700
- mode
6701
- );
6702
- let written = false;
6703
- if (!dryRun) {
6704
- fs5.mkdirSync(path8.dirname(barrelAbs), { recursive: true });
6705
- fs5.writeFileSync(barrelAbs, content);
6706
- written = true;
6707
- }
6708
- return {
6709
- subsystemBarrel: barrelAbs,
6710
- emitted,
6711
- skipped,
6712
- content,
6713
- written
6714
- };
6715
- }
6716
-
6717
- // src/cli/shared/subsystem-schema-generator.ts
6718
- import fs6 from "fs";
6719
- import path9 from "path";
6720
- var PACKAGE3 = "@pattern-stack/codegen";
6721
- var SCHEMA_SYMBOLS = {
6722
- events: ["domainEvents"],
6723
- jobs: [
6724
- "jobs",
6725
- "jobRuns",
6726
- "jobSteps",
6727
- "jobRunStatusEnum",
6728
- "jobStepKindEnum",
6729
- "jobStepStatusEnum",
6730
- "collisionModeEnum",
6731
- "replayFromEnum",
6732
- "parentClosePolicyEnum",
6733
- "waitKindEnum",
6734
- "triggerSourceEnum"
6735
- ],
6736
- bridge: ["bridgeDelivery", "bridgeDeliveryStatusEnum"],
6737
- integration: [
6738
- "integrationSubscriptions",
6739
- "integrationRuns",
6740
- "integrationRunItems",
6741
- "integrationRunDirectionEnum",
6742
- "integrationRunActionEnum",
6743
- "integrationRunStatusEnum",
6744
- "integrationRunItemOperationEnum",
6745
- "integrationRunItemStatusEnum"
6746
- ]
6747
- };
6748
- var SCHEMA_ORDER = ["events", "jobs", "bridge", "integration"];
6749
- var HEADER4 = `// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.
6750
- // Subsystem Drizzle schema barrel \u2014 re-exports the tables + pgEnums of every
6751
- // installed subsystem so drizzle-kit emits their CREATE TABLE / CREATE TYPE.
6752
- //
6753
- // Fold into your drizzle-kit schema entrypoint once, alongside the entity
6754
- // schema barrel:
6755
- //
6756
- // // src/schema.ts
6757
- // export * from './generated/schema'; // entity tables
6758
- // export * from './generated/subsystems-schema'; // subsystem tables + enums
6759
- //
6760
- // Regenerated by every \`codegen entity new\` / \`codegen subsystem install\`.
6761
-
6762
- `;
6763
- function schemaImportFor(mode, subsystem, subsystemsRel) {
6764
- return mode === "vendored" ? `${subsystemsRel}/${subsystem}` : `${PACKAGE3}/runtime/subsystems/${subsystem}/index`;
6765
- }
6766
- function buildSubsystemSchemaBarrel(installed, subsystemsRel, mode) {
6767
- const actable = installed.filter((i) => i.status !== "incomplete");
6768
- const installedNames = new Set(actable.map((i) => i.name));
6769
- const emitted = [];
6770
- const lines = [];
6771
- for (const name of SCHEMA_ORDER) {
6772
- if (!installedNames.has(name)) continue;
6773
- const symbols = SCHEMA_SYMBOLS[name];
6774
- if (!symbols || symbols.length === 0) continue;
6775
- const importSpec = schemaImportFor(mode, name, subsystemsRel);
6776
- lines.push(`export { ${symbols.join(", ")} } from '${importSpec}';`);
6777
- emitted.push(name);
6778
- }
6779
- const body = lines.length === 0 ? "export {};\n" : lines.join("\n") + "\n";
6780
- return { content: HEADER4 + body, emitted };
6781
- }
6782
- async function regenerateSubsystemSchemaBarrel(opts) {
6783
- const { ctx, dryRun = false } = opts;
6784
- const generatedDir = opts.generatedDir ?? resolveGeneratedDir(ctx);
6785
- const mode = resolveRuntimeMode(ctx.config);
6786
- const installed = mode === "package" ? configuredInstalledSubsystems(
6787
- ctx.config
6788
- ) : await detectInstalledSubsystems(ctx);
6789
- const subsystemsAbs = resolveSubsystemsRoot(ctx);
6790
- const barrelAbs = path9.resolve(generatedDir, "subsystems-schema.ts");
6791
- let subsystemsRel = path9.relative(path9.dirname(barrelAbs), subsystemsAbs).split(path9.sep).join("/");
6792
- if (!subsystemsRel.startsWith(".")) subsystemsRel = "./" + subsystemsRel;
6793
- const { content, emitted } = buildSubsystemSchemaBarrel(
6794
- installed,
6795
- subsystemsRel,
6796
- mode
6797
- );
6798
- let written = false;
6799
- if (!dryRun) {
6800
- fs6.mkdirSync(path9.dirname(barrelAbs), { recursive: true });
6801
- fs6.writeFileSync(barrelAbs, content);
6802
- written = true;
6803
- }
6804
- return { schemaBarrel: barrelAbs, emitted, content, written };
6805
- }
6806
-
6807
6544
  // src/cli/shared/bridge-registry-generator.ts
6808
- import fs7 from "fs";
6809
- import path10 from "path";
6545
+ import fs5 from "fs";
6546
+ import path8 from "path";
6810
6547
  import ts2 from "typescript";
6811
- var HEADER5 = `// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.
6548
+ var PACKAGE_BRIDGE_TYPE_IMPORT = "@pattern-stack/codegen/runtime/subsystems/bridge/index";
6549
+ var OUTPUT_FILE_BY_MODE = {
6550
+ vendored: "registry.ts",
6551
+ package: "bridge-registry.ts"
6552
+ };
6553
+ var HEADER3 = `// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.
6812
6554
  // Run \`codegen entity new --all\` to refresh.
6813
6555
  `;
6814
6556
  var DuplicateTriggerError = class extends Error {
@@ -6866,12 +6608,12 @@ var UnknownTriggerEventError = class extends Error {
6866
6608
  name = "UnknownTriggerEventError";
6867
6609
  };
6868
6610
  function findHandlerFiles(dir) {
6869
- if (!fs7.existsSync(dir)) return [];
6611
+ if (!fs5.existsSync(dir)) return [];
6870
6612
  const out = [];
6871
- for (const entry of fs7.readdirSync(dir, { withFileTypes: true })) {
6613
+ for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
6872
6614
  if (entry.name.startsWith(".")) continue;
6873
6615
  if (entry.name === "node_modules" || entry.name === "generated") continue;
6874
- const full = path10.join(dir, entry.name);
6616
+ const full = path8.join(dir, entry.name);
6875
6617
  if (entry.isDirectory()) {
6876
6618
  out.push(...findHandlerFiles(full));
6877
6619
  } else if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) {
@@ -6934,7 +6676,7 @@ function scanHandlerFiles(handlersDir) {
6934
6676
  const files = findHandlerFiles(handlersDir);
6935
6677
  const out = [];
6936
6678
  for (const filePath of files) {
6937
- const text2 = fs7.readFileSync(filePath, "utf8");
6679
+ const text2 = fs5.readFileSync(filePath, "utf8");
6938
6680
  const sourceFile = ts2.createSourceFile(
6939
6681
  filePath,
6940
6682
  text2,
@@ -6949,9 +6691,9 @@ function scanHandlerFiles(handlersDir) {
6949
6691
  }
6950
6692
  function readKnownEventTypes(eventsGeneratedDir) {
6951
6693
  if (!eventsGeneratedDir) return [];
6952
- const registryPath = path10.join(eventsGeneratedDir, "registry.ts");
6953
- if (!fs7.existsSync(registryPath)) return [];
6954
- const text2 = fs7.readFileSync(registryPath, "utf8");
6694
+ const registryPath = path8.join(eventsGeneratedDir, "registry.ts");
6695
+ if (!fs5.existsSync(registryPath)) return [];
6696
+ const text2 = fs5.readFileSync(registryPath, "utf8");
6955
6697
  const out = /* @__PURE__ */ new Set();
6956
6698
  const re = /^\s*'([a-zA-Z0-9_.-]+)':\s*\{/gm;
6957
6699
  let m;
@@ -6963,9 +6705,9 @@ function readKnownEventTypes(eventsGeneratedDir) {
6963
6705
  function readEventTiers(eventsGeneratedDir) {
6964
6706
  const out = /* @__PURE__ */ new Map();
6965
6707
  if (!eventsGeneratedDir) return out;
6966
- const registryPath = path10.join(eventsGeneratedDir, "registry.ts");
6967
- if (!fs7.existsSync(registryPath)) return out;
6968
- const text2 = fs7.readFileSync(registryPath, "utf8");
6708
+ const registryPath = path8.join(eventsGeneratedDir, "registry.ts");
6709
+ if (!fs5.existsSync(registryPath)) return out;
6710
+ const text2 = fs5.readFileSync(registryPath, "utf8");
6969
6711
  const re = /'([a-zA-Z0-9_.-]+)':\s*\{[^}]*?tier:\s*'(domain|audit)'/g;
6970
6712
  let m;
6971
6713
  while ((m = re.exec(text2)) !== null) {
@@ -7019,91 +6761,400 @@ function validateAgainstEventRegistry(triggers, knownEventTypes) {
7019
6761
  );
7020
6762
  }
7021
6763
  }
7022
- }
7023
- function buildBridgeRegistryContent(triggers) {
7024
- const chunks = [];
7025
- chunks.push(HEADER5);
7026
- chunks.push("");
7027
- chunks.push(`import type { BridgeRegistry } from '../bridge.protocol';`);
7028
- chunks.push("");
7029
- if (triggers.length === 0) {
7030
- chunks.push(`export const bridgeRegistry: BridgeRegistry = {};`);
7031
- chunks.push("");
7032
- return chunks.join("\n");
6764
+ }
6765
+ function buildBridgeRegistryContent(triggers, typeImport = "../bridge.protocol") {
6766
+ const chunks = [];
6767
+ chunks.push(HEADER3);
6768
+ chunks.push("");
6769
+ chunks.push(`import type { BridgeRegistry } from '${typeImport}';`);
6770
+ chunks.push("");
6771
+ if (triggers.length === 0) {
6772
+ chunks.push(`export const bridgeRegistry: BridgeRegistry = {};`);
6773
+ chunks.push("");
6774
+ return chunks.join("\n");
6775
+ }
6776
+ const grouped = /* @__PURE__ */ new Map();
6777
+ for (const t of triggers) {
6778
+ const list = grouped.get(t.event) ?? [];
6779
+ list.push(t);
6780
+ grouped.set(t.event, list);
6781
+ }
6782
+ const sortedEventTypes = Array.from(grouped.keys()).sort();
6783
+ chunks.push(`export const bridgeRegistry: BridgeRegistry = {`);
6784
+ for (const eventType of sortedEventTypes) {
6785
+ chunks.push(` '${eventType}': [`);
6786
+ for (const t of grouped.get(eventType)) {
6787
+ chunks.push(` {`);
6788
+ chunks.push(` triggerId: '${t.triggerId}',`);
6789
+ chunks.push(` jobType: '${t.jobType}',`);
6790
+ chunks.push(` map: ${t.mapSource},`);
6791
+ if (t.whenSource) {
6792
+ chunks.push(` when: ${t.whenSource},`);
6793
+ }
6794
+ chunks.push(` },`);
6795
+ }
6796
+ chunks.push(` ],`);
6797
+ }
6798
+ chunks.push(`};`);
6799
+ chunks.push("");
6800
+ return chunks.join("\n");
6801
+ }
6802
+ async function generateBridgeRegistry(opts) {
6803
+ const {
6804
+ handlersDir,
6805
+ eventsGeneratedDir,
6806
+ outputDir,
6807
+ mode = "vendored",
6808
+ bridgeInstalled = false,
6809
+ dryRun = false
6810
+ } = opts;
6811
+ const outputFileName = OUTPUT_FILE_BY_MODE[mode];
6812
+ const typeImport = mode === "package" ? PACKAGE_BRIDGE_TYPE_IMPORT : "../bridge.protocol";
6813
+ const installed = mode === "package" ? bridgeInstalled : fs5.existsSync(path8.resolve(outputDir, "..", "bridge.protocol.ts"));
6814
+ if (!installed) {
6815
+ const strayPath = path8.join(outputDir, outputFileName);
6816
+ if (!dryRun && fs5.existsSync(strayPath)) {
6817
+ fs5.rmSync(strayPath);
6818
+ }
6819
+ return {
6820
+ outputDir,
6821
+ triggerCount: 0,
6822
+ triggers: [],
6823
+ eventTypeCount: 0,
6824
+ written: false,
6825
+ files: [],
6826
+ skipped: true
6827
+ };
6828
+ }
6829
+ const triggers = scanHandlerFiles(handlersDir);
6830
+ validateNoDuplicateTriggers(triggers);
6831
+ const knownEventTypes = readKnownEventTypes(eventsGeneratedDir);
6832
+ validateAgainstEventRegistry(triggers, knownEventTypes);
6833
+ const eventTiers = readEventTiers(eventsGeneratedDir);
6834
+ validateNoAuditTriggers(triggers, eventTiers);
6835
+ const content = buildBridgeRegistryContent(triggers, typeImport);
6836
+ const file = {
6837
+ name: outputFileName,
6838
+ outputPath: path8.join(outputDir, outputFileName),
6839
+ content
6840
+ };
6841
+ let written = false;
6842
+ if (!dryRun) {
6843
+ fs5.mkdirSync(outputDir, { recursive: true });
6844
+ fs5.writeFileSync(file.outputPath, file.content);
6845
+ written = true;
6846
+ }
6847
+ const eventTypeCount = new Set(triggers.map((t) => t.event)).size;
6848
+ return {
6849
+ outputDir,
6850
+ triggerCount: triggers.length,
6851
+ triggers,
6852
+ eventTypeCount,
6853
+ written,
6854
+ files: [file],
6855
+ skipped: false
6856
+ };
6857
+ }
6858
+
6859
+ // src/cli/shared/subsystem-barrel-generator.ts
6860
+ function quoteOpts(opts) {
6861
+ const entries = Object.entries(opts).filter(([, v]) => v !== void 0);
6862
+ if (entries.length === 0) return "";
6863
+ return "{ " + entries.map(([k, v]) => `${k}: ${typeof v === "string" ? `'${v}'` : String(v)}`).join(", ") + " }";
6864
+ }
6865
+ function jsonToTs(value) {
6866
+ if (value === null || value === void 0) return "undefined";
6867
+ if (typeof value === "string") return `'${value.replace(/'/g, "\\'")}'`;
6868
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
6869
+ if (Array.isArray(value)) return `[${value.map(jsonToTs).join(", ")}]`;
6870
+ if (typeof value === "object") {
6871
+ const entries = Object.entries(value).filter(
6872
+ ([, v]) => v !== void 0
6873
+ );
6874
+ return `{ ${entries.map(([k, v]) => `${k}: ${jsonToTs(v)}`).join(", ")} }`;
6875
+ }
6876
+ return "undefined";
6877
+ }
6878
+ function quoteBullmqDomainOpts(input) {
6879
+ const { backend, multiTenant, bullExt } = input;
6880
+ if (backend !== "bullmq" || !bullExt) {
6881
+ return quoteOpts({ backend, multiTenant });
6882
+ }
6883
+ const parts = [`backend: 'bullmq'`];
6884
+ if (multiTenant) parts.push(`multiTenant: true`);
6885
+ parts.push(`extensions: { bullmq: ${jsonToTs(bullExt)} }`);
6886
+ return `{ ${parts.join(", ")} }`;
6887
+ }
6888
+ function workerPoolsClause(cfg, bridgeInstalled) {
6889
+ const explicit = cfg?.worker_pools;
6890
+ if (Array.isArray(explicit) && explicit.length > 0) {
6891
+ const list = explicit.filter((p) => typeof p === "string").map((p) => `'${p}'`).join(", ");
6892
+ if (list.length > 0) return `pools: [${list}]`;
6893
+ }
6894
+ if (cfg?.all_pools === true) return "allPools: true";
6895
+ if (bridgeInstalled) return "allPools: true";
6896
+ return "";
6897
+ }
6898
+ var COMPOSERS = {
6899
+ events: ({ moduleImport, cfg }) => {
6900
+ const backend = cfg?.backend ?? "drizzle";
6901
+ const multiTenant = Boolean(cfg?.multi_tenant);
6902
+ return {
6903
+ imports: [
6904
+ `import { EventsModule } from '${moduleImport("events", "events.module")}';`
6905
+ ],
6906
+ calls: [
6907
+ ` EventsModule.forRoot(${quoteOpts({ backend, multiTenant })}),`
6908
+ ]
6909
+ };
6910
+ },
6911
+ jobs: ({ moduleImport, cfg, bridgeInstalled }) => {
6912
+ const backend = cfg?.backend ?? "drizzle";
6913
+ const multiTenant = Boolean(cfg?.multi_tenant);
6914
+ const workerMode = (cfg?.worker_mode ?? "standalone").trim();
6915
+ const imports = [
6916
+ `import { JobsDomainModule } from '${moduleImport("jobs", "jobs-domain.module")}';`
6917
+ ];
6918
+ const bullExt = backend === "bullmq" ? cfg?.extensions?.bullmq : void 0;
6919
+ const domainOpts = quoteBullmqDomainOpts({ backend, multiTenant, bullExt });
6920
+ const calls = [` JobsDomainModule.forRoot(${domainOpts}),`];
6921
+ if (workerMode === "embedded") {
6922
+ imports.push(
6923
+ `import { JobWorkerModule } from '${moduleImport("jobs", "job-worker.module")}';`
6924
+ );
6925
+ const parts = [`mode: 'embedded'`];
6926
+ if (backend === "bullmq") {
6927
+ parts.push(`backend: 'bullmq'`);
6928
+ if (bullExt) {
6929
+ parts.push(`domainModuleExtensions: { bullmq: ${jsonToTs(bullExt)} }`);
6930
+ }
6931
+ }
6932
+ const poolsClause = workerPoolsClause(cfg, bridgeInstalled);
6933
+ if (poolsClause) parts.push(poolsClause);
6934
+ calls.push(` JobWorkerModule.forRoot({ ${parts.join(", ")} }),`);
6935
+ }
6936
+ return { imports, calls };
6937
+ },
6938
+ bridge: ({ moduleImport, cfg, mode }) => {
6939
+ const backend = cfg?.backend ?? "drizzle";
6940
+ const multiTenant = Boolean(cfg?.multi_tenant);
6941
+ const imports = [
6942
+ `import { BridgeModule } from '${moduleImport("bridge", "bridge.module")}';`
6943
+ ];
6944
+ if (mode === "package") {
6945
+ imports.push(`import { bridgeRegistry } from './bridge-registry';`);
6946
+ return {
6947
+ imports,
6948
+ calls: [
6949
+ ` BridgeModule.forRoot({ backend: '${backend}', multiTenant: ${multiTenant}, registry: bridgeRegistry }),`
6950
+ ]
6951
+ };
6952
+ }
6953
+ return {
6954
+ imports,
6955
+ calls: [
6956
+ ` BridgeModule.forRoot(${quoteOpts({ backend, multiTenant })}),`
6957
+ ]
6958
+ };
6959
+ },
6960
+ integration: ({ moduleImport, cfg }) => {
6961
+ const backend = cfg?.backend ?? "drizzle";
6962
+ const multiTenant = Boolean(cfg?.multi_tenant);
6963
+ return {
6964
+ imports: [
6965
+ `import { IntegrationModule } from '${moduleImport("integration", "integration.module")}';`
6966
+ ],
6967
+ calls: [
6968
+ ` IntegrationModule.forRoot(${quoteOpts({ backend, multiTenant })}),`
6969
+ ]
6970
+ };
6971
+ }
6972
+ };
6973
+ var PACKAGE2 = "@pattern-stack/codegen";
6974
+ function makeModuleImport(mode, subsystemsRel) {
6975
+ if (mode === "vendored") {
6976
+ return (subsystem, moduleBasename) => `${subsystemsRel}/${subsystem}/${moduleBasename}`;
7033
6977
  }
7034
- const grouped = /* @__PURE__ */ new Map();
7035
- for (const t of triggers) {
7036
- const list = grouped.get(t.event) ?? [];
7037
- list.push(t);
7038
- grouped.set(t.event, list);
6978
+ return (subsystem) => subsystem === "events" ? `${PACKAGE2}/subsystems` : `${PACKAGE2}/runtime/subsystems/${subsystem}/index`;
6979
+ }
6980
+ var COMPOSABLE_ORDER = ["events", "jobs", "bridge", "integration"];
6981
+ var HEADER4 = `// AUTO-GENERATED by @pattern-stack/codegen. DO NOT EDIT.
6982
+ // Subsystem composition barrel \u2014 reflects \`subsystems.install\` in
6983
+ // codegen.config.yaml and the per-subsystem option blocks
6984
+ // (\`events:\`, \`jobs:\`, \`bridge:\`, \`integration:\`).
6985
+ //
6986
+ // Wire into AppModule once:
6987
+ //
6988
+ // import { SUBSYSTEM_MODULES } from './generated/subsystems';
6989
+ // @Module({ imports: [DatabaseModule, ...SUBSYSTEM_MODULES, ...GENERATED_MODULES] })
6990
+ //
6991
+ // Regenerated by every \`codegen entity new\` / \`codegen subsystem install\`.
6992
+
6993
+ `;
6994
+ function buildSubsystemBarrel(installed, config, subsystemsRel, mode = "vendored") {
6995
+ const moduleImport = makeModuleImport(mode, subsystemsRel);
6996
+ const actable = installed.filter((i) => i.status !== "incomplete");
6997
+ const installedNames = new Set(actable.map((i) => i.name));
6998
+ const bridgeInstalled = installedNames.has("bridge");
6999
+ const emitted = [];
7000
+ const skipped = [];
7001
+ const allImports = [`import type { DynamicModule } from '@nestjs/common';`];
7002
+ const allCalls = [];
7003
+ for (const name of COMPOSABLE_ORDER) {
7004
+ if (!installedNames.has(name)) continue;
7005
+ const composer = COMPOSERS[name];
7006
+ if (!composer) {
7007
+ skipped.push(name);
7008
+ continue;
7009
+ }
7010
+ const cfg = config?.[name] ?? void 0;
7011
+ const out = composer({ moduleImport, cfg, mode, bridgeInstalled });
7012
+ allImports.push(...out.imports);
7013
+ allCalls.push(...out.calls);
7014
+ emitted.push(name);
7039
7015
  }
7040
- const sortedEventTypes = Array.from(grouped.keys()).sort();
7041
- chunks.push(`export const bridgeRegistry: BridgeRegistry = {`);
7042
- for (const eventType of sortedEventTypes) {
7043
- chunks.push(` '${eventType}': [`);
7044
- for (const t of grouped.get(eventType)) {
7045
- chunks.push(` {`);
7046
- chunks.push(` triggerId: '${t.triggerId}',`);
7047
- chunks.push(` jobType: '${t.jobType}',`);
7048
- chunks.push(` map: ${t.mapSource},`);
7049
- if (t.whenSource) {
7050
- chunks.push(` when: ${t.whenSource},`);
7051
- }
7052
- chunks.push(` },`);
7016
+ for (const inst of actable) {
7017
+ if (!COMPOSABLE_ORDER.includes(inst.name) && !COMPOSERS[inst.name]) {
7018
+ skipped.push(inst.name);
7053
7019
  }
7054
- chunks.push(` ],`);
7055
7020
  }
7056
- chunks.push(`};`);
7057
- chunks.push("");
7058
- return chunks.join("\n");
7021
+ const exportLine = allCalls.length === 0 ? `export const SUBSYSTEM_MODULES: DynamicModule[] = [];
7022
+ ` : `export const SUBSYSTEM_MODULES: DynamicModule[] = [
7023
+ ${allCalls.join("\n")}
7024
+ ];
7025
+ `;
7026
+ const body = allImports.join("\n") + "\n\n" + exportLine;
7027
+ return { content: HEADER4 + body, emitted, skipped };
7059
7028
  }
7060
- var OUTPUT_FILE_NAME = "registry.ts";
7061
- async function generateBridgeRegistry(opts) {
7062
- const { handlersDir, eventsGeneratedDir, outputDir, dryRun = false } = opts;
7063
- const bridgeProtocolPath = path10.resolve(outputDir, "..", "bridge.protocol.ts");
7064
- if (!fs7.existsSync(bridgeProtocolPath)) {
7065
- const strayPath = path10.join(outputDir, OUTPUT_FILE_NAME);
7066
- if (!dryRun && fs7.existsSync(strayPath)) {
7067
- fs7.rmSync(strayPath);
7029
+ async function regenerateSubsystemBarrel(opts) {
7030
+ const { ctx, dryRun = false } = opts;
7031
+ const generatedDir = opts.generatedDir ?? resolveGeneratedDir(ctx);
7032
+ const mode = resolveRuntimeMode(ctx.config);
7033
+ const installed = mode === "package" ? configuredInstalledSubsystems(
7034
+ ctx.config
7035
+ ) : await detectInstalledSubsystems(ctx);
7036
+ const subsystemsAbs = resolveSubsystemsRoot(ctx);
7037
+ const barrelAbs = path9.resolve(generatedDir, "subsystems.ts");
7038
+ let subsystemsRel = path9.relative(path9.dirname(barrelAbs), subsystemsAbs).split(path9.sep).join("/");
7039
+ if (!subsystemsRel.startsWith(".")) subsystemsRel = "./" + subsystemsRel;
7040
+ const { content, emitted, skipped } = buildSubsystemBarrel(
7041
+ installed,
7042
+ ctx.config,
7043
+ subsystemsRel,
7044
+ mode
7045
+ );
7046
+ let written = false;
7047
+ if (!dryRun) {
7048
+ fs6.mkdirSync(path9.dirname(barrelAbs), { recursive: true });
7049
+ fs6.writeFileSync(barrelAbs, content);
7050
+ written = true;
7051
+ if (mode === "package" && emitted.includes("bridge")) {
7052
+ const registryPath = path9.resolve(generatedDir, "bridge-registry.ts");
7053
+ if (!fs6.existsSync(registryPath)) {
7054
+ fs6.writeFileSync(
7055
+ registryPath,
7056
+ buildBridgeRegistryContent([], PACKAGE_BRIDGE_TYPE_IMPORT)
7057
+ );
7058
+ }
7068
7059
  }
7069
- return {
7070
- outputDir,
7071
- triggerCount: 0,
7072
- triggers: [],
7073
- eventTypeCount: 0,
7074
- written: false,
7075
- files: [],
7076
- skipped: true
7077
- };
7078
7060
  }
7079
- const triggers = scanHandlerFiles(handlersDir);
7080
- validateNoDuplicateTriggers(triggers);
7081
- const knownEventTypes = readKnownEventTypes(eventsGeneratedDir);
7082
- validateAgainstEventRegistry(triggers, knownEventTypes);
7083
- const eventTiers = readEventTiers(eventsGeneratedDir);
7084
- validateNoAuditTriggers(triggers, eventTiers);
7085
- const content = buildBridgeRegistryContent(triggers);
7086
- const file = {
7087
- name: OUTPUT_FILE_NAME,
7088
- outputPath: path10.join(outputDir, OUTPUT_FILE_NAME),
7089
- content
7061
+ return {
7062
+ subsystemBarrel: barrelAbs,
7063
+ emitted,
7064
+ skipped,
7065
+ content,
7066
+ written
7090
7067
  };
7068
+ }
7069
+
7070
+ // src/cli/shared/subsystem-schema-generator.ts
7071
+ import fs7 from "fs";
7072
+ import path10 from "path";
7073
+ var PACKAGE3 = "@pattern-stack/codegen";
7074
+ var SCHEMA_SYMBOLS = {
7075
+ events: ["domainEvents"],
7076
+ jobs: [
7077
+ "jobs",
7078
+ "jobRuns",
7079
+ "jobSteps",
7080
+ "jobRunStatusEnum",
7081
+ "jobStepKindEnum",
7082
+ "jobStepStatusEnum",
7083
+ "collisionModeEnum",
7084
+ "replayFromEnum",
7085
+ "parentClosePolicyEnum",
7086
+ "waitKindEnum",
7087
+ "triggerSourceEnum"
7088
+ ],
7089
+ bridge: ["bridgeDelivery", "bridgeDeliveryStatusEnum"],
7090
+ integration: [
7091
+ "integrationSubscriptions",
7092
+ "integrationRuns",
7093
+ "integrationRunItems",
7094
+ "integrationRunDirectionEnum",
7095
+ "integrationRunActionEnum",
7096
+ "integrationRunStatusEnum",
7097
+ "integrationRunItemOperationEnum",
7098
+ "integrationRunItemStatusEnum"
7099
+ ]
7100
+ };
7101
+ var SCHEMA_ORDER = ["events", "jobs", "bridge", "integration"];
7102
+ var HEADER5 = `// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.
7103
+ // Subsystem Drizzle schema barrel \u2014 re-exports the tables + pgEnums of every
7104
+ // installed subsystem so drizzle-kit emits their CREATE TABLE / CREATE TYPE.
7105
+ //
7106
+ // Fold into your drizzle-kit schema entrypoint once, alongside the entity
7107
+ // schema barrel:
7108
+ //
7109
+ // // src/schema.ts
7110
+ // export * from './generated/schema'; // entity tables
7111
+ // export * from './generated/subsystems-schema'; // subsystem tables + enums
7112
+ //
7113
+ // Regenerated by every \`codegen entity new\` / \`codegen subsystem install\`.
7114
+
7115
+ `;
7116
+ function schemaImportFor(mode, subsystem, subsystemsRel) {
7117
+ return mode === "vendored" ? `${subsystemsRel}/${subsystem}` : `${PACKAGE3}/runtime/subsystems/${subsystem}/index`;
7118
+ }
7119
+ function buildSubsystemSchemaBarrel(installed, subsystemsRel, mode) {
7120
+ const actable = installed.filter((i) => i.status !== "incomplete");
7121
+ const installedNames = new Set(actable.map((i) => i.name));
7122
+ const emitted = [];
7123
+ const lines = [];
7124
+ for (const name of SCHEMA_ORDER) {
7125
+ if (!installedNames.has(name)) continue;
7126
+ const symbols = SCHEMA_SYMBOLS[name];
7127
+ if (!symbols || symbols.length === 0) continue;
7128
+ const importSpec = schemaImportFor(mode, name, subsystemsRel);
7129
+ lines.push(`export { ${symbols.join(", ")} } from '${importSpec}';`);
7130
+ emitted.push(name);
7131
+ }
7132
+ const body = lines.length === 0 ? "export {};\n" : lines.join("\n") + "\n";
7133
+ return { content: HEADER5 + body, emitted };
7134
+ }
7135
+ async function regenerateSubsystemSchemaBarrel(opts) {
7136
+ const { ctx, dryRun = false } = opts;
7137
+ const generatedDir = opts.generatedDir ?? resolveGeneratedDir(ctx);
7138
+ const mode = resolveRuntimeMode(ctx.config);
7139
+ const installed = mode === "package" ? configuredInstalledSubsystems(
7140
+ ctx.config
7141
+ ) : await detectInstalledSubsystems(ctx);
7142
+ const subsystemsAbs = resolveSubsystemsRoot(ctx);
7143
+ const barrelAbs = path10.resolve(generatedDir, "subsystems-schema.ts");
7144
+ let subsystemsRel = path10.relative(path10.dirname(barrelAbs), subsystemsAbs).split(path10.sep).join("/");
7145
+ if (!subsystemsRel.startsWith(".")) subsystemsRel = "./" + subsystemsRel;
7146
+ const { content, emitted } = buildSubsystemSchemaBarrel(
7147
+ installed,
7148
+ subsystemsRel,
7149
+ mode
7150
+ );
7091
7151
  let written = false;
7092
7152
  if (!dryRun) {
7093
- fs7.mkdirSync(outputDir, { recursive: true });
7094
- fs7.writeFileSync(file.outputPath, file.content);
7153
+ fs7.mkdirSync(path10.dirname(barrelAbs), { recursive: true });
7154
+ fs7.writeFileSync(barrelAbs, content);
7095
7155
  written = true;
7096
7156
  }
7097
- const eventTypeCount = new Set(triggers.map((t) => t.event)).size;
7098
- return {
7099
- outputDir,
7100
- triggerCount: triggers.length,
7101
- triggers,
7102
- eventTypeCount,
7103
- written,
7104
- files: [file],
7105
- skipped: false
7106
- };
7157
+ return { schemaBarrel: barrelAbs, emitted, content, written };
7107
7158
  }
7108
7159
 
7109
7160
  // src/cli/shared/orchestration-generator.ts
@@ -9737,12 +9788,12 @@ var EntityNewCommand = class extends Command2 {
9737
9788
  subsystemsRoot,
9738
9789
  "events/generated"
9739
9790
  );
9740
- const bridgeRegistryOutputDir = path14.resolve(
9741
- subsystemsRoot,
9742
- "bridge/generated"
9743
- );
9744
- const backendSrcForHandlers = ctx.config?.paths?.backend_src ?? "src";
9745
9791
  const runtimeMode = resolveRuntimeMode(ctx.config);
9792
+ const bridgeInstalledForRegistry = configuredSubsystemNames(
9793
+ ctx.config
9794
+ ).includes("bridge");
9795
+ const bridgeRegistryOutputDir = runtimeMode === "package" ? generatedDir : path14.resolve(subsystemsRoot, "bridge/generated");
9796
+ const backendSrcForHandlers = ctx.config?.paths?.backend_src ?? "src";
9746
9797
  const bridgeHandlersDir = path14.resolve(
9747
9798
  ctx.cwd,
9748
9799
  backendSrcForHandlers,
@@ -9793,6 +9844,8 @@ var EntityNewCommand = class extends Command2 {
9793
9844
  handlersDir: bridgeHandlersDir,
9794
9845
  eventsGeneratedDir: eventCodegenOutputDir,
9795
9846
  outputDir: bridgeRegistryOutputDir,
9847
+ mode: runtimeMode,
9848
+ bridgeInstalled: bridgeInstalledForRegistry,
9796
9849
  dryRun: true
9797
9850
  });
9798
9851
  const orchestrationPatterns = await loadOrchestrationPatterns();
@@ -9987,7 +10040,9 @@ var EntityNewCommand = class extends Command2 {
9987
10040
  bridgeRegistryResult = await generateBridgeRegistry({
9988
10041
  handlersDir: bridgeHandlersDir,
9989
10042
  eventsGeneratedDir: eventCodegenOutputDir,
9990
- outputDir: bridgeRegistryOutputDir
10043
+ outputDir: bridgeRegistryOutputDir,
10044
+ mode: runtimeMode,
10045
+ bridgeInstalled: bridgeInstalledForRegistry
9991
10046
  });
9992
10047
  if (bridgeRegistryResult.skipped && !isJsonMode()) {
9993
10048
  printInfo(