@apollo-deploy/tesseract 1.8.0 → 2.0.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 (194) hide show
  1. package/README.md +218 -110
  2. package/dist/adapters/csharp/index.d.ts +5 -8
  3. package/dist/adapters/csharp/index.d.ts.map +1 -1
  4. package/dist/adapters/csharp/index.js +314 -74
  5. package/dist/adapters/csharp/index.js.map +1 -1
  6. package/dist/adapters/documentation.d.ts +17 -0
  7. package/dist/adapters/documentation.d.ts.map +1 -0
  8. package/dist/adapters/documentation.js +268 -0
  9. package/dist/adapters/documentation.js.map +1 -0
  10. package/dist/adapters/go/index.d.ts +5 -8
  11. package/dist/adapters/go/index.d.ts.map +1 -1
  12. package/dist/adapters/go/index.js +197 -101
  13. package/dist/adapters/go/index.js.map +1 -1
  14. package/dist/adapters/kotlin/index.d.ts +5 -9
  15. package/dist/adapters/kotlin/index.d.ts.map +1 -1
  16. package/dist/adapters/kotlin/index.js +280 -212
  17. package/dist/adapters/kotlin/index.js.map +1 -1
  18. package/dist/adapters/php/index.d.ts +5 -15
  19. package/dist/adapters/php/index.d.ts.map +1 -1
  20. package/dist/adapters/php/index.js +362 -90
  21. package/dist/adapters/php/index.js.map +1 -1
  22. package/dist/adapters/python/index.d.ts +5 -8
  23. package/dist/adapters/python/index.d.ts.map +1 -1
  24. package/dist/adapters/python/index.js +240 -109
  25. package/dist/adapters/python/index.js.map +1 -1
  26. package/dist/adapters/ruby/index.d.ts +3 -3
  27. package/dist/adapters/ruby/index.d.ts.map +1 -1
  28. package/dist/adapters/ruby/index.js +235 -46
  29. package/dist/adapters/ruby/index.js.map +1 -1
  30. package/dist/adapters/rust/index.d.ts +5 -9
  31. package/dist/adapters/rust/index.d.ts.map +1 -1
  32. package/dist/adapters/rust/index.js +237 -169
  33. package/dist/adapters/rust/index.js.map +1 -1
  34. package/dist/adapters/shared.d.ts +7 -0
  35. package/dist/adapters/shared.d.ts.map +1 -0
  36. package/dist/adapters/shared.js +68 -0
  37. package/dist/adapters/shared.js.map +1 -0
  38. package/dist/adapters/type-utils.d.ts +13 -0
  39. package/dist/adapters/type-utils.d.ts.map +1 -0
  40. package/dist/adapters/type-utils.js +105 -0
  41. package/dist/adapters/type-utils.js.map +1 -0
  42. package/dist/adapters/types.d.ts.map +1 -1
  43. package/dist/adapters/typescript/emitter/emitSchema.d.ts +2 -2
  44. package/dist/adapters/typescript/emitter/emitSchema.js +39 -27
  45. package/dist/adapters/typescript/emitter/emitSchema.js.map +1 -1
  46. package/dist/adapters/typescript/emitter/emitTypeScriptModels.d.ts +2 -2
  47. package/dist/adapters/typescript/emitter/emitTypeScriptModels.js +15 -15
  48. package/dist/adapters/typescript/emitter/importCollector.d.ts +2 -4
  49. package/dist/adapters/typescript/emitter/importCollector.d.ts.map +1 -1
  50. package/dist/adapters/typescript/emitter/importCollector.js +40 -50
  51. package/dist/adapters/typescript/emitter/importCollector.js.map +1 -1
  52. package/dist/adapters/typescript/emitter/parsers.d.ts +1 -1
  53. package/dist/adapters/typescript/emitter/parsers.js +13 -13
  54. package/dist/adapters/typescript/emitter/typeHoister.d.ts +1 -1
  55. package/dist/adapters/typescript/emitter/typeHoister.d.ts.map +1 -1
  56. package/dist/adapters/typescript/emitter/typeHoister.js +12 -20
  57. package/dist/adapters/typescript/emitter/typeHoister.js.map +1 -1
  58. package/dist/adapters/typescript/index.d.ts +3 -3
  59. package/dist/adapters/typescript/index.d.ts.map +1 -1
  60. package/dist/adapters/typescript/index.js +148 -166
  61. package/dist/adapters/typescript/index.js.map +1 -1
  62. package/dist/adapters/typescript/shared.d.ts +2 -2
  63. package/dist/adapters/typescript/shared.js +12 -12
  64. package/dist/cli.js +50 -37
  65. package/dist/cli.js.map +1 -1
  66. package/dist/collector.d.ts +77 -3
  67. package/dist/collector.d.ts.map +1 -1
  68. package/dist/collector.js +198 -20
  69. package/dist/collector.js.map +1 -1
  70. package/dist/elysia.js +2 -2
  71. package/dist/elysia.js.map +1 -1
  72. package/dist/express.d.ts.map +1 -1
  73. package/dist/express.js.map +1 -1
  74. package/dist/fastify.d.ts +8 -9
  75. package/dist/fastify.d.ts.map +1 -1
  76. package/dist/fastify.js +105 -164
  77. package/dist/fastify.js.map +1 -1
  78. package/dist/helpers/handlebars.d.ts +7 -16
  79. package/dist/helpers/handlebars.d.ts.map +1 -1
  80. package/dist/helpers/handlebars.js +127 -177
  81. package/dist/helpers/handlebars.js.map +1 -1
  82. package/dist/hono.d.ts.map +1 -1
  83. package/dist/hono.js.map +1 -1
  84. package/dist/index.d.ts +14 -12
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +32 -30
  87. package/dist/index.js.map +1 -1
  88. package/dist/koa.d.ts.map +1 -1
  89. package/dist/koa.js.map +1 -1
  90. package/dist/nestjs.d.ts.map +1 -1
  91. package/dist/nestjs.js +41 -14
  92. package/dist/nestjs.js.map +1 -1
  93. package/dist/pipeline/enrich.d.ts +2 -13
  94. package/dist/pipeline/enrich.d.ts.map +1 -1
  95. package/dist/pipeline/enrich.js +157 -212
  96. package/dist/pipeline/enrich.js.map +1 -1
  97. package/dist/pipeline/intake.d.ts +3 -3
  98. package/dist/pipeline/intake.d.ts.map +1 -1
  99. package/dist/pipeline/intake.js +342 -238
  100. package/dist/pipeline/intake.js.map +1 -1
  101. package/dist/pipeline/write.d.ts +1 -14
  102. package/dist/pipeline/write.d.ts.map +1 -1
  103. package/dist/pipeline/write.js +73 -113
  104. package/dist/pipeline/write.js.map +1 -1
  105. package/dist/types/config.d.ts +14 -26
  106. package/dist/types/config.d.ts.map +1 -1
  107. package/dist/types/config.js +16 -12
  108. package/dist/types/config.js.map +1 -1
  109. package/dist/types/ir.d.ts +12 -8
  110. package/dist/types/ir.d.ts.map +1 -1
  111. package/dist/types/manifest.d.ts +10 -11
  112. package/dist/types/manifest.d.ts.map +1 -1
  113. package/dist/types/manifest.js +54 -14
  114. package/dist/types/manifest.js.map +1 -1
  115. package/dist/types/sdk-module.d.ts +2 -2
  116. package/dist/types/sdk-module.js +1 -1
  117. package/dist/utils/format.d.ts +1 -3
  118. package/dist/utils/format.d.ts.map +1 -1
  119. package/dist/utils/format.js +3 -10
  120. package/dist/utils/format.js.map +1 -1
  121. package/dist/utils/naming.d.ts.map +1 -1
  122. package/dist/utils/naming.js +174 -184
  123. package/dist/utils/naming.js.map +1 -1
  124. package/dist/utils/npm-token.d.ts +1 -17
  125. package/dist/utils/npm-token.d.ts.map +1 -1
  126. package/dist/utils/npm-token.js +27 -76
  127. package/dist/utils/npm-token.js.map +1 -1
  128. package/dist/utils/version.d.ts +14 -0
  129. package/dist/utils/version.d.ts.map +1 -0
  130. package/dist/utils/version.js +60 -0
  131. package/dist/utils/version.js.map +1 -0
  132. package/package.json +4 -3
  133. package/templates/csharp/client.hbs +26 -49
  134. package/templates/csharp/csproj.hbs +7 -0
  135. package/templates/csharp/domain.hbs +48 -130
  136. package/templates/csharp/errors.hbs +17 -25
  137. package/templates/csharp/readme.hbs +31 -44
  138. package/templates/csharp/transport.hbs +238 -136
  139. package/templates/csharp/types.hbs +30 -76
  140. package/templates/go/client.hbs +44 -109
  141. package/templates/go/domain.hbs +83 -25
  142. package/templates/go/go-mod.hbs +1 -4
  143. package/templates/go/readme.hbs +32 -29
  144. package/templates/go/transport.hbs +174 -173
  145. package/templates/go/types.hbs +17 -53
  146. package/templates/go/utils.hbs +3 -2
  147. package/templates/kotlin/build-gradle.hbs +1 -1
  148. package/templates/kotlin/client.hbs +18 -15
  149. package/templates/kotlin/domain.hbs +54 -51
  150. package/templates/kotlin/errors.hbs +1 -1
  151. package/templates/kotlin/readme.hbs +35 -137
  152. package/templates/kotlin/transport.hbs +140 -123
  153. package/templates/kotlin/types.hbs +30 -81
  154. package/templates/php/client.hbs +8 -46
  155. package/templates/php/composer.hbs +2 -1
  156. package/templates/php/domain.hbs +86 -117
  157. package/templates/php/errors.hbs +1 -1
  158. package/templates/php/readme.hbs +42 -49
  159. package/templates/php/transport.hbs +192 -145
  160. package/templates/php/types.hbs +63 -60
  161. package/templates/python/client.hbs +15 -2
  162. package/templates/python/domain.hbs +50 -108
  163. package/templates/python/pyproject.hbs +5 -0
  164. package/templates/python/readme.hbs +47 -30
  165. package/templates/python/resources-init.hbs +1 -1
  166. package/templates/python/transport.hbs +167 -53
  167. package/templates/python/types.hbs +22 -58
  168. package/templates/ruby/client.hbs +10 -6
  169. package/templates/ruby/domain.hbs +48 -67
  170. package/templates/ruby/errors.hbs +3 -3
  171. package/templates/ruby/gemspec.hbs +3 -10
  172. package/templates/ruby/index.hbs +3 -3
  173. package/templates/ruby/readme.hbs +33 -70
  174. package/templates/ruby/transport.hbs +129 -103
  175. package/templates/ruby/types.hbs +11 -16
  176. package/templates/ruby/version.hbs +1 -1
  177. package/templates/rust/cargo.hbs +2 -0
  178. package/templates/rust/client.hbs +10 -1
  179. package/templates/rust/domain.hbs +69 -52
  180. package/templates/rust/error.hbs +3 -1
  181. package/templates/rust/lib.hbs +4 -5
  182. package/templates/rust/readme.hbs +33 -46
  183. package/templates/rust/transport.hbs +170 -159
  184. package/templates/rust/types.hbs +34 -111
  185. package/templates/typescript/domain-class.hbs +14 -6
  186. package/templates/typescript/domain.hbs +13 -5
  187. package/templates/typescript/package-json.hbs +3 -1
  188. package/templates/typescript/readme.hbs +42 -42
  189. package/templates/typescript/transport.hbs +46 -8
  190. package/templates/typescript/types-errors.hbs +1 -1
  191. package/dist/adapters/typescript/model-emitter.d.ts +0 -13
  192. package/dist/adapters/typescript/model-emitter.d.ts.map +0 -1
  193. package/dist/adapters/typescript/model-emitter.js +0 -415
  194. package/dist/adapters/typescript/model-emitter.js.map +0 -1
package/dist/cli.js CHANGED
@@ -2,19 +2,19 @@
2
2
  /**
3
3
  * Tesseract CLI — manifest-first SDK generator (refactored, scalable).
4
4
  */
5
- import { Command } from "commander";
6
- import { readFileSync } from "node:fs";
7
- import { resolve, join, dirname } from "node:path";
8
- import { fileURLToPath } from "node:url";
9
- import { spawnSync } from "node:child_process";
10
- import { generate } from "./index.js";
5
+ import { Command } from 'commander';
6
+ import { readFileSync } from 'node:fs';
7
+ import { resolve, join, dirname } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { spawnSync } from 'node:child_process';
10
+ import { generate } from './index.js';
11
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
12
  /**
13
13
  * Package metadata loader (isolated for testability + reuse)
14
14
  */
15
15
  function loadPackageVersion() {
16
- const pkgPath = join(__dirname, "..", "package.json");
17
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
16
+ const pkgPath = join(__dirname, '..', 'package.json');
17
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
18
18
  return pkg.version;
19
19
  }
20
20
  /**
@@ -24,9 +24,10 @@ function buildConfig(opts) {
24
24
  return {
25
25
  input: resolve(opts.input),
26
26
  output: resolve(opts.output),
27
- language: opts.language ?? "typescript",
27
+ language: opts.language ?? 'typescript',
28
28
  packageName: opts.name,
29
29
  packageVersion: opts.packageVersion,
30
+ versionBump: opts.versionBump,
30
31
  npmToken: opts.npmToken,
31
32
  clientName: opts.clientName,
32
33
  baseUrl: opts.baseUrl,
@@ -42,12 +43,12 @@ function buildConfig(opts) {
42
43
  function printWarnings(warnings) {
43
44
  if (!warnings.length)
44
45
  return;
45
- console.warn("\nWarnings:");
46
+ console.warn('\nWarnings:');
46
47
  for (const w of warnings) {
47
48
  console.warn(` ⚠ ${w}`);
48
49
  }
49
50
  }
50
- function printFileList(files, prefix = " - ") {
51
+ function printFileList(files, prefix = ' - ') {
51
52
  for (const file of files) {
52
53
  console.log(`${prefix}${file}`);
53
54
  }
@@ -58,7 +59,7 @@ function printFileList(files, prefix = " - ") {
58
59
  function handleResult(opts, result) {
59
60
  printWarnings(result.warnings);
60
61
  switch (result.mode) {
61
- case "check":
62
+ case 'check':
62
63
  if (result.hasChanges) {
63
64
  console.error(`\n✗ Generated output is out of date: ${result.filesWritten} files would change`);
64
65
  printFileList(result.changedFiles);
@@ -66,7 +67,7 @@ function handleResult(opts, result) {
66
67
  }
67
68
  console.log(`\n✓ Generated output is up to date → ${opts.output}`);
68
69
  return;
69
- case "dry-run":
70
+ case 'dry-run':
70
71
  console.log(`\n✓ Dry run complete: ${result.filesWritten} files would change → ${opts.output}`);
71
72
  if (result.changedFiles.length) {
72
73
  printFileList(result.changedFiles);
@@ -74,12 +75,18 @@ function handleResult(opts, result) {
74
75
  if (result.filesSkipped > 0) {
75
76
  console.log(` ${result.filesSkipped} files unchanged`);
76
77
  }
78
+ if (result.filesDeleted > 0) {
79
+ console.log(` ${result.filesDeleted} stale files would be removed`);
80
+ }
77
81
  return;
78
82
  default:
79
83
  console.log(`\n✓ Generated ${result.filesWritten} files → ${opts.output}`);
80
84
  if (result.filesSkipped > 0) {
81
85
  console.log(` ${result.filesSkipped} files unchanged (skipped)`);
82
86
  }
87
+ if (result.filesDeleted > 0) {
88
+ console.log(` ${result.filesDeleted} stale files removed`);
89
+ }
83
90
  }
84
91
  }
85
92
  /**
@@ -87,7 +94,12 @@ function handleResult(opts, result) {
87
94
  */
88
95
  function validateFlags(opts) {
89
96
  if (opts.dryRun && opts.check) {
90
- console.error("\n✗ --dry-run and --check are mutually exclusive");
97
+ console.error('\n✗ --dry-run and --check are mutually exclusive');
98
+ process.exit(1);
99
+ }
100
+ if (opts.versionBump &&
101
+ !['patch', 'minor', 'major'].includes(opts.versionBump)) {
102
+ console.error('\n✗ --version-bump must be patch, minor, or major');
91
103
  process.exit(1);
92
104
  }
93
105
  }
@@ -113,8 +125,8 @@ async function handleGenerate(opts) {
113
125
  function handleRun(appPath) {
114
126
  const resolved = resolve(appPath);
115
127
  const result = spawnSync(process.execPath, [resolved], {
116
- env: { ...process.env, TESSERACT_GENERATE: "1" },
117
- stdio: "inherit",
128
+ env: { ...process.env, TESSERACT_GENERATE: '1' },
129
+ stdio: 'inherit',
118
130
  });
119
131
  process.exit(result.status ?? 0);
120
132
  }
@@ -125,32 +137,33 @@ function createCLI() {
125
137
  const program = new Command();
126
138
  const version = loadPackageVersion();
127
139
  program
128
- .name("tesseract")
129
- .description("Manifest-first SDK generator — turns sdk-manifold/v1 manifests into production-ready TypeScript SDKs")
140
+ .name('tesseract')
141
+ .description('Manifest-first SDK generator — turns sdk-manifold/v1 manifests into production-ready TypeScript SDKs')
130
142
  .version(version);
131
143
  program
132
- .command("generate")
133
- .description("Generate an SDK from an sdk-manifold/v1 manifest file")
134
- .requiredOption("-i, --input <path>", "Path to the sdk-manifold/v1 manifest JSON file")
135
- .requiredOption("-o, --output <dir>", "Output directory for the generated SDK")
136
- .option("-l, --language <lang>", "Target language: typescript, python, ruby, php, go, rust, kotlin, csharp")
137
- .option("-n, --name <name>", "Override the SDK package name")
138
- .option("--package-version <version>", "Override the generated package version")
139
- .option("--client-name <name>", "Override the client class name")
140
- .option("--base-url <url>", "Override the base URL")
141
- .option("--dry-run", "Preview output without writing files")
142
- .option("--check", "Exit non-zero if generated output is out of date")
143
- .option("--sdk-style <style>", 'SDK style: functional (default) or class (Resend-style: new MySDK("key"))')
144
- .option("--client-type <type>", "Client type: internal (full options, default) or public (auth key only, baseUrl baked in)")
145
- .option("--npm-token <token>", "NPM auth token for resolving private package versions (defaults to NPM_TOKEN env var)")
144
+ .command('generate')
145
+ .description('Generate an SDK from an sdk-manifold/v1 manifest file')
146
+ .requiredOption('-i, --input <path>', 'Path to the sdk-manifold/v1 manifest JSON file')
147
+ .requiredOption('-o, --output <dir>', 'Output directory for the generated SDK')
148
+ .option('-l, --language <lang>', 'Target language: typescript, python, ruby, php, go, rust, kotlin, csharp')
149
+ .option('-n, --name <name>', 'Override the SDK package name')
150
+ .option('--package-version <version>', 'Override the generated package version')
151
+ .option('--version-bump <type>', 'Version bump when package version is resolved: patch, minor, or major')
152
+ .option('--client-name <name>', 'Override the client class name')
153
+ .option('--base-url <url>', 'Override the base URL')
154
+ .option('--dry-run', 'Preview output without writing files')
155
+ .option('--check', 'Exit non-zero if generated output is out of date')
156
+ .option('--sdk-style <style>', 'SDK style: functional (default) or class (Resend-style: new MySDK("key"))')
157
+ .option('--client-type <type>', 'Client type: internal (full options, default) or public (auth key only, baseUrl baked in)')
158
+ .option('--npm-token <token>', 'NPM auth token for resolving private package versions (defaults to NPM_TOKEN env var)')
146
159
  .action(handleGenerate);
147
160
  program
148
- .command("run")
161
+ .command('run')
149
162
  .description([
150
- "Boot an instrumented Fastify app with TESSERACT_GENERATE=1 to collect routes and generate an SDK.",
151
- "The app must register `tesseractPlugin` from `@apollo-deploy/tesseract/fastify`.",
152
- ].join("\n"))
153
- .argument("<app>", "Path to the compiled app entry-point (e.g. dist/app.js)")
163
+ 'Boot an instrumented Fastify app with TESSERACT_GENERATE=1 to collect routes and generate an SDK.',
164
+ 'The app must register `tesseractPlugin` from `@apollo-deploy/tesseract/fastify`.',
165
+ ].join('\n'))
166
+ .argument('<app>', 'Path to the compiled app entry-point (e.g. dist/app.js)')
154
167
  .action(handleRun);
155
168
  return program;
156
169
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAuBtC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D;;GAEG;AACH,SAAS,kBAAkB;IACzB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,IAAgB;IACnC,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAC1B,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;QAC5B,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,YAAY;QACvC,WAAW,EAAE,IAAI,CAAC,IAAI;QACtB,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,QAAkB;IACvC,IAAI,CAAC,QAAQ,CAAC,MAAM;QAAE,OAAO;IAC7B,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAe,EAAE,MAAM,GAAG,MAAM;IACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,IAAgB,EAAE,MAAsB;IAC5D,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE/B,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,OAAO;YACV,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CACX,wCAAwC,MAAM,CAAC,YAAY,qBAAqB,CACjF,CAAC;gBACF,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;gBACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,wCAAwC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACnE,OAAO;QAET,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CACT,yBAAyB,MAAM,CAAC,YAAY,yBAAyB,IAAI,CAAC,MAAM,EAAE,CACnF,CAAC;YAEF,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;gBAC/B,aAAa,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YACrC,CAAC;YAED,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,kBAAkB,CAAC,CAAC;YAC1D,CAAC;YACD,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,+BAA+B,CAAC,CAAC;YACvE,CAAC;YACD,OAAO;QAET;YACE,OAAO,CAAC,GAAG,CACT,iBAAiB,MAAM,CAAC,YAAY,YAAY,IAAI,CAAC,MAAM,EAAE,CAC9D,CAAC;YAEF,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,4BAA4B,CAAC,CAAC;YACpE,CAAC;YACD,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,sBAAsB,CAAC,CAAC;YAC9D,CAAC;IACL,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,IAAgB;IACrC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IACE,IAAI,CAAC,WAAW;QAChB,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EACvD,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,cAAc,CAAC,IAAgB;IAC5C,aAAa,CAAC,IAAI,CAAC,CAAC;IAEpB,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,OAAe;IAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE;QACrD,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE;QAChD,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,SAAS,SAAS;IAChB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IAErC,OAAO;SACJ,IAAI,CAAC,WAAW,CAAC;SACjB,WAAW,CACV,sGAAsG,CACvG;SACA,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,uDAAuD,CAAC;SACpE,cAAc,CACb,oBAAoB,EACpB,gDAAgD,CACjD;SACA,cAAc,CACb,oBAAoB,EACpB,wCAAwC,CACzC;SACA,MAAM,CACL,uBAAuB,EACvB,0EAA0E,CAC3E;SACA,MAAM,CAAC,mBAAmB,EAAE,+BAA+B,CAAC;SAC5D,MAAM,CACL,6BAA6B,EAC7B,wCAAwC,CACzC;SACA,MAAM,CACL,uBAAuB,EACvB,uEAAuE,CACxE;SACA,MAAM,CAAC,sBAAsB,EAAE,gCAAgC,CAAC;SAChE,MAAM,CAAC,kBAAkB,EAAE,uBAAuB,CAAC;SACnD,MAAM,CAAC,WAAW,EAAE,sCAAsC,CAAC;SAC3D,MAAM,CAAC,SAAS,EAAE,kDAAkD,CAAC;SACrE,MAAM,CACL,qBAAqB,EACrB,2EAA2E,CAC5E;SACA,MAAM,CACL,sBAAsB,EACtB,2FAA2F,CAC5F;SACA,MAAM,CACL,qBAAqB,EACrB,uFAAuF,CACxF;SACA,MAAM,CAAC,cAAc,CAAC,CAAC;IAE1B,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CACV;QACE,mGAAmG;QACnG,kFAAkF;KACnF,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;SACA,QAAQ,CACP,OAAO,EACP,yDAAyD,CAC1D;SACA,MAAM,CAAC,SAAS,CAAC,CAAC;IAErB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC"}
@@ -28,7 +28,18 @@
28
28
  */
29
29
  import type { BackendManifest, ManifestRouteSchema } from './types/manifest.js';
30
30
  import type { SDKModuleConfig, SDKRouteConfig } from './types/sdk-module.js';
31
- import type { TargetLanguage } from './types/ir.js';
31
+ import type { TargetLanguage, VersionBump } from './types/ir.js';
32
+ /**
33
+ * Minimal interface for Zod v4's global registry — only what Tesseract needs.
34
+ * Declared here so adapters don't need a hard dependency on `zod`.
35
+ */
36
+ export interface ZodGlobalRegistry {
37
+ get(schema: unknown): {
38
+ id?: string;
39
+ } | undefined;
40
+ /** Internal id→schema map present in Zod v4 registries. */
41
+ _idmap?: Map<string, unknown>;
42
+ }
32
43
  export interface CollectorOptions {
33
44
  /** API metadata written into the generated package.json and README. */
34
45
  info: {
@@ -50,6 +61,33 @@ export interface CollectorOptions {
50
61
  version?: string;
51
62
  importPath?: string;
52
63
  };
64
+ /**
65
+ * Function to convert framework-specific schema objects (e.g. raw Zod schemas)
66
+ * to JSON Schema at generation time.
67
+ *
68
+ * Required when using `fastify-type-provider-zod` or passing raw Zod schemas
69
+ * directly to route/collector configs. Pass `toJSONSchema` from `zod` v4.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * import { toJSONSchema } from 'zod';
74
+ * new SDKCollector({ ..., schemaConverter: toJSONSchema });
75
+ * ```
76
+ */
77
+ schemaConverter?: (schema: unknown) => unknown;
78
+ /**
79
+ * Zod v4 global registry — controls how registered schemas are resolved
80
+ * when `schemaConverter` is set.
81
+ *
82
+ * - With `schemaPackage`: registered schemas emit a bare `$ref: 'Id'` so
83
+ * intake creates external import stubs.
84
+ * - Without `schemaPackage` (or when a target sets `schemaPackage: null`):
85
+ * registered schemas are expanded and wrapped in `$defs` so intake
86
+ * generates named data classes (e.g. Kotlin `data class`).
87
+ *
88
+ * Pass `z.globalRegistry` from your app.
89
+ */
90
+ zodGlobalRegistry?: ZodGlobalRegistry;
53
91
  /** `'functional'` (default) or `'class'` (Resend-style `new MySDK('key')`). */
54
92
  sdkStyle?: 'functional' | 'class';
55
93
  /** `'internal'` (default) or `'public'` (auth key only, baseUrl baked in). */
@@ -58,6 +96,8 @@ export interface CollectorOptions {
58
96
  packageName?: string;
59
97
  /** Override the generated package version. */
60
98
  packageVersion?: string;
99
+ /** Version increment used when packageVersion is omitted. */
100
+ versionBump?: VersionBump;
61
101
  /**
62
102
  * Target SDK language for the primary output. Defaults to `'typescript'`.
63
103
  * Use `additionalTargets` to emit multiple languages simultaneously.
@@ -86,6 +126,7 @@ export interface CollectorOptions {
86
126
  output: string;
87
127
  packageName?: string;
88
128
  packageVersion?: string;
129
+ versionBump?: VersionBump;
89
130
  clientType?: 'internal' | 'public';
90
131
  sdkStyle?: 'functional' | 'class';
91
132
  /**
@@ -96,12 +137,17 @@ export interface CollectorOptions {
96
137
  * from a shared TypeScript package but an additional target (e.g. Kotlin)
97
138
  * needs self-contained inline types.
98
139
  *
99
- * Omit to inherit the primary `schemaPackage`.
140
+ * Non-TypeScript targets default to expanding types inline (as if
141
+ * `schemaPackage: null`) when this field is omitted, since they cannot
142
+ * import a TypeScript schema package.
143
+ *
144
+ * Omit on a TypeScript additional target to inherit the primary `schemaPackage`.
100
145
  *
101
146
  * @example
102
147
  * ```ts
103
148
  * additionalTargets: [
104
- * { language: 'kotlin', output: './sdk/java', schemaPackage: null },
149
+ * { language: 'kotlin', output: './sdk/java' }, // auto-expands types
150
+ * { language: 'kotlin', output: './sdk/java', schemaPackage: null }, // explicit
105
151
  * ]
106
152
  * ```
107
153
  */
@@ -152,6 +198,8 @@ export declare class SDKCollector {
152
198
  * @param config - Schema and SDK options for this route.
153
199
  */
154
200
  route(url: string, method: string, config: CollectorRouteConfig): this;
201
+ /** Number of routes currently registered. */
202
+ get routeCount(): number;
155
203
  /** Build and return the `BackendManifest` from all accumulated routes and domains. */
156
204
  buildManifest(): BackendManifest;
157
205
  /** Generate the SDK from accumulated routes and domains. */
@@ -169,6 +217,32 @@ export declare class SDKCollector {
169
217
  */
170
218
  tryGenerate(): Promise<boolean>;
171
219
  }
220
+ /**
221
+ * Post-process a JSON Schema produced by `toJSONSchema` so that any `$defs`
222
+ * entry whose key matches a registered global id is lifted to a bare `$ref`.
223
+ * Used in the external-target path so intake treats them as import stubs.
224
+ */
225
+ export declare function liftRegisteredRefs(schema: unknown, registeredIds: Set<string>): unknown;
226
+ /**
227
+ * Convert a single raw schema value to JSON Schema.
228
+ *
229
+ * - `isExternalTarget: true` — registered schema → bare `$ref: 'Id'` (external import stub)
230
+ * - `isExternalTarget: false` — registered schema → `{ $defs: { Id: <expanded> }, $ref: '#/$defs/Id' }`
231
+ * so `buildManifestFromRoutes` can extract it as a named local definition.
232
+ * - No registry — calls `toJSONSchema` directly; nested `$defs` are extracted by
233
+ * `buildManifestFromRoutes`.
234
+ */
235
+ export declare function convertSchemaValue(value: unknown, toJSONSchema: (s: unknown) => unknown, zodRegistry?: ZodGlobalRegistry, isExternalTarget?: boolean): unknown;
236
+ /**
237
+ * Convert all schema fields on a single route schema, applying the correct
238
+ * Zod→JSON Schema conversion strategy for the target.
239
+ */
240
+ export declare function convertRouteSchema(schema: ManifestRouteSchema | undefined, toJSONSchema: (s: unknown) => unknown, zodRegistry?: ZodGlobalRegistry, isExternalTarget?: boolean): ManifestRouteSchema | undefined;
241
+ /**
242
+ * Resolve the `toJSONSchema` converter: use the explicit one if provided,
243
+ * otherwise attempt auto-detection from the host app's `zod` package.
244
+ */
245
+ export declare function resolveSchemaConverter(explicit?: (s: unknown) => unknown): Promise<((s: unknown) => unknown) | undefined>;
172
246
  /**
173
247
  * Builds a `BackendManifest` from a flat list of collected routes and a domain
174
248
  * registry. Exported so framework adapters (including the Fastify plugin) can
@@ -1 +1 @@
1
- {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"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"}
package/dist/collector.js CHANGED
@@ -47,7 +47,11 @@ export class SDKCollector {
47
47
  * @param config - Optional domain metadata — name override, description, stability.
48
48
  */
49
49
  domain(prefix, config) {
50
- this._registry.set(prefix, { prefix, ...config });
50
+ const normalizedPrefix = normalizePath(prefix);
51
+ this._registry.set(normalizedPrefix, {
52
+ prefix: normalizedPrefix,
53
+ ...config,
54
+ });
51
55
  return this;
52
56
  }
53
57
  /**
@@ -63,7 +67,7 @@ export class SDKCollector {
63
67
  if (config.sdk?.exclude)
64
68
  return this;
65
69
  this._routes.push({
66
- url,
70
+ url: normalizePath(url),
67
71
  method: method.toUpperCase(),
68
72
  schema: config.schema,
69
73
  sdk: config.sdk,
@@ -71,6 +75,10 @@ export class SDKCollector {
71
75
  });
72
76
  return this;
73
77
  }
78
+ /** Number of routes currently registered. */
79
+ get routeCount() {
80
+ return this._routes.length;
81
+ }
74
82
  /** Build and return the `BackendManifest` from all accumulated routes and domains. */
75
83
  buildManifest() {
76
84
  return buildManifestFromRoutes(this._routes, this._registry, this.opts.info, this.opts.schemaPackage);
@@ -78,24 +86,52 @@ export class SDKCollector {
78
86
  /** Generate the SDK from accumulated routes and domains. */
79
87
  async generate() {
80
88
  const { generate } = await import('./index.js');
81
- const manifest = this.buildManifest();
89
+ const toJSONSchema = await resolveSchemaConverter(this.opts.schemaConverter);
90
+ /**
91
+ * Build a manifest for a specific schemaPackage context.
92
+ * When `toJSONSchema` is available, routes are re-converted with the
93
+ * correct `isExternalTarget` flag before the manifest is built.
94
+ */
95
+ const buildManifestFor = (schemaPackage) => {
96
+ if (!toJSONSchema) {
97
+ return buildManifestFromRoutes(this._routes, this._registry, this.opts.info, schemaPackage);
98
+ }
99
+ const isExternal = !!schemaPackage;
100
+ // Always pass the registry when available so non-external targets can
101
+ // expand registered schemas into `$defs` (named local models). External
102
+ // targets use the same registry to emit bare `$ref` import stubs.
103
+ const registry = this.opts.zodGlobalRegistry;
104
+ const converted = this._routes.map((r) => ({
105
+ ...r,
106
+ schema: convertRouteSchema(r.schema, toJSONSchema, registry, isExternal),
107
+ }));
108
+ return buildManifestFromRoutes(converted, this._registry, this.opts.info, schemaPackage);
109
+ };
110
+ const primaryManifest = buildManifestFor(this.opts.schemaPackage);
82
111
  const primary = await generate({
83
- manifest,
112
+ manifest: primaryManifest,
84
113
  output: this.opts.output,
85
114
  language: this.opts.language,
86
115
  clientType: this.opts.clientType,
87
116
  packageName: this.opts.packageName,
88
117
  packageVersion: this.opts.packageVersion,
118
+ versionBump: this.opts.versionBump,
89
119
  sdkStyle: this.opts.sdkStyle,
90
120
  });
91
121
  for (const target of this.opts.additionalTargets ?? []) {
92
- // If the target overrides schemaPackage (including null to disable it),
93
- // rebuild the manifest with the target-specific schemaPackage so that
94
- // intake resolves types correctly for this language.
95
122
  const hasSchemaPackageOverride = Object.prototype.hasOwnProperty.call(target, 'schemaPackage');
96
- const targetManifest = hasSchemaPackageOverride
97
- ? buildManifestFromRoutes(this._routes, this._registry, this.opts.info, target.schemaPackage ?? undefined)
98
- : manifest;
123
+ // Non-TypeScript targets cannot import a TS schema package — expand
124
+ // registered types into local definitions unless explicitly overridden.
125
+ const inheritsSchemaPackage = !hasSchemaPackageOverride && target.language !== 'typescript';
126
+ const targetSchemaPackage = hasSchemaPackageOverride
127
+ ? (target.schemaPackage ?? undefined)
128
+ : inheritsSchemaPackage
129
+ ? undefined
130
+ : this.opts.schemaPackage;
131
+ const targetManifest = hasSchemaPackageOverride ||
132
+ targetSchemaPackage !== this.opts.schemaPackage
133
+ ? buildManifestFor(targetSchemaPackage)
134
+ : primaryManifest;
99
135
  const extra = await generate({
100
136
  manifest: targetManifest,
101
137
  output: target.output,
@@ -103,12 +139,13 @@ export class SDKCollector {
103
139
  clientType: target.clientType ?? this.opts.clientType,
104
140
  packageName: target.packageName ?? this.opts.packageName,
105
141
  packageVersion: target.packageVersion ?? this.opts.packageVersion,
142
+ versionBump: target.versionBump ?? this.opts.versionBump,
106
143
  sdkStyle: target.sdkStyle ?? this.opts.sdkStyle,
107
144
  });
108
- // Merge warnings and counts back into the primary result so callers
109
- // get a single aggregated result regardless of target count.
110
145
  primary.filesWritten += extra.filesWritten;
111
146
  primary.filesSkipped += extra.filesSkipped;
147
+ primary.filesDeleted += extra.filesDeleted;
148
+ primary.hasChanges ||= extra.hasChanges;
112
149
  primary.warnings.push(...extra.warnings);
113
150
  primary.changedFiles.push(...extra.changedFiles);
114
151
  }
@@ -133,11 +170,139 @@ export class SDKCollector {
133
170
  for (const w of result.warnings)
134
171
  console.warn(` ⚠ ${w}`);
135
172
  }
136
- const targets = [this.opts.output, ...(this.opts.additionalTargets ?? []).map((t) => t.output)];
173
+ const targets = [
174
+ this.opts.output,
175
+ ...(this.opts.additionalTargets ?? []).map((t) => t.output),
176
+ ];
137
177
  console.log(`[tesseract] ✓ ${result.filesWritten} files written → ${targets.join(', ')}`);
138
178
  return true;
139
179
  }
140
180
  }
181
+ // ── Zod schema conversion ─────────────────────────────────────────────────────
182
+ /** Returns true when `value` is a Zod v4 schema instance. */
183
+ function isZodSchema(value) {
184
+ return !!value && typeof value === 'object' && '_zod' in value;
185
+ }
186
+ /**
187
+ * Post-process a JSON Schema produced by `toJSONSchema` so that any `$defs`
188
+ * entry whose key matches a registered global id is lifted to a bare `$ref`.
189
+ * Used in the external-target path so intake treats them as import stubs.
190
+ */
191
+ export function liftRegisteredRefs(schema, registeredIds) {
192
+ if (!schema || typeof schema !== 'object')
193
+ return schema;
194
+ if (Array.isArray(schema)) {
195
+ return schema.map((item) => liftRegisteredRefs(item, registeredIds));
196
+ }
197
+ const s = schema;
198
+ if (typeof s.$ref === 'string' && s.$ref.startsWith('#/$defs/')) {
199
+ const id = s.$ref.slice('#/$defs/'.length);
200
+ if (registeredIds.has(id))
201
+ return { $ref: id };
202
+ }
203
+ const result = {};
204
+ for (const [key, val] of Object.entries(s)) {
205
+ if (key === '$defs')
206
+ continue;
207
+ result[key] = liftRegisteredRefs(val, registeredIds);
208
+ }
209
+ if (s.$defs && typeof s.$defs === 'object' && !Array.isArray(s.$defs)) {
210
+ const remainingDefs = {};
211
+ for (const [defKey, defVal] of Object.entries(s.$defs)) {
212
+ if (!registeredIds.has(defKey)) {
213
+ remainingDefs[defKey] = liftRegisteredRefs(defVal, registeredIds);
214
+ }
215
+ }
216
+ if (Object.keys(remainingDefs).length > 0)
217
+ result.$defs = remainingDefs;
218
+ }
219
+ return result;
220
+ }
221
+ /**
222
+ * Convert a single raw schema value to JSON Schema.
223
+ *
224
+ * - `isExternalTarget: true` — registered schema → bare `$ref: 'Id'` (external import stub)
225
+ * - `isExternalTarget: false` — registered schema → `{ $defs: { Id: <expanded> }, $ref: '#/$defs/Id' }`
226
+ * so `buildManifestFromRoutes` can extract it as a named local definition.
227
+ * - No registry — calls `toJSONSchema` directly; nested `$defs` are extracted by
228
+ * `buildManifestFromRoutes`.
229
+ */
230
+ export function convertSchemaValue(value, toJSONSchema, zodRegistry, isExternalTarget) {
231
+ if (isZodSchema(value)) {
232
+ if (zodRegistry) {
233
+ const entry = zodRegistry.get(value);
234
+ if (entry?.id) {
235
+ if (isExternalTarget) {
236
+ return { $ref: entry.id };
237
+ }
238
+ const expanded = toJSONSchema(value);
239
+ return { $defs: { [entry.id]: expanded }, $ref: `#/$defs/${entry.id}` };
240
+ }
241
+ }
242
+ const jsonSchema = toJSONSchema(value);
243
+ // Only lift registered `$defs` → bare `$ref` for external (schemaPackage)
244
+ // targets. Inline targets must keep `$defs` so they become local models.
245
+ if (isExternalTarget &&
246
+ zodRegistry?._idmap &&
247
+ jsonSchema &&
248
+ typeof jsonSchema === 'object') {
249
+ const registeredIds = new Set(zodRegistry._idmap.keys());
250
+ return liftRegisteredRefs(jsonSchema, registeredIds);
251
+ }
252
+ return jsonSchema;
253
+ }
254
+ return value;
255
+ }
256
+ // Schema fields eligible for registry-based $ref replacement.
257
+ // headers are always expanded inline since they're rarely top-level registered schemas.
258
+ const REGISTRY_ELIGIBLE_FIELDS = new Set([
259
+ 'body',
260
+ 'querystring',
261
+ 'query',
262
+ 'params',
263
+ ]);
264
+ /**
265
+ * Convert all schema fields on a single route schema, applying the correct
266
+ * Zod→JSON Schema conversion strategy for the target.
267
+ */
268
+ export function convertRouteSchema(schema, toJSONSchema, zodRegistry, isExternalTarget) {
269
+ if (!schema)
270
+ return schema;
271
+ const result = {};
272
+ for (const [key, val] of Object.entries(schema)) {
273
+ if (key === 'response' && val && typeof val === 'object') {
274
+ const serialized = {};
275
+ for (const [status, responseSchema] of Object.entries(val)) {
276
+ serialized[status] = convertSchemaValue(responseSchema, toJSONSchema, zodRegistry, isExternalTarget);
277
+ }
278
+ result[key] = serialized;
279
+ }
280
+ else if (REGISTRY_ELIGIBLE_FIELDS.has(key)) {
281
+ result[key] = convertSchemaValue(val, toJSONSchema, zodRegistry, isExternalTarget);
282
+ }
283
+ else {
284
+ result[key] = convertSchemaValue(val, toJSONSchema);
285
+ }
286
+ }
287
+ return result;
288
+ }
289
+ /**
290
+ * Resolve the `toJSONSchema` converter: use the explicit one if provided,
291
+ * otherwise attempt auto-detection from the host app's `zod` package.
292
+ */
293
+ export async function resolveSchemaConverter(explicit) {
294
+ if (typeof explicit === 'function')
295
+ return explicit;
296
+ try {
297
+ const zodPkg = 'zod';
298
+ const zodModule = (await import(zodPkg));
299
+ const converter = zodModule.toJSONSchema;
300
+ return typeof converter === 'function' ? converter : undefined;
301
+ }
302
+ catch {
303
+ return undefined;
304
+ }
305
+ }
141
306
  // ── Shared manifest builder ───────────────────────────────────────────────────
142
307
  /**
143
308
  * Builds a `BackendManifest` from a flat list of collected routes and a domain
@@ -149,15 +314,15 @@ export function buildManifestFromRoutes(routes, registry, info, schemaPackage) {
149
314
  const sortedPrefixes = [...registry.keys()].sort((a, b) => b.length - a.length);
150
315
  const domainMap = new Map();
151
316
  for (const route of routes) {
152
- const matchedPrefix = sortedPrefixes.find((p) => route.url === p || route.url.startsWith(p + '/')) ??
153
- derivePrefix(route.url);
317
+ const url = normalizePath(route.url);
318
+ const matchedPrefix = sortedPrefixes.find((prefix) => prefix === '/' || url === prefix || url.startsWith(`${prefix}/`)) ?? derivePrefix(url);
154
319
  if (!domainMap.has(matchedPrefix)) {
155
320
  domainMap.set(matchedPrefix, {
156
321
  config: registry.get(matchedPrefix) ?? { prefix: matchedPrefix },
157
322
  routes: [],
158
323
  });
159
324
  }
160
- const tail = route.url.substring(matchedPrefix.length) || '/';
325
+ const tail = url.substring(matchedPrefix === '/' ? 0 : matchedPrefix.length) || '/';
161
326
  domainMap.get(matchedPrefix).routes.push({
162
327
  method: route.method,
163
328
  url: tail.startsWith('/') ? tail : '/' + tail,
@@ -175,14 +340,25 @@ export function buildManifestFromRoutes(routes, registry, info, schemaPackage) {
175
340
  baseUrl: info.baseUrl,
176
341
  },
177
342
  ...(schemaPackage && { schemaPackage }),
178
- domains: [...domainMap.values()].map(({ config, routes }) => ({ ...config, routes })),
343
+ domains: [...domainMap.values()].map(({ config, routes }) => ({
344
+ ...config,
345
+ routes,
346
+ })),
179
347
  ...buildDefinitionsFromDefs(routes),
180
348
  };
181
349
  }
182
350
  /** Derives a domain prefix from the first non-parameter URL segment. */
183
351
  function derivePrefix(url) {
184
- const first = url.split('/').find((s) => s.length > 0 && !s.startsWith(':'));
185
- return first ? '/' + first : '/';
352
+ const first = url
353
+ .split('/')
354
+ .find((segment) => segment && !segment.startsWith(':'));
355
+ return first ? `/${first}` : '/';
356
+ }
357
+ function normalizePath(value) {
358
+ const path = value.trim();
359
+ if (!path || path === '/')
360
+ return '/';
361
+ return `/${path.replace(/^\/+|\/+$/g, '')}`;
186
362
  }
187
363
  // ── $defs extraction ──────────────────────────────────────────────────────────
188
364
  /**
@@ -224,7 +400,9 @@ function buildDefinitionsFromDefs(routes) {
224
400
  function collectDefs(schema, out) {
225
401
  if (!schema || typeof schema !== 'object')
226
402
  return;
227
- if (schema.$defs && typeof schema.$defs === 'object' && !Array.isArray(schema.$defs)) {
403
+ if (schema.$defs &&
404
+ typeof schema.$defs === 'object' &&
405
+ !Array.isArray(schema.$defs)) {
228
406
  for (const [key, val] of Object.entries(schema.$defs)) {
229
407
  if (!(key in out))
230
408
  out[key] = val;