@pattern-stack/codegen 0.13.0 → 0.14.0

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 (161) hide show
  1. package/dist/{job-orchestrator.protocol-CHOEqBDk.d.ts → job-orchestrator.protocol-CARhMLCO.d.ts} +1 -1
  2. package/dist/runtime/subsystems/analytics/analytics.module.js +6 -2
  3. package/dist/runtime/subsystems/analytics/analytics.module.js.map +1 -1
  4. package/dist/runtime/subsystems/analytics/analytics.tokens.d.ts +0 -11
  5. package/dist/runtime/subsystems/analytics/analytics.tokens.js +6 -2
  6. package/dist/runtime/subsystems/analytics/analytics.tokens.js.map +1 -1
  7. package/dist/runtime/subsystems/analytics/cube-backend.js +6 -2
  8. package/dist/runtime/subsystems/analytics/cube-backend.js.map +1 -1
  9. package/dist/runtime/subsystems/analytics/index.js +6 -2
  10. package/dist/runtime/subsystems/analytics/index.js.map +1 -1
  11. package/dist/runtime/subsystems/auth/auth.module.js +12 -6
  12. package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
  13. package/dist/runtime/subsystems/auth/auth.tokens.d.ts +0 -28
  14. package/dist/runtime/subsystems/auth/auth.tokens.js +12 -8
  15. package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
  16. package/dist/runtime/subsystems/auth/controllers/auth.controller.js +12 -5
  17. package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -1
  18. package/dist/runtime/subsystems/auth/index.js +12 -8
  19. package/dist/runtime/subsystems/auth/index.js.map +1 -1
  20. package/dist/runtime/subsystems/auth/middleware/requester-context.js +12 -1
  21. package/dist/runtime/subsystems/auth/middleware/requester-context.js.map +1 -1
  22. package/dist/runtime/subsystems/bridge/bridge-delivery-handler.d.ts +1 -1
  23. package/dist/runtime/subsystems/bridge/bridge-delivery-handler.js +10 -2
  24. package/dist/runtime/subsystems/bridge/bridge-delivery-handler.js.map +1 -1
  25. package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js +10 -2
  26. package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js.map +1 -1
  27. package/dist/runtime/subsystems/bridge/bridge.module.d.ts +1 -1
  28. package/dist/runtime/subsystems/bridge/bridge.module.js +14 -9
  29. package/dist/runtime/subsystems/bridge/bridge.module.js.map +1 -1
  30. package/dist/runtime/subsystems/bridge/bridge.protocol.d.ts +1 -1
  31. package/dist/runtime/subsystems/bridge/event-flow.service.d.ts +1 -1
  32. package/dist/runtime/subsystems/bridge/event-flow.service.js +9 -1
  33. package/dist/runtime/subsystems/bridge/event-flow.service.js.map +1 -1
  34. package/dist/runtime/subsystems/bridge/index.d.ts +1 -1
  35. package/dist/runtime/subsystems/bridge/index.js +14 -9
  36. package/dist/runtime/subsystems/bridge/index.js.map +1 -1
  37. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js +6 -1
  38. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js.map +1 -1
  39. package/dist/runtime/subsystems/cache/cache.memory-backend.js +6 -1
  40. package/dist/runtime/subsystems/cache/cache.memory-backend.js.map +1 -1
  41. package/dist/runtime/subsystems/cache/cache.module.js +6 -2
  42. package/dist/runtime/subsystems/cache/cache.module.js.map +1 -1
  43. package/dist/runtime/subsystems/cache/cache.tokens.d.ts +0 -10
  44. package/dist/runtime/subsystems/cache/cache.tokens.js +6 -2
  45. package/dist/runtime/subsystems/cache/cache.tokens.js.map +1 -1
  46. package/dist/runtime/subsystems/cache/index.js +6 -2
  47. package/dist/runtime/subsystems/cache/index.js.map +1 -1
  48. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +5 -0
  49. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -1
  50. package/dist/runtime/subsystems/events/event-bus.memory-backend.js +5 -0
  51. package/dist/runtime/subsystems/events/event-bus.memory-backend.js.map +1 -1
  52. package/dist/runtime/subsystems/events/event-bus.redis-backend.js +5 -1
  53. package/dist/runtime/subsystems/events/event-bus.redis-backend.js.map +1 -1
  54. package/dist/runtime/subsystems/events/events.module.js +5 -1
  55. package/dist/runtime/subsystems/events/events.module.js.map +1 -1
  56. package/dist/runtime/subsystems/events/events.tokens.d.ts +5 -11
  57. package/dist/runtime/subsystems/events/events.tokens.js +5 -1
  58. package/dist/runtime/subsystems/events/events.tokens.js.map +1 -1
  59. package/dist/runtime/subsystems/events/generated/bus.js +5 -0
  60. package/dist/runtime/subsystems/events/generated/bus.js.map +1 -1
  61. package/dist/runtime/subsystems/events/generated/index.js +5 -0
  62. package/dist/runtime/subsystems/events/generated/index.js.map +1 -1
  63. package/dist/runtime/subsystems/events/index.js +5 -1
  64. package/dist/runtime/subsystems/events/index.js.map +1 -1
  65. package/dist/runtime/subsystems/index.d.ts +3 -3
  66. package/dist/runtime/subsystems/index.js +34 -26
  67. package/dist/runtime/subsystems/index.js.map +1 -1
  68. package/dist/runtime/subsystems/integration/incremental-read.d.ts +35 -8
  69. package/dist/runtime/subsystems/integration/incremental-read.js +9 -6
  70. package/dist/runtime/subsystems/integration/incremental-read.js.map +1 -1
  71. package/dist/runtime/subsystems/integration/index.d.ts +1 -1
  72. package/dist/runtime/subsystems/integration/index.js +9 -6
  73. package/dist/runtime/subsystems/integration/index.js.map +1 -1
  74. package/dist/runtime/subsystems/jobs/bullmq.config.d.ts +0 -9
  75. package/dist/runtime/subsystems/jobs/bullmq.config.js +6 -2
  76. package/dist/runtime/subsystems/jobs/bullmq.config.js.map +1 -1
  77. package/dist/runtime/subsystems/jobs/index.d.ts +1 -1
  78. package/dist/runtime/subsystems/jobs/index.js +13 -9
  79. package/dist/runtime/subsystems/jobs/index.js.map +1 -1
  80. package/dist/runtime/subsystems/jobs/job-handler.base.d.ts +1 -1
  81. package/dist/runtime/subsystems/jobs/job-handler.base.js +5 -1
  82. package/dist/runtime/subsystems/jobs/job-handler.base.js.map +1 -1
  83. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.d.ts +1 -1
  84. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js +10 -3
  85. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js.map +1 -1
  86. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.d.ts +1 -1
  87. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js +8 -1
  88. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js.map +1 -1
  89. package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.d.ts +1 -1
  90. package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js +9 -1
  91. package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js.map +1 -1
  92. package/dist/runtime/subsystems/jobs/job-orchestrator.protocol.d.ts +1 -1
  93. package/dist/runtime/subsystems/jobs/job-run-keyset-cursor.d.ts +1 -1
  94. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.d.ts +1 -1
  95. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js +8 -2
  96. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js.map +1 -1
  97. package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.d.ts +1 -1
  98. package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js +8 -2
  99. package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js.map +1 -1
  100. package/dist/runtime/subsystems/jobs/job-run-service.protocol.d.ts +1 -1
  101. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.d.ts +1 -1
  102. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +5 -0
  103. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js.map +1 -1
  104. package/dist/runtime/subsystems/jobs/job-worker.d.ts +1 -1
  105. package/dist/runtime/subsystems/jobs/job-worker.js +10 -4
  106. package/dist/runtime/subsystems/jobs/job-worker.js.map +1 -1
  107. package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +5 -2
  108. package/dist/runtime/subsystems/jobs/job-worker.module.js +13 -8
  109. package/dist/runtime/subsystems/jobs/job-worker.module.js.map +1 -1
  110. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +11 -6
  111. package/dist/runtime/subsystems/jobs/jobs-domain.module.js.map +1 -1
  112. package/dist/runtime/subsystems/jobs/jobs-domain.tokens.d.ts +0 -11
  113. package/dist/runtime/subsystems/jobs/jobs-domain.tokens.js +8 -4
  114. package/dist/runtime/subsystems/jobs/jobs-domain.tokens.js.map +1 -1
  115. package/dist/runtime/subsystems/jobs/jobs-errors.d.ts +1 -1
  116. package/dist/runtime/subsystems/observability/index.d.ts +1 -1
  117. package/dist/runtime/subsystems/observability/index.js +9 -1
  118. package/dist/runtime/subsystems/observability/index.js.map +1 -1
  119. package/dist/runtime/subsystems/observability/observability.module.js +9 -1
  120. package/dist/runtime/subsystems/observability/observability.module.js.map +1 -1
  121. package/dist/runtime/subsystems/observability/observability.protocol.d.ts +1 -1
  122. package/dist/runtime/subsystems/observability/observability.service.d.ts +1 -1
  123. package/dist/runtime/subsystems/observability/observability.service.js +9 -1
  124. package/dist/runtime/subsystems/observability/observability.service.js.map +1 -1
  125. package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.d.ts +1 -1
  126. package/dist/runtime/subsystems/observability/reporters/index.d.ts +1 -1
  127. package/dist/runtime/subsystems/storage/index.js +5 -1
  128. package/dist/runtime/subsystems/storage/index.js.map +1 -1
  129. package/dist/runtime/subsystems/storage/storage.module.js +5 -1
  130. package/dist/runtime/subsystems/storage/storage.module.js.map +1 -1
  131. package/dist/runtime/subsystems/storage/storage.tokens.d.ts +0 -8
  132. package/dist/runtime/subsystems/storage/storage.tokens.js +5 -1
  133. package/dist/runtime/subsystems/storage/storage.tokens.js.map +1 -1
  134. package/dist/runtime/subsystems/token-key.d.ts +7 -0
  135. package/dist/runtime/subsystems/token-key.js +8 -0
  136. package/dist/runtime/subsystems/token-key.js.map +1 -0
  137. package/dist/src/cli/index.js +362 -233
  138. package/dist/src/cli/index.js.map +1 -1
  139. package/package.json +5 -1
  140. package/runtime/subsystems/analytics/analytics.tokens.ts +6 -2
  141. package/runtime/subsystems/auth/auth.tokens.ts +15 -8
  142. package/runtime/subsystems/cache/cache.tokens.ts +7 -2
  143. package/runtime/subsystems/events/events.tokens.ts +8 -1
  144. package/runtime/subsystems/index.ts +6 -1
  145. package/runtime/subsystems/integration/incremental-read.ts +43 -9
  146. package/runtime/subsystems/integration/index.ts +1 -0
  147. package/runtime/subsystems/jobs/bullmq.config.ts +5 -2
  148. package/runtime/subsystems/jobs/job-handler.base.ts +6 -1
  149. package/runtime/subsystems/jobs/job-worker.module.ts +5 -1
  150. package/runtime/subsystems/jobs/job-worker.ts +4 -1
  151. package/runtime/subsystems/jobs/jobs-domain.tokens.ts +10 -7
  152. package/runtime/subsystems/storage/storage.tokens.ts +6 -1
  153. package/runtime/subsystems/token-key.ts +7 -0
  154. package/src/config/runtime-mode.mjs +82 -0
  155. package/templates/entity/new/backend/modules/core/integration-source.ejs.t +3 -2
  156. package/templates/entity/new/clean-lite-ps/controller.ejs.t +1 -1
  157. package/templates/entity/new/clean-lite-ps/module.ejs.t +1 -1
  158. package/templates/entity/new/clean-lite-ps/prompt-extension.js +8 -2
  159. package/templates/entity/new/clean-lite-ps/repository.ejs.t +4 -4
  160. package/templates/entity/new/clean-lite-ps/service.ejs.t +4 -4
  161. package/templates/entity/new/prompt.js +49 -10
@@ -8105,164 +8105,35 @@ function validateEntityEmits(entities, events) {
8105
8105
  }
8106
8106
 
8107
8107
  // src/cli/shared/provider-module-generator.ts
8108
- import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync7, statSync as statSync5, writeFileSync as writeFileSync2 } from "fs";
8109
- import { dirname, isAbsolute as isAbsolute2, join as join11, resolve as resolve5 } from "path";
8110
- function providerPascalCase(slug) {
8111
- return slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
8112
- }
8113
- function providerConstantCase(slug) {
8114
- return slug.replace(/-/g, "_").toUpperCase();
8115
- }
8116
- function providerModuleBanner(sourceYaml) {
8117
- return `// @generated by @pattern-stack/codegen from ${sourceYaml} \u2014 DO NOT EDIT.
8118
- // Hand edits are overwritten on re-emit. Regenerate with \`bun run codegen\`. To change this provider, edit its \`definitions/providers/*.yaml\`.`;
8119
- }
8120
- function generateProviderModule(def, sourceYaml) {
8121
- const { slug } = def;
8122
- const Pascal = providerPascalCase(slug);
8123
- const CONST = providerConstantCase(slug);
8124
- const strategy = parseImportRef(def.auth.strategy);
8125
- const client = parseImportRef(def.client.class);
8126
- const strategyToken = `${CONST}_AUTH_STRATEGY`;
8127
- const clientToken = `${CONST}_CLIENT`;
8128
- const surfaces = def.surfaces.join(", ");
8129
- const title = def.display_name ? `${def.display_name} (\`${slug}\`)` : `\`${slug}\``;
8130
- return `${providerModuleBanner(sourceYaml)}
8131
- /**
8132
- * Provider module for ${title}.
8133
- *
8134
- * Surfaces: ${surfaces}.
8135
- *
8136
- * Wires the declared auth strategy and API client under the provider-specific
8137
- * DI tokens \`${strategyToken}\` and \`${clientToken}\`. Per the auth subsystem
8138
- * contract, strategies are registered under provider-specific tokens rather
8139
- * than a single \`AUTH_STRATEGY\`. Registry aggregation (RFC-0001 \xA73) is
8140
- * emitted by a later codegen step.
8141
- */
8142
- import { Module } from '@nestjs/common';
8143
- import { ${strategy.exportName} } from '${strategy.path}';
8144
- import { ${client.exportName} } from '${client.path}';
8108
+ import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, statSync as statSync6, writeFileSync as writeFileSync3 } from "fs";
8109
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join12, resolve as resolve6 } from "path";
8145
8110
 
8146
- /** DI token for the \`${slug}\` provider's auth strategy. */
8147
- export const ${strategyToken} = Symbol('${strategyToken}');
8148
- /** DI token for the \`${slug}\` provider's API client. */
8149
- export const ${clientToken} = Symbol('${clientToken}');
8111
+ // src/cli/shared/adapter-emission-generator.ts
8112
+ import {
8113
+ existsSync as existsSync9,
8114
+ mkdirSync as mkdirSync2,
8115
+ readFileSync as readFileSync7,
8116
+ statSync as statSync5,
8117
+ writeFileSync as writeFileSync2
8118
+ } from "fs";
8119
+ import { dirname, join as join11 } from "path";
8150
8120
 
8151
- @Module({
8152
- providers: [
8153
- ${strategy.exportName},
8154
- ${client.exportName},
8155
- { provide: ${strategyToken}, useExisting: ${strategy.exportName} },
8156
- { provide: ${clientToken}, useExisting: ${client.exportName} },
8157
- ],
8158
- exports: [
8159
- ${strategy.exportName},
8160
- ${client.exportName},
8161
- ${strategyToken},
8162
- ${clientToken},
8163
- ],
8164
- })
8165
- export class ${Pascal}ProviderModule {}
8166
- `;
8167
- }
8168
- function resolveTsconfigAliases(consumerRoot) {
8169
- const tsconfigPath = join11(consumerRoot, "tsconfig.json");
8170
- if (!existsSync9(tsconfigPath)) return null;
8171
- let parsed;
8172
- try {
8173
- parsed = JSON.parse(stripJsonComments(readFileSync7(tsconfigPath, "utf-8")));
8174
- } catch {
8175
- return null;
8176
- }
8177
- const compilerOptions = parsed.compilerOptions ?? {};
8178
- const baseUrl = compilerOptions.baseUrl ?? ".";
8179
- const sourceRoot = isAbsolute2(baseUrl) ? baseUrl : resolve5(consumerRoot, baseUrl);
8180
- const aliases = {};
8181
- for (const [pattern, targets] of Object.entries(compilerOptions.paths ?? {})) {
8182
- if (!Array.isArray(targets) || targets.length === 0) continue;
8183
- const aliasKey = pattern.replace(/\/\*$/, "");
8184
- const target = targets[0].replace(/\/\*$/, "");
8185
- aliases[aliasKey] = isAbsolute2(target) ? target : resolve5(sourceRoot, target);
8186
- }
8187
- return { sourceRoot, aliases };
8188
- }
8189
- function stripJsonComments(input) {
8190
- return input.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
8121
+ // src/cli/shared/runtime-import.ts
8122
+ var PACKAGE = "@pattern-stack/codegen";
8123
+ function resolveRuntimeMode(config) {
8124
+ return config?.runtime === "vendored" ? "vendored" : "package";
8191
8125
  }
8192
- function generateProviderModules(opts) {
8193
- const base = {
8194
- providersDir: opts.providersDir,
8195
- skipped: false,
8196
- written: [],
8197
- loadFailures: [],
8198
- issues: []
8199
- };
8200
- if (!existsSync9(opts.providersDir) || !statSync5(opts.providersDir).isDirectory()) {
8201
- return { ...base, skipped: true };
8202
- }
8203
- const files = findYamlFiles(opts.providersDir);
8204
- if (files.length === 0) return { ...base, skipped: true };
8205
- const { successes, failures } = loadProvidersFromYaml(files);
8206
- const loaded = successes.map((s) => ({
8207
- definition: s.definition,
8208
- filePath: s.filePath
8209
- }));
8210
- const issues = failures.map((f) => ({
8211
- severity: "error",
8212
- type: "provider_load_failed",
8213
- message: `${f.error}${f.details?.length ? ` \u2014 ${f.details.join("; ")}` : ""}`,
8214
- path: f.filePath
8215
- }));
8216
- issues.push(
8217
- ...validateProviders(loaded, {
8218
- entitySurfaces: opts.entitySurfaces,
8219
- sourceRoot: opts.sourceRoot,
8220
- aliases: opts.aliases,
8221
- skipImportCheck: opts.skipImportCheck
8222
- })
8223
- );
8224
- if (issues.some((i) => i.severity === "error")) {
8225
- return { ...base, loadFailures: failures, issues };
8226
- }
8227
- const written = [];
8228
- for (const { definition, filePath } of loaded) {
8229
- const sourceYaml = relativeSource(filePath);
8230
- const content = generateProviderModule(definition, sourceYaml);
8231
- const outPath = join11(
8232
- opts.outputRoot,
8233
- definition.slug,
8234
- `${definition.slug}.provider.module.ts`
8235
- );
8236
- if (!opts.dryRun) {
8237
- writeIfChanged(outPath, content);
8238
- }
8239
- written.push(outPath);
8126
+ function subsystemsImport(mode, subsystem) {
8127
+ if (mode === "vendored") {
8128
+ return subsystem ? `@shared/subsystems/${subsystem}` : "@shared/subsystems";
8240
8129
  }
8241
- return { ...base, written, loadFailures: failures, issues };
8242
- }
8243
- function writeIfChanged(outPath, content) {
8244
- if (existsSync9(outPath) && readFileSync7(outPath, "utf-8") === content) return;
8245
- mkdirSync2(dirname(outPath), { recursive: true });
8246
- writeFileSync2(outPath, content);
8130
+ return `${PACKAGE}/subsystems`;
8247
8131
  }
8248
- function relativeSource(filePath) {
8249
- const marker = "definitions/providers/";
8250
- const idx = filePath.lastIndexOf(marker);
8251
- if (idx !== -1) return filePath.slice(idx);
8252
- const slash = filePath.lastIndexOf("/");
8253
- return slash === -1 ? filePath : `definitions/providers/${filePath.slice(slash + 1)}`;
8132
+ function runtimeImport(mode, relpath) {
8133
+ const clean = relpath.replace(/^\/+/, "");
8134
+ return mode === "vendored" ? `@shared/${clean}` : `${PACKAGE}/runtime/${clean}`;
8254
8135
  }
8255
8136
 
8256
- // src/cli/shared/adapter-emission-generator.ts
8257
- import {
8258
- existsSync as existsSync10,
8259
- mkdirSync as mkdirSync3,
8260
- readFileSync as readFileSync8,
8261
- statSync as statSync6,
8262
- writeFileSync as writeFileSync3
8263
- } from "fs";
8264
- import { dirname as dirname2, join as join12 } from "path";
8265
-
8266
8137
  // src/cli/shared/sink-emission-generator.ts
8267
8138
  var SCAFFOLD_SENTINEL = "// <CODEGEN-SCAFFOLD-V1>";
8268
8139
  var USER_ID_FIELD = "userId";
@@ -8321,7 +8192,7 @@ function generateDefaultSink(input) {
8321
8192
  // for entities with external FK join-keys, fill the marked TODO(s) below.
8322
8193
  // Source: definitions entity '${input.entityName}' (surface: ${input.surface}).
8323
8194
  import { Injectable } from '@nestjs/common';
8324
- import type { IIntegrationSink } from '@pattern-stack/codegen/subsystems';
8195
+ import type { IIntegrationSink } from '${subsystemsImport(input.mode ?? "package", "integration")}';
8325
8196
  import {
8326
8197
  ${n.repoClass},
8327
8198
  type ${n.projectionType},
@@ -8374,7 +8245,7 @@ function relationLabel(writeKey) {
8374
8245
  }
8375
8246
 
8376
8247
  // src/cli/shared/assembly-emission-generator.ts
8377
- import { relative, resolve as resolve6, sep } from "path";
8248
+ import { relative, resolve as resolve5, sep } from "path";
8378
8249
  function generatedBanner(sourceDesc) {
8379
8250
  return `// @generated by @pattern-stack/codegen from ${sourceDesc} \u2014 DO NOT EDIT.
8380
8251
  // Hand edits are overwritten on re-emit. Regenerate with \`bun run codegen\`.`;
@@ -8412,7 +8283,7 @@ import {
8412
8283
  ExecuteIntegrationUseCase,
8413
8284
  INTEGRATION_CHANGE_SOURCE,
8414
8285
  INTEGRATION_SINK,
8415
- } from '@pattern-stack/codegen/subsystems';
8286
+ } from '${subsystemsImport(input.mode ?? "package", "integration")}';
8416
8287
  import { ${adapterClass} } from '${adapterImport}';
8417
8288
  import { ${adapterModuleClass} } from '${adapterModuleImport}';
8418
8289
  import { ${sinkClass} } from '${sinkImport}';
@@ -8425,7 +8296,7 @@ import { ${token} } from '${tokensImport}';
8425
8296
  * inbound-integration assembly (RFC-0002 \xA72, Option A).
8426
8297
  *
8427
8298
  * Binds this module's INTEGRATION_CHANGE_SOURCE from the adapter's
8428
- * \`changeSources['${input.entityName}']\` and INTEGRATION_SINK from
8299
+ * \`changeSources.${input.entityName}\` and INTEGRATION_SINK from
8429
8300
  * ${sinkClass}, provides a local ExecuteIntegrationUseCase, and aliases+exports
8430
8301
  * it under ${token} (the bare class token is ambiguous at app root \u2014 every
8431
8302
  * assembly provides it). The substrate (cursor store, run recorder, differ,
@@ -8437,7 +8308,7 @@ import { ${token} } from '${tokensImport}';
8437
8308
  providers: [
8438
8309
  {
8439
8310
  provide: INTEGRATION_CHANGE_SOURCE,
8440
- useFactory: (adapter: ${adapterClass}) => adapter.changeSources['${input.entityName}'],
8311
+ useFactory: (adapter: ${adapterClass}) => adapter.changeSources.${input.entityName},
8441
8312
  inject: [${adapterClass}],
8442
8313
  },
8443
8314
  {
@@ -8539,17 +8410,17 @@ function resolveEntityModuleImports(input) {
8539
8410
  const repoClass = `${entityClass}Repository`;
8540
8411
  const moduleClass = `${pluralPascalCase(input.entityPlural)}Module`;
8541
8412
  const moduleGroupSegs = input.context ? ["modules", input.context, input.entityPlural] : ["modules", input.entityPlural];
8542
- const repoFileAbs = resolve6(
8413
+ const repoFileAbs = resolve5(
8543
8414
  input.backendSrcAbs,
8544
8415
  ...moduleGroupSegs,
8545
8416
  `${input.entityName}.repository.ts`
8546
8417
  );
8547
- const moduleFileAbs = resolve6(
8418
+ const moduleFileAbs = resolve5(
8548
8419
  input.backendSrcAbs,
8549
8420
  ...moduleGroupSegs,
8550
8421
  `${input.entityPlural}.module.ts`
8551
8422
  );
8552
- const assemblyDirAbs = resolve6(
8423
+ const assemblyDirAbs = resolve5(
8553
8424
  input.backendSrcAbs,
8554
8425
  "integrations",
8555
8426
  input.surface,
@@ -8623,8 +8494,24 @@ var SURFACE_REGISTRY = {
8623
8494
  noCapsConst: "NO_TRANSCRIPT_CAPABILITIES",
8624
8495
  l2Ports: [],
8625
8496
  readPrimitive: true
8497
+ },
8498
+ // messaging (swe-brain ADR-0008) — interaction surface like transcript: the
8499
+ // adapter contributes per-entity change sources for `channel` + `message`
8500
+ // (`conversation` is domain-derived by segmentation, not vendor-read). The
8501
+ // capability descriptor adds an optional `canWrite` flag for the bot-user write
8502
+ // path, which ships dark in v1; the scaffold still only constructs `entities`.
8503
+ messaging: {
8504
+ packageName: "@pattern-stack/codegen-messaging",
8505
+ portType: "MessagingPort",
8506
+ capabilitiesType: "MessagingCapabilities",
8507
+ noCapsConst: "NO_MESSAGING_CAPABILITIES",
8508
+ l2Ports: [],
8509
+ readPrimitive: true
8626
8510
  }
8627
8511
  };
8512
+ function isClientlessProvider(surfaces) {
8513
+ return surfaces.length > 0 && surfaces.every((s) => SURFACE_REGISTRY[s]?.readPrimitive === true);
8514
+ }
8628
8515
  var SCAFFOLD_SENTINEL2 = "// <CODEGEN-SCAFFOLD-V1>";
8629
8516
  function generatedBanner2(sourceDesc) {
8630
8517
  return `// @generated by @pattern-stack/codegen from ${sourceDesc} \u2014 DO NOT EDIT.
@@ -8679,7 +8566,7 @@ function serializeFilterArray(filters) {
8679
8566
  ${items.join("\n")}
8680
8567
  ]`;
8681
8568
  }
8682
- function buildReadPrimitiveEmission(providerSlug, providerPascal, surface, entities, entityDetection, clientExportName) {
8569
+ function buildReadPrimitiveEmission(providerSlug, providerPascal, surface, entities, entityDetection) {
8683
8570
  const canonicalTypes = [];
8684
8571
  const blocks = [];
8685
8572
  const entries = [];
@@ -8711,24 +8598,32 @@ export class ${className} extends IncrementalReadBase<${canonical}, ResolvedFilt
8711
8598
  // (e.g. Gmail \`q=\`); leave \`false\` to filter post-hydrate via \`matchesRecord\`.
8712
8599
  protected override readonly filterPushdown = false;${cursorOverride}
8713
8600
 
8714
- constructor(
8715
- private readonly auth: IAuthStrategy,
8716
- private readonly client: ${clientExportName},
8717
- ) {
8601
+ constructor(private readonly auth: IAuthStrategy) {
8718
8602
  super();
8719
8603
  }
8720
8604
 
8721
- /** TODO: walk the vendor list endpoint \u2192 pages of \`Ref\` (id + cursor + meta). */
8605
+ /**
8606
+ * TODO: walk the vendor list endpoint \u2192 pages of \`Ref\` (id + cursor + meta).
8607
+ * Per-connection (multi-account) adapters resolve credentials here from the
8608
+ * threaded subscription, e.g.
8609
+ * \`const client = <vendorClientFactory>({ accessToken: async () => (await this.auth.resolve(_ctx!.subscription!.externalRef)).accessToken });\`
8610
+ * \u2014 there is no provider-level singleton client. Provider-level-auth adapters
8611
+ * ignore \`_ctx\`.
8612
+ */
8722
8613
  protected async *enumerate(
8723
8614
  _mode: ReadMode,
8724
8615
  _filter?: ResolvedFilter[],
8725
8616
  _pageSize?: number,
8617
+ _ctx?: ReadContext,
8726
8618
  ): AsyncIterable<Ref[]> {
8727
8619
  throw new Error('not implemented: ${className}.enumerate');
8728
8620
  }
8729
8621
 
8730
- /** TODO: batched fetch-by-id \u2192 \`Map<id, raw>\` (\`mapConcurrent\`, or a vendor /batch). */
8731
- protected async hydrate(_ids: string[]): Promise<Map<string, unknown>> {
8622
+ /**
8623
+ * TODO: batched fetch-by-id \u2192 \`Map<id, raw>\` (\`mapConcurrent\`, or a vendor /batch).
8624
+ * Use \`_ctx?.subscription?.id\` to key raw-landing rows per connection.
8625
+ */
8626
+ protected async hydrate(_ids: string[], _ctx?: ReadContext): Promise<Map<string, unknown>> {
8732
8627
  throw new Error('not implemented: ${className}.hydrate');
8733
8628
  }
8734
8629
 
@@ -8743,15 +8638,16 @@ export class ${className} extends IncrementalReadBase<${canonical}, ResolvedFilt
8743
8638
  return ${constName};
8744
8639
  }
8745
8640
  }`);
8746
- entries.push(` ${entity}: new ${className}(this.auth, this.client),`);
8641
+ entries.push(` ${entity}: new ${className}(this.auth),`);
8747
8642
  }
8748
8643
  return { canonicalTypes, preamble: blocks.join("\n\n"), changeSourceEntries: entries };
8749
8644
  }
8750
- function generateAdapterScaffold(def, surface, entities, entityDetection) {
8645
+ function generateAdapterScaffold(def, surface, entities, entityDetection, mode = "package") {
8751
8646
  const spec = SURFACE_REGISTRY[surface];
8752
8647
  if (!spec) throw new Error(`no surface package for '${surface}'`);
8753
8648
  const n = names(def.slug, surface);
8754
8649
  const client = parseImportRef(def.client.class);
8650
+ const subsystemsSpec = subsystemsImport(mode, "integration");
8755
8651
  const entitiesLiteral = entities.length ? `[${entities.map((e) => `'${e}'`).join(", ")}]` : "[]";
8756
8652
  const readPrimitive = !!spec.readPrimitive && entities.length > 0;
8757
8653
  const rp = readPrimitive ? buildReadPrimitiveEmission(
@@ -8759,21 +8655,26 @@ function generateAdapterScaffold(def, surface, entities, entityDetection) {
8759
8655
  n.providerPascal,
8760
8656
  surface,
8761
8657
  entities,
8762
- entityDetection,
8763
- client.exportName
8658
+ entityDetection
8764
8659
  ) : null;
8765
8660
  const surfaceTypeImports = [
8766
8661
  spec.portType,
8767
8662
  ...spec.l2Ports.map((p) => p.type),
8768
8663
  spec.capabilitiesType,
8769
8664
  ...rp ? rp.canonicalTypes : []
8770
- ].map((t) => ` ${t},`).join("\n");
8771
- const subsystemValueImport = rp ? `import { IncrementalReadBase } from '@pattern-stack/codegen/subsystems';
8665
+ ].sort().map((t) => ` ${t},`).join("\n");
8666
+ const subsystemValueImport = rp ? `import { IncrementalReadBase } from '${subsystemsSpec}';
8772
8667
  ` : "";
8773
8668
  const subsystemTypeImports = [
8774
8669
  "IAuthStrategy",
8775
8670
  "IChangeSource",
8776
- ...rp ? ["IntegrationSubscriptionView", "ReadMode", "Ref", "ResolvedFilter"] : []
8671
+ ...rp ? [
8672
+ "IntegrationSubscriptionView",
8673
+ "ReadContext",
8674
+ "ReadMode",
8675
+ "Ref",
8676
+ "ResolvedFilter"
8677
+ ] : []
8777
8678
  ].map((t) => ` ${t},`).join("\n");
8778
8679
  const changeSourcesAssign = rp ? `
8779
8680
  this.changeSources = {
@@ -8813,6 +8714,14 @@ ${rp.preamble}
8813
8714
  const l2Section = l2Members ? `
8814
8715
  ${l2Members}
8815
8716
  ` : "";
8717
+ const clientTypeImport = rp ? "" : `import type { ${client.exportName} } from '${client.path}';
8718
+ `;
8719
+ const providerTokenImport = rp ? `import { ${n.strategyToken} } from '../../../providers/${def.slug}/${def.slug}.provider.module';` : `import { ${n.strategyToken}, ${n.clientToken} } from '../../../providers/${def.slug}/${def.slug}.provider.module';`;
8720
+ const ctorClientParam = rp ? "" : `
8721
+ @Inject(${n.clientToken}) private readonly client: ${client.exportName},`;
8722
+ const ctorOpen = rp ? ` constructor(@Inject(${n.strategyToken}) readonly auth: IAuthStrategy) {${changeSourcesAssign}}` : ` constructor(
8723
+ @Inject(${n.strategyToken}) readonly auth: IAuthStrategy,${ctorClientParam}
8724
+ ) {${changeSourcesAssign}}`;
8816
8725
  return `${SCAFFOLD_SENTINEL2}
8817
8726
  // Scaffolded once by @pattern-stack/codegen, then author-owned. Re-running
8818
8727
  // codegen detects the sentinel above and SKIPS this file \u2014 your edits are safe.
@@ -8824,9 +8733,8 @@ ${surfaceTypeImports}
8824
8733
  import { ${spec.noCapsConst} } from '${spec.packageName}';
8825
8734
  ${subsystemValueImport}import type {
8826
8735
  ${subsystemTypeImports}
8827
- } from '@pattern-stack/codegen/subsystems';
8828
- import type { ${client.exportName} } from '${client.path}';
8829
- import { ${n.strategyToken}, ${n.clientToken} } from '../../../providers/${def.slug}/${def.slug}.provider.module';
8736
+ } from '${subsystemsSpec}';
8737
+ ${clientTypeImport}${providerTokenImport}
8830
8738
  ${preambleSection}
8831
8739
  @Injectable()
8832
8740
  export class ${n.adapterClass} implements ${spec.portType} {
@@ -8835,10 +8743,7 @@ export class ${n.adapterClass} implements ${spec.portType} {
8835
8743
  ${capabilityBody}
8836
8744
  };
8837
8745
 
8838
- constructor(
8839
- @Inject(${n.strategyToken}) readonly auth: IAuthStrategy,
8840
- @Inject(${n.clientToken}) private readonly client: ${client.exportName},
8841
- ) {${changeSourcesAssign}}
8746
+ ${ctorOpen}
8842
8747
  ${l2Section}
8843
8748
  ${changeSourcesDecl}
8844
8749
 
@@ -8870,10 +8775,10 @@ function generateAdaptersBarrel(surface, providerSlugs) {
8870
8775
  ${lines}
8871
8776
  `;
8872
8777
  }
8873
- function generateSurfaceTokens(surface) {
8778
+ function generateSurfaceTokens(surface, mode = "package") {
8874
8779
  const n = names("__placeholder__", surface);
8875
8780
  return `${generatedBanner2(`surface: ${surface}`)}
8876
- import type { IChangeSource } from '@pattern-stack/codegen/subsystems';
8781
+ import type { IChangeSource } from '${subsystemsImport(mode, "integration")}';
8877
8782
 
8878
8783
  /** The assembled list of every ${surface} adapter's contribution. */
8879
8784
  export const ${n.contributionsToken} = Symbol.for('@app/integrations/${surface}.adapter-contributions');
@@ -8890,7 +8795,7 @@ export interface AdapterContribution {
8890
8795
  }
8891
8796
  `;
8892
8797
  }
8893
- function generateSurfaceAggregator(surface, providerSlugs) {
8798
+ function generateSurfaceAggregator(surface, providerSlugs, mode = "package") {
8894
8799
  const n = names("__placeholder__", surface);
8895
8800
  const slugs = [...providerSlugs].sort();
8896
8801
  const per = slugs.map((slug) => names(slug, surface));
@@ -8917,7 +8822,7 @@ import {
8917
8822
  MemoryEntityChangeSourceRegistry,
8918
8823
  type IChangeSource,
8919
8824
  type IEntityChangeSourceRegistry,
8920
- } from '@pattern-stack/codegen/subsystems';
8825
+ } from '${subsystemsImport(mode, "integration")}';
8921
8826
  ${moduleImport}
8922
8827
  ${adapterImports}
8923
8828
  import {
@@ -9006,6 +8911,7 @@ function jsKey(key) {
9006
8911
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : `'${key}'`;
9007
8912
  }
9008
8913
  function emitAdapters(opts) {
8914
+ const mode = opts.mode ?? "package";
9009
8915
  const result = {
9010
8916
  written: [],
9011
8917
  scaffoldsWritten: [],
@@ -9036,14 +8942,14 @@ function emitAdapters(opts) {
9036
8942
  }
9037
8943
  const defBySlug = new Map(opts.providers.map((p) => [p.definition.slug, p.definition]));
9038
8944
  for (const [surface, slugs] of bySurface) {
9039
- const surfaceDir = join12(opts.outputRoot, surface);
9040
- const adaptersDir = join12(surfaceDir, "adapters");
8945
+ const surfaceDir = join11(opts.outputRoot, surface);
8946
+ const adaptersDir = join11(surfaceDir, "adapters");
9041
8947
  for (const slug of slugs) {
9042
8948
  const def = defBySlug.get(slug);
9043
- const providerDir = join12(adaptersDir, slug);
9044
- const scaffoldPath = join12(providerDir, `${slug}-${surface}.adapter.ts`);
9045
- const modulePath = join12(providerDir, `${slug}-${surface}.adapter.module.ts`);
9046
- if (existsSync10(scaffoldPath)) {
8949
+ const providerDir = join11(adaptersDir, slug);
8950
+ const scaffoldPath = join11(providerDir, `${slug}-${surface}.adapter.ts`);
8951
+ const modulePath = join11(providerDir, `${slug}-${surface}.adapter.module.ts`);
8952
+ if (existsSync9(scaffoldPath)) {
9047
8953
  result.scaffoldsSkipped.push(scaffoldPath);
9048
8954
  } else {
9049
8955
  const surfaceEntityNames = entitiesBySurface.get(surface) ?? [];
@@ -9056,27 +8962,28 @@ function emitAdapters(opts) {
9056
8962
  def,
9057
8963
  surface,
9058
8964
  surfaceEntityNames,
9059
- entityDetection
8965
+ entityDetection,
8966
+ mode
9060
8967
  );
9061
8968
  if (!opts.dryRun) writeFile(scaffoldPath, content);
9062
8969
  result.scaffoldsWritten.push(scaffoldPath);
9063
8970
  }
9064
8971
  const moduleContent = generateAdapterModule(def, surface);
9065
- if (!opts.dryRun) writeIfChanged2(modulePath, moduleContent);
8972
+ if (!opts.dryRun) writeIfChanged(modulePath, moduleContent);
9066
8973
  result.written.push(modulePath);
9067
8974
  }
9068
- const barrelPath = join12(adaptersDir, "index.ts");
9069
- const tokensPath = join12(surfaceDir, `${surface}-adapters.tokens.ts`);
9070
- const aggregatorPath = join12(surfaceDir, `${surface}-adapters.module.ts`);
9071
- const typedViewPath = join12(surfaceDir, "types.generated.ts");
8975
+ const barrelPath = join11(adaptersDir, "index.ts");
8976
+ const tokensPath = join11(surfaceDir, `${surface}-adapters.tokens.ts`);
8977
+ const aggregatorPath = join11(surfaceDir, `${surface}-adapters.module.ts`);
8978
+ const typedViewPath = join11(surfaceDir, "types.generated.ts");
9072
8979
  const files = [
9073
8980
  [barrelPath, generateAdaptersBarrel(surface, slugs)],
9074
- [tokensPath, generateSurfaceTokens(surface)],
9075
- [aggregatorPath, generateSurfaceAggregator(surface, slugs)],
8981
+ [tokensPath, generateSurfaceTokens(surface, mode)],
8982
+ [aggregatorPath, generateSurfaceAggregator(surface, slugs, mode)],
9076
8983
  [typedViewPath, generateTypedView(surface, slugs, entitiesBySurface.get(surface) ?? [])]
9077
8984
  ];
9078
8985
  for (const [path34, content] of files) {
9079
- if (!opts.dryRun) writeIfChanged2(path34, content);
8986
+ if (!opts.dryRun) writeIfChanged(path34, content);
9080
8987
  result.written.push(path34);
9081
8988
  }
9082
8989
  if (opts.backendSrcAbs) {
@@ -9084,8 +8991,8 @@ function emitAdapters(opts) {
9084
8991
  const surfaceEntities = entitiesBySurface.get(surface) ?? [];
9085
8992
  const tokenEntries = [];
9086
8993
  const assemblyEntries = [];
9087
- const sinksDir = join12(surfaceDir, "sinks");
9088
- const modulesDir = join12(surfaceDir, "modules");
8994
+ const sinksDir = join11(surfaceDir, "sinks");
8995
+ const modulesDir = join11(surfaceDir, "modules");
9089
8996
  for (const entityName of surfaceEntities) {
9090
8997
  const def = entityByName.get(entityName);
9091
8998
  const pattern = def?.entity.pattern ?? (Array.isArray(def?.entity.patterns) ? def?.entity.patterns?.[0] : void 0);
@@ -9110,17 +9017,17 @@ function emitAdapters(opts) {
9110
9017
  backendSrcAbs: opts.backendSrcAbs,
9111
9018
  aliases
9112
9019
  });
9113
- const sinkPath = join12(sinksDir, `${entityName}.sink.ts`);
9114
- if (existsSync10(sinkPath)) {
9020
+ const sinkPath = join11(sinksDir, `${entityName}.sink.ts`);
9021
+ if (existsSync9(sinkPath)) {
9115
9022
  result.scaffoldsSkipped.push(sinkPath);
9116
9023
  } else {
9117
9024
  const sinkInput = buildSinkInput(def, surface, slugs[0], loc.repoImportSpecifier);
9118
- const sinkContent = generateDefaultSink(sinkInput);
9025
+ const sinkContent = generateDefaultSink({ ...sinkInput, mode });
9119
9026
  if (!opts.dryRun) writeFile(sinkPath, sinkContent);
9120
9027
  result.scaffoldsWritten.push(sinkPath);
9121
9028
  }
9122
9029
  for (const slug of slugs) {
9123
- const assemblyPath = join12(
9030
+ const assemblyPath = join11(
9124
9031
  modulesDir,
9125
9032
  slug,
9126
9033
  `${entityName}-integration.module.ts`
@@ -9134,23 +9041,24 @@ function emitAdapters(opts) {
9134
9041
  moduleClass: loc.moduleClass,
9135
9042
  repoImportSpecifier: loc.repoImportSpecifier,
9136
9043
  repoClass: loc.repoClass,
9137
- sourceDesc: `definitions/providers/${slug}.yaml`
9044
+ sourceDesc: `definitions/providers/${slug}.yaml`,
9045
+ mode
9138
9046
  });
9139
- if (!opts.dryRun) writeIfChanged2(assemblyPath, assemblyContent);
9047
+ if (!opts.dryRun) writeIfChanged(assemblyPath, assemblyContent);
9140
9048
  result.assembliesWritten.push(assemblyPath);
9141
9049
  tokenEntries.push({ entityName, entityClass: loc.entityClass, provider: slug });
9142
9050
  assemblyEntries.push({ entityName, provider: slug });
9143
9051
  }
9144
9052
  }
9145
- const integrationTokensPath = join12(
9053
+ const integrationTokensPath = join11(
9146
9054
  surfaceDir,
9147
9055
  `${surface}-integration.tokens.ts`
9148
9056
  );
9149
9057
  const tokensContent = generateIntegrationTokens(surface, tokenEntries);
9150
- if (!opts.dryRun) writeIfChanged2(integrationTokensPath, tokensContent);
9058
+ if (!opts.dryRun) writeIfChanged(integrationTokensPath, tokensContent);
9151
9059
  result.tokensWritten.push(integrationTokensPath);
9152
9060
  if (assemblyEntries.length > 0) {
9153
- const integrationAggregatorPath = join12(
9061
+ const integrationAggregatorPath = join11(
9154
9062
  surfaceDir,
9155
9063
  `${surface}-integration.module.ts`
9156
9064
  );
@@ -9158,7 +9066,7 @@ function emitAdapters(opts) {
9158
9066
  surface,
9159
9067
  assemblyEntries
9160
9068
  );
9161
- if (!opts.dryRun) writeIfChanged2(integrationAggregatorPath, aggregatorContent);
9069
+ if (!opts.dryRun) writeIfChanged(integrationAggregatorPath, aggregatorContent);
9162
9070
  result.integrationAggregatorsWritten.push(integrationAggregatorPath);
9163
9071
  }
9164
9072
  }
@@ -9215,16 +9123,212 @@ function pascalFromSnake(s) {
9215
9123
  return camel.charAt(0).toUpperCase() + camel.slice(1);
9216
9124
  }
9217
9125
  function writeFile(outPath, content) {
9218
- mkdirSync3(dirname2(outPath), { recursive: true });
9219
- writeFileSync3(outPath, content);
9126
+ mkdirSync2(dirname(outPath), { recursive: true });
9127
+ writeFileSync2(outPath, content);
9220
9128
  }
9221
- function writeIfChanged2(outPath, content) {
9222
- if (existsSync10(outPath) && statSync6(outPath).isFile() && readFileSync8(outPath, "utf-8") === content) {
9129
+ function writeIfChanged(outPath, content) {
9130
+ if (existsSync9(outPath) && statSync5(outPath).isFile() && readFileSync7(outPath, "utf-8") === content) {
9223
9131
  return;
9224
9132
  }
9225
9133
  writeFile(outPath, content);
9226
9134
  }
9227
9135
 
9136
+ // src/cli/shared/provider-module-generator.ts
9137
+ function providerPascalCase(slug) {
9138
+ return slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
9139
+ }
9140
+ function providerConstantCase(slug) {
9141
+ return slug.replace(/-/g, "_").toUpperCase();
9142
+ }
9143
+ function providerModuleBanner(sourceYaml) {
9144
+ return `// @generated by @pattern-stack/codegen from ${sourceYaml} \u2014 DO NOT EDIT.
9145
+ // Hand edits are overwritten on re-emit. Regenerate with \`bun run codegen\`. To change this provider, edit its \`definitions/providers/*.yaml\`.`;
9146
+ }
9147
+ function generateProviderModule(def, sourceYaml, mode = "package") {
9148
+ const { slug } = def;
9149
+ const Pascal = providerPascalCase(slug);
9150
+ const CONST = providerConstantCase(slug);
9151
+ const strategy = parseImportRef(def.auth.strategy);
9152
+ const client = parseImportRef(def.client.class);
9153
+ const strategyToken = `${CONST}_AUTH_STRATEGY`;
9154
+ const clientToken = `${CONST}_CLIENT`;
9155
+ const surfaces = def.surfaces.join(", ");
9156
+ const title = def.display_name ? `${def.display_name} (\`${slug}\`)` : `\`${slug}\``;
9157
+ if (isClientlessProvider(def.surfaces)) {
9158
+ return `${providerModuleBanner(sourceYaml)}
9159
+ /**
9160
+ * Provider module for ${title}.
9161
+ *
9162
+ * Surfaces: ${surfaces}.
9163
+ *
9164
+ * Per-connection (read-primitive) provider \u2014 exposes \`${strategyToken}\`, the
9165
+ * per-connection credential resolver the interaction adapters use (RFC-0003 R5:
9166
+ * \`auth.resolve(ctx.subscription.externalRef)\`). There is NO provider-level
9167
+ * singleton client; adapters build a per-connection client inside their
9168
+ * \`enumerate\`/\`hydrate\`. \`${strategyToken}\` resolves the already-built
9169
+ * \`${slug}\` strategy from the @Global \`STRATEGY_REGISTRY\` (wired by the
9170
+ * consumer's AuthBindings module) \u2014 the strategy may need DI deps a bare class
9171
+ * can't satisfy, so it is registry-resolved, not provided directly.
9172
+ */
9173
+ import { Module } from '@nestjs/common';
9174
+ import {
9175
+ type ProviderStrategyRegistry,
9176
+ STRATEGY_REGISTRY,
9177
+ } from '${subsystemsImport(mode, "auth")}';
9178
+
9179
+ /** DI token for the \`${slug}\` provider's auth strategy (resolved from STRATEGY_REGISTRY). */
9180
+ export const ${strategyToken} = Symbol('${strategyToken}');
9181
+
9182
+ const PROVIDER_SLUG = '${slug}';
9183
+
9184
+ @Module({
9185
+ providers: [
9186
+ {
9187
+ provide: ${strategyToken},
9188
+ useFactory: (registry: ProviderStrategyRegistry) => {
9189
+ const strategy = registry.get(PROVIDER_SLUG);
9190
+ if (!strategy) {
9191
+ throw new Error(
9192
+ \`${Pascal}ProviderModule: no '\${PROVIDER_SLUG}' strategy registered in STRATEGY_REGISTRY (wire it in your consumer AuthBindings module)\`,
9193
+ );
9194
+ }
9195
+ return strategy;
9196
+ },
9197
+ inject: [STRATEGY_REGISTRY],
9198
+ },
9199
+ ],
9200
+ exports: [${strategyToken}],
9201
+ })
9202
+ export class ${Pascal}ProviderModule {}
9203
+ `;
9204
+ }
9205
+ return `${providerModuleBanner(sourceYaml)}
9206
+ /**
9207
+ * Provider module for ${title}.
9208
+ *
9209
+ * Surfaces: ${surfaces}.
9210
+ *
9211
+ * Wires the declared auth strategy and API client under the provider-specific
9212
+ * DI tokens \`${strategyToken}\` and \`${clientToken}\`. Per the auth subsystem
9213
+ * contract, strategies are registered under provider-specific tokens rather
9214
+ * than a single \`AUTH_STRATEGY\`. Registry aggregation (RFC-0001 \xA73) is
9215
+ * emitted by a later codegen step.
9216
+ */
9217
+ import { Module } from '@nestjs/common';
9218
+ import { ${strategy.exportName} } from '${strategy.path}';
9219
+ import { ${client.exportName} } from '${client.path}';
9220
+
9221
+ /** DI token for the \`${slug}\` provider's auth strategy. */
9222
+ export const ${strategyToken} = Symbol('${strategyToken}');
9223
+ /** DI token for the \`${slug}\` provider's API client. */
9224
+ export const ${clientToken} = Symbol('${clientToken}');
9225
+
9226
+ @Module({
9227
+ providers: [
9228
+ ${strategy.exportName},
9229
+ ${client.exportName},
9230
+ { provide: ${strategyToken}, useExisting: ${strategy.exportName} },
9231
+ { provide: ${clientToken}, useExisting: ${client.exportName} },
9232
+ ],
9233
+ exports: [
9234
+ ${strategy.exportName},
9235
+ ${client.exportName},
9236
+ ${strategyToken},
9237
+ ${clientToken},
9238
+ ],
9239
+ })
9240
+ export class ${Pascal}ProviderModule {}
9241
+ `;
9242
+ }
9243
+ function resolveTsconfigAliases(consumerRoot) {
9244
+ const tsconfigPath = join12(consumerRoot, "tsconfig.json");
9245
+ if (!existsSync10(tsconfigPath)) return null;
9246
+ let parsed;
9247
+ try {
9248
+ parsed = JSON.parse(stripJsonComments(readFileSync8(tsconfigPath, "utf-8")));
9249
+ } catch {
9250
+ return null;
9251
+ }
9252
+ const compilerOptions = parsed.compilerOptions ?? {};
9253
+ const baseUrl = compilerOptions.baseUrl ?? ".";
9254
+ const sourceRoot = isAbsolute2(baseUrl) ? baseUrl : resolve6(consumerRoot, baseUrl);
9255
+ const aliases = {};
9256
+ for (const [pattern, targets] of Object.entries(compilerOptions.paths ?? {})) {
9257
+ if (!Array.isArray(targets) || targets.length === 0) continue;
9258
+ const aliasKey = pattern.replace(/\/\*$/, "");
9259
+ const target = targets[0].replace(/\/\*$/, "");
9260
+ aliases[aliasKey] = isAbsolute2(target) ? target : resolve6(sourceRoot, target);
9261
+ }
9262
+ return { sourceRoot, aliases };
9263
+ }
9264
+ function stripJsonComments(input) {
9265
+ return input.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
9266
+ }
9267
+ function generateProviderModules(opts) {
9268
+ const base = {
9269
+ providersDir: opts.providersDir,
9270
+ skipped: false,
9271
+ written: [],
9272
+ loadFailures: [],
9273
+ issues: []
9274
+ };
9275
+ if (!existsSync10(opts.providersDir) || !statSync6(opts.providersDir).isDirectory()) {
9276
+ return { ...base, skipped: true };
9277
+ }
9278
+ const files = findYamlFiles(opts.providersDir);
9279
+ if (files.length === 0) return { ...base, skipped: true };
9280
+ const { successes, failures } = loadProvidersFromYaml(files);
9281
+ const loaded = successes.map((s) => ({
9282
+ definition: s.definition,
9283
+ filePath: s.filePath
9284
+ }));
9285
+ const issues = failures.map((f) => ({
9286
+ severity: "error",
9287
+ type: "provider_load_failed",
9288
+ message: `${f.error}${f.details?.length ? ` \u2014 ${f.details.join("; ")}` : ""}`,
9289
+ path: f.filePath
9290
+ }));
9291
+ issues.push(
9292
+ ...validateProviders(loaded, {
9293
+ entitySurfaces: opts.entitySurfaces,
9294
+ sourceRoot: opts.sourceRoot,
9295
+ aliases: opts.aliases,
9296
+ skipImportCheck: opts.skipImportCheck
9297
+ })
9298
+ );
9299
+ if (issues.some((i) => i.severity === "error")) {
9300
+ return { ...base, loadFailures: failures, issues };
9301
+ }
9302
+ const mode = opts.mode ?? "package";
9303
+ const written = [];
9304
+ for (const { definition, filePath } of loaded) {
9305
+ const sourceYaml = relativeSource(filePath);
9306
+ const content = generateProviderModule(definition, sourceYaml, mode);
9307
+ const outPath = join12(
9308
+ opts.outputRoot,
9309
+ definition.slug,
9310
+ `${definition.slug}.provider.module.ts`
9311
+ );
9312
+ if (!opts.dryRun) {
9313
+ writeIfChanged2(outPath, content);
9314
+ }
9315
+ written.push(outPath);
9316
+ }
9317
+ return { ...base, written, loadFailures: failures, issues };
9318
+ }
9319
+ function writeIfChanged2(outPath, content) {
9320
+ if (existsSync10(outPath) && readFileSync8(outPath, "utf-8") === content) return;
9321
+ mkdirSync3(dirname2(outPath), { recursive: true });
9322
+ writeFileSync3(outPath, content);
9323
+ }
9324
+ function relativeSource(filePath) {
9325
+ const marker = "definitions/providers/";
9326
+ const idx = filePath.lastIndexOf(marker);
9327
+ if (idx !== -1) return filePath.slice(idx);
9328
+ const slash = filePath.lastIndexOf("/");
9329
+ return slash === -1 ? filePath : `definitions/providers/${filePath.slice(slash + 1)}`;
9330
+ }
9331
+
9228
9332
  // src/cli/shared/events-path.ts
9229
9333
  import path12 from "path";
9230
9334
  var FALLBACK = "events";
@@ -9504,6 +9608,7 @@ var EntityNewCommand = class extends Command2 {
9504
9608
  "bridge/generated"
9505
9609
  );
9506
9610
  const backendSrcForHandlers = ctx.config?.paths?.backend_src ?? "src";
9611
+ const runtimeMode = resolveRuntimeMode(ctx.config);
9507
9612
  const bridgeHandlersDir = path13.resolve(
9508
9613
  ctx.cwd,
9509
9614
  backendSrcForHandlers,
@@ -9790,7 +9895,8 @@ var EntityNewCommand = class extends Command2 {
9790
9895
  entitySurfaces,
9791
9896
  sourceRoot: tsAliases?.sourceRoot,
9792
9897
  aliases: tsAliases?.aliases,
9793
- skipImportCheck: tsAliases === null
9898
+ skipImportCheck: tsAliases === null,
9899
+ mode: runtimeMode
9794
9900
  });
9795
9901
  if (!providerResult.skipped && !isJsonMode()) {
9796
9902
  for (const issue of providerResult.issues) {
@@ -9834,7 +9940,8 @@ var EntityNewCommand = class extends Command2 {
9834
9940
  entities: entityDefs,
9835
9941
  outputRoot: adapterOutputRoot,
9836
9942
  backendSrcAbs: path13.resolve(ctx.cwd, backendSrcForHandlers),
9837
- aliases: assemblyTsAliases?.aliases ?? {}
9943
+ aliases: assemblyTsAliases?.aliases ?? {},
9944
+ mode: runtimeMode
9838
9945
  });
9839
9946
  if (!isJsonMode()) {
9840
9947
  if (adapterResult.written.length || adapterResult.scaffoldsWritten.length) {
@@ -11907,12 +12014,13 @@ var VENDORED_RUNTIME_FILES = [
11907
12014
  },
11908
12015
  { runtime: "shared/openapi/index.ts", target: "src/shared/openapi/index.ts" }
11909
12016
  ];
11910
- function databaseModuleContent() {
12017
+ function databaseModuleContent(mode) {
12018
+ const drizzleTokenImport = mode === "vendored" ? "../constants/tokens" : runtimeImport(mode, "constants/tokens");
11911
12019
  return `import { Module, Global } from '@nestjs/common';
11912
12020
  import { drizzle } from 'drizzle-orm/node-postgres';
11913
12021
  import { Pool } from 'pg';
11914
12022
  import * as schema from '../../schema';
11915
- import { DRIZZLE } from '../constants/tokens';
12023
+ import { DRIZZLE } from '${drizzleTokenImport}';
11916
12024
 
11917
12025
  export { DRIZZLE };
11918
12026
  export type DrizzleDB = ReturnType<typeof drizzle<typeof schema>>;
@@ -11939,11 +12047,12 @@ export type DrizzleDB = ReturnType<typeof drizzle<typeof schema>>;
11939
12047
  export class DatabaseModule {}
11940
12048
  `;
11941
12049
  }
11942
- function appModuleContent() {
12050
+ function appModuleContent(mode) {
12051
+ const openApiImport = mode === "vendored" ? "./shared/openapi" : runtimeImport(mode, "shared/openapi");
11943
12052
  return `import { Global, Module } from '@nestjs/common';
11944
12053
  import { DatabaseModule } from './shared/database/database.module';
11945
12054
  import { GENERATED_MODULES } from './generated/modules';
11946
- import { OPENAPI_REGISTRY, OpenApiRegistry } from './shared/openapi';
12055
+ import { OPENAPI_REGISTRY, OpenApiRegistry } from '${openApiImport}';
11947
12056
 
11948
12057
  /**
11949
12058
  * OpenApiModule \u2014 @Global() wrapper around the OPENAPI_REGISTRY singleton.
@@ -11985,7 +12094,8 @@ class OpenApiModule {}
11985
12094
  export class AppModule {}
11986
12095
  `;
11987
12096
  }
11988
- function mainTsContent() {
12097
+ function mainTsContent(mode) {
12098
+ const openApiImport = mode === "vendored" ? "./shared/openapi" : runtimeImport(mode, "shared/openapi");
11989
12099
  return `import 'reflect-metadata';
11990
12100
  import fs from 'node:fs';
11991
12101
  import path from 'node:path';
@@ -11993,7 +12103,7 @@ import { NestFactory } from '@nestjs/core';
11993
12103
  import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
11994
12104
  import { parse as parseYaml } from 'yaml';
11995
12105
  import { AppModule } from './app.module';
11996
- import { OPENAPI_REGISTRY, OpenApiRegistry } from './shared/openapi';
12106
+ import { OPENAPI_REGISTRY, OpenApiRegistry } from '${openApiImport}';
11997
12107
 
11998
12108
  interface OpenApiConfig {
11999
12109
  enabled?: boolean;
@@ -12302,6 +12412,7 @@ function dirEntry(cwd, absPath) {
12302
12412
  async function buildInitPlan(ctx, options) {
12303
12413
  const cwd = options.cwd;
12304
12414
  const force = Boolean(options.force);
12415
+ const runtimeMode = options.runtimeMode === "vendored" ? "vendored" : "package";
12305
12416
  let framework = "nestjs";
12306
12417
  let orm = "drizzle";
12307
12418
  let architecture = "clean-lite-ps";
@@ -12324,6 +12435,11 @@ async function buildInitPlan(ctx, options) {
12324
12435
  {
12325
12436
  const configPath = path23.join(cwd, "codegen.config.yaml");
12326
12437
  const config = {
12438
+ // Runtime mode (ADR-037). `package` (default) imports the runtime from
12439
+ // `@pattern-stack/codegen/*`; `vendored` imports it via `@shared/*` and
12440
+ // vendors `src/shared/**`. Existing vendored projects MUST set this to
12441
+ // `vendored` explicitly — the default does not silently flip them.
12442
+ runtime: runtimeMode,
12327
12443
  paths: {
12328
12444
  backend_src: "src",
12329
12445
  entities_dir: "entities",
@@ -12400,14 +12516,16 @@ async function buildInitPlan(ctx, options) {
12400
12516
  fileEntry(
12401
12517
  cwd,
12402
12518
  path23.join(cwd, "src", "shared", "database", "database.module.ts"),
12403
- databaseModuleContent(),
12519
+ databaseModuleContent(runtimeMode),
12404
12520
  { force }
12405
12521
  )
12406
12522
  );
12407
- for (const v of VENDORED_RUNTIME_FILES) {
12408
- entries.push(
12409
- fileEntry(cwd, path23.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
12410
- );
12523
+ if (runtimeMode === "vendored") {
12524
+ for (const v of VENDORED_RUNTIME_FILES) {
12525
+ entries.push(
12526
+ fileEntry(cwd, path23.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
12527
+ );
12528
+ }
12411
12529
  }
12412
12530
  entries.push(
12413
12531
  fileEntry(
@@ -12432,7 +12550,7 @@ async function buildInitPlan(ctx, options) {
12432
12550
  path: appModulePath,
12433
12551
  relPath: relOf(cwd, appModulePath),
12434
12552
  action: "create",
12435
- content: appModuleContent()
12553
+ content: appModuleContent(runtimeMode)
12436
12554
  });
12437
12555
  } else {
12438
12556
  entries.push({
@@ -12450,7 +12568,7 @@ async function buildInitPlan(ctx, options) {
12450
12568
  path: mainPath,
12451
12569
  relPath: relOf(cwd, mainPath),
12452
12570
  action: "create",
12453
- content: mainTsContent()
12571
+ content: mainTsContent(runtimeMode)
12454
12572
  });
12455
12573
  } else {
12456
12574
  entries.push({
@@ -13593,7 +13711,8 @@ var ProjectInitCommand = class extends Command7 {
13593
13711
  static usage = Command7.Usage({
13594
13712
  description: "Scaffold a consumer project (config, shims, barrels, app.module)",
13595
13713
  examples: [
13596
- ["Initialize with defaults", "codegen project init --yes"],
13714
+ ["Initialize with defaults (package runtime)", "codegen project init --yes"],
13715
+ ["Vendored runtime (legacy @shared/** model)", "codegen project init --yes --runtime vendored"],
13597
13716
  ["Preview without writing", "codegen project init --dry-run"],
13598
13717
  ["Create tsconfig if missing", "codegen project init --yes --with-tsconfig"],
13599
13718
  ["Overwrite existing shims", "codegen project init --force"]
@@ -13603,6 +13722,9 @@ var ProjectInitCommand = class extends Command7 {
13603
13722
  dryRun = Option7.Boolean("--dry-run", false);
13604
13723
  force = Option7.Boolean("--force", false);
13605
13724
  withTsconfig = Option7.Boolean("--with-tsconfig", false);
13725
+ // Runtime mode (ADR-037). `package` (default) ⇒ depend on the npm package,
13726
+ // vendor nothing; `vendored` ⇒ vendor src/shared/** and import via @shared/*.
13727
+ runtime = Option7.String("--runtime", "package");
13606
13728
  // Vendor consumer skills into .claude/skills by default; opt out with --no-skills.
13607
13729
  skills = Option7.Boolean("--skills", true);
13608
13730
  json = Option7.Boolean("--json", false);
@@ -13614,11 +13736,18 @@ var ProjectInitCommand = class extends Command7 {
13614
13736
  json: this.json,
13615
13737
  skipDetection: false
13616
13738
  });
13739
+ const runtimeMode = this.runtime === "vendored" ? "vendored" : "package";
13740
+ if (this.runtime !== "package" && this.runtime !== "vendored" && !isJsonMode()) {
13741
+ printWarning(
13742
+ `--runtime '${this.runtime}' is not recognized (expected 'package' or 'vendored'); using 'package'.`
13743
+ );
13744
+ }
13617
13745
  const plan = await buildInitPlan(ctx, {
13618
13746
  cwd: ctx.cwd,
13619
13747
  force: this.force,
13620
13748
  withTsconfig: this.withTsconfig,
13621
- skipScan: false
13749
+ skipScan: false,
13750
+ runtimeMode
13622
13751
  });
13623
13752
  if (this.force && !isJsonMode()) {
13624
13753
  printWarning("--force: existing scaffold files will be overwritten.");