@pattern-stack/codegen 0.10.0 → 0.10.1

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 (44) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/consumer-skills/events/typed-bus-and-outbox.md +1 -1
  3. package/consumer-skills/subsystems/SKILL.md +56 -0
  4. package/dist/runtime/subsystems/bridge/bridge.module.d.ts +0 -1
  5. package/dist/runtime/subsystems/bridge/bridge.module.js +294 -710
  6. package/dist/runtime/subsystems/bridge/bridge.module.js.map +1 -1
  7. package/dist/runtime/subsystems/bridge/index.d.ts +0 -1
  8. package/dist/runtime/subsystems/bridge/index.js +248 -664
  9. package/dist/runtime/subsystems/bridge/index.js.map +1 -1
  10. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +18 -10
  11. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -1
  12. package/dist/runtime/subsystems/events/events.module.js +43 -244
  13. package/dist/runtime/subsystems/events/events.module.js.map +1 -1
  14. package/dist/runtime/subsystems/events/index.d.ts +0 -1
  15. package/dist/runtime/subsystems/events/index.js +39 -241
  16. package/dist/runtime/subsystems/events/index.js.map +1 -1
  17. package/dist/runtime/subsystems/index.js +174 -791
  18. package/dist/runtime/subsystems/index.js.map +1 -1
  19. package/dist/runtime/subsystems/jobs/bullmq.config.d.ts +22 -3
  20. package/dist/runtime/subsystems/jobs/bullmq.config.js.map +1 -1
  21. package/dist/runtime/subsystems/jobs/index.d.ts +1 -4
  22. package/dist/runtime/subsystems/jobs/index.js +87 -506
  23. package/dist/runtime/subsystems/jobs/index.js.map +1 -1
  24. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js.map +1 -1
  25. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +3 -0
  26. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js.map +1 -1
  27. package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +11 -4
  28. package/dist/runtime/subsystems/jobs/job-worker.module.js +248 -664
  29. package/dist/runtime/subsystems/jobs/job-worker.module.js.map +1 -1
  30. package/dist/runtime/subsystems/jobs/jobs-domain.module.d.ts +0 -1
  31. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +89 -391
  32. package/dist/runtime/subsystems/jobs/jobs-domain.module.js.map +1 -1
  33. package/dist/src/cli/index.js +152 -35
  34. package/dist/src/cli/index.js.map +1 -1
  35. package/package.json +1 -1
  36. package/runtime/subsystems/events/event-bus.drizzle-backend.ts +32 -10
  37. package/runtime/subsystems/events/events.module.ts +38 -6
  38. package/runtime/subsystems/events/index.ts +7 -1
  39. package/runtime/subsystems/jobs/bullmq.config.ts +23 -3
  40. package/runtime/subsystems/jobs/index.ts +13 -8
  41. package/runtime/subsystems/jobs/job-worker.bullmq-backend.ts +5 -2
  42. package/runtime/subsystems/jobs/job-worker.module.ts +27 -7
  43. package/runtime/subsystems/jobs/jobs-domain.module.ts +27 -2
  44. package/templates/subsystem/events/domain-events.schema.ejs.t +43 -2
@@ -6012,6 +6012,19 @@ var SUBSYSTEMS = [
6012
6012
  }
6013
6013
  ];
6014
6014
  var KNOWN_NAMES = SUBSYSTEMS.map((s) => s.name);
6015
+ var SUBSYSTEM_MODULE_FILE = {
6016
+ events: "events.module.ts",
6017
+ jobs: "jobs-domain.module.ts",
6018
+ cache: "cache.module.ts",
6019
+ storage: "storage.module.ts",
6020
+ sync: "sync.module.ts",
6021
+ bridge: "bridge.module.ts",
6022
+ observability: "observability.module.ts",
6023
+ auth: "auth.module.ts"
6024
+ };
6025
+ function subsystemModuleFile(name) {
6026
+ return SUBSYSTEM_MODULE_FILE[name] ?? null;
6027
+ }
6015
6028
  function candidateRoots(cwd, configured) {
6016
6029
  const roots = [
6017
6030
  ...configured ? [path6.resolve(cwd, configured)] : [],
@@ -6034,7 +6047,7 @@ function inferBackend(dir, name) {
6034
6047
  if (hasMemory) return "memory";
6035
6048
  return "unknown";
6036
6049
  }
6037
- async function detectInstalledSubsystems(ctx) {
6050
+ async function detectSubsystemStatesImpl(ctx) {
6038
6051
  const configured = ctx.config?.paths?.subsystems;
6039
6052
  const roots = candidateRoots(ctx.cwd, configured);
6040
6053
  const found = [];
@@ -6048,16 +6061,16 @@ async function detectInstalledSubsystems(ctx) {
6048
6061
  const dir = path6.join(root, name);
6049
6062
  if (!fs4.existsSync(dir) || !fs4.statSync(dir).isDirectory()) continue;
6050
6063
  const files = fs4.readdirSync(dir);
6051
- let hasProtocol = files.some((f) => f.endsWith(".protocol.ts"));
6052
- if (name === "auth") {
6053
- hasProtocol = files.includes("auth.module.ts");
6054
- }
6055
- if (!hasProtocol) continue;
6064
+ const moduleFile = subsystemModuleFile(name);
6065
+ const hasModule = moduleFile ? files.includes(moduleFile) : false;
6066
+ const present = name === "auth" ? hasModule : files.some((f) => f.endsWith(".protocol.ts")) || hasModule;
6067
+ if (!present) continue;
6056
6068
  seen.add(name);
6057
6069
  found.push({
6058
6070
  name,
6059
6071
  path: dir,
6060
- backend: inferBackend(dir, name)
6072
+ backend: inferBackend(dir, name),
6073
+ status: hasModule ? "installed" : "incomplete"
6061
6074
  });
6062
6075
  }
6063
6076
  }
@@ -6073,7 +6086,8 @@ async function detectInstalledSubsystems(ctx) {
6073
6086
  found.push({
6074
6087
  name: "openapi-config",
6075
6088
  path: configPath,
6076
- backend: "config-only"
6089
+ backend: "config-only",
6090
+ status: "installed"
6077
6091
  });
6078
6092
  }
6079
6093
  } catch {
@@ -6096,7 +6110,8 @@ async function detectInstalledSubsystems(ctx) {
6096
6110
  found.push({
6097
6111
  name: "auth-integrations",
6098
6112
  path: path6.dirname(moduleFile),
6099
- backend: "drizzle"
6113
+ backend: "drizzle",
6114
+ status: "installed"
6100
6115
  });
6101
6116
  break;
6102
6117
  }
@@ -6104,6 +6119,13 @@ async function detectInstalledSubsystems(ctx) {
6104
6119
  }
6105
6120
  return found;
6106
6121
  }
6122
+ async function detectSubsystemStates(ctx) {
6123
+ return detectSubsystemStatesImpl(ctx);
6124
+ }
6125
+ async function detectInstalledSubsystems(ctx) {
6126
+ const states = await detectSubsystemStatesImpl(ctx);
6127
+ return states.filter((s) => s.status === "installed");
6128
+ }
6107
6129
 
6108
6130
  // src/cli/shared/subsystems-path.ts
6109
6131
  import path7 from "path";
@@ -6223,7 +6245,8 @@ var HEADER3 = `// AUTO-GENERATED by @pattern-stack/codegen. DO NOT EDIT.
6223
6245
 
6224
6246
  `;
6225
6247
  function buildSubsystemBarrel(installed, config, subsystemsRel) {
6226
- const installedNames = new Set(installed.map((i) => i.name));
6248
+ const actable = installed.filter((i) => i.status !== "incomplete");
6249
+ const installedNames = new Set(actable.map((i) => i.name));
6227
6250
  const emitted = [];
6228
6251
  const skipped = [];
6229
6252
  const allImports = [`import type { DynamicModule } from '@nestjs/common';`];
@@ -6241,25 +6264,17 @@ function buildSubsystemBarrel(installed, config, subsystemsRel) {
6241
6264
  allCalls.push(...out.calls);
6242
6265
  emitted.push(name);
6243
6266
  }
6244
- for (const inst of installed) {
6267
+ for (const inst of actable) {
6245
6268
  if (!COMPOSABLE_ORDER.includes(inst.name) && !COMPOSERS[inst.name]) {
6246
6269
  skipped.push(inst.name);
6247
6270
  }
6248
6271
  }
6249
- if (allCalls.length === 0) {
6250
- return {
6251
- content: HEADER3 + `export const SUBSYSTEM_MODULES: DynamicModule[] = [];
6252
- `,
6253
- emitted,
6254
- skipped
6255
- };
6256
- }
6257
- const body = allImports.join("\n") + `
6258
-
6259
- export const SUBSYSTEM_MODULES: DynamicModule[] = [
6272
+ const exportLine = allCalls.length === 0 ? `export const SUBSYSTEM_MODULES: DynamicModule[] = [];
6273
+ ` : `export const SUBSYSTEM_MODULES: DynamicModule[] = [
6260
6274
  ${allCalls.join("\n")}
6261
6275
  ];
6262
6276
  `;
6277
+ const body = allImports.join("\n") + "\n\n" + exportLine;
6263
6278
  return { content: HEADER3 + body, emitted, skipped };
6264
6279
  }
6265
6280
  async function regenerateSubsystemBarrel(opts) {
@@ -8993,6 +9008,8 @@ function backendFileFilter(backend, subsystemName) {
8993
9008
  if (subsystemName === "auth" && file === "auth-oauth-state.schema.ts") {
8994
9009
  return false;
8995
9010
  }
9011
+ if (file.endsWith(".redis-backend.ts") && backend !== "redis") return false;
9012
+ if (file.endsWith(".bullmq-backend.ts") && backend !== "bullmq") return false;
8996
9013
  if (backend === "memory") {
8997
9014
  if (file.endsWith(".drizzle-backend.ts")) return false;
8998
9015
  if (file.endsWith(".schema.ts")) return false;
@@ -10055,14 +10072,14 @@ var SubsystemListCommand = class extends Command3 {
10055
10072
  json: this.json,
10056
10073
  skipDetection: true
10057
10074
  });
10058
- const installed = await detectInstalledSubsystems(ctx);
10075
+ const states = await detectSubsystemStates(ctx);
10059
10076
  const byName = /* @__PURE__ */ new Map();
10060
- for (const i of installed) byName.set(i.name, i);
10077
+ for (const i of states) byName.set(i.name, i);
10061
10078
  const rows = SUBSYSTEMS.map((s) => {
10062
10079
  const inst = byName.get(s.name);
10063
10080
  return {
10064
10081
  name: s.name,
10065
- status: inst ? "installed" : "available",
10082
+ status: inst ? inst.status : "available",
10066
10083
  backend: inst ? inst.backend : null,
10067
10084
  path: inst ? path22.relative(ctx.cwd, inst.path) || inst.path : null
10068
10085
  };
@@ -10086,29 +10103,129 @@ var SubsystemListCommand = class extends Command3 {
10086
10103
  var SubsystemRemoveCommand = class extends Command3 {
10087
10104
  static paths = [["subsystem", "remove"]];
10088
10105
  static usage = Command3.Usage({
10089
- description: "Remove a subsystem (not yet implemented)"
10106
+ description: "Remove a vendored subsystem",
10107
+ examples: [
10108
+ ["Remove the jobs subsystem", "codegen subsystem remove jobs"],
10109
+ [
10110
+ "Skip the git-safety check (uncommitted edits will be lost)",
10111
+ "codegen subsystem remove jobs --force"
10112
+ ],
10113
+ ["Non-interactive parity with install", "codegen subsystem remove jobs --yes"]
10114
+ ]
10090
10115
  });
10091
10116
  name = Option3.String({ required: true });
10117
+ // #7: parity with `subsystem install` so a non-interactive caller can pass
10118
+ // the same flag set across install/remove. Accepted but currently a no-op
10119
+ // (remove has no interactive prompt yet); kept for forward-compatibility.
10120
+ yes = Option3.Boolean("--yes,-y", false);
10121
+ force = Option3.Boolean("--force", false);
10092
10122
  json = Option3.Boolean("--json", false);
10093
10123
  cwd = Option3.String("--cwd", { required: false });
10094
10124
  configPath = Option3.String("--config", { required: false });
10095
10125
  async execute() {
10096
10126
  if (this.json) setJsonMode(true);
10127
+ const ctx = await loadContext({
10128
+ cwd: this.cwd,
10129
+ configPath: this.configPath,
10130
+ json: this.json,
10131
+ skipDetection: true
10132
+ });
10133
+ const desc3 = describeSubsystem(this.name);
10134
+ if (!desc3) {
10135
+ printError(
10136
+ `Unknown subsystem '${this.name}'. Known: ${SUBSYSTEMS.map((s) => s.name).join(", ")}`
10137
+ );
10138
+ return 2;
10139
+ }
10140
+ if (desc3.name === "openapi-config") {
10141
+ printError(
10142
+ "openapi-config has no vendored runtime to remove \u2014 it's a config-only pseudo-subsystem."
10143
+ );
10144
+ printInfo(
10145
+ "To uninstall: delete the `openapi:` block from codegen.config.yaml and uninstall the @nestjs/swagger / @anatine/zod-openapi peer deps."
10146
+ );
10147
+ return 1;
10148
+ }
10149
+ if (desc3.name === "auth-integrations") {
10150
+ printError(
10151
+ "auth-integrations is vendored under <modules>/integrations/ alongside the codegen-emitted entity layer \u2014 not auto-removable here."
10152
+ );
10153
+ printInfo(
10154
+ "To uninstall: remove the integrations/ directory and the IntegrationsAuthModule registration from app.module.ts by hand."
10155
+ );
10156
+ return 1;
10157
+ }
10158
+ const installed = await detectInstalledSubsystems(ctx);
10159
+ const target = installed.find((i) => i.name === desc3.name);
10160
+ if (!target) {
10161
+ if (isJsonMode()) {
10162
+ printJson({
10163
+ command: "subsystem remove",
10164
+ subsystem: desc3.name,
10165
+ status: "not-installed"
10166
+ });
10167
+ } else {
10168
+ printError(`${desc3.name} is not installed \u2014 nothing to remove.`);
10169
+ }
10170
+ return 1;
10171
+ }
10172
+ const subsystemDir = target.path;
10173
+ if (!fs11.existsSync(subsystemDir)) {
10174
+ printError(
10175
+ `Detected install at ${subsystemDir} but the directory is gone \u2014 refusing to act.`
10176
+ );
10177
+ return 1;
10178
+ }
10179
+ if (!this.force) {
10180
+ const rel2 = path22.relative(ctx.cwd, subsystemDir) || subsystemDir;
10181
+ const gitCheck = checkGitSafety([rel2], ctx.cwd);
10182
+ if (gitCheck.inRepo && !gitCheck.clean) {
10183
+ printWarning(
10184
+ `Uncommitted changes under ${subsystemDir}. Pass --force to delete anyway.`
10185
+ );
10186
+ if (!isJsonMode()) return 1;
10187
+ }
10188
+ }
10189
+ try {
10190
+ fs11.rmSync(subsystemDir, { recursive: true, force: true });
10191
+ } catch (err) {
10192
+ const message = err instanceof Error ? err.message : String(err);
10193
+ printError(`Failed to remove ${subsystemDir}: ${message}`);
10194
+ return 1;
10195
+ }
10196
+ let barrelRegenerated = false;
10197
+ try {
10198
+ const generatedDir = resolveGeneratedDir(ctx);
10199
+ await regenerateSubsystemBarrel({ ctx, generatedDir });
10200
+ barrelRegenerated = true;
10201
+ } catch (err) {
10202
+ const msg = err instanceof Error ? err.message : String(err);
10203
+ printWarning(`subsystem barrel regeneration failed \u2014 ${msg}`);
10204
+ }
10097
10205
  if (isJsonMode()) {
10098
10206
  printJson({
10099
10207
  command: "subsystem remove",
10100
- status: "not-implemented",
10101
- message: "Manually delete the subsystem directory and remove the module registration from your app.module.ts."
10208
+ subsystem: desc3.name,
10209
+ status: "removed",
10210
+ path: subsystemDir,
10211
+ barrelRegenerated
10102
10212
  });
10103
- return 1;
10213
+ return 0;
10104
10214
  }
10105
- printError("subsystem remove is not yet implemented.");
10106
- console.log(
10107
- theme.muted(
10108
- " Manually delete the subsystem directory and remove the module\n registration from your app.module.ts."
10109
- )
10215
+ printSuccess(
10216
+ `${desc3.name} subsystem removed (${path22.relative(ctx.cwd, subsystemDir) || subsystemDir}).`
10110
10217
  );
10111
- return 1;
10218
+ if (barrelRegenerated) {
10219
+ printInfo("Regenerated <generated>/subsystems.ts barrel.");
10220
+ }
10221
+ printInfo("Next steps (manual):");
10222
+ printInfo(
10223
+ ` 1. Remove the \`${capitalize(desc3.name)}Module.forRoot(...)\` registration from app.module.ts.`
10224
+ );
10225
+ printInfo(
10226
+ ` 2. Remove the \`${desc3.name}:\` block from codegen.config.yaml (if you no longer want it).`
10227
+ );
10228
+ return 0;
10112
10229
  }
10113
10230
  };
10114
10231
  var subsystemNoun = {