@pattern-stack/codegen 0.13.1 → 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 (153) 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 +2 -2
  66. package/dist/runtime/subsystems/index.js +25 -20
  67. package/dist/runtime/subsystems/index.js.map +1 -1
  68. package/dist/runtime/subsystems/jobs/bullmq.config.d.ts +0 -9
  69. package/dist/runtime/subsystems/jobs/bullmq.config.js +6 -2
  70. package/dist/runtime/subsystems/jobs/bullmq.config.js.map +1 -1
  71. package/dist/runtime/subsystems/jobs/index.d.ts +1 -1
  72. package/dist/runtime/subsystems/jobs/index.js +13 -9
  73. package/dist/runtime/subsystems/jobs/index.js.map +1 -1
  74. package/dist/runtime/subsystems/jobs/job-handler.base.d.ts +1 -1
  75. package/dist/runtime/subsystems/jobs/job-handler.base.js +5 -1
  76. package/dist/runtime/subsystems/jobs/job-handler.base.js.map +1 -1
  77. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.d.ts +1 -1
  78. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js +10 -3
  79. package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js.map +1 -1
  80. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.d.ts +1 -1
  81. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js +8 -1
  82. package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js.map +1 -1
  83. package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.d.ts +1 -1
  84. package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js +9 -1
  85. package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js.map +1 -1
  86. package/dist/runtime/subsystems/jobs/job-orchestrator.protocol.d.ts +1 -1
  87. package/dist/runtime/subsystems/jobs/job-run-keyset-cursor.d.ts +1 -1
  88. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.d.ts +1 -1
  89. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js +8 -2
  90. package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js.map +1 -1
  91. package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.d.ts +1 -1
  92. package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js +8 -2
  93. package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js.map +1 -1
  94. package/dist/runtime/subsystems/jobs/job-run-service.protocol.d.ts +1 -1
  95. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.d.ts +1 -1
  96. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +5 -0
  97. package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js.map +1 -1
  98. package/dist/runtime/subsystems/jobs/job-worker.d.ts +1 -1
  99. package/dist/runtime/subsystems/jobs/job-worker.js +10 -4
  100. package/dist/runtime/subsystems/jobs/job-worker.js.map +1 -1
  101. package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +5 -2
  102. package/dist/runtime/subsystems/jobs/job-worker.module.js +13 -8
  103. package/dist/runtime/subsystems/jobs/job-worker.module.js.map +1 -1
  104. package/dist/runtime/subsystems/jobs/jobs-domain.module.js +11 -6
  105. package/dist/runtime/subsystems/jobs/jobs-domain.module.js.map +1 -1
  106. package/dist/runtime/subsystems/jobs/jobs-domain.tokens.d.ts +0 -11
  107. package/dist/runtime/subsystems/jobs/jobs-domain.tokens.js +8 -4
  108. package/dist/runtime/subsystems/jobs/jobs-domain.tokens.js.map +1 -1
  109. package/dist/runtime/subsystems/jobs/jobs-errors.d.ts +1 -1
  110. package/dist/runtime/subsystems/observability/index.d.ts +1 -1
  111. package/dist/runtime/subsystems/observability/index.js +9 -1
  112. package/dist/runtime/subsystems/observability/index.js.map +1 -1
  113. package/dist/runtime/subsystems/observability/observability.module.js +9 -1
  114. package/dist/runtime/subsystems/observability/observability.module.js.map +1 -1
  115. package/dist/runtime/subsystems/observability/observability.protocol.d.ts +1 -1
  116. package/dist/runtime/subsystems/observability/observability.service.d.ts +1 -1
  117. package/dist/runtime/subsystems/observability/observability.service.js +9 -1
  118. package/dist/runtime/subsystems/observability/observability.service.js.map +1 -1
  119. package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.d.ts +1 -1
  120. package/dist/runtime/subsystems/observability/reporters/index.d.ts +1 -1
  121. package/dist/runtime/subsystems/storage/index.js +5 -1
  122. package/dist/runtime/subsystems/storage/index.js.map +1 -1
  123. package/dist/runtime/subsystems/storage/storage.module.js +5 -1
  124. package/dist/runtime/subsystems/storage/storage.module.js.map +1 -1
  125. package/dist/runtime/subsystems/storage/storage.tokens.d.ts +0 -8
  126. package/dist/runtime/subsystems/storage/storage.tokens.js +5 -1
  127. package/dist/runtime/subsystems/storage/storage.tokens.js.map +1 -1
  128. package/dist/runtime/subsystems/token-key.d.ts +7 -0
  129. package/dist/runtime/subsystems/token-key.js +8 -0
  130. package/dist/runtime/subsystems/token-key.js.map +1 -0
  131. package/dist/src/cli/index.js +349 -233
  132. package/dist/src/cli/index.js.map +1 -1
  133. package/package.json +5 -1
  134. package/runtime/subsystems/analytics/analytics.tokens.ts +6 -2
  135. package/runtime/subsystems/auth/auth.tokens.ts +15 -8
  136. package/runtime/subsystems/cache/cache.tokens.ts +7 -2
  137. package/runtime/subsystems/events/events.tokens.ts +8 -1
  138. package/runtime/subsystems/index.ts +5 -1
  139. package/runtime/subsystems/jobs/bullmq.config.ts +5 -2
  140. package/runtime/subsystems/jobs/job-handler.base.ts +6 -1
  141. package/runtime/subsystems/jobs/job-worker.module.ts +5 -1
  142. package/runtime/subsystems/jobs/job-worker.ts +4 -1
  143. package/runtime/subsystems/jobs/jobs-domain.tokens.ts +10 -7
  144. package/runtime/subsystems/storage/storage.tokens.ts +6 -1
  145. package/runtime/subsystems/token-key.ts +7 -0
  146. package/src/config/runtime-mode.mjs +82 -0
  147. package/templates/entity/new/backend/modules/core/integration-source.ejs.t +3 -2
  148. package/templates/entity/new/clean-lite-ps/controller.ejs.t +1 -1
  149. package/templates/entity/new/clean-lite-ps/module.ejs.t +1 -1
  150. package/templates/entity/new/clean-lite-ps/prompt-extension.js +8 -2
  151. package/templates/entity/new/clean-lite-ps/repository.ejs.t +4 -4
  152. package/templates/entity/new/clean-lite-ps/service.ejs.t +4 -4
  153. package/templates/entity/new/prompt.js +49 -10
@@ -8105,163 +8105,34 @@ 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
- `;
8121
+ // src/cli/shared/runtime-import.ts
8122
+ var PACKAGE = "@pattern-stack/codegen";
8123
+ function resolveRuntimeMode(config) {
8124
+ return config?.runtime === "vendored" ? "vendored" : "package";
8167
8125
  }
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);
8126
+ function subsystemsImport(mode, subsystem) {
8127
+ if (mode === "vendored") {
8128
+ return subsystem ? `@shared/subsystems/${subsystem}` : "@shared/subsystems";
8186
8129
  }
8187
- return { sourceRoot, aliases };
8130
+ return `${PACKAGE}/subsystems`;
8188
8131
  }
8189
- function stripJsonComments(input) {
8190
- return input.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
8132
+ function runtimeImport(mode, relpath) {
8133
+ const clean = relpath.replace(/^\/+/, "");
8134
+ return mode === "vendored" ? `@shared/${clean}` : `${PACKAGE}/runtime/${clean}`;
8191
8135
  }
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);
8240
- }
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);
8247
- }
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)}`;
8254
- }
8255
-
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
8136
 
8266
8137
  // src/cli/shared/sink-emission-generator.ts
8267
8138
  var SCAFFOLD_SENTINEL = "// <CODEGEN-SCAFFOLD-V1>";
@@ -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,
@@ -8638,6 +8509,9 @@ var SURFACE_REGISTRY = {
8638
8509
  readPrimitive: true
8639
8510
  }
8640
8511
  };
8512
+ function isClientlessProvider(surfaces) {
8513
+ return surfaces.length > 0 && surfaces.every((s) => SURFACE_REGISTRY[s]?.readPrimitive === true);
8514
+ }
8641
8515
  var SCAFFOLD_SENTINEL2 = "// <CODEGEN-SCAFFOLD-V1>";
8642
8516
  function generatedBanner2(sourceDesc) {
8643
8517
  return `// @generated by @pattern-stack/codegen from ${sourceDesc} \u2014 DO NOT EDIT.
@@ -8692,7 +8566,7 @@ function serializeFilterArray(filters) {
8692
8566
  ${items.join("\n")}
8693
8567
  ]`;
8694
8568
  }
8695
- function buildReadPrimitiveEmission(providerSlug, providerPascal, surface, entities, entityDetection, clientExportName) {
8569
+ function buildReadPrimitiveEmission(providerSlug, providerPascal, surface, entities, entityDetection) {
8696
8570
  const canonicalTypes = [];
8697
8571
  const blocks = [];
8698
8572
  const entries = [];
@@ -8724,24 +8598,32 @@ export class ${className} extends IncrementalReadBase<${canonical}, ResolvedFilt
8724
8598
  // (e.g. Gmail \`q=\`); leave \`false\` to filter post-hydrate via \`matchesRecord\`.
8725
8599
  protected override readonly filterPushdown = false;${cursorOverride}
8726
8600
 
8727
- constructor(
8728
- private readonly auth: IAuthStrategy,
8729
- private readonly client: ${clientExportName},
8730
- ) {
8601
+ constructor(private readonly auth: IAuthStrategy) {
8731
8602
  super();
8732
8603
  }
8733
8604
 
8734
- /** 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
+ */
8735
8613
  protected async *enumerate(
8736
8614
  _mode: ReadMode,
8737
8615
  _filter?: ResolvedFilter[],
8738
8616
  _pageSize?: number,
8617
+ _ctx?: ReadContext,
8739
8618
  ): AsyncIterable<Ref[]> {
8740
8619
  throw new Error('not implemented: ${className}.enumerate');
8741
8620
  }
8742
8621
 
8743
- /** TODO: batched fetch-by-id \u2192 \`Map<id, raw>\` (\`mapConcurrent\`, or a vendor /batch). */
8744
- 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>> {
8745
8627
  throw new Error('not implemented: ${className}.hydrate');
8746
8628
  }
8747
8629
 
@@ -8756,15 +8638,16 @@ export class ${className} extends IncrementalReadBase<${canonical}, ResolvedFilt
8756
8638
  return ${constName};
8757
8639
  }
8758
8640
  }`);
8759
- entries.push(` ${entity}: new ${className}(this.auth, this.client),`);
8641
+ entries.push(` ${entity}: new ${className}(this.auth),`);
8760
8642
  }
8761
8643
  return { canonicalTypes, preamble: blocks.join("\n\n"), changeSourceEntries: entries };
8762
8644
  }
8763
- function generateAdapterScaffold(def, surface, entities, entityDetection) {
8645
+ function generateAdapterScaffold(def, surface, entities, entityDetection, mode = "package") {
8764
8646
  const spec = SURFACE_REGISTRY[surface];
8765
8647
  if (!spec) throw new Error(`no surface package for '${surface}'`);
8766
8648
  const n = names(def.slug, surface);
8767
8649
  const client = parseImportRef(def.client.class);
8650
+ const subsystemsSpec = subsystemsImport(mode, "integration");
8768
8651
  const entitiesLiteral = entities.length ? `[${entities.map((e) => `'${e}'`).join(", ")}]` : "[]";
8769
8652
  const readPrimitive = !!spec.readPrimitive && entities.length > 0;
8770
8653
  const rp = readPrimitive ? buildReadPrimitiveEmission(
@@ -8772,21 +8655,26 @@ function generateAdapterScaffold(def, surface, entities, entityDetection) {
8772
8655
  n.providerPascal,
8773
8656
  surface,
8774
8657
  entities,
8775
- entityDetection,
8776
- client.exportName
8658
+ entityDetection
8777
8659
  ) : null;
8778
8660
  const surfaceTypeImports = [
8779
8661
  spec.portType,
8780
8662
  ...spec.l2Ports.map((p) => p.type),
8781
8663
  spec.capabilitiesType,
8782
8664
  ...rp ? rp.canonicalTypes : []
8783
- ].map((t) => ` ${t},`).join("\n");
8784
- 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}';
8785
8667
  ` : "";
8786
8668
  const subsystemTypeImports = [
8787
8669
  "IAuthStrategy",
8788
8670
  "IChangeSource",
8789
- ...rp ? ["IntegrationSubscriptionView", "ReadMode", "Ref", "ResolvedFilter"] : []
8671
+ ...rp ? [
8672
+ "IntegrationSubscriptionView",
8673
+ "ReadContext",
8674
+ "ReadMode",
8675
+ "Ref",
8676
+ "ResolvedFilter"
8677
+ ] : []
8790
8678
  ].map((t) => ` ${t},`).join("\n");
8791
8679
  const changeSourcesAssign = rp ? `
8792
8680
  this.changeSources = {
@@ -8826,6 +8714,14 @@ ${rp.preamble}
8826
8714
  const l2Section = l2Members ? `
8827
8715
  ${l2Members}
8828
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}}`;
8829
8725
  return `${SCAFFOLD_SENTINEL2}
8830
8726
  // Scaffolded once by @pattern-stack/codegen, then author-owned. Re-running
8831
8727
  // codegen detects the sentinel above and SKIPS this file \u2014 your edits are safe.
@@ -8837,9 +8733,8 @@ ${surfaceTypeImports}
8837
8733
  import { ${spec.noCapsConst} } from '${spec.packageName}';
8838
8734
  ${subsystemValueImport}import type {
8839
8735
  ${subsystemTypeImports}
8840
- } from '@pattern-stack/codegen/subsystems';
8841
- import type { ${client.exportName} } from '${client.path}';
8842
- import { ${n.strategyToken}, ${n.clientToken} } from '../../../providers/${def.slug}/${def.slug}.provider.module';
8736
+ } from '${subsystemsSpec}';
8737
+ ${clientTypeImport}${providerTokenImport}
8843
8738
  ${preambleSection}
8844
8739
  @Injectable()
8845
8740
  export class ${n.adapterClass} implements ${spec.portType} {
@@ -8848,10 +8743,7 @@ export class ${n.adapterClass} implements ${spec.portType} {
8848
8743
  ${capabilityBody}
8849
8744
  };
8850
8745
 
8851
- constructor(
8852
- @Inject(${n.strategyToken}) readonly auth: IAuthStrategy,
8853
- @Inject(${n.clientToken}) private readonly client: ${client.exportName},
8854
- ) {${changeSourcesAssign}}
8746
+ ${ctorOpen}
8855
8747
  ${l2Section}
8856
8748
  ${changeSourcesDecl}
8857
8749
 
@@ -8883,10 +8775,10 @@ function generateAdaptersBarrel(surface, providerSlugs) {
8883
8775
  ${lines}
8884
8776
  `;
8885
8777
  }
8886
- function generateSurfaceTokens(surface) {
8778
+ function generateSurfaceTokens(surface, mode = "package") {
8887
8779
  const n = names("__placeholder__", surface);
8888
8780
  return `${generatedBanner2(`surface: ${surface}`)}
8889
- import type { IChangeSource } from '@pattern-stack/codegen/subsystems';
8781
+ import type { IChangeSource } from '${subsystemsImport(mode, "integration")}';
8890
8782
 
8891
8783
  /** The assembled list of every ${surface} adapter's contribution. */
8892
8784
  export const ${n.contributionsToken} = Symbol.for('@app/integrations/${surface}.adapter-contributions');
@@ -8903,7 +8795,7 @@ export interface AdapterContribution {
8903
8795
  }
8904
8796
  `;
8905
8797
  }
8906
- function generateSurfaceAggregator(surface, providerSlugs) {
8798
+ function generateSurfaceAggregator(surface, providerSlugs, mode = "package") {
8907
8799
  const n = names("__placeholder__", surface);
8908
8800
  const slugs = [...providerSlugs].sort();
8909
8801
  const per = slugs.map((slug) => names(slug, surface));
@@ -8930,7 +8822,7 @@ import {
8930
8822
  MemoryEntityChangeSourceRegistry,
8931
8823
  type IChangeSource,
8932
8824
  type IEntityChangeSourceRegistry,
8933
- } from '@pattern-stack/codegen/subsystems';
8825
+ } from '${subsystemsImport(mode, "integration")}';
8934
8826
  ${moduleImport}
8935
8827
  ${adapterImports}
8936
8828
  import {
@@ -9019,6 +8911,7 @@ function jsKey(key) {
9019
8911
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : `'${key}'`;
9020
8912
  }
9021
8913
  function emitAdapters(opts) {
8914
+ const mode = opts.mode ?? "package";
9022
8915
  const result = {
9023
8916
  written: [],
9024
8917
  scaffoldsWritten: [],
@@ -9049,14 +8942,14 @@ function emitAdapters(opts) {
9049
8942
  }
9050
8943
  const defBySlug = new Map(opts.providers.map((p) => [p.definition.slug, p.definition]));
9051
8944
  for (const [surface, slugs] of bySurface) {
9052
- const surfaceDir = join12(opts.outputRoot, surface);
9053
- const adaptersDir = join12(surfaceDir, "adapters");
8945
+ const surfaceDir = join11(opts.outputRoot, surface);
8946
+ const adaptersDir = join11(surfaceDir, "adapters");
9054
8947
  for (const slug of slugs) {
9055
8948
  const def = defBySlug.get(slug);
9056
- const providerDir = join12(adaptersDir, slug);
9057
- const scaffoldPath = join12(providerDir, `${slug}-${surface}.adapter.ts`);
9058
- const modulePath = join12(providerDir, `${slug}-${surface}.adapter.module.ts`);
9059
- 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)) {
9060
8953
  result.scaffoldsSkipped.push(scaffoldPath);
9061
8954
  } else {
9062
8955
  const surfaceEntityNames = entitiesBySurface.get(surface) ?? [];
@@ -9069,27 +8962,28 @@ function emitAdapters(opts) {
9069
8962
  def,
9070
8963
  surface,
9071
8964
  surfaceEntityNames,
9072
- entityDetection
8965
+ entityDetection,
8966
+ mode
9073
8967
  );
9074
8968
  if (!opts.dryRun) writeFile(scaffoldPath, content);
9075
8969
  result.scaffoldsWritten.push(scaffoldPath);
9076
8970
  }
9077
8971
  const moduleContent = generateAdapterModule(def, surface);
9078
- if (!opts.dryRun) writeIfChanged2(modulePath, moduleContent);
8972
+ if (!opts.dryRun) writeIfChanged(modulePath, moduleContent);
9079
8973
  result.written.push(modulePath);
9080
8974
  }
9081
- const barrelPath = join12(adaptersDir, "index.ts");
9082
- const tokensPath = join12(surfaceDir, `${surface}-adapters.tokens.ts`);
9083
- const aggregatorPath = join12(surfaceDir, `${surface}-adapters.module.ts`);
9084
- 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");
9085
8979
  const files = [
9086
8980
  [barrelPath, generateAdaptersBarrel(surface, slugs)],
9087
- [tokensPath, generateSurfaceTokens(surface)],
9088
- [aggregatorPath, generateSurfaceAggregator(surface, slugs)],
8981
+ [tokensPath, generateSurfaceTokens(surface, mode)],
8982
+ [aggregatorPath, generateSurfaceAggregator(surface, slugs, mode)],
9089
8983
  [typedViewPath, generateTypedView(surface, slugs, entitiesBySurface.get(surface) ?? [])]
9090
8984
  ];
9091
8985
  for (const [path34, content] of files) {
9092
- if (!opts.dryRun) writeIfChanged2(path34, content);
8986
+ if (!opts.dryRun) writeIfChanged(path34, content);
9093
8987
  result.written.push(path34);
9094
8988
  }
9095
8989
  if (opts.backendSrcAbs) {
@@ -9097,8 +8991,8 @@ function emitAdapters(opts) {
9097
8991
  const surfaceEntities = entitiesBySurface.get(surface) ?? [];
9098
8992
  const tokenEntries = [];
9099
8993
  const assemblyEntries = [];
9100
- const sinksDir = join12(surfaceDir, "sinks");
9101
- const modulesDir = join12(surfaceDir, "modules");
8994
+ const sinksDir = join11(surfaceDir, "sinks");
8995
+ const modulesDir = join11(surfaceDir, "modules");
9102
8996
  for (const entityName of surfaceEntities) {
9103
8997
  const def = entityByName.get(entityName);
9104
8998
  const pattern = def?.entity.pattern ?? (Array.isArray(def?.entity.patterns) ? def?.entity.patterns?.[0] : void 0);
@@ -9123,17 +9017,17 @@ function emitAdapters(opts) {
9123
9017
  backendSrcAbs: opts.backendSrcAbs,
9124
9018
  aliases
9125
9019
  });
9126
- const sinkPath = join12(sinksDir, `${entityName}.sink.ts`);
9127
- if (existsSync10(sinkPath)) {
9020
+ const sinkPath = join11(sinksDir, `${entityName}.sink.ts`);
9021
+ if (existsSync9(sinkPath)) {
9128
9022
  result.scaffoldsSkipped.push(sinkPath);
9129
9023
  } else {
9130
9024
  const sinkInput = buildSinkInput(def, surface, slugs[0], loc.repoImportSpecifier);
9131
- const sinkContent = generateDefaultSink(sinkInput);
9025
+ const sinkContent = generateDefaultSink({ ...sinkInput, mode });
9132
9026
  if (!opts.dryRun) writeFile(sinkPath, sinkContent);
9133
9027
  result.scaffoldsWritten.push(sinkPath);
9134
9028
  }
9135
9029
  for (const slug of slugs) {
9136
- const assemblyPath = join12(
9030
+ const assemblyPath = join11(
9137
9031
  modulesDir,
9138
9032
  slug,
9139
9033
  `${entityName}-integration.module.ts`
@@ -9147,23 +9041,24 @@ function emitAdapters(opts) {
9147
9041
  moduleClass: loc.moduleClass,
9148
9042
  repoImportSpecifier: loc.repoImportSpecifier,
9149
9043
  repoClass: loc.repoClass,
9150
- sourceDesc: `definitions/providers/${slug}.yaml`
9044
+ sourceDesc: `definitions/providers/${slug}.yaml`,
9045
+ mode
9151
9046
  });
9152
- if (!opts.dryRun) writeIfChanged2(assemblyPath, assemblyContent);
9047
+ if (!opts.dryRun) writeIfChanged(assemblyPath, assemblyContent);
9153
9048
  result.assembliesWritten.push(assemblyPath);
9154
9049
  tokenEntries.push({ entityName, entityClass: loc.entityClass, provider: slug });
9155
9050
  assemblyEntries.push({ entityName, provider: slug });
9156
9051
  }
9157
9052
  }
9158
- const integrationTokensPath = join12(
9053
+ const integrationTokensPath = join11(
9159
9054
  surfaceDir,
9160
9055
  `${surface}-integration.tokens.ts`
9161
9056
  );
9162
9057
  const tokensContent = generateIntegrationTokens(surface, tokenEntries);
9163
- if (!opts.dryRun) writeIfChanged2(integrationTokensPath, tokensContent);
9058
+ if (!opts.dryRun) writeIfChanged(integrationTokensPath, tokensContent);
9164
9059
  result.tokensWritten.push(integrationTokensPath);
9165
9060
  if (assemblyEntries.length > 0) {
9166
- const integrationAggregatorPath = join12(
9061
+ const integrationAggregatorPath = join11(
9167
9062
  surfaceDir,
9168
9063
  `${surface}-integration.module.ts`
9169
9064
  );
@@ -9171,7 +9066,7 @@ function emitAdapters(opts) {
9171
9066
  surface,
9172
9067
  assemblyEntries
9173
9068
  );
9174
- if (!opts.dryRun) writeIfChanged2(integrationAggregatorPath, aggregatorContent);
9069
+ if (!opts.dryRun) writeIfChanged(integrationAggregatorPath, aggregatorContent);
9175
9070
  result.integrationAggregatorsWritten.push(integrationAggregatorPath);
9176
9071
  }
9177
9072
  }
@@ -9228,16 +9123,212 @@ function pascalFromSnake(s) {
9228
9123
  return camel.charAt(0).toUpperCase() + camel.slice(1);
9229
9124
  }
9230
9125
  function writeFile(outPath, content) {
9231
- mkdirSync3(dirname2(outPath), { recursive: true });
9232
- writeFileSync3(outPath, content);
9126
+ mkdirSync2(dirname(outPath), { recursive: true });
9127
+ writeFileSync2(outPath, content);
9233
9128
  }
9234
- function writeIfChanged2(outPath, content) {
9235
- 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) {
9236
9131
  return;
9237
9132
  }
9238
9133
  writeFile(outPath, content);
9239
9134
  }
9240
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
+
9241
9332
  // src/cli/shared/events-path.ts
9242
9333
  import path12 from "path";
9243
9334
  var FALLBACK = "events";
@@ -9517,6 +9608,7 @@ var EntityNewCommand = class extends Command2 {
9517
9608
  "bridge/generated"
9518
9609
  );
9519
9610
  const backendSrcForHandlers = ctx.config?.paths?.backend_src ?? "src";
9611
+ const runtimeMode = resolveRuntimeMode(ctx.config);
9520
9612
  const bridgeHandlersDir = path13.resolve(
9521
9613
  ctx.cwd,
9522
9614
  backendSrcForHandlers,
@@ -9803,7 +9895,8 @@ var EntityNewCommand = class extends Command2 {
9803
9895
  entitySurfaces,
9804
9896
  sourceRoot: tsAliases?.sourceRoot,
9805
9897
  aliases: tsAliases?.aliases,
9806
- skipImportCheck: tsAliases === null
9898
+ skipImportCheck: tsAliases === null,
9899
+ mode: runtimeMode
9807
9900
  });
9808
9901
  if (!providerResult.skipped && !isJsonMode()) {
9809
9902
  for (const issue of providerResult.issues) {
@@ -9847,7 +9940,8 @@ var EntityNewCommand = class extends Command2 {
9847
9940
  entities: entityDefs,
9848
9941
  outputRoot: adapterOutputRoot,
9849
9942
  backendSrcAbs: path13.resolve(ctx.cwd, backendSrcForHandlers),
9850
- aliases: assemblyTsAliases?.aliases ?? {}
9943
+ aliases: assemblyTsAliases?.aliases ?? {},
9944
+ mode: runtimeMode
9851
9945
  });
9852
9946
  if (!isJsonMode()) {
9853
9947
  if (adapterResult.written.length || adapterResult.scaffoldsWritten.length) {
@@ -11920,12 +12014,13 @@ var VENDORED_RUNTIME_FILES = [
11920
12014
  },
11921
12015
  { runtime: "shared/openapi/index.ts", target: "src/shared/openapi/index.ts" }
11922
12016
  ];
11923
- function databaseModuleContent() {
12017
+ function databaseModuleContent(mode) {
12018
+ const drizzleTokenImport = mode === "vendored" ? "../constants/tokens" : runtimeImport(mode, "constants/tokens");
11924
12019
  return `import { Module, Global } from '@nestjs/common';
11925
12020
  import { drizzle } from 'drizzle-orm/node-postgres';
11926
12021
  import { Pool } from 'pg';
11927
12022
  import * as schema from '../../schema';
11928
- import { DRIZZLE } from '../constants/tokens';
12023
+ import { DRIZZLE } from '${drizzleTokenImport}';
11929
12024
 
11930
12025
  export { DRIZZLE };
11931
12026
  export type DrizzleDB = ReturnType<typeof drizzle<typeof schema>>;
@@ -11952,11 +12047,12 @@ export type DrizzleDB = ReturnType<typeof drizzle<typeof schema>>;
11952
12047
  export class DatabaseModule {}
11953
12048
  `;
11954
12049
  }
11955
- function appModuleContent() {
12050
+ function appModuleContent(mode) {
12051
+ const openApiImport = mode === "vendored" ? "./shared/openapi" : runtimeImport(mode, "shared/openapi");
11956
12052
  return `import { Global, Module } from '@nestjs/common';
11957
12053
  import { DatabaseModule } from './shared/database/database.module';
11958
12054
  import { GENERATED_MODULES } from './generated/modules';
11959
- import { OPENAPI_REGISTRY, OpenApiRegistry } from './shared/openapi';
12055
+ import { OPENAPI_REGISTRY, OpenApiRegistry } from '${openApiImport}';
11960
12056
 
11961
12057
  /**
11962
12058
  * OpenApiModule \u2014 @Global() wrapper around the OPENAPI_REGISTRY singleton.
@@ -11998,7 +12094,8 @@ class OpenApiModule {}
11998
12094
  export class AppModule {}
11999
12095
  `;
12000
12096
  }
12001
- function mainTsContent() {
12097
+ function mainTsContent(mode) {
12098
+ const openApiImport = mode === "vendored" ? "./shared/openapi" : runtimeImport(mode, "shared/openapi");
12002
12099
  return `import 'reflect-metadata';
12003
12100
  import fs from 'node:fs';
12004
12101
  import path from 'node:path';
@@ -12006,7 +12103,7 @@ import { NestFactory } from '@nestjs/core';
12006
12103
  import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
12007
12104
  import { parse as parseYaml } from 'yaml';
12008
12105
  import { AppModule } from './app.module';
12009
- import { OPENAPI_REGISTRY, OpenApiRegistry } from './shared/openapi';
12106
+ import { OPENAPI_REGISTRY, OpenApiRegistry } from '${openApiImport}';
12010
12107
 
12011
12108
  interface OpenApiConfig {
12012
12109
  enabled?: boolean;
@@ -12315,6 +12412,7 @@ function dirEntry(cwd, absPath) {
12315
12412
  async function buildInitPlan(ctx, options) {
12316
12413
  const cwd = options.cwd;
12317
12414
  const force = Boolean(options.force);
12415
+ const runtimeMode = options.runtimeMode === "vendored" ? "vendored" : "package";
12318
12416
  let framework = "nestjs";
12319
12417
  let orm = "drizzle";
12320
12418
  let architecture = "clean-lite-ps";
@@ -12337,6 +12435,11 @@ async function buildInitPlan(ctx, options) {
12337
12435
  {
12338
12436
  const configPath = path23.join(cwd, "codegen.config.yaml");
12339
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,
12340
12443
  paths: {
12341
12444
  backend_src: "src",
12342
12445
  entities_dir: "entities",
@@ -12413,14 +12516,16 @@ async function buildInitPlan(ctx, options) {
12413
12516
  fileEntry(
12414
12517
  cwd,
12415
12518
  path23.join(cwd, "src", "shared", "database", "database.module.ts"),
12416
- databaseModuleContent(),
12519
+ databaseModuleContent(runtimeMode),
12417
12520
  { force }
12418
12521
  )
12419
12522
  );
12420
- for (const v of VENDORED_RUNTIME_FILES) {
12421
- entries.push(
12422
- fileEntry(cwd, path23.join(cwd, v.target), loadRuntimeFile(v.runtime), { force })
12423
- );
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
+ }
12424
12529
  }
12425
12530
  entries.push(
12426
12531
  fileEntry(
@@ -12445,7 +12550,7 @@ async function buildInitPlan(ctx, options) {
12445
12550
  path: appModulePath,
12446
12551
  relPath: relOf(cwd, appModulePath),
12447
12552
  action: "create",
12448
- content: appModuleContent()
12553
+ content: appModuleContent(runtimeMode)
12449
12554
  });
12450
12555
  } else {
12451
12556
  entries.push({
@@ -12463,7 +12568,7 @@ async function buildInitPlan(ctx, options) {
12463
12568
  path: mainPath,
12464
12569
  relPath: relOf(cwd, mainPath),
12465
12570
  action: "create",
12466
- content: mainTsContent()
12571
+ content: mainTsContent(runtimeMode)
12467
12572
  });
12468
12573
  } else {
12469
12574
  entries.push({
@@ -13606,7 +13711,8 @@ var ProjectInitCommand = class extends Command7 {
13606
13711
  static usage = Command7.Usage({
13607
13712
  description: "Scaffold a consumer project (config, shims, barrels, app.module)",
13608
13713
  examples: [
13609
- ["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"],
13610
13716
  ["Preview without writing", "codegen project init --dry-run"],
13611
13717
  ["Create tsconfig if missing", "codegen project init --yes --with-tsconfig"],
13612
13718
  ["Overwrite existing shims", "codegen project init --force"]
@@ -13616,6 +13722,9 @@ var ProjectInitCommand = class extends Command7 {
13616
13722
  dryRun = Option7.Boolean("--dry-run", false);
13617
13723
  force = Option7.Boolean("--force", false);
13618
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");
13619
13728
  // Vendor consumer skills into .claude/skills by default; opt out with --no-skills.
13620
13729
  skills = Option7.Boolean("--skills", true);
13621
13730
  json = Option7.Boolean("--json", false);
@@ -13627,11 +13736,18 @@ var ProjectInitCommand = class extends Command7 {
13627
13736
  json: this.json,
13628
13737
  skipDetection: false
13629
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
+ }
13630
13745
  const plan = await buildInitPlan(ctx, {
13631
13746
  cwd: ctx.cwd,
13632
13747
  force: this.force,
13633
13748
  withTsconfig: this.withTsconfig,
13634
- skipScan: false
13749
+ skipScan: false,
13750
+ runtimeMode
13635
13751
  });
13636
13752
  if (this.force && !isJsonMode()) {
13637
13753
  printWarning("--force: existing scaffold files will be overwritten.");