@pattern-stack/codegen 0.6.3 → 0.6.5

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +2 -0
  3. package/dist/runtime/subsystems/auth/auth-oauth-state.schema.d.ts +81 -0
  4. package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js +12 -0
  5. package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js.map +1 -0
  6. package/dist/runtime/subsystems/auth/auth.module.d.ts +39 -24
  7. package/dist/runtime/subsystems/auth/auth.module.js +246 -13
  8. package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
  9. package/dist/runtime/subsystems/auth/auth.tokens.d.ts +15 -2
  10. package/dist/runtime/subsystems/auth/auth.tokens.js +9 -1
  11. package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
  12. package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.d.ts +23 -0
  13. package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js +68 -0
  14. package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js.map +1 -0
  15. package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.d.ts +21 -0
  16. package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js +51 -0
  17. package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js.map +1 -0
  18. package/dist/runtime/subsystems/auth/controllers/auth.controller.d.ts +31 -0
  19. package/dist/runtime/subsystems/auth/controllers/auth.controller.js +137 -0
  20. package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -0
  21. package/dist/runtime/subsystems/auth/index.d.ts +13 -4
  22. package/dist/runtime/subsystems/auth/index.js +253 -14
  23. package/dist/runtime/subsystems/auth/index.js.map +1 -1
  24. package/dist/runtime/subsystems/auth/protocols/integration-store.d.ts +36 -1
  25. package/dist/runtime/subsystems/auth/protocols/oauth-state-store.d.ts +33 -7
  26. package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js +12 -0
  27. package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js.map +1 -1
  28. package/dist/runtime/subsystems/auth/protocols/provider-strategy.d.ts +47 -0
  29. package/dist/runtime/subsystems/auth/protocols/provider-strategy.js +1 -0
  30. package/dist/runtime/subsystems/auth/protocols/provider-strategy.js.map +1 -0
  31. package/dist/runtime/subsystems/auth/protocols/user-context.d.ts +24 -0
  32. package/dist/runtime/subsystems/auth/protocols/user-context.js +1 -0
  33. package/dist/runtime/subsystems/auth/protocols/user-context.js.map +1 -0
  34. package/dist/runtime/subsystems/index.d.ts +9 -4
  35. package/dist/runtime/subsystems/index.js +247 -14
  36. package/dist/runtime/subsystems/index.js.map +1 -1
  37. package/dist/src/cli/index.js +578 -143
  38. package/dist/src/cli/index.js.map +1 -1
  39. package/package.json +2 -1
  40. package/runtime/subsystems/auth/auth-oauth-state.schema.ts +30 -0
  41. package/runtime/subsystems/auth/auth.module.ts +89 -32
  42. package/runtime/subsystems/auth/auth.tokens.ts +14 -1
  43. package/runtime/subsystems/auth/backends/state-store.drizzle-backend.ts +83 -0
  44. package/runtime/subsystems/auth/backends/state-store.memory-backend.ts +76 -0
  45. package/runtime/subsystems/auth/controllers/auth.controller.ts +155 -0
  46. package/runtime/subsystems/auth/index.ts +43 -4
  47. package/runtime/subsystems/auth/protocols/integration-store.ts +37 -0
  48. package/runtime/subsystems/auth/protocols/oauth-state-store.ts +38 -6
  49. package/runtime/subsystems/auth/protocols/provider-strategy.ts +41 -0
  50. package/runtime/subsystems/auth/protocols/user-context.ts +22 -0
  51. package/runtime/subsystems/index.ts +17 -2
  52. package/templates/entity/new/backend/modules/core/sync-source.ejs.t +2 -2
  53. package/templates/entity/new/backend/modules/core/sync-source.providers.ejs.t +1 -1
  54. package/templates/entity/new/clean-lite-ps/prompt-extension.js +14 -0
  55. package/templates/entity/new/prompt.js +1 -0
  56. package/templates/subsystem/auth/app-module-hook.ejs.t +21 -0
  57. package/templates/subsystem/auth/auth-oauth-state.schema.ejs.t +35 -0
  58. package/templates/subsystem/auth/env-config.ejs.t +20 -0
  59. package/templates/subsystem/auth/prompt.js +46 -0
  60. package/templates/subsystem/auth-config/codegen-config-auth-block.ejs.t +20 -0
  61. package/templates/subsystem/auth-config/prompt.js +20 -0
  62. package/templates/subsystem/auth-integrations/app-module-hook.ejs.t +16 -0
  63. package/templates/subsystem/auth-integrations/prompt.js +23 -0
  64. package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.d.ts +0 -24
  65. package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.js +0 -24
  66. package/dist/runtime/subsystems/auth/backends/oauth-state-store/in-memory.js.map +0 -1
  67. package/runtime/subsystems/auth/backends/oauth-state-store/in-memory.ts +0 -42
@@ -2839,8 +2839,8 @@ function loadEntityFromYaml(filePath) {
2839
2839
  }
2840
2840
  function formatZodErrors(error) {
2841
2841
  return error.errors.map((err) => {
2842
- const path27 = err.path.join(".");
2843
- const location = path27 ? `at '${path27}'` : "at root";
2842
+ const path29 = err.path.join(".");
2843
+ const location = path29 ? `at '${path29}'` : "at root";
2844
2844
  return `${err.message} ${location}`;
2845
2845
  });
2846
2846
  }
@@ -3392,19 +3392,19 @@ function findCircularDependencies(graph) {
3392
3392
  const cycles = [];
3393
3393
  const visited = /* @__PURE__ */ new Set();
3394
3394
  const recursionStack = /* @__PURE__ */ new Set();
3395
- function dfs(node, path27) {
3395
+ function dfs(node, path29) {
3396
3396
  visited.add(node);
3397
3397
  recursionStack.add(node);
3398
3398
  const outgoingEdges = graph.edges.filter((e) => e.from === node);
3399
3399
  for (const edge of outgoingEdges) {
3400
3400
  if (!visited.has(edge.to)) {
3401
- dfs(edge.to, [...path27, edge.to]);
3401
+ dfs(edge.to, [...path29, edge.to]);
3402
3402
  } else if (recursionStack.has(edge.to)) {
3403
- const cycleStart = path27.indexOf(edge.to);
3403
+ const cycleStart = path29.indexOf(edge.to);
3404
3404
  if (cycleStart !== -1) {
3405
- cycles.push([...path27.slice(cycleStart), edge.to]);
3405
+ cycles.push([...path29.slice(cycleStart), edge.to]);
3406
3406
  } else {
3407
- cycles.push([...path27, edge.to]);
3407
+ cycles.push([...path29, edge.to]);
3408
3408
  }
3409
3409
  }
3410
3410
  }
@@ -4001,8 +4001,8 @@ function suggestTransitiveRelationships(graph, options) {
4001
4001
  for (const [entityName, entity] of graph.entities) {
4002
4002
  if (shouldExcludeEntity(entityName, opts)) continue;
4003
4003
  const paths = findTransitivePaths(graph, entityName, opts);
4004
- for (const path27 of paths) {
4005
- suggestions.push(createSuggestion(path27));
4004
+ for (const path29 of paths) {
4005
+ suggestions.push(createSuggestion(path29));
4006
4006
  }
4007
4007
  }
4008
4008
  return suggestions;
@@ -4033,7 +4033,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
4033
4033
  while (queue.length > 0) {
4034
4034
  const current = queue.shift();
4035
4035
  if (!current) continue;
4036
- const { entity, depth, path: path27, visited } = current;
4036
+ const { entity, depth, path: path29, visited } = current;
4037
4037
  if (depth >= opts.maxDepth) continue;
4038
4038
  const currentEntity = graph.entities.get(entity);
4039
4039
  if (!currentEntity) continue;
@@ -4044,7 +4044,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
4044
4044
  if (shouldExcludeEntity(target, opts)) continue;
4045
4045
  if (visited.has(target)) continue;
4046
4046
  const newPath = [
4047
- ...path27,
4047
+ ...path29,
4048
4048
  {
4049
4049
  via: entity,
4050
4050
  relationship: relName,
@@ -4112,15 +4112,15 @@ function generateYamlSnippet(name, target, throughPath) {
4112
4112
  target: ${target}
4113
4113
  through: "${throughPath}"`;
4114
4114
  }
4115
- function createSuggestion(path27) {
4116
- const pathDescription = [path27.source, ...path27.hops.map((h) => h.via), path27.target].join(" -> ");
4115
+ function createSuggestion(path29) {
4116
+ const pathDescription = [path29.source, ...path29.hops.map((h) => h.via), path29.target].join(" -> ");
4117
4117
  return {
4118
4118
  severity: "info",
4119
4119
  type: "transitive_suggestion",
4120
- entity: path27.source,
4120
+ entity: path29.source,
4121
4121
  message: `Potential transitive relationship: ${pathDescription}`,
4122
- suggestion: `Add "${path27.suggestedName}" relationship via "${path27.throughPath}"`,
4123
- path: path27
4122
+ suggestion: `Add "${path29.suggestedName}" relationship via "${path29.throughPath}"`,
4123
+ path: path29
4124
4124
  };
4125
4125
  }
4126
4126
 
@@ -7902,7 +7902,7 @@ var entity_default = entityNoun;
7902
7902
 
7903
7903
  // src/cli/commands/subsystem.ts
7904
7904
  import fs10 from "fs";
7905
- import path19 from "path";
7905
+ import path21 from "path";
7906
7906
  import { Command as Command3, Option as Option3 } from "clipanion";
7907
7907
 
7908
7908
  // src/cli/shared/config-block-detect.ts
@@ -8146,9 +8146,90 @@ function localsToHygenArgs5(locals) {
8146
8146
  ];
8147
8147
  }
8148
8148
 
8149
+ // src/cli/shared/auth-scaffold-locals.ts
8150
+ import crypto2 from "crypto";
8151
+ import path17 from "path";
8152
+ var FALLBACK_BACKEND_SRC3 = "src";
8153
+ var DEFAULT_REDIRECT_URI_BASE = "http://localhost:3000";
8154
+ function resolveAuthScaffoldLocals(input) {
8155
+ const { cwd, config } = input;
8156
+ const backendSrc = typeof config?.paths?.backend_src === "string" && config.paths.backend_src.length > 0 ? config.paths.backend_src : FALLBACK_BACKEND_SRC3;
8157
+ const subsystemsRoot = resolveSubsystemsRootFromConfig(cwd, config);
8158
+ const authBlock = config?.auth ?? {};
8159
+ const redirectRaw = authBlock.redirect_uri_base;
8160
+ const redirectUriBase = typeof redirectRaw === "string" && redirectRaw.length > 0 ? redirectRaw : DEFAULT_REDIRECT_URI_BASE;
8161
+ const tokenEncryptionKey = crypto2.randomBytes(32).toString("base64");
8162
+ return {
8163
+ appName: path17.basename(cwd),
8164
+ configPath: path17.resolve(cwd, "codegen.config.yaml"),
8165
+ schemaPath: path17.resolve(
8166
+ subsystemsRoot,
8167
+ "auth",
8168
+ "auth-oauth-state.schema.ts"
8169
+ ),
8170
+ appModulePath: path17.resolve(cwd, backendSrc, "app.module.ts"),
8171
+ envConfigPath: path17.resolve(cwd, ".env.config"),
8172
+ redirectUriBase,
8173
+ tokenEncryptionKey
8174
+ };
8175
+ }
8176
+ function localsToHygenArgs6(locals) {
8177
+ return [
8178
+ "--appName",
8179
+ locals.appName,
8180
+ "--configPath",
8181
+ locals.configPath,
8182
+ "--schemaPath",
8183
+ locals.schemaPath,
8184
+ "--appModulePath",
8185
+ locals.appModulePath,
8186
+ "--envConfigPath",
8187
+ locals.envConfigPath,
8188
+ "--redirectUriBase",
8189
+ locals.redirectUriBase,
8190
+ "--tokenEncryptionKey",
8191
+ locals.tokenEncryptionKey
8192
+ ];
8193
+ }
8194
+
8195
+ // src/cli/shared/auth-integrations-scaffold-locals.ts
8196
+ import path18 from "path";
8197
+ var FALLBACK_BACKEND_SRC4 = "src";
8198
+ var SHARED_DIR_NAME = "shared";
8199
+ var DEFAULT_DEFINITIONS_DIR = "definitions/entities";
8200
+ function resolveAuthIntegrationsScaffoldLocals(input) {
8201
+ const { cwd, config } = input;
8202
+ const backendSrc = typeof config?.paths?.backend_src === "string" && config.paths.backend_src.length > 0 ? config.paths.backend_src : FALLBACK_BACKEND_SRC4;
8203
+ const sharedConfigured = config?.paths?.shared;
8204
+ const sharedRoot = typeof sharedConfigured === "string" && sharedConfigured.length > 0 ? path18.resolve(cwd, sharedConfigured) : path18.resolve(cwd, backendSrc, SHARED_DIR_NAME);
8205
+ const definitionsConfigured = config?.paths?.definitions;
8206
+ const definitionsPath = typeof definitionsConfigured === "string" && definitionsConfigured.length > 0 ? path18.resolve(cwd, definitionsConfigured, "integration.yaml") : path18.resolve(cwd, DEFAULT_DEFINITIONS_DIR, "integration.yaml");
8207
+ const appModulePath = path18.resolve(cwd, backendSrc, "app.module.ts");
8208
+ let authModuleRegistered = false;
8209
+ const appModuleSource = input.readFile(appModulePath);
8210
+ if (appModuleSource && appModuleSource.includes("AuthModule.forRoot")) {
8211
+ authModuleRegistered = true;
8212
+ }
8213
+ return {
8214
+ appName: path18.basename(cwd),
8215
+ appModulePath,
8216
+ sharedRoot,
8217
+ definitionsPath,
8218
+ authModuleRegistered
8219
+ };
8220
+ }
8221
+ function localsToHygenArgs7(locals) {
8222
+ return [
8223
+ "--appName",
8224
+ locals.appName,
8225
+ "--appModulePath",
8226
+ locals.appModulePath
8227
+ ];
8228
+ }
8229
+
8149
8230
  // src/cli/shared/runtime-copier.ts
8150
8231
  import fs8 from "fs";
8151
- import path17 from "path";
8232
+ import path19 from "path";
8152
8233
  function readIfExists(p) {
8153
8234
  try {
8154
8235
  return fs8.readFileSync(p, "utf-8");
@@ -8159,7 +8240,7 @@ function readIfExists(p) {
8159
8240
  function writeFile(target, content) {
8160
8241
  const existing = readIfExists(target);
8161
8242
  if (existing === content) return "unchanged";
8162
- fs8.mkdirSync(path17.dirname(target), { recursive: true });
8243
+ fs8.mkdirSync(path19.dirname(target), { recursive: true });
8163
8244
  fs8.writeFileSync(target, content);
8164
8245
  return existing === null ? "written" : "updated";
8165
8246
  }
@@ -8173,8 +8254,8 @@ function extractRelativeImports(source) {
8173
8254
  return out;
8174
8255
  }
8175
8256
  function resolveSourceImport(sourceFile, specifier) {
8176
- const base = path17.resolve(path17.dirname(sourceFile), specifier);
8177
- const candidates = [base + ".ts", base + ".tsx", path17.join(base, "index.ts")];
8257
+ const base = path19.resolve(path19.dirname(sourceFile), specifier);
8258
+ const candidates = [base + ".ts", base + ".tsx", path19.join(base, "index.ts")];
8178
8259
  for (const c of candidates) {
8179
8260
  if (fs8.existsSync(c)) return c;
8180
8261
  }
@@ -8185,8 +8266,8 @@ async function copyRuntime(opts) {
8185
8266
  if (!fs8.existsSync(sourceDir) || !fs8.statSync(sourceDir).isDirectory()) {
8186
8267
  throw new Error(`runtime source directory not found: ${sourceDir}`);
8187
8268
  }
8188
- const runtimeRoot4 = opts.runtimeRoot ? path17.resolve(opts.runtimeRoot) : path17.resolve(sourceDir, "..", "..");
8189
- const depsTargetRoot = opts.depsTargetRoot ?? path17.resolve(targetDir, "..");
8269
+ const runtimeRoot4 = opts.runtimeRoot ? path19.resolve(opts.runtimeRoot) : path19.resolve(sourceDir, "..", "..");
8270
+ const depsTargetRoot = opts.depsTargetRoot ?? path19.resolve(targetDir, "..");
8190
8271
  const result = {
8191
8272
  written: [],
8192
8273
  updated: [],
@@ -8197,7 +8278,7 @@ async function copyRuntime(opts) {
8197
8278
  const queue = [];
8198
8279
  function walk(dir) {
8199
8280
  for (const entry of fs8.readdirSync(dir)) {
8200
- const src = path17.join(dir, entry);
8281
+ const src = path19.join(dir, entry);
8201
8282
  const stat = fs8.statSync(src);
8202
8283
  if (stat.isDirectory()) {
8203
8284
  if (entry === "generated") continue;
@@ -8206,9 +8287,9 @@ async function copyRuntime(opts) {
8206
8287
  }
8207
8288
  if (!stat.isFile()) continue;
8208
8289
  if (!entry.endsWith(".ts") && !entry.endsWith(".tsx")) continue;
8209
- const rel = path17.relative(sourceDir, src);
8290
+ const rel = path19.relative(sourceDir, src);
8210
8291
  if (filter && !filter(rel) && !filter(entry)) continue;
8211
- queue.push({ src, dest: path17.join(targetDir, rel), isDep: false });
8292
+ queue.push({ src, dest: path19.join(targetDir, rel), isDep: false });
8212
8293
  }
8213
8294
  }
8214
8295
  walk(sourceDir);
@@ -8230,11 +8311,11 @@ async function copyRuntime(opts) {
8230
8311
  for (const spec of extractRelativeImports(content)) {
8231
8312
  const resolvedSrc = resolveSourceImport(next.src, spec);
8232
8313
  if (!resolvedSrc) continue;
8233
- const relToRuntime = path17.relative(runtimeRoot4, resolvedSrc);
8234
- if (relToRuntime.startsWith("..") || path17.isAbsolute(relToRuntime)) continue;
8235
- const relToSource = path17.relative(sourceDir, resolvedSrc);
8236
- if (!relToSource.startsWith("..") && !path17.isAbsolute(relToSource)) continue;
8237
- const depDest = path17.join(depsTargetRoot, relToRuntime);
8314
+ const relToRuntime = path19.relative(runtimeRoot4, resolvedSrc);
8315
+ if (relToRuntime.startsWith("..") || path19.isAbsolute(relToRuntime)) continue;
8316
+ const relToSource = path19.relative(sourceDir, resolvedSrc);
8317
+ if (!relToSource.startsWith("..") && !path19.isAbsolute(relToSource)) continue;
8318
+ const depDest = path19.join(depsTargetRoot, relToRuntime);
8238
8319
  queue.push({ src: resolvedSrc, dest: depDest, isDep: true });
8239
8320
  }
8240
8321
  }
@@ -8244,7 +8325,7 @@ async function copyRuntime(opts) {
8244
8325
 
8245
8326
  // src/cli/shared/subsystem-detect.ts
8246
8327
  import fs9 from "fs";
8247
- import path18 from "path";
8328
+ import path20 from "path";
8248
8329
  var SUBSYSTEMS = [
8249
8330
  {
8250
8331
  name: "events",
@@ -8301,21 +8382,49 @@ var SUBSYSTEMS = [
8301
8382
  description: "Observability combiner \u2014 composes sibling read ports via @Optional() DI (ADR-025)",
8302
8383
  backends: ["combiner"],
8303
8384
  defaultBackend: "combiner"
8385
+ },
8386
+ {
8387
+ // #287. Auth subsystem (PR #289) — AuthModule + ports + OAuth state
8388
+ // store + AuthController. Backends: drizzle (prod, persists OAuth
8389
+ // state in `auth_oauth_state`) or memory (dev/tests). Detection in
8390
+ // `detectInstalledSubsystems` is a special case: auth's protocols
8391
+ // live under `protocols/`, not at the subsystem root, so we look
8392
+ // for `auth.module.ts` instead of `*.protocol.ts`.
8393
+ name: "auth",
8394
+ description: "OAuth integration auth (AuthModule + ports + state store)",
8395
+ backends: ["drizzle", "memory"],
8396
+ defaultBackend: "drizzle"
8397
+ },
8398
+ {
8399
+ // #287. Auth-integrations starter (PR #290) — vendored from
8400
+ // `examples/auth-integrations/`, NOT from `runtime/subsystems/`.
8401
+ // Bundles a canonical `integration` entity yaml + the three
8402
+ // integration-store-port adapters + the `IntegrationsService`
8403
+ // facade. Single-backend (drizzle); the runtime adapters call
8404
+ // directly into the codegen-emitted `IntegrationService` from the
8405
+ // entity layer. Detection: presence of
8406
+ // `<sharedRoot>/integrations/integrations-auth.module.ts`.
8407
+ name: "auth-integrations",
8408
+ description: "Vendored integrations entity + adapters (consumes auth subsystem)",
8409
+ backends: ["drizzle"],
8410
+ defaultBackend: "drizzle"
8304
8411
  }
8305
8412
  ];
8306
8413
  var KNOWN_NAMES = SUBSYSTEMS.map((s) => s.name);
8307
8414
  function candidateRoots(cwd, configured) {
8308
8415
  const roots = [
8309
- ...configured ? [path18.resolve(cwd, configured)] : [],
8310
- path18.resolve(cwd, "src/shared/subsystems"),
8311
- path18.resolve(cwd, "src/subsystems"),
8312
- path18.resolve(cwd, "shared/subsystems")
8416
+ ...configured ? [path20.resolve(cwd, configured)] : [],
8417
+ path20.resolve(cwd, "src/shared/subsystems"),
8418
+ path20.resolve(cwd, "src/subsystems"),
8419
+ path20.resolve(cwd, "shared/subsystems")
8313
8420
  ];
8314
8421
  return Array.from(new Set(roots));
8315
8422
  }
8316
8423
  function inferBackend(dir, name) {
8317
8424
  if (name === "observability") return "combiner";
8318
- const hasDrizzle = fs9.existsSync(path18.join(dir, `${name.replace(/s$/, "")}-bus.drizzle-backend.ts`)) || fs9.readdirSync(dir).some((f) => f.endsWith(".drizzle-backend.ts"));
8425
+ if (name === "auth") return "drizzle";
8426
+ if (name === "auth-integrations") return "drizzle";
8427
+ const hasDrizzle = fs9.existsSync(path20.join(dir, `${name.replace(/s$/, "")}-bus.drizzle-backend.ts`)) || fs9.readdirSync(dir).some((f) => f.endsWith(".drizzle-backend.ts"));
8319
8428
  const hasMemory = fs9.readdirSync(dir).some((f) => f.endsWith(".memory-backend.ts"));
8320
8429
  const hasLocal = fs9.readdirSync(dir).some((f) => f.includes("local"));
8321
8430
  if (hasDrizzle && hasMemory) return "drizzle";
@@ -8334,10 +8443,14 @@ async function detectInstalledSubsystems(ctx) {
8334
8443
  for (const name of KNOWN_NAMES) {
8335
8444
  if (seen.has(name)) continue;
8336
8445
  if (name === "openapi-config") continue;
8337
- const dir = path18.join(root, name);
8446
+ if (name === "auth-integrations") continue;
8447
+ const dir = path20.join(root, name);
8338
8448
  if (!fs9.existsSync(dir) || !fs9.statSync(dir).isDirectory()) continue;
8339
8449
  const files = fs9.readdirSync(dir);
8340
- const hasProtocol = files.some((f) => f.endsWith(".protocol.ts"));
8450
+ let hasProtocol = files.some((f) => f.endsWith(".protocol.ts"));
8451
+ if (name === "auth") {
8452
+ hasProtocol = files.includes("auth.module.ts");
8453
+ }
8341
8454
  if (!hasProtocol) continue;
8342
8455
  seen.add(name);
8343
8456
  found.push({
@@ -8348,7 +8461,7 @@ async function detectInstalledSubsystems(ctx) {
8348
8461
  }
8349
8462
  }
8350
8463
  if (!seen.has("openapi-config")) {
8351
- const configPath = path18.resolve(
8464
+ const configPath = path20.resolve(
8352
8465
  ctx.cwd,
8353
8466
  ctx.config ? "codegen.config.yaml" : "codegen.config.yaml"
8354
8467
  );
@@ -8366,18 +8479,35 @@ async function detectInstalledSubsystems(ctx) {
8366
8479
  }
8367
8480
  }
8368
8481
  }
8482
+ if (!seen.has("auth-integrations")) {
8483
+ const backendSrc = ctx.config?.paths?.backend_src ?? "src";
8484
+ const sharedConfigured = ctx.config?.paths?.shared;
8485
+ const sharedRoot = typeof sharedConfigured === "string" && sharedConfigured.length > 0 ? path20.resolve(ctx.cwd, sharedConfigured) : path20.resolve(ctx.cwd, backendSrc, "shared");
8486
+ const moduleFile = path20.join(
8487
+ sharedRoot,
8488
+ "integrations",
8489
+ "integrations-auth.module.ts"
8490
+ );
8491
+ if (fs9.existsSync(moduleFile)) {
8492
+ found.push({
8493
+ name: "auth-integrations",
8494
+ path: path20.dirname(moduleFile),
8495
+ backend: "drizzle"
8496
+ });
8497
+ }
8498
+ }
8369
8499
  return found;
8370
8500
  }
8371
8501
 
8372
8502
  // src/cli/commands/subsystem.ts
8373
8503
  function runtimeRoot() {
8374
- const pkgRoot = path19.resolve(import.meta.dirname, "..", "..", "..");
8375
- const topLevel = path19.join(pkgRoot, "runtime");
8504
+ const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
8505
+ const topLevel = path21.join(pkgRoot, "runtime");
8376
8506
  if (fs10.existsSync(topLevel)) return topLevel;
8377
- return path19.join(pkgRoot, "dist", "runtime");
8507
+ return path21.join(pkgRoot, "dist", "runtime");
8378
8508
  }
8379
8509
  function subsystemSource(name) {
8380
- return path19.join(runtimeRoot(), "subsystems", name);
8510
+ return path21.join(runtimeRoot(), "subsystems", name);
8381
8511
  }
8382
8512
  function describeSubsystem(name) {
8383
8513
  return SUBSYSTEMS.find((s) => s.name === name) ?? null;
@@ -8404,7 +8534,7 @@ async function summary2(ctx) {
8404
8534
  }
8405
8535
  body.push(theme.muted("Installed:"));
8406
8536
  for (const i of installed) {
8407
- const rel = path19.relative(ctx.cwd, i.path) || i.path;
8537
+ const rel = path21.relative(ctx.cwd, i.path) || i.path;
8408
8538
  body.push(
8409
8539
  ` ${theme.success(icons.check)} ${i.name.padEnd(10)} ${theme.muted(
8410
8540
  `${i.backend} backend`
@@ -8461,6 +8591,9 @@ function backendFileFilter(backend, subsystemName) {
8461
8591
  if (subsystemName === "sync" && file === "sync-audit.schema.ts") {
8462
8592
  return false;
8463
8593
  }
8594
+ if (subsystemName === "auth" && file === "auth-oauth-state.schema.ts") {
8595
+ return false;
8596
+ }
8464
8597
  if (backend === "memory") {
8465
8598
  if (file.endsWith(".drizzle-backend.ts")) return false;
8466
8599
  if (file.endsWith(".schema.ts")) return false;
@@ -8519,6 +8652,9 @@ var SubsystemInstallCommand = class extends Command3 {
8519
8652
  if (desc3.name === "openapi-config") {
8520
8653
  return this.executeOpenApiConfig(ctx);
8521
8654
  }
8655
+ if (desc3.name === "auth-integrations") {
8656
+ return this.executeAuthIntegrations(ctx);
8657
+ }
8522
8658
  const installed = await detectInstalledSubsystems(ctx);
8523
8659
  const already = installed.find((i) => i.name === desc3.name);
8524
8660
  if (already && !this.force) {
@@ -8536,14 +8672,14 @@ var SubsystemInstallCommand = class extends Command3 {
8536
8672
  return 0;
8537
8673
  }
8538
8674
  const targetRoot = resolveSubsystemsRoot(ctx, this.target);
8539
- const subsystemTarget = path19.join(targetRoot, desc3.name);
8675
+ const subsystemTarget = path21.join(targetRoot, desc3.name);
8540
8676
  const source = subsystemSource(desc3.name);
8541
8677
  if (!fs10.existsSync(source)) {
8542
8678
  printError(`Runtime subsystem source missing: ${source}`);
8543
8679
  return 1;
8544
8680
  }
8545
8681
  if (!this.force) {
8546
- const gitCheck = checkGitSafety([path19.relative(ctx.cwd, subsystemTarget) || subsystemTarget], ctx.cwd);
8682
+ const gitCheck = checkGitSafety([path21.relative(ctx.cwd, subsystemTarget) || subsystemTarget], ctx.cwd);
8547
8683
  if (gitCheck.inRepo && !gitCheck.clean) {
8548
8684
  printWarning(
8549
8685
  `Uncommitted changes under ${subsystemTarget}. Pass --force to overwrite.`
@@ -8552,7 +8688,7 @@ var SubsystemInstallCommand = class extends Command3 {
8552
8688
  }
8553
8689
  }
8554
8690
  if (!isJsonMode()) {
8555
- printInfo(`target = ${path19.relative(ctx.cwd, subsystemTarget) || subsystemTarget}`);
8691
+ printInfo(`target = ${path21.relative(ctx.cwd, subsystemTarget) || subsystemTarget}`);
8556
8692
  printInfo(`backend = ${backend}`);
8557
8693
  }
8558
8694
  const result = await copyRuntime({
@@ -8561,7 +8697,7 @@ var SubsystemInstallCommand = class extends Command3 {
8561
8697
  filter: backendFileFilter(backend, desc3.name),
8562
8698
  resolveDeps: true,
8563
8699
  runtimeRoot: runtimeRoot(),
8564
- depsTargetRoot: path19.resolve(targetRoot, ".."),
8700
+ depsTargetRoot: path21.resolve(targetRoot, ".."),
8565
8701
  dryRun: this.dryRun
8566
8702
  });
8567
8703
  const jobsScaffold = desc3.name === "jobs" ? runJobsScaffold(ctx.cwd, ctx.config, {
@@ -8589,6 +8725,11 @@ var SubsystemInstallCommand = class extends Command3 {
8589
8725
  json: isJsonMode(),
8590
8726
  forceConfig: this.forceConfig
8591
8727
  }) : null;
8728
+ const authScaffold = desc3.name === "auth" ? runAuthScaffold(ctx.cwd, ctx.config, {
8729
+ dryRun: this.dryRun,
8730
+ json: isJsonMode(),
8731
+ forceConfig: this.forceConfig
8732
+ }) : null;
8592
8733
  if (jobsScaffold?.configBlockOutcome === "parse-error") {
8593
8734
  printError(
8594
8735
  "codegen.config.yaml is not valid YAML: refusing to inject jobs config block. Fix the YAML and re-run."
@@ -8619,6 +8760,12 @@ var SubsystemInstallCommand = class extends Command3 {
8619
8760
  );
8620
8761
  return 1;
8621
8762
  }
8763
+ if (authScaffold?.configBlockOutcome === "parse-error") {
8764
+ printError(
8765
+ "codegen.config.yaml is not valid YAML: refusing to inject auth config block. Fix the YAML and re-run."
8766
+ );
8767
+ return 1;
8768
+ }
8622
8769
  if (isJsonMode()) {
8623
8770
  printJson({
8624
8771
  command: "subsystem install",
@@ -8637,21 +8784,22 @@ var SubsystemInstallCommand = class extends Command3 {
8637
8784
  ...eventsScaffold ? { scaffold: eventsScaffold } : {},
8638
8785
  ...syncScaffold ? { scaffold: syncScaffold } : {},
8639
8786
  ...bridgeScaffold ? { scaffold: bridgeScaffold } : {},
8640
- ...observabilityScaffold ? { scaffold: observabilityScaffold } : {}
8787
+ ...observabilityScaffold ? { scaffold: observabilityScaffold } : {},
8788
+ ...authScaffold ? { scaffold: authScaffold } : {}
8641
8789
  });
8642
8790
  return 0;
8643
8791
  }
8644
8792
  if (this.dryRun) {
8645
8793
  printInfo(`Dry run \u2014 ${result.planned.length} files would be written`);
8646
8794
  for (const p of result.planned) {
8647
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8795
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8648
8796
  }
8649
8797
  if (jobsScaffold?.planned?.length) {
8650
8798
  printInfo(
8651
8799
  `Jobs scaffold \u2014 ${jobsScaffold.planned.length} template targets`
8652
8800
  );
8653
8801
  for (const p of jobsScaffold.planned) {
8654
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8802
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8655
8803
  }
8656
8804
  }
8657
8805
  if (eventsScaffold?.planned?.length) {
@@ -8659,7 +8807,7 @@ var SubsystemInstallCommand = class extends Command3 {
8659
8807
  `Events scaffold \u2014 ${eventsScaffold.planned.length} template targets`
8660
8808
  );
8661
8809
  for (const p of eventsScaffold.planned) {
8662
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8810
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8663
8811
  }
8664
8812
  }
8665
8813
  if (syncScaffold?.planned?.length) {
@@ -8667,7 +8815,7 @@ var SubsystemInstallCommand = class extends Command3 {
8667
8815
  `Sync scaffold \u2014 ${syncScaffold.planned.length} template targets`
8668
8816
  );
8669
8817
  for (const p of syncScaffold.planned) {
8670
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8818
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8671
8819
  }
8672
8820
  }
8673
8821
  if (bridgeScaffold?.planned?.length) {
@@ -8675,7 +8823,7 @@ var SubsystemInstallCommand = class extends Command3 {
8675
8823
  `Bridge scaffold \u2014 ${bridgeScaffold.planned.length} template targets`
8676
8824
  );
8677
8825
  for (const p of bridgeScaffold.planned) {
8678
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8826
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8679
8827
  }
8680
8828
  }
8681
8829
  if (observabilityScaffold?.planned?.length) {
@@ -8683,7 +8831,15 @@ var SubsystemInstallCommand = class extends Command3 {
8683
8831
  `Observability scaffold \u2014 ${observabilityScaffold.planned.length} template targets`
8684
8832
  );
8685
8833
  for (const p of observabilityScaffold.planned) {
8686
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, p) || p}`);
8834
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8835
+ }
8836
+ }
8837
+ if (authScaffold?.planned?.length) {
8838
+ printInfo(
8839
+ `Auth scaffold \u2014 ${authScaffold.planned.length} template targets`
8840
+ );
8841
+ for (const p of authScaffold.planned) {
8842
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`);
8687
8843
  }
8688
8844
  }
8689
8845
  return 0;
@@ -8750,11 +8906,29 @@ var SubsystemInstallCommand = class extends Command3 {
8750
8906
  );
8751
8907
  }
8752
8908
  }
8909
+ if (authScaffold) {
8910
+ if (authScaffold.ok) {
8911
+ printSuccess(
8912
+ `auth scaffold applied (schema, config block, app.module.ts hint, .env.config key)`
8913
+ );
8914
+ } else {
8915
+ printWarning(
8916
+ `auth scaffold (Hygen) failed \u2014 runtime files were written; re-run after fixing: ${authScaffold.error ?? "unknown error"}`
8917
+ );
8918
+ }
8919
+ }
8753
8920
  printSuccess(`${desc3.name} subsystem installed with ${backend} backend.`);
8754
8921
  if (desc3.name === "observability") {
8755
8922
  printInfo(
8756
8923
  "Register `ObservabilityModule.forRoot()` AFTER Events/Jobs/Bridge/Sync in app.module.ts"
8757
8924
  );
8925
+ } else if (desc3.name === "auth") {
8926
+ printInfo("auth subsystem installed.");
8927
+ printInfo("Next steps:");
8928
+ printInfo(" 1. Provide an IUserContext adapter (your app's session/JWT scheme \u2014 req is typed `unknown`, narrow to your framework's Request inside the adapter).");
8929
+ printInfo(" 2. Install the auth-integrations starter: cdp subsystem install auth-integrations");
8930
+ printInfo(" 3. Bind per-provider strategies into STRATEGY_REGISTRY (HubSpot, SFDC, Google, ...).");
8931
+ printInfo(" 4. Configure provider client_id/client_secret in secrets/secrets.yaml.");
8758
8932
  } else {
8759
8933
  printInfo(
8760
8934
  `Register ${capitalize(desc3.name)}Module.forRoot({ backend: '${backend}' }) in your app.module.ts`
@@ -8778,7 +8952,7 @@ var SubsystemInstallCommand = class extends Command3 {
8778
8952
  * semantics as jobs/events/sync/bridge.
8779
8953
  */
8780
8954
  async executeOpenApiConfig(ctx) {
8781
- const configPath = path19.join(ctx.cwd, "codegen.config.yaml");
8955
+ const configPath = path21.join(ctx.cwd, "codegen.config.yaml");
8782
8956
  const outcome = planConfigBlockAction(configPath, "openapi", this.forceConfig);
8783
8957
  if (outcome === "parse-error") {
8784
8958
  printError(
@@ -8797,7 +8971,7 @@ var SubsystemInstallCommand = class extends Command3 {
8797
8971
  });
8798
8972
  } else {
8799
8973
  printInfo(`Dry run \u2014 openapi config block would be ${outcome}`);
8800
- console.log(` ${theme.muted(icons.arrow)} ${path19.relative(ctx.cwd, configPath) || configPath}`);
8974
+ console.log(` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, configPath) || configPath}`);
8801
8975
  }
8802
8976
  return 0;
8803
8977
  }
@@ -8833,6 +9007,87 @@ var SubsystemInstallCommand = class extends Command3 {
8833
9007
  );
8834
9008
  return 0;
8835
9009
  }
9010
+ /**
9011
+ * #287: install flow for the `auth-integrations` starter.
9012
+ *
9013
+ * Source is `examples/auth-integrations/`, NOT `runtime/subsystems/`,
9014
+ * so this method short-circuits the `copyRuntime` flow. It vendors the
9015
+ * adapters tree + the canonical `integration.yaml`, then invokes the
9016
+ * `subsystem auth-integrations` Hygen action to append the
9017
+ * `IntegrationsAuthModule` TODO to `app.module.ts`.
9018
+ *
9019
+ * Idempotent: pre-existing files are skipped unless `--force` is set.
9020
+ */
9021
+ async executeAuthIntegrations(ctx) {
9022
+ const installed = await detectInstalledSubsystems(ctx);
9023
+ const already = installed.find((i) => i.name === "auth-integrations");
9024
+ if (already && !this.force) {
9025
+ if (isJsonMode()) {
9026
+ printJson({
9027
+ command: "subsystem install",
9028
+ subsystem: "auth-integrations",
9029
+ status: "already-installed",
9030
+ path: already.path,
9031
+ backend: already.backend
9032
+ });
9033
+ } else {
9034
+ printInfo(
9035
+ `auth-integrations is already installed at ${already.path} (pass --force to reinstall)`
9036
+ );
9037
+ }
9038
+ return 0;
9039
+ }
9040
+ const scaffold = runAuthIntegrationsScaffold(ctx.cwd, ctx.config, {
9041
+ dryRun: this.dryRun,
9042
+ json: isJsonMode(),
9043
+ force: this.force
9044
+ });
9045
+ if (!scaffold.ok) {
9046
+ printError(
9047
+ `auth-integrations install failed: ${scaffold.error ?? "unknown error"}`
9048
+ );
9049
+ return 1;
9050
+ }
9051
+ if (isJsonMode()) {
9052
+ printJson({
9053
+ command: "subsystem install",
9054
+ subsystem: "auth-integrations",
9055
+ dryRun: this.dryRun,
9056
+ planned: scaffold.planned,
9057
+ written: scaffold.written ?? [],
9058
+ skipped: scaffold.skipped ?? [],
9059
+ authModuleRegistered: scaffold.authModuleRegistered ?? false
9060
+ });
9061
+ return 0;
9062
+ }
9063
+ if (this.dryRun) {
9064
+ printInfo(
9065
+ `Dry run \u2014 auth-integrations would vendor adapters + integration.yaml + append TODO`
9066
+ );
9067
+ for (const p of scaffold.planned) {
9068
+ console.log(
9069
+ ` ${theme.muted(icons.arrow)} ${path21.relative(ctx.cwd, p) || p}`
9070
+ );
9071
+ }
9072
+ return 0;
9073
+ }
9074
+ const writtenCount = scaffold.written?.length ?? 0;
9075
+ const skippedCount = scaffold.skipped?.length ?? 0;
9076
+ printSuccess(
9077
+ `auth-integrations starter vendored (${writtenCount} files written, ${skippedCount} skipped).`
9078
+ );
9079
+ if (scaffold.authModuleRegistered === false) {
9080
+ printWarning(
9081
+ "AuthModule.forRoot(...) not detected in app.module.ts. Run `cdp subsystem install auth` first \u2014 IntegrationsAuthModule requires ENCRYPTION_KEY from it."
9082
+ );
9083
+ }
9084
+ printInfo("auth-integrations starter vendored.");
9085
+ printInfo("Next steps:");
9086
+ printInfo(" 1. Run `cdp entity new integration` to scaffold the codegen layer (apps/api/src/modules/integrations/integration.service) the adapters import.");
9087
+ printInfo(" 2. Ensure AuthModule.forRoot(...) is registered in AppModule (run `cdp subsystem install auth` if not).");
9088
+ printInfo(" 3. Wire IntegrationsAuthModule into AppModule (see TODO appended to app.module.ts).");
9089
+ return 0;
9090
+ }
8836
9091
  };
8837
9092
  function planConfigBlockAction(configPath, subsystem, forceConfig) {
8838
9093
  if (!fs10.existsSync(configPath)) {
@@ -9171,6 +9426,183 @@ function runObservabilityScaffold(cwd, config, opts) {
9171
9426
  }
9172
9427
  return { ok: true, planned, configBlockOutcome };
9173
9428
  }
9429
+ function runAuthScaffold(cwd, config, opts) {
9430
+ const locals = resolveAuthScaffoldLocals({
9431
+ cwd,
9432
+ config
9433
+ });
9434
+ const planned = [
9435
+ locals.schemaPath,
9436
+ locals.configPath,
9437
+ locals.appModulePath,
9438
+ locals.envConfigPath
9439
+ ];
9440
+ const configBlockOutcome = planConfigBlockAction(
9441
+ locals.configPath,
9442
+ "auth",
9443
+ opts.forceConfig
9444
+ );
9445
+ if (configBlockOutcome === "parse-error") {
9446
+ return { ok: false, planned, configBlockOutcome };
9447
+ }
9448
+ if (opts.dryRun) {
9449
+ return { ok: true, planned, configBlockOutcome };
9450
+ }
9451
+ if (!fs10.existsSync(locals.envConfigPath)) {
9452
+ fs10.mkdirSync(path21.dirname(locals.envConfigPath), { recursive: true });
9453
+ fs10.writeFileSync(locals.envConfigPath, "", "utf-8");
9454
+ }
9455
+ const result = invokeHygen({
9456
+ generator: "subsystem",
9457
+ action: "auth",
9458
+ cwd,
9459
+ args: localsToHygenArgs6(locals),
9460
+ inherit: !opts.json
9461
+ });
9462
+ if (!result.ok) {
9463
+ return {
9464
+ ok: false,
9465
+ planned,
9466
+ error: result.stderr?.trim() || "hygen exited non-zero",
9467
+ configBlockOutcome
9468
+ };
9469
+ }
9470
+ const configResult = runConfigBlockAction({
9471
+ cwd,
9472
+ actionFolder: "auth-config",
9473
+ configPath: locals.configPath,
9474
+ subsystem: "auth",
9475
+ outcome: configBlockOutcome,
9476
+ json: opts.json
9477
+ });
9478
+ if (!configResult.ok) {
9479
+ return {
9480
+ ok: false,
9481
+ planned,
9482
+ error: configResult.error,
9483
+ configBlockOutcome
9484
+ };
9485
+ }
9486
+ return { ok: true, planned, configBlockOutcome };
9487
+ }
9488
+ function authIntegrationsExamplesRoot() {
9489
+ const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
9490
+ const topLevel = path21.join(pkgRoot, "examples", "auth-integrations");
9491
+ if (fs10.existsSync(topLevel)) return topLevel;
9492
+ return path21.join(pkgRoot, "dist", "examples", "auth-integrations");
9493
+ }
9494
+ function copyTreeIdempotent(srcDir, destDir, force) {
9495
+ const written = [];
9496
+ const skipped = [];
9497
+ const walk = (src, dest) => {
9498
+ const entries = fs10.readdirSync(src, { withFileTypes: true });
9499
+ for (const entry of entries) {
9500
+ const srcPath = path21.join(src, entry.name);
9501
+ const destPath = path21.join(dest, entry.name);
9502
+ if (entry.isDirectory()) {
9503
+ fs10.mkdirSync(destPath, { recursive: true });
9504
+ walk(srcPath, destPath);
9505
+ continue;
9506
+ }
9507
+ if (!entry.isFile()) continue;
9508
+ if (fs10.existsSync(destPath) && !force) {
9509
+ skipped.push(destPath);
9510
+ continue;
9511
+ }
9512
+ fs10.mkdirSync(path21.dirname(destPath), { recursive: true });
9513
+ fs10.copyFileSync(srcPath, destPath);
9514
+ written.push(destPath);
9515
+ }
9516
+ };
9517
+ if (!fs10.existsSync(srcDir)) return { written, skipped };
9518
+ fs10.mkdirSync(destDir, { recursive: true });
9519
+ walk(srcDir, destDir);
9520
+ return { written, skipped };
9521
+ }
9522
+ function runAuthIntegrationsScaffold(cwd, config, opts) {
9523
+ const locals = resolveAuthIntegrationsScaffoldLocals({
9524
+ cwd,
9525
+ config,
9526
+ fileExists: (p) => fs10.existsSync(p),
9527
+ readFile: (p) => fs10.existsSync(p) ? fs10.readFileSync(p, "utf-8") : null
9528
+ });
9529
+ const examplesRoot = authIntegrationsExamplesRoot();
9530
+ if (!fs10.existsSync(examplesRoot)) {
9531
+ return {
9532
+ ok: false,
9533
+ planned: [],
9534
+ error: `auth-integrations starter source missing: ${examplesRoot}`
9535
+ };
9536
+ }
9537
+ const adaptersSrc = path21.join(examplesRoot, "runtime", "integrations");
9538
+ const adaptersDest = path21.join(locals.sharedRoot, "integrations");
9539
+ const integrationYamlSrc = path21.join(
9540
+ examplesRoot,
9541
+ "definitions",
9542
+ "entities",
9543
+ "integration.yaml"
9544
+ );
9545
+ const integrationYamlDest = locals.definitionsPath;
9546
+ const planned = [
9547
+ adaptersDest,
9548
+ integrationYamlDest,
9549
+ locals.appModulePath
9550
+ ];
9551
+ if (opts.dryRun) {
9552
+ return {
9553
+ ok: true,
9554
+ planned,
9555
+ authModuleRegistered: locals.authModuleRegistered
9556
+ };
9557
+ }
9558
+ const adapterCopy = copyTreeIdempotent(
9559
+ adaptersSrc,
9560
+ adaptersDest,
9561
+ opts.force
9562
+ );
9563
+ let yamlWritten = false;
9564
+ let yamlSkipped = false;
9565
+ try {
9566
+ if (fs10.existsSync(integrationYamlDest) && !opts.force) {
9567
+ yamlSkipped = true;
9568
+ } else if (fs10.existsSync(integrationYamlSrc)) {
9569
+ fs10.mkdirSync(path21.dirname(integrationYamlDest), { recursive: true });
9570
+ fs10.copyFileSync(integrationYamlSrc, integrationYamlDest);
9571
+ yamlWritten = true;
9572
+ }
9573
+ } catch (err) {
9574
+ return {
9575
+ ok: false,
9576
+ planned,
9577
+ error: `failed to vendor integration.yaml: ${err instanceof Error ? err.message : String(err)}`,
9578
+ authModuleRegistered: locals.authModuleRegistered
9579
+ };
9580
+ }
9581
+ const result = invokeHygen({
9582
+ generator: "subsystem",
9583
+ action: "auth-integrations",
9584
+ cwd,
9585
+ args: localsToHygenArgs7(locals),
9586
+ inherit: !opts.json
9587
+ });
9588
+ if (!result.ok) {
9589
+ return {
9590
+ ok: false,
9591
+ planned,
9592
+ error: result.stderr?.trim() || "hygen exited non-zero",
9593
+ written: adapterCopy.written.concat(yamlWritten ? [integrationYamlDest] : []),
9594
+ skipped: adapterCopy.skipped.concat(yamlSkipped ? [integrationYamlDest] : []),
9595
+ authModuleRegistered: locals.authModuleRegistered
9596
+ };
9597
+ }
9598
+ return {
9599
+ ok: true,
9600
+ planned,
9601
+ written: adapterCopy.written.concat(yamlWritten ? [integrationYamlDest] : []),
9602
+ skipped: adapterCopy.skipped.concat(yamlSkipped ? [integrationYamlDest] : []),
9603
+ authModuleRegistered: locals.authModuleRegistered
9604
+ };
9605
+ }
9174
9606
  function capitalize(s) {
9175
9607
  return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
9176
9608
  }
@@ -9200,7 +9632,7 @@ var SubsystemListCommand = class extends Command3 {
9200
9632
  name: s.name,
9201
9633
  status: inst ? "installed" : "available",
9202
9634
  backend: inst ? inst.backend : null,
9203
- path: inst ? path19.relative(ctx.cwd, inst.path) || inst.path : null
9635
+ path: inst ? path21.relative(ctx.cwd, inst.path) || inst.path : null
9204
9636
  };
9205
9637
  });
9206
9638
  if (isJsonMode()) {
@@ -9261,27 +9693,27 @@ var subsystem_default = subsystemNoun;
9261
9693
 
9262
9694
  // src/cli/commands/project.ts
9263
9695
  import fs13 from "fs";
9264
- import path22 from "path";
9696
+ import path24 from "path";
9265
9697
  import readline from "readline";
9266
9698
  import { Command as Command5, Option as Option5 } from "clipanion";
9267
9699
  import { stringify as stringifyYaml2 } from "yaml";
9268
9700
 
9269
9701
  // src/cli/shared/init-scaffold.ts
9270
9702
  import fs11 from "fs";
9271
- import path20 from "path";
9703
+ import path22 from "path";
9272
9704
  import { stringify as stringifyYaml } from "yaml";
9273
9705
  function runtimeRoot2() {
9274
- const pkgRoot = path20.resolve(import.meta.dirname, "..", "..", "..");
9275
- const topLevel = path20.join(pkgRoot, "runtime");
9706
+ const pkgRoot = path22.resolve(import.meta.dirname, "..", "..", "..");
9707
+ const topLevel = path22.join(pkgRoot, "runtime");
9276
9708
  if (fs11.existsSync(topLevel)) return topLevel;
9277
- return path20.join(pkgRoot, "dist", "runtime");
9709
+ return path22.join(pkgRoot, "dist", "runtime");
9278
9710
  }
9279
9711
  function resolveRuntimePath(cwd) {
9280
- const shimDir = path20.join(cwd, "src", "shared", "base-classes");
9281
- return path20.relative(shimDir, runtimeRoot2());
9712
+ const shimDir = path22.join(cwd, "src", "shared", "base-classes");
9713
+ return path22.relative(shimDir, runtimeRoot2());
9282
9714
  }
9283
9715
  function loadRuntimeFile(relPath2) {
9284
- return fs11.readFileSync(path20.join(runtimeRoot2(), relPath2), "utf-8");
9716
+ return fs11.readFileSync(path22.join(runtimeRoot2(), relPath2), "utf-8");
9285
9717
  }
9286
9718
  var VENDORED_RUNTIME_FILES = [
9287
9719
  // base-classes — consumer-facing inheritance targets
@@ -9523,7 +9955,10 @@ function emptyModulesBarrel() {
9523
9955
  return `// AUTO-GENERATED \u2014 DO NOT EDIT.
9524
9956
  // Regenerated on every \`codegen entity new\` / \`codegen entity new --all\`.
9525
9957
  // See ADR-017.
9526
- export const GENERATED_MODULES: unknown[] = [];
9958
+ import type { DynamicModule, ForwardReference, Type } from '@nestjs/common';
9959
+ export const GENERATED_MODULES: Array<
9960
+ Type | DynamicModule | Promise<DynamicModule> | ForwardReference
9961
+ > = [];
9527
9962
  `;
9528
9963
  }
9529
9964
  function emptySchemaBarrel() {
@@ -9675,7 +10110,7 @@ function mergeTsconfig(raw) {
9675
10110
  };
9676
10111
  }
9677
10112
  function relOf(cwd, abs) {
9678
- return path20.relative(cwd, abs) || abs;
10113
+ return path22.relative(cwd, abs) || abs;
9679
10114
  }
9680
10115
  function fileEntry(cwd, absPath, content, opts) {
9681
10116
  const exists = fs11.existsSync(absPath);
@@ -9725,7 +10160,7 @@ async function buildInitPlan(ctx, options) {
9725
10160
  const runtimePath = options.runtimePath ?? resolveRuntimePath(cwd);
9726
10161
  const entries = [];
9727
10162
  {
9728
- const configPath = path20.join(cwd, "codegen.config.yaml");
10163
+ const configPath = path22.join(cwd, "codegen.config.yaml");
9729
10164
  const config = {
9730
10165
  paths: {
9731
10166
  backend_src: "src",
@@ -9755,7 +10190,7 @@ async function buildInitPlan(ctx, options) {
9755
10190
  entries.push(fileEntry(cwd, configPath, content, { force }));
9756
10191
  }
9757
10192
  {
9758
- const tsconfigPath = path20.join(cwd, "tsconfig.json");
10193
+ const tsconfigPath = path22.join(cwd, "tsconfig.json");
9759
10194
  if (fs11.existsSync(tsconfigPath)) {
9760
10195
  const raw = fs11.readFileSync(tsconfigPath, "utf-8");
9761
10196
  const merged = mergeTsconfig(raw);
@@ -9802,20 +10237,20 @@ async function buildInitPlan(ctx, options) {
9802
10237
  entries.push(
9803
10238
  fileEntry(
9804
10239
  cwd,
9805
- path20.join(cwd, "src", "shared", "database", "database.module.ts"),
10240
+ path22.join(cwd, "src", "shared", "database", "database.module.ts"),
9806
10241
  databaseModuleContent(),
9807
10242
  { force }
9808
10243
  )
9809
10244
  );
9810
10245
  for (const v of VENDORED_RUNTIME_FILES) {
9811
10246
  entries.push(
9812
- fileEntry(cwd, path20.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
10247
+ fileEntry(cwd, path22.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
9813
10248
  );
9814
10249
  }
9815
10250
  entries.push(
9816
10251
  fileEntry(
9817
10252
  cwd,
9818
- path20.join(cwd, "src", "generated", "modules.ts"),
10253
+ path22.join(cwd, "src", "generated", "modules.ts"),
9819
10254
  emptyModulesBarrel(),
9820
10255
  { force }
9821
10256
  )
@@ -9823,13 +10258,13 @@ async function buildInitPlan(ctx, options) {
9823
10258
  entries.push(
9824
10259
  fileEntry(
9825
10260
  cwd,
9826
- path20.join(cwd, "src", "generated", "schema.ts"),
10261
+ path22.join(cwd, "src", "generated", "schema.ts"),
9827
10262
  emptySchemaBarrel(),
9828
10263
  { force }
9829
10264
  )
9830
10265
  );
9831
10266
  {
9832
- const appModulePath = path20.join(cwd, "src", "app.module.ts");
10267
+ const appModulePath = path22.join(cwd, "src", "app.module.ts");
9833
10268
  if (!fs11.existsSync(appModulePath)) {
9834
10269
  entries.push({
9835
10270
  path: appModulePath,
@@ -9847,7 +10282,7 @@ async function buildInitPlan(ctx, options) {
9847
10282
  }
9848
10283
  }
9849
10284
  {
9850
- const mainPath = path20.join(cwd, "src", "main.ts");
10285
+ const mainPath = path22.join(cwd, "src", "main.ts");
9851
10286
  if (!fs11.existsSync(mainPath)) {
9852
10287
  entries.push({
9853
10288
  path: mainPath,
@@ -9865,7 +10300,7 @@ async function buildInitPlan(ctx, options) {
9865
10300
  }
9866
10301
  }
9867
10302
  {
9868
- const schemaPath = path20.join(cwd, "src", "schema.ts");
10303
+ const schemaPath = path22.join(cwd, "src", "schema.ts");
9869
10304
  if (!fs11.existsSync(schemaPath)) {
9870
10305
  entries.push({
9871
10306
  path: schemaPath,
@@ -9882,10 +10317,10 @@ async function buildInitPlan(ctx, options) {
9882
10317
  });
9883
10318
  }
9884
10319
  }
9885
- entries.push(dirEntry(cwd, path20.join(cwd, "entities")));
10320
+ entries.push(dirEntry(cwd, path22.join(cwd, "entities")));
9886
10321
  {
9887
- const entitiesDir = path20.join(cwd, "entities");
9888
- const examplePath = path20.join(entitiesDir, "example.yaml");
10322
+ const entitiesDir = path22.join(cwd, "entities");
10323
+ const examplePath = path22.join(entitiesDir, "example.yaml");
9889
10324
  const hasOtherYamls = fs11.existsSync(entitiesDir) && fs11.readdirSync(entitiesDir).some(
9890
10325
  (f) => (f.endsWith(".yaml") || f.endsWith(".yml")) && f !== "example.yaml"
9891
10326
  );
@@ -9943,7 +10378,7 @@ function writePlan(plan) {
9943
10378
  skipped.push(e);
9944
10379
  continue;
9945
10380
  }
9946
- fs11.mkdirSync(path20.dirname(e.path), { recursive: true });
10381
+ fs11.mkdirSync(path22.dirname(e.path), { recursive: true });
9947
10382
  fs11.writeFileSync(e.path, e.content, "utf-8");
9948
10383
  if (e.action === "create") created.push(e);
9949
10384
  else if (e.action === "merge") merged.push(e);
@@ -9954,7 +10389,7 @@ function writePlan(plan) {
9954
10389
 
9955
10390
  // src/cli/commands/project-upgrade-openapi.ts
9956
10391
  import fs12 from "fs";
9957
- import path21 from "path";
10392
+ import path23 from "path";
9958
10393
  import { Command as Command4, Option as Option4 } from "clipanion";
9959
10394
  import { Project, IndentationText, QuoteKind, NewLineKind } from "ts-morph";
9960
10395
 
@@ -10193,31 +10628,31 @@ var MAIN_SWAGGER_IMPORTS = [
10193
10628
  "import { OPENAPI_REGISTRY, OpenApiRegistry } from './shared/openapi';"
10194
10629
  ];
10195
10630
  function runtimeRoot3() {
10196
- const pkgRoot = path21.resolve(import.meta.dirname, "..", "..", "..");
10197
- const topLevel = path21.join(pkgRoot, "runtime");
10631
+ const pkgRoot = path23.resolve(import.meta.dirname, "..", "..", "..");
10632
+ const topLevel = path23.join(pkgRoot, "runtime");
10198
10633
  if (fs12.existsSync(topLevel)) return topLevel;
10199
- return path21.join(pkgRoot, "dist", "runtime");
10634
+ return path23.join(pkgRoot, "dist", "runtime");
10200
10635
  }
10201
10636
  function loadRuntimeFile2(rel) {
10202
- return fs12.readFileSync(path21.join(runtimeRoot3(), rel), "utf-8");
10637
+ return fs12.readFileSync(path23.join(runtimeRoot3(), rel), "utf-8");
10203
10638
  }
10204
10639
  function resolveProjectRoot(startDir) {
10205
- let dir = path21.resolve(startDir);
10640
+ let dir = path23.resolve(startDir);
10206
10641
  for (let i = 0; i < 16; i++) {
10207
- if (fs12.existsSync(path21.join(dir, "codegen.config.yaml")) || fs12.existsSync(path21.join(dir, "package.json"))) {
10642
+ if (fs12.existsSync(path23.join(dir, "codegen.config.yaml")) || fs12.existsSync(path23.join(dir, "package.json"))) {
10208
10643
  return dir;
10209
10644
  }
10210
- const parent = path21.dirname(dir);
10645
+ const parent = path23.dirname(dir);
10211
10646
  if (parent === dir) break;
10212
10647
  dir = parent;
10213
10648
  }
10214
- return path21.resolve(startDir);
10649
+ return path23.resolve(startDir);
10215
10650
  }
10216
10651
  async function runUpgradeOpenapi(opts) {
10217
10652
  const { projectRoot, dryRun, force } = opts;
10218
10653
  const changes = [];
10219
10654
  for (const v of OPENAPI_VENDORED_FILES) {
10220
- const target = path21.join(projectRoot, v.target);
10655
+ const target = path23.join(projectRoot, v.target);
10221
10656
  const exists = fs12.existsSync(target);
10222
10657
  const newContent = loadRuntimeFile2(v.runtime);
10223
10658
  if (exists && !force) {
@@ -10233,7 +10668,7 @@ async function runUpgradeOpenapi(opts) {
10233
10668
  }
10234
10669
  } else {
10235
10670
  if (!dryRun) {
10236
- fs12.mkdirSync(path21.dirname(target), { recursive: true });
10671
+ fs12.mkdirSync(path23.dirname(target), { recursive: true });
10237
10672
  fs12.writeFileSync(target, newContent);
10238
10673
  }
10239
10674
  changes.push({
@@ -10242,7 +10677,7 @@ async function runUpgradeOpenapi(opts) {
10242
10677
  });
10243
10678
  }
10244
10679
  }
10245
- const appModulePath = path21.join(projectRoot, "src", "app.module.ts");
10680
+ const appModulePath = path23.join(projectRoot, "src", "app.module.ts");
10246
10681
  if (!fs12.existsSync(appModulePath)) {
10247
10682
  return {
10248
10683
  projectRoot,
@@ -10326,7 +10761,7 @@ async function runUpgradeOpenapi(opts) {
10326
10761
  } else {
10327
10762
  changes.push({ path: "src/app.module.ts", action: "unchanged" });
10328
10763
  }
10329
- const mainPath = path21.join(projectRoot, "src", "main.ts");
10764
+ const mainPath = path23.join(projectRoot, "src", "main.ts");
10330
10765
  if (fs12.existsSync(mainPath)) {
10331
10766
  const mainSource = project.addSourceFileAtPath(mainPath);
10332
10767
  const mainBefore = mainSource.getFullText();
@@ -10407,7 +10842,7 @@ var ProjectUpgradeOpenapiCommand = class extends Command4 {
10407
10842
  json = Option4.Boolean("--json", false);
10408
10843
  async execute() {
10409
10844
  if (this.json) setJsonMode(true);
10410
- const startDir = this.pathOpt ? path21.resolve(this.pathOpt) : process.cwd();
10845
+ const startDir = this.pathOpt ? path23.resolve(this.pathOpt) : process.cwd();
10411
10846
  if (!fs12.existsSync(startDir)) {
10412
10847
  printError(`Directory not found: ${startDir}`);
10413
10848
  return 1;
@@ -10692,8 +11127,8 @@ var ProjectScanCommand = class extends Command5 {
10692
11127
  cwd = Option5.String("--cwd", { required: false });
10693
11128
  async execute() {
10694
11129
  if (this.json) setJsonMode(true);
10695
- const baseCwd = this.cwd ? path22.resolve(this.cwd) : process.cwd();
10696
- const target = this.directory ? path22.resolve(baseCwd, this.directory) : baseCwd;
11130
+ const baseCwd = this.cwd ? path24.resolve(this.cwd) : process.cwd();
11131
+ const target = this.directory ? path24.resolve(baseCwd, this.directory) : baseCwd;
10697
11132
  if (!fs13.existsSync(target)) {
10698
11133
  printError(`Directory not found: ${target}`);
10699
11134
  return 1;
@@ -10744,7 +11179,7 @@ var ProjectScanCommand = class extends Command5 {
10744
11179
  `architecture: ${profile.architecture.evidence.join(", ") || "\u2014"}`
10745
11180
  ]);
10746
11181
  }
10747
- const outPath = path22.join(target, "codegen.config.yaml");
11182
+ const outPath = path24.join(target, "codegen.config.yaml");
10748
11183
  const existsNow = fs13.existsSync(outPath);
10749
11184
  if (this.dryRun) {
10750
11185
  console.log("");
@@ -10865,8 +11300,8 @@ var ProjectInspectCommand = class extends Command5 {
10865
11300
  return 2;
10866
11301
  }
10867
11302
  resolveEntitiesDir(ctx) {
10868
- if (this.dir) return path22.resolve(ctx.cwd, this.dir);
10869
- return ctx.entitiesDir ?? path22.resolve(ctx.cwd, "entities");
11303
+ if (this.dir) return path24.resolve(ctx.cwd, this.dir);
11304
+ return ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
10870
11305
  }
10871
11306
  async runAnalysis(ctx, kind) {
10872
11307
  const entitiesDir = this.resolveEntitiesDir(ctx);
@@ -11069,15 +11504,15 @@ var ProjectGraphCommand = class extends Command5 {
11069
11504
  json: this.json,
11070
11505
  skipDetection: true
11071
11506
  });
11072
- const entitiesDir = this.dir ? path22.resolve(ctx.cwd, this.dir) : ctx.entitiesDir ?? path22.resolve(ctx.cwd, "entities");
11507
+ const entitiesDir = this.dir ? path24.resolve(ctx.cwd, this.dir) : ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
11073
11508
  if (!fs13.existsSync(entitiesDir)) {
11074
11509
  printError(`Entity directory not found: ${entitiesDir}`);
11075
11510
  return 1;
11076
11511
  }
11077
11512
  const relCandidates = [
11078
- path22.resolve(path22.dirname(entitiesDir), "relationships"),
11079
- path22.resolve(entitiesDir, "relationships"),
11080
- path22.resolve(ctx.cwd, "relationships")
11513
+ path24.resolve(path24.dirname(entitiesDir), "relationships"),
11514
+ path24.resolve(entitiesDir, "relationships"),
11515
+ path24.resolve(ctx.cwd, "relationships")
11081
11516
  ];
11082
11517
  const relationshipsDir = relCandidates.find((d) => fs13.existsSync(d));
11083
11518
  const result = await analyzeDomain(entitiesDir, relationshipsDir);
@@ -11093,20 +11528,20 @@ var ProjectGraphCommand = class extends Command5 {
11093
11528
  return 0;
11094
11529
  }
11095
11530
  if (this.output) {
11096
- const outPath = path22.resolve(ctx.cwd, this.output);
11531
+ const outPath = path24.resolve(ctx.cwd, this.output);
11097
11532
  fs13.writeFileSync(outPath, JSON.stringify(serialized, null, 2));
11098
11533
  printSuccess(`Graph written to ${outPath}`);
11099
11534
  printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
11100
11535
  return 0;
11101
11536
  }
11102
11537
  const os = await import("os");
11103
- const tmpDir = fs13.mkdtempSync(path22.join(os.default.tmpdir(), "codegen-graph-"));
11104
- const graphPath = path22.join(tmpDir, "graph.json");
11538
+ const tmpDir = fs13.mkdtempSync(path24.join(os.default.tmpdir(), "codegen-graph-"));
11539
+ const graphPath = path24.join(tmpDir, "graph.json");
11105
11540
  fs13.writeFileSync(graphPath, JSON.stringify(serialized, null, 2));
11106
- const viewerDir = path22.resolve(import.meta.dirname, "..", "..", "..", "tools", "schema-graph-viewer");
11107
- const viewerDist = path22.join(viewerDir, "dist", "index.html");
11541
+ const viewerDir = path24.resolve(import.meta.dirname, "..", "..", "..", "tools", "schema-graph-viewer");
11542
+ const viewerDist = path24.join(viewerDir, "dist", "index.html");
11108
11543
  if (fs13.existsSync(viewerDist)) {
11109
- fs13.copyFileSync(graphPath, path22.join(viewerDir, "dist", "graph.json"));
11544
+ fs13.copyFileSync(graphPath, path24.join(viewerDir, "dist", "graph.json"));
11110
11545
  printSuccess("Graph exported");
11111
11546
  printInfo(`${result.entities.length} entities, ${result.relationshipDefinitions.length} relationships, ${result.graph.edges.length} edges`);
11112
11547
  printInfo(`Graph JSON: ${graphPath}`);
@@ -11137,7 +11572,7 @@ var project_default = projectNoun;
11137
11572
 
11138
11573
  // src/cli/commands/dev.ts
11139
11574
  import fs14 from "fs";
11140
- import path23 from "path";
11575
+ import path25 from "path";
11141
11576
  import { execSync as execSync3, spawn, spawnSync } from "child_process";
11142
11577
  import { Command as Command6, Option as Option6 } from "clipanion";
11143
11578
  var DEFAULT_APP_PORT = 3e3;
@@ -11170,14 +11605,14 @@ function getRedisPort(_ctx) {
11170
11605
  return Number(process.env.DEV_REDIS_PORT ?? DEFAULT_REDIS_PORT);
11171
11606
  }
11172
11607
  function composeFilePath(cwd) {
11173
- const devPath = path23.join(cwd, COMPOSE_FILE);
11608
+ const devPath = path25.join(cwd, COMPOSE_FILE);
11174
11609
  if (fs14.existsSync(devPath)) return devPath;
11175
- const rootPath = path23.join(cwd, "docker-compose.yml");
11610
+ const rootPath = path25.join(cwd, "docker-compose.yml");
11176
11611
  if (fs14.existsSync(rootPath)) return rootPath;
11177
11612
  return devPath;
11178
11613
  }
11179
11614
  function pidFilePath(cwd) {
11180
- return path23.join(cwd, PID_FILE);
11615
+ return path25.join(cwd, PID_FILE);
11181
11616
  }
11182
11617
  function readAppPid(cwd) {
11183
11618
  const p = pidFilePath(cwd);
@@ -11246,7 +11681,7 @@ function formatServiceLine(svc) {
11246
11681
  return `${icon} ${svc.name.padEnd(12)} ${theme.muted(`${svc.host}:${svc.port}`)} ${status}${pidStr}`;
11247
11682
  }
11248
11683
  function ensureComposeFile(cwd, pgPort, redisPort) {
11249
- const composePath = path23.join(cwd, COMPOSE_FILE);
11684
+ const composePath = path25.join(cwd, COMPOSE_FILE);
11250
11685
  if (fs14.existsSync(composePath)) return composePath;
11251
11686
  const content = `# Auto-generated by codegen dev
11252
11687
  # Ports offset from defaults to avoid conflicts with other local services.
@@ -11331,7 +11766,7 @@ var DevUpCommand = class extends Command6 {
11331
11766
  if (!pgReady) printWarning("postgres did not become healthy in time");
11332
11767
  if (!redisReady) printWarning("redis did not become healthy in time");
11333
11768
  const drizzleConfig = ["drizzle.config.ts", "drizzle.config.js"].find(
11334
- (f) => fs14.existsSync(path23.join(ctx.cwd, f))
11769
+ (f) => fs14.existsSync(path25.join(ctx.cwd, f))
11335
11770
  );
11336
11771
  if (drizzleConfig) {
11337
11772
  if (!isJsonMode()) printInfo("pushing database schema...");
@@ -11351,7 +11786,7 @@ var DevUpCommand = class extends Command6 {
11351
11786
  if (!isJsonMode()) printInfo("starting NestJS app...");
11352
11787
  const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
11353
11788
  const redisUrl = `redis://localhost:${redisPort}`;
11354
- const logFile = path23.join(ctx.cwd, ".dev-app.log");
11789
+ const logFile = path25.join(ctx.cwd, ".dev-app.log");
11355
11790
  const logFd = fs14.openSync(logFile, "a");
11356
11791
  const child = spawn("bun", ["src/main.ts"], {
11357
11792
  cwd: ctx.cwd,
@@ -11509,7 +11944,7 @@ var DevLogsCommand = class extends Command6 {
11509
11944
  }
11510
11945
  return 0;
11511
11946
  }
11512
- const logFile = path23.join(ctx.cwd, ".dev-app.log");
11947
+ const logFile = path25.join(ctx.cwd, ".dev-app.log");
11513
11948
  if (!fs14.existsSync(logFile)) {
11514
11949
  printInfo("no app logs found \u2014 is the app running?");
11515
11950
  return 0;
@@ -11553,7 +11988,7 @@ var DevRestartCommand = class extends Command6 {
11553
11988
  spawnSync("sleep", ["1"]);
11554
11989
  const dbUrl = `postgres://postgres:postgres@localhost:${pgPort}/codegen_dev`;
11555
11990
  const redisUrl = `redis://localhost:${redisPort}`;
11556
- const logFile = path23.join(ctx.cwd, ".dev-app.log");
11991
+ const logFile = path25.join(ctx.cwd, ".dev-app.log");
11557
11992
  const logFd = fs14.openSync(logFile, "a");
11558
11993
  const child = spawn("bun", ["src/main.ts"], {
11559
11994
  cwd: ctx.cwd,
@@ -11683,14 +12118,14 @@ var dev_default = devNoun;
11683
12118
 
11684
12119
  // src/cli/commands/relationship.ts
11685
12120
  import fs15 from "fs";
11686
- import path24 from "path";
12121
+ import path26 from "path";
11687
12122
  import { Command as Command7, Option as Option7 } from "clipanion";
11688
12123
  function listRelationshipYamls2(dir) {
11689
12124
  if (!fs15.existsSync(dir)) return [];
11690
12125
  return fs15.readdirSync(dir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml")).filter((f) => {
11691
- const fullPath = path24.join(dir, f);
12126
+ const fullPath = path26.join(dir, f);
11692
12127
  return detectYamlType(fullPath) === "relationship";
11693
- }).map((f) => path24.join(dir, f));
12128
+ }).map((f) => path26.join(dir, f));
11694
12129
  }
11695
12130
  function summarizeRelationshipFile(filePath) {
11696
12131
  const result = loadRelationshipFromYaml(filePath);
@@ -11711,7 +12146,7 @@ function padRight2(s, n) {
11711
12146
  return s.length >= n ? s : s + " ".repeat(n - s.length);
11712
12147
  }
11713
12148
  async function summary5(ctx) {
11714
- const relDir = path24.resolve(ctx.cwd, "relationships");
12149
+ const relDir = path26.resolve(ctx.cwd, "relationships");
11715
12150
  const files = listRelationshipYamls2(relDir);
11716
12151
  if (files.length === 0) {
11717
12152
  return {
@@ -11781,14 +12216,14 @@ var RelationshipNewCommand = class extends Command7 {
11781
12216
  }
11782
12217
  let targets = [];
11783
12218
  if (this.all) {
11784
- const dir = path24.resolve(ctx.cwd, "relationships");
12219
+ const dir = path26.resolve(ctx.cwd, "relationships");
11785
12220
  targets = listRelationshipYamls2(dir);
11786
12221
  if (targets.length === 0) {
11787
12222
  printError(`No relationship YAML files found in ${dir}`);
11788
12223
  return 1;
11789
12224
  }
11790
12225
  } else if (this.yaml) {
11791
- targets = [path24.resolve(ctx.cwd, this.yaml)];
12226
+ targets = [path26.resolve(ctx.cwd, this.yaml)];
11792
12227
  } else {
11793
12228
  printError("Missing YAML path. Pass a file or --all.");
11794
12229
  return 2;
@@ -11805,7 +12240,7 @@ var RelationshipNewCommand = class extends Command7 {
11805
12240
  }
11806
12241
  if (invalid.length > 0) {
11807
12242
  for (const i of invalid) {
11808
- printError(`${path24.basename(i.file)} \u2014 ${i.message}`);
12243
+ printError(`${path26.basename(i.file)} \u2014 ${i.message}`);
11809
12244
  }
11810
12245
  if (!isJsonMode()) return 1;
11811
12246
  }
@@ -11836,7 +12271,7 @@ var RelationshipNewCommand = class extends Command7 {
11836
12271
  }
11837
12272
  const succeeded = [];
11838
12273
  const failed = [
11839
- ...invalid.map((i) => ({ name: path24.basename(i.file), file: i.file, message: i.message }))
12274
+ ...invalid.map((i) => ({ name: path26.basename(i.file), file: i.file, message: i.message }))
11840
12275
  ];
11841
12276
  for (const v of validated) {
11842
12277
  if (!isJsonMode()) {
@@ -11855,8 +12290,8 @@ var RelationshipNewCommand = class extends Command7 {
11855
12290
  if (!isJsonMode()) printError(`${v.name} \u2014 ${res.stderr ?? "failed"}`);
11856
12291
  }
11857
12292
  }
11858
- const entitiesDir = ctx.entitiesDir ?? path24.resolve(ctx.cwd, "entities");
11859
- const relationshipsDir = path24.resolve(ctx.cwd, "relationships");
12293
+ const entitiesDir = ctx.entitiesDir ?? path26.resolve(ctx.cwd, "entities");
12294
+ const relationshipsDir = path26.resolve(ctx.cwd, "relationships");
11860
12295
  const generatedDir = resolveGeneratedDir(ctx);
11861
12296
  const architecture = resolveArchitecture(ctx);
11862
12297
  let barrelResult = null;
@@ -11901,7 +12336,7 @@ var RelationshipNewCommand = class extends Command7 {
11901
12336
  }
11902
12337
  if (barrelResult) {
11903
12338
  printInfo(
11904
- `barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path24.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path24.relative(ctx.cwd, barrelResult.schemaBarrel)}`
12339
+ `barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path26.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path26.relative(ctx.cwd, barrelResult.schemaBarrel)}`
11905
12340
  );
11906
12341
  }
11907
12342
  }
@@ -11924,7 +12359,7 @@ var RelationshipListCommand = class extends Command7 {
11924
12359
  json: this.json,
11925
12360
  skipDetection: true
11926
12361
  });
11927
- const relDir = path24.resolve(ctx.cwd, "relationships");
12362
+ const relDir = path26.resolve(ctx.cwd, "relationships");
11928
12363
  const files = listRelationshipYamls2(relDir);
11929
12364
  if (files.length === 0) {
11930
12365
  printInfo("No relationship definitions found.");
@@ -11965,7 +12400,7 @@ var relationship_default = relationshipNoun;
11965
12400
 
11966
12401
  // src/cli/commands/events.ts
11967
12402
  import fs16 from "fs";
11968
- import path25 from "path";
12403
+ import path27 from "path";
11969
12404
  import ts2 from "typescript";
11970
12405
  import { Command as Command8, Option as Option8 } from "clipanion";
11971
12406
  function scanSourceFileForConsumers(sourceFile, filePath, eventType) {
@@ -12101,7 +12536,7 @@ function suggestEventTypes(target, known, limit = 3) {
12101
12536
  return known.map((t) => ({ t, d: levenshtein(target, t) })).sort((a, b) => a.d - b.d).slice(0, limit).map((x) => x.t);
12102
12537
  }
12103
12538
  function renderConsumerReport(result, cwd) {
12104
- const rel = (p) => path25.relative(cwd, p) || p;
12539
+ const rel = (p) => path27.relative(cwd, p) || p;
12105
12540
  const lines = [];
12106
12541
  const total = result.tier3.length + result.tier2.length + result.tier1.length;
12107
12542
  lines.push(`Event: ${result.eventType}`);
@@ -12137,7 +12572,7 @@ function renderConsumerReport(result, cwd) {
12137
12572
  return lines;
12138
12573
  }
12139
12574
  function runConsumersScan(opts) {
12140
- const scanRoot = opts.scanRoot ?? path25.join(opts.cwd, "src");
12575
+ const scanRoot = opts.scanRoot ?? path27.join(opts.cwd, "src");
12141
12576
  const handlersDir = opts.handlersDir ?? scanRoot;
12142
12577
  const allTriggers = scanHandlerFiles(handlersDir);
12143
12578
  const tier3 = allTriggers.filter((t) => t.event === opts.eventType).map((t) => ({
@@ -12147,7 +12582,7 @@ function runConsumersScan(opts) {
12147
12582
  sourceLine: t.sourceLine
12148
12583
  }));
12149
12584
  const tier21 = fs16.existsSync(scanRoot) ? scanDirectoryForConsumers(scanRoot, opts.eventType) : { tier2: [], tier1: [], hasEventFlowImport: false };
12150
- const eventsGeneratedDir = opts.eventsGeneratedDir ?? path25.join(
12585
+ const eventsGeneratedDir = opts.eventsGeneratedDir ?? path27.join(
12151
12586
  resolveSubsystemsRootFromContext(opts.cwd, opts.config),
12152
12587
  "events",
12153
12588
  "generated"
@@ -12168,11 +12603,11 @@ function runConsumersScan(opts) {
12168
12603
  function resolveSubsystemsRootFromContext(cwd, config) {
12169
12604
  const configured = config?.paths?.subsystems;
12170
12605
  if (typeof configured === "string" && configured.length > 0) {
12171
- return path25.resolve(cwd, configured);
12606
+ return path27.resolve(cwd, configured);
12172
12607
  }
12173
12608
  const backendSrc = config?.paths?.backend_src;
12174
12609
  const base = typeof backendSrc === "string" && backendSrc.length > 0 ? backendSrc : "src";
12175
- return path25.resolve(cwd, base, "shared", "subsystems");
12610
+ return path27.resolve(cwd, base, "shared", "subsystems");
12176
12611
  }
12177
12612
  var EventsConsumersCommand = class extends Command8 {
12178
12613
  static paths = [["events", "consumers"]];
@@ -12261,7 +12696,7 @@ var eventsNoun = {
12261
12696
  var events_default = eventsNoun;
12262
12697
 
12263
12698
  // src/cli/commands/orchestration.ts
12264
- import path26 from "path";
12699
+ import path28 from "path";
12265
12700
  import { Command as Command9, Option as Option9 } from "clipanion";
12266
12701
  var DEFAULT_PATTERN_GLOBS = ["src/patterns/*.pattern.ts"];
12267
12702
  function resolvePatternGlobs(ctx) {
@@ -12275,10 +12710,10 @@ function resolveOrchestrationOutputRoot(ctx) {
12275
12710
  const paths = ctx.config?.paths;
12276
12711
  const explicit = paths?.orchestration_src;
12277
12712
  if (typeof explicit === "string" && explicit.length > 0) {
12278
- return path26.resolve(ctx.cwd, explicit);
12713
+ return path28.resolve(ctx.cwd, explicit);
12279
12714
  }
12280
12715
  const backendSrc = typeof paths?.backend_src === "string" && paths.backend_src.length > 0 ? paths.backend_src : "app/backend/src";
12281
- return path26.resolve(ctx.cwd, backendSrc, "orchestration");
12716
+ return path28.resolve(ctx.cwd, backendSrc, "orchestration");
12282
12717
  }
12283
12718
  async function reloadRegistry(ctx) {
12284
12719
  _resetRegistryForTests({ includeLibrary: false });
@@ -12367,12 +12802,12 @@ var OrchestrationGenCommand = class extends Command9 {
12367
12802
  );
12368
12803
  for (const f of result.files) {
12369
12804
  console.log(
12370
- ` ${theme.muted(icons.arrow)} ${path26.relative(ctx.cwd, f.outputPath)}`
12805
+ ` ${theme.muted(icons.arrow)} ${path28.relative(ctx.cwd, f.outputPath)}`
12371
12806
  );
12372
12807
  }
12373
12808
  } else {
12374
12809
  printSuccess(
12375
- `Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${path26.relative(ctx.cwd, outputRoot)}`
12810
+ `Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${path28.relative(ctx.cwd, outputRoot)}`
12376
12811
  );
12377
12812
  }
12378
12813
  return 0;