@dudousxd/nestjs-codegen 0.25.2 → 0.27.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.
package/dist/index.cjs CHANGED
@@ -149,11 +149,32 @@ function validateUserConfig(userConfig) {
149
149
  "validation adapter is required \u2014 install @dudousxd/nestjs-codegen-zod and pass zodAdapter, or use @dudousxd/nestjs-codegen-valibot / -arktype"
150
150
  );
151
151
  }
152
- if (userConfig.pages && typeof userConfig.pages.glob !== "string") {
152
+ if (userConfig.pages && !isGlobInput(userConfig.pages.glob)) {
153
153
  throw new ConfigError(
154
- "Config validation failed: `pages.glob` must be a string when `pages` is set"
154
+ "Config validation failed: `pages.glob` must be a string or a non-empty array of strings when `pages` is set"
155
155
  );
156
156
  }
157
+ for (const [scope, scopeConfig] of Object.entries(userConfig.pages?.scopes ?? {})) {
158
+ if (scope === "default") {
159
+ throw new ConfigError(
160
+ 'Config validation failed: `pages.scopes` cannot declare "default" \u2014 the default app is `pages.glob` (InertiaModule.forRoot).'
161
+ );
162
+ }
163
+ if (!isGlobInput(scopeConfig?.glob)) {
164
+ throw new ConfigError(
165
+ `Config validation failed: \`pages.scopes.${scope}.glob\` must be a string or a non-empty array of strings`
166
+ );
167
+ }
168
+ }
169
+ if (userConfig.scopes && Object.keys(userConfig.scopes).length > 0) {
170
+ console.warn(
171
+ "[nestjs-codegen] The top-level `scopes` option has no effect and is deprecated. For several Inertia apps use `pages.scopes` (one entry per InertiaModule.forFeature scope); for several controller sets use one `contracts.glob` (e.g. a brace glob)."
172
+ );
173
+ }
174
+ }
175
+ function isGlobInput(value) {
176
+ if (typeof value === "string") return true;
177
+ return Array.isArray(value) && value.length > 0 && value.every((glob) => typeof glob === "string");
157
178
  }
158
179
  function applyDefaults(userConfig, cwd) {
159
180
  validateUserConfig(userConfig);
@@ -181,7 +202,17 @@ function applyDefaults(userConfig, cwd) {
181
202
  pages: userConfig.pages ? {
182
203
  glob: userConfig.pages.glob,
183
204
  propsExport: userConfig.pages.propsExport ?? "ComponentProps",
184
- componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext"
205
+ componentNameStrategy: userConfig.pages.componentNameStrategy ?? "relative-no-ext",
206
+ scopes: Object.fromEntries(
207
+ Object.entries(userConfig.pages.scopes ?? {}).map(([scope, scopeConfig]) => [
208
+ scope,
209
+ {
210
+ glob: scopeConfig.glob,
211
+ prefix: scopeConfig.prefix ?? `${scope}/`,
212
+ componentNameStrategy: scopeConfig.componentNameStrategy ?? userConfig.pages?.componentNameStrategy ?? "relative-no-ext"
213
+ }
214
+ ])
215
+ )
185
216
  } : null,
186
217
  contracts: {
187
218
  glob: userConfig.contracts?.glob ?? "src/**/*.controller.ts",
@@ -258,23 +289,81 @@ var import_promises2 = require("fs/promises");
258
289
  var import_node_path2 = require("path");
259
290
  var import_fast_glob = __toESM(require("fast-glob"), 1);
260
291
  var NON_PAGE_FILE_RE = /\.(?:test|spec|stories|story)\.(?:tsx?|jsx?|vue|svelte)$/i;
292
+ var MAGIC_SEGMENT_RE = /[*?{}[\]()!]/;
293
+ function globStaticBase(glob) {
294
+ const segments = glob.split("/");
295
+ const staticSegments = [];
296
+ for (const segment of segments.slice(0, -1)) {
297
+ if (MAGIC_SEGMENT_RE.test(segment)) break;
298
+ staticSegments.push(segment);
299
+ }
300
+ return staticSegments.join("/");
301
+ }
261
302
  async function discoverPages(opts) {
262
- const allFiles = await (0, import_fast_glob.default)(opts.glob, { cwd: opts.cwd, absolute: true });
263
- const files = allFiles.filter((f) => !NON_PAGE_FILE_RE.test(f));
264
- files.sort();
265
- const globStatic = opts.glob.split("*")[0]?.replace(/\/$/, "") ?? "";
266
- const pagesBase = (0, import_node_path2.join)(opts.cwd, globStatic);
303
+ const globs = typeof opts.glob === "string" ? [opts.glob] : opts.glob;
304
+ const prefix = opts.prefix ?? "";
305
+ const scope = opts.scope ?? "default";
306
+ const seenFiles = /* @__PURE__ */ new Set();
267
307
  const out = [];
268
- for (const file of files) {
269
- const rel = (0, import_node_path2.relative)(opts.cwd, file);
270
- const nameRel = (0, import_node_path2.relative)(pagesBase, file);
271
- const name = computeName(nameRel, opts.componentNameStrategy);
272
- const source = await (0, import_promises2.readFile)(file, "utf8");
273
- const propsSource = extractPropsSource(source, opts.propsExport);
274
- out.push({ name, absolutePath: file, relativePath: rel, propsSource });
308
+ for (const glob of globs) {
309
+ const files = (await (0, import_fast_glob.default)(glob, { cwd: opts.cwd, absolute: true })).filter((f) => !NON_PAGE_FILE_RE.test(f) && !seenFiles.has(f)).sort();
310
+ const pagesBase = (0, import_node_path2.join)(opts.cwd, globStaticBase(glob));
311
+ for (const file of files) {
312
+ seenFiles.add(file);
313
+ const rel = (0, import_node_path2.relative)(opts.cwd, file);
314
+ const nameRel = (0, import_node_path2.relative)(pagesBase, file).split(import_node_path2.sep).join("/");
315
+ const name = `${prefix}${computeName(nameRel, opts.componentNameStrategy)}`;
316
+ const source = await (0, import_promises2.readFile)(file, "utf8");
317
+ const propsSource = extractPropsSource(source, opts.propsExport);
318
+ out.push({ name, absolutePath: file, relativePath: rel, propsSource, scope });
319
+ }
320
+ }
321
+ assertUniqueNames(out);
322
+ return out;
323
+ }
324
+ async function discoverPageScopes(config) {
325
+ const pages = config.pages;
326
+ if (!pages) return [];
327
+ const common = { cwd: config.codegen.cwd, propsExport: pages.propsExport };
328
+ const out = await discoverPages({
329
+ ...common,
330
+ glob: pages.glob,
331
+ componentNameStrategy: pages.componentNameStrategy
332
+ });
333
+ for (const [scope, scopeConfig] of Object.entries(pages.scopes ?? {})) {
334
+ out.push(
335
+ ...await discoverPages({
336
+ ...common,
337
+ glob: scopeConfig.glob,
338
+ componentNameStrategy: scopeConfig.componentNameStrategy,
339
+ prefix: scopeConfig.prefix,
340
+ scope
341
+ })
342
+ );
275
343
  }
344
+ assertUniqueNames(out);
276
345
  return out;
277
346
  }
347
+ function allPageGlobs(config) {
348
+ if (!config.pages) return [];
349
+ const asList = (glob) => typeof glob === "string" ? [glob] : glob;
350
+ return [
351
+ ...asList(config.pages.glob),
352
+ ...Object.values(config.pages.scopes ?? {}).flatMap((scope) => asList(scope.glob))
353
+ ];
354
+ }
355
+ function assertUniqueNames(pages) {
356
+ const byName = /* @__PURE__ */ new Map();
357
+ for (const page of pages) {
358
+ const previous = byName.get(page.name);
359
+ if (previous) {
360
+ throw new Error(
361
+ `Two Inertia pages resolve to the component name "${page.name}": ${previous.relativePath} (scope "${previous.scope}") and ${page.relativePath} (scope "${page.scope}"). Give one of them another name, directory or scope prefix.`
362
+ );
363
+ }
364
+ byName.set(page.name, page);
365
+ }
366
+ }
278
367
  function computeName(rel, strat) {
279
368
  if (typeof strat === "function") return strat(rel);
280
369
  const noExt = rel.replace(/\.(tsx?|vue|svelte)$/, "");
@@ -584,16 +673,16 @@ var import_node_path7 = require("path");
584
673
 
585
674
  // src/extension/registry.ts
586
675
  var import_node_path6 = require("path");
587
- var import_ts_morph10 = require("ts-morph");
676
+ var import_ts_morph13 = require("ts-morph");
588
677
 
589
678
  // src/discovery/contracts-fast.ts
590
679
  var import_node_fs = require("fs");
591
680
  var import_node_path5 = require("path");
592
681
  var import_fast_glob2 = __toESM(require("fast-glob"), 1);
593
- var import_ts_morph9 = require("ts-morph");
682
+ var import_ts_morph12 = require("ts-morph");
594
683
 
595
684
  // src/discovery/dto-type-resolver.ts
596
- var import_ts_morph7 = require("ts-morph");
685
+ var import_ts_morph11 = require("ts-morph");
597
686
 
598
687
  // src/discovery/dto-to-ir.ts
599
688
  var import_ts_morph3 = require("ts-morph");
@@ -2121,6 +2210,672 @@ function extractFilterableEntityFields(filterClass, project, entityOverride, pre
2121
2210
  return fields;
2122
2211
  }
2123
2212
 
2213
+ // src/discovery/pipe-schema.ts
2214
+ var import_ts_morph10 = require("ts-morph");
2215
+
2216
+ // src/discovery/schema-type-inference.ts
2217
+ var import_ts_morph8 = require("ts-morph");
2218
+
2219
+ // src/discovery/schema-type-program.ts
2220
+ var import_ts_morph7 = require("ts-morph");
2221
+ var PARAM_DECORATORS = /* @__PURE__ */ new Set(["Body", "Query", "Param"]);
2222
+ var SchemaTypeProgram = class {
2223
+ constructor(discovery) {
2224
+ this.discovery = discovery;
2225
+ const base = discovery.getCompilerOptions();
2226
+ this.options = {
2227
+ ...base,
2228
+ // A tsconfig-less consumer gets ES5 by default, whose lib has no `Map`/`Set`/
2229
+ // `Promise` for the schema libraries' declarations to lean on.
2230
+ target: base.target ?? import_ts_morph7.ts.ScriptTarget.ES2022,
2231
+ // With neither set, resolve the way a bundler does: package `exports`
2232
+ // (`zod/v4`) and extensionless or `.js` relative imports all resolve.
2233
+ ...base.module === void 0 && base.moduleResolution === void 0 ? { module: import_ts_morph7.ts.ModuleKind.ESNext, moduleResolution: import_ts_morph7.ts.ModuleResolutionKind.Bundler } : {},
2234
+ // Without it `.nullable()` and `.optional()` would erase to the bare type.
2235
+ strictNullChecks: true,
2236
+ // No ambient `@types/*` (a tsconfig's `types: ['node']`): a schema does not
2237
+ // need them, and they are a hundred-odd files of program to build.
2238
+ types: [],
2239
+ noEmit: true
2240
+ };
2241
+ this.project = new import_ts_morph7.Project({
2242
+ skipAddingFilesFromTsConfig: true,
2243
+ compilerOptions: this.options
2244
+ });
2245
+ for (const sf of discovery.getSourceFiles()) this.request(sf.getFilePath(), { schema: true });
2246
+ this.flush();
2247
+ }
2248
+ project;
2249
+ options;
2250
+ /** Parses a file that is not in discovery's Project, without adding it there. */
2251
+ scratch = new import_ts_morph7.Project({
2252
+ skipAddingFilesFromTsConfig: true,
2253
+ skipLoadingLibFiles: true,
2254
+ skipFileDependencyResolution: true
2255
+ });
2256
+ needs = /* @__PURE__ */ new Map();
2257
+ /** Pruned text per file, as last written into {@link project}. */
2258
+ written = /* @__PURE__ */ new Map();
2259
+ /**
2260
+ * The typed copy of a discovery file, with its schema positions kept. Adding one
2261
+ * that was not there yet (a contract file discovery reached lazily) rebuilds the
2262
+ * program once.
2263
+ */
2264
+ sourceFileFor(sf) {
2265
+ this.request(sf.getFilePath(), { schema: true });
2266
+ this.flush();
2267
+ return this.project.getSourceFile(sf.getFilePath());
2268
+ }
2269
+ // -------------------------------------------------------------------------
2270
+ queue = [];
2271
+ request(path, want) {
2272
+ let needs = this.needs.get(path);
2273
+ const isNew = !needs;
2274
+ needs ??= { schema: false, all: false, names: /* @__PURE__ */ new Set() };
2275
+ let grew = isNew;
2276
+ if (want.schema && !needs.schema) {
2277
+ needs.schema = true;
2278
+ grew = true;
2279
+ }
2280
+ if (want.all && !needs.all) {
2281
+ needs.all = true;
2282
+ grew = true;
2283
+ }
2284
+ for (const name of want.names ?? []) {
2285
+ if (!needs.names.has(name)) {
2286
+ needs.names.add(name);
2287
+ grew = true;
2288
+ }
2289
+ }
2290
+ this.needs.set(path, needs);
2291
+ if (grew) this.queue.push(path);
2292
+ }
2293
+ /** Run the worklist to a fixpoint, then write every changed file into the program. */
2294
+ flush() {
2295
+ const changed = /* @__PURE__ */ new Map();
2296
+ while (this.queue.length > 0) {
2297
+ const path = this.queue.pop();
2298
+ const original = this.original(path);
2299
+ if (!original) continue;
2300
+ const needs = this.needs.get(path);
2301
+ const text = this.prune(original, needs);
2302
+ if (this.written.get(path) !== text) changed.set(path, text);
2303
+ }
2304
+ for (const [path, text] of changed) {
2305
+ this.project.createSourceFile(path, text, { overwrite: true });
2306
+ this.written.set(path, text);
2307
+ }
2308
+ }
2309
+ /** The file as discovery sees it (its in-memory text), else as it is on disk. */
2310
+ original(path) {
2311
+ return this.discovery.getSourceFile(path) ?? this.scratch.getSourceFile(path) ?? this.scratch.addSourceFileAtPathIfExists(path);
2312
+ }
2313
+ /**
2314
+ * `sf`'s text with every import/re-export nothing in `needs` references blanked,
2315
+ * requesting from each kept one's target the names it brings in.
2316
+ */
2317
+ prune(sf, needs) {
2318
+ const locals = topLevelDeclarations(sf);
2319
+ const roots = [];
2320
+ if (needs.all) roots.push(...sf.getStatements());
2321
+ if (needs.schema) roots.push(...schemaPositions(sf));
2322
+ const reexported = /* @__PURE__ */ new Map();
2323
+ for (const exp of sf.getExportDeclarations()) {
2324
+ const spec = exp.getModuleSpecifierValue();
2325
+ if (spec === void 0) {
2326
+ for (const named of exp.getNamedExports()) {
2327
+ const exposed = (named.getAliasNode() ?? named.getNameNode()).getText();
2328
+ if (needs.all || needs.names.has(exposed)) roots.push(named.getNameNode());
2329
+ }
2330
+ continue;
2331
+ }
2332
+ if (exp.isNamespaceExport() || exp.getNamedExports().length === 0) continue;
2333
+ for (const named of exp.getNamedExports()) {
2334
+ const exposed = (named.getAliasNode() ?? named.getNameNode()).getText();
2335
+ const list = reexported.get(exposed) ?? [];
2336
+ list.push({ from: spec, name: named.getNameNode().getText() });
2337
+ reexported.set(exposed, list);
2338
+ }
2339
+ }
2340
+ const unresolvedNames = [];
2341
+ for (const name of needs.names) {
2342
+ const decls = name === "default" ? defaultExport(sf) : locals.get(name) ?? [];
2343
+ if (decls.length > 0) roots.push(...decls);
2344
+ else if (!reexported.has(name)) unresolvedNames.push(name);
2345
+ }
2346
+ const referenced = /* @__PURE__ */ new Set();
2347
+ const queue = [...roots];
2348
+ const seen = new Set(queue);
2349
+ while (queue.length > 0) {
2350
+ const node = queue.pop();
2351
+ const ids = import_ts_morph7.Node.isIdentifier(node) ? [node] : node.getDescendantsOfKind(import_ts_morph7.ts.SyntaxKind.Identifier);
2352
+ for (const id of ids) {
2353
+ const name = id.getText();
2354
+ if (referenced.has(name)) continue;
2355
+ referenced.add(name);
2356
+ for (const local of locals.get(name) ?? []) {
2357
+ if (seen.has(local)) continue;
2358
+ seen.add(local);
2359
+ queue.push(local);
2360
+ }
2361
+ }
2362
+ }
2363
+ const chars = sf.getFullText().split("");
2364
+ const blank = (node) => {
2365
+ for (let i = node.getStart(); i < node.getEnd(); i++) {
2366
+ if (chars[i] !== "\n" && chars[i] !== "\r") chars[i] = " ";
2367
+ }
2368
+ };
2369
+ for (const decl of sf.getImportDeclarations()) {
2370
+ const target = this.resolve(decl.getModuleSpecifierValue(), sf);
2371
+ const namespace = decl.getNamespaceImport()?.getText();
2372
+ const def = decl.getDefaultImport()?.getText();
2373
+ const named = decl.getNamedImports().map((n) => ({
2374
+ local: (n.getAliasNode() ?? n.getNameNode()).getText(),
2375
+ imported: n.getName()
2376
+ })).filter((n) => referenced.has(n.local));
2377
+ const wantsNamespace = namespace !== void 0 && referenced.has(namespace);
2378
+ const wantsDefault = def !== void 0 && referenced.has(def);
2379
+ if (!wantsNamespace && !wantsDefault && named.length === 0) {
2380
+ blank(decl);
2381
+ continue;
2382
+ }
2383
+ if (target) {
2384
+ this.request(target, {
2385
+ all: wantsNamespace,
2386
+ names: [...wantsDefault ? ["default"] : [], ...named.map((n) => n.imported)]
2387
+ });
2388
+ }
2389
+ }
2390
+ for (const exp of sf.getExportDeclarations()) {
2391
+ const spec = exp.getModuleSpecifierValue();
2392
+ if (spec === void 0) continue;
2393
+ const target = this.resolve(spec, sf);
2394
+ if (exp.isNamespaceExport() || exp.getNamedExports().length === 0) {
2395
+ if (!needs.all && unresolvedNames.length === 0) {
2396
+ blank(exp);
2397
+ } else if (target) {
2398
+ this.request(target, { all: needs.all, names: unresolvedNames });
2399
+ }
2400
+ continue;
2401
+ }
2402
+ const wanted = exp.getNamedExports().filter(
2403
+ (n) => needs.all || needs.names.has((n.getAliasNode() ?? n.getNameNode()).getText())
2404
+ ).map((n) => n.getNameNode().getText());
2405
+ if (wanted.length === 0) blank(exp);
2406
+ else if (target) this.request(target, { names: wanted });
2407
+ }
2408
+ return chars.join("");
2409
+ }
2410
+ /**
2411
+ * The project source file a module specifier resolves to, or undefined for a
2412
+ * package (read unpruned by the program itself) or an unresolvable one.
2413
+ */
2414
+ resolve(specifier, from) {
2415
+ const resolved = import_ts_morph7.ts.resolveModuleName(
2416
+ specifier,
2417
+ from.getFilePath(),
2418
+ this.options,
2419
+ import_ts_morph7.ts.sys
2420
+ ).resolvedModule;
2421
+ if (!resolved || resolved.isExternalLibraryImport) return void 0;
2422
+ const file = resolved.resolvedFileName;
2423
+ if (file.endsWith(".d.ts") || !/\.(m|c)?tsx?$/.test(file)) return void 0;
2424
+ return file;
2425
+ }
2426
+ };
2427
+ function schemaPositions(sf) {
2428
+ const roots = [];
2429
+ sf.forEachDescendant((node) => {
2430
+ if (import_ts_morph7.Node.isDecorator(node)) {
2431
+ const name = node.getName();
2432
+ if (name === "ApplyContract") {
2433
+ roots.push(...node.getArguments());
2434
+ } else if (PARAM_DECORATORS.has(name)) {
2435
+ for (const arg of node.getArguments()) {
2436
+ if (import_ts_morph7.Node.isNewExpression(arg) || import_ts_morph7.Node.isCallExpression(arg)) {
2437
+ roots.push(...arg.getArguments());
2438
+ }
2439
+ }
2440
+ }
2441
+ } else if (import_ts_morph7.Node.isCallExpression(node)) {
2442
+ const callee = node.getExpression();
2443
+ const name = import_ts_morph7.Node.isIdentifier(callee) ? callee.getText() : import_ts_morph7.Node.isPropertyAccessExpression(callee) ? callee.getName() : void 0;
2444
+ if (name === "defineContract") roots.push(...node.getArguments());
2445
+ }
2446
+ });
2447
+ return roots;
2448
+ }
2449
+ function topLevelDeclarations(sf) {
2450
+ const byName = /* @__PURE__ */ new Map();
2451
+ const add = (name, node) => {
2452
+ if (!name) return;
2453
+ const list = byName.get(name);
2454
+ if (list) list.push(node);
2455
+ else byName.set(name, [node]);
2456
+ };
2457
+ for (const decl of sf.getVariableDeclarations()) add(decl.getName(), decl);
2458
+ for (const decl of sf.getFunctions()) add(decl.getName(), decl);
2459
+ for (const decl of sf.getClasses()) add(decl.getName(), decl);
2460
+ for (const decl of sf.getEnums()) add(decl.getName(), decl);
2461
+ for (const decl of sf.getInterfaces()) add(decl.getName(), decl);
2462
+ for (const decl of sf.getTypeAliases()) add(decl.getName(), decl);
2463
+ for (const decl of sf.getModules()) add(decl.getName(), decl);
2464
+ return byName;
2465
+ }
2466
+ function defaultExport(sf) {
2467
+ const nodes = [];
2468
+ for (const assignment of sf.getExportAssignments()) nodes.push(assignment);
2469
+ for (const fn of sf.getFunctions()) if (fn.isDefaultExport()) nodes.push(fn);
2470
+ for (const cls of sf.getClasses()) if (cls.isDefaultExport()) nodes.push(cls);
2471
+ return nodes;
2472
+ }
2473
+
2474
+ // src/discovery/schema-type-inference.ts
2475
+ var programs = /* @__PURE__ */ new WeakMap();
2476
+ function programFor(discovery) {
2477
+ let program = programs.get(discovery);
2478
+ if (!program) {
2479
+ program = new SchemaTypeProgram(discovery);
2480
+ programs.set(discovery, program);
2481
+ }
2482
+ return program;
2483
+ }
2484
+ function clearSchemaTypeProject(discovery) {
2485
+ programs.delete(discovery);
2486
+ }
2487
+ function counterpart(typedSf, node) {
2488
+ const start = node.getStart();
2489
+ const end = node.getEnd();
2490
+ const kind = node.getKind();
2491
+ let candidate = typedSf.getDescendantAtPos(start);
2492
+ while (candidate) {
2493
+ if (candidate.getStart() === start && candidate.getEnd() === end && candidate.getKind() === kind) {
2494
+ return candidate;
2495
+ }
2496
+ if (candidate.getStart() < start || candidate.getEnd() > end) return void 0;
2497
+ candidate = candidate.getParent();
2498
+ }
2499
+ return void 0;
2500
+ }
2501
+ function propType(type, name, at) {
2502
+ return type.getProperty(name)?.getTypeAtLocation(at);
2503
+ }
2504
+ function isAnyOrUnknown(type) {
2505
+ return type.isAny() || type.isUnknown();
2506
+ }
2507
+ function inferSchema(expr, discovery) {
2508
+ try {
2509
+ const typedSf = programFor(discovery).sourceFileFor(expr.getSourceFile());
2510
+ const at = typedSf && counterpart(typedSf, expr);
2511
+ if (!at) return { kind: "unresolved" };
2512
+ const schemaType = at.getType();
2513
+ if (isAnyOrUnknown(schemaType)) return { kind: "unresolved" };
2514
+ const standard = propType(schemaType, "~standard", at);
2515
+ const stdTypes = standard ? propType(standard, "types", at)?.getNonNullableType() : void 0;
2516
+ const stdInput = stdTypes ? propType(stdTypes, "input", at) : void 0;
2517
+ const stdOutput = stdTypes ? propType(stdTypes, "output", at) : void 0;
2518
+ if (stdInput && stdOutput) {
2519
+ return { kind: "schema", types: { input: stdInput, output: stdOutput, at } };
2520
+ }
2521
+ const zodInput = propType(schemaType, "_input", at);
2522
+ const zodOutput = propType(schemaType, "_output", at);
2523
+ if (zodInput && zodOutput) {
2524
+ return { kind: "schema", types: { input: zodInput, output: zodOutput, at } };
2525
+ }
2526
+ return { kind: "not-schema" };
2527
+ } catch (err) {
2528
+ dbg("schema inference failed:", err);
2529
+ return { kind: "unresolved" };
2530
+ }
2531
+ }
2532
+ var GLOBAL_NAMED_TYPES = /* @__PURE__ */ new Set([
2533
+ "Date",
2534
+ "File",
2535
+ "Blob",
2536
+ "FormData",
2537
+ "URL",
2538
+ "RegExp",
2539
+ "Map",
2540
+ "Set",
2541
+ "ArrayBuffer",
2542
+ "Uint8Array"
2543
+ ]);
2544
+ var MAX_DEPTH = 12;
2545
+ function objectKey(name) {
2546
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
2547
+ }
2548
+ function isOptionalSymbol(sym) {
2549
+ return (sym.getFlags() & import_ts_morph8.ts.SymbolFlags.Optional) !== 0;
2550
+ }
2551
+ function isSymbolKeyed(sym) {
2552
+ return sym.getName().startsWith("__@");
2553
+ }
2554
+ function orderedProperties(type) {
2555
+ const position = (sym) => {
2556
+ const decl = sym.getDeclarations()[0];
2557
+ return decl ? [decl.getSourceFile().getFilePath(), decl.getStart()] : void 0;
2558
+ };
2559
+ return type.getProperties().map((sym, index) => ({ sym, index, at: position(sym) })).sort((a, b) => {
2560
+ if (a.at && b.at) {
2561
+ if (a.at[0] !== b.at[0]) return a.at[0] < b.at[0] ? -1 : 1;
2562
+ if (a.at[1] !== b.at[1]) return a.at[1] - b.at[1];
2563
+ } else if (a.at || b.at) {
2564
+ return a.at ? -1 : 1;
2565
+ }
2566
+ return a.index - b.index;
2567
+ }).map((entry) => entry.sym);
2568
+ }
2569
+ function isFromDeclarationFile(sym) {
2570
+ const decl = sym?.getDeclarations()[0];
2571
+ return !!decl && decl.getSourceFile().isDeclarationFile();
2572
+ }
2573
+ function render(type, state, paired) {
2574
+ if (state.depth > MAX_DEPTH) return "unknown";
2575
+ if (isAnyOrUnknown(type)) {
2576
+ return paired && !isAnyOrUnknown(paired) ? render(paired, state) : "unknown";
2577
+ }
2578
+ if (type.isNever()) return "never";
2579
+ if (type.isString() || type.isTemplateLiteral()) return "string";
2580
+ if (type.isNumber()) return "number";
2581
+ if (type.isBoolean()) return "boolean";
2582
+ if (type.isBigInt()) return "bigint";
2583
+ if (type.isNull()) return "null";
2584
+ if (type.isUndefined() || type.isVoid()) return "undefined";
2585
+ if (type.isBooleanLiteral()) return type.getText();
2586
+ if (type.isStringLiteral() || type.isNumberLiteral() || type.isEnumLiteral()) {
2587
+ const value = type.getLiteralValue();
2588
+ return typeof value === "string" ? JSON.stringify(value) : String(value);
2589
+ }
2590
+ if (type.isBigIntLiteral()) return type.getText();
2591
+ if (type.isTypeParameter()) return "unknown";
2592
+ if (type.isUnion()) return renderUnion(type, state, paired);
2593
+ if (type.isIntersection()) return renderIntersection(type, state);
2594
+ const next = { ...state, depth: state.depth + 1 };
2595
+ if (type.isArray() || type.isReadonlyArray()) {
2596
+ const element = type.getArrayElementType() ?? type.getTypeArguments()[0];
2597
+ const pairedElement = paired?.getArrayElementType() ?? paired?.getTypeArguments()[0];
2598
+ return element ? `Array<${render(element, next, pairedElement)}>` : "Array<unknown>";
2599
+ }
2600
+ if (type.isTuple()) {
2601
+ const elements = type.getTupleElements();
2602
+ const pairedElements = paired?.isTuple() ? paired.getTupleElements() : [];
2603
+ return `[${elements.map((e, i) => render(e, next, pairedElements[i])).join(", ")}]`;
2604
+ }
2605
+ if (type.isObject()) return renderObject(type, next, paired);
2606
+ return "unknown";
2607
+ }
2608
+ function renderUnion(type, state, paired) {
2609
+ const members = type.getUnionTypes();
2610
+ const hasTrue = members.some((m) => m.isBooleanLiteral() && m.getText() === "true");
2611
+ const hasFalse = members.some((m) => m.isBooleanLiteral() && m.getText() === "false");
2612
+ const pairedNonNull = paired?.getNonNullableType();
2613
+ const arms = [];
2614
+ let sawBoolean = false;
2615
+ let hasNull = false;
2616
+ let hasUndefined = false;
2617
+ for (const member of members) {
2618
+ if (member.isNull()) {
2619
+ hasNull = true;
2620
+ continue;
2621
+ }
2622
+ if (member.isUndefined()) {
2623
+ hasUndefined = true;
2624
+ continue;
2625
+ }
2626
+ if (member.isBooleanLiteral() && hasTrue && hasFalse) {
2627
+ if (!sawBoolean) arms.push("boolean");
2628
+ sawBoolean = true;
2629
+ continue;
2630
+ }
2631
+ arms.push(render(member, state, members.length === 1 ? paired : pairedNonNull));
2632
+ }
2633
+ if (hasNull) arms.push("null");
2634
+ if (hasUndefined) arms.push("undefined");
2635
+ const unique = [...new Set(arms)];
2636
+ if (unique.includes("unknown")) return "unknown";
2637
+ return unique.join(" | ");
2638
+ }
2639
+ function renderIntersection(type, state) {
2640
+ const members = type.getIntersectionTypes();
2641
+ const primitive = members.find((m) => !m.isObject());
2642
+ if (primitive) return render(primitive, state);
2643
+ return renderObject(type, { ...state, depth: state.depth + 1 }, void 0);
2644
+ }
2645
+ function renderObject(type, state, paired) {
2646
+ const symbol = type.getSymbol() ?? type.getAliasSymbol();
2647
+ const name = symbol?.getName();
2648
+ if (name && GLOBAL_NAMED_TYPES.has(name) && isFromDeclarationFile(symbol)) {
2649
+ const args = type.getTypeArguments();
2650
+ return args.length ? `${name}<${args.map((a) => render(a, state)).join(", ")}>` : name;
2651
+ }
2652
+ if (type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0) {
2653
+ return "unknown";
2654
+ }
2655
+ if (type.isClassOrInterface() && isFromDeclarationFile(symbol)) return "unknown";
2656
+ if (state.stack.has(type.compilerType)) return "unknown";
2657
+ const stack = new Set(state.stack).add(type.compilerType);
2658
+ const inner = { ...state, stack };
2659
+ const fields = [];
2660
+ for (const prop of orderedProperties(type)) {
2661
+ if (isSymbolKeyed(prop)) continue;
2662
+ const propName = prop.getName();
2663
+ const propT = prop.getTypeAtLocation(state.at);
2664
+ if (propT.getCallSignatures().length > 0 && !propT.isUnion()) continue;
2665
+ const pairedProp = paired?.getProperty(propName)?.getTypeAtLocation(state.at);
2666
+ const optional = isOptionalSymbol(prop) ? "?" : "";
2667
+ fields.push(`${objectKey(propName)}${optional}: ${render(propT, inner, pairedProp)}`);
2668
+ }
2669
+ const stringIndex = type.getStringIndexType();
2670
+ if (stringIndex) {
2671
+ const pairedIndex = paired?.getStringIndexType();
2672
+ const value = render(stringIndex, inner, pairedIndex);
2673
+ if (fields.length === 0) return `Record<string, ${value}>`;
2674
+ fields.push(`[key: string]: ${value}`);
2675
+ }
2676
+ return fields.length ? `{ ${fields.join("; ")} }` : "{}";
2677
+ }
2678
+ function stateAt(at) {
2679
+ return { at, stack: /* @__PURE__ */ new Set(), depth: 0 };
2680
+ }
2681
+ function requestTypeOf(types) {
2682
+ return render(types.input, stateAt(types.at), types.output);
2683
+ }
2684
+ function responseTypeOf(types) {
2685
+ return render(types.output, stateAt(types.at));
2686
+ }
2687
+ function requestFieldsOf(types) {
2688
+ const { input, output, at } = types;
2689
+ const objectInput = input.getNonNullableType();
2690
+ if (!objectInput.isObject() || objectInput.isArray() || objectInput.isTuple()) return null;
2691
+ const state = stateAt(at);
2692
+ return orderedProperties(objectInput).filter((prop) => !isSymbolKeyed(prop)).map((prop) => ({
2693
+ name: prop.getName(),
2694
+ type: render(
2695
+ prop.getTypeAtLocation(at),
2696
+ state,
2697
+ output.getProperty(prop.getName())?.getTypeAtLocation(at)
2698
+ ),
2699
+ optional: isOptionalSymbol(prop)
2700
+ }));
2701
+ }
2702
+ function acceptsUndefined(types) {
2703
+ const { input, output } = types;
2704
+ const accepted = isAnyOrUnknown(input) ? output : input;
2705
+ if (isAnyOrUnknown(accepted) || accepted.isUndefined()) return true;
2706
+ return accepted.isUnion() && accepted.getUnionTypes().some((t) => t.isUndefined());
2707
+ }
2708
+
2709
+ // src/discovery/zod-ast-to-ts.ts
2710
+ var import_ts_morph9 = require("ts-morph");
2711
+ function zodAstToTs(node) {
2712
+ if (!import_ts_morph9.Node.isCallExpression(node)) return "unknown";
2713
+ const expr = node.getExpression();
2714
+ if (import_ts_morph9.Node.isPropertyAccessExpression(expr)) {
2715
+ const methodName = expr.getName();
2716
+ const receiver = expr.getExpression();
2717
+ if (methodName === "optional") {
2718
+ return `${zodAstToTs(receiver)} | undefined`;
2719
+ }
2720
+ if (methodName === "nullable") {
2721
+ return `${zodAstToTs(receiver)} | null`;
2722
+ }
2723
+ const args = node.getArguments();
2724
+ switch (methodName) {
2725
+ case "string":
2726
+ return "string";
2727
+ case "number":
2728
+ return "number";
2729
+ case "boolean":
2730
+ return "boolean";
2731
+ case "unknown":
2732
+ return "unknown";
2733
+ case "any":
2734
+ return "unknown";
2735
+ case "literal": {
2736
+ const lit = args[0];
2737
+ if (!lit) return "unknown";
2738
+ if (import_ts_morph9.Node.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
2739
+ if (import_ts_morph9.Node.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
2740
+ if (lit.getKind() === import_ts_morph9.SyntaxKind.TrueKeyword) return "true";
2741
+ if (lit.getKind() === import_ts_morph9.SyntaxKind.FalseKeyword) return "false";
2742
+ return "unknown";
2743
+ }
2744
+ case "enum": {
2745
+ const arrArg = args[0];
2746
+ if (!arrArg || !import_ts_morph9.Node.isArrayLiteralExpression(arrArg)) return "unknown";
2747
+ const members = arrArg.getElements().map(
2748
+ (el) => import_ts_morph9.Node.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
2749
+ );
2750
+ return members.join(" | ");
2751
+ }
2752
+ case "array": {
2753
+ const inner = args[0];
2754
+ if (!inner) return "unknown";
2755
+ return `Array<${zodAstToTs(inner)}>`;
2756
+ }
2757
+ case "object": {
2758
+ const objArg = args[0];
2759
+ if (!objArg || !import_ts_morph9.Node.isObjectLiteralExpression(objArg)) return "unknown";
2760
+ const lines = [];
2761
+ for (const prop of objArg.getProperties()) {
2762
+ if (!import_ts_morph9.Node.isPropertyAssignment(prop)) continue;
2763
+ const key = prop.getName();
2764
+ const valNode = prop.getInitializer();
2765
+ if (!valNode) continue;
2766
+ const tsType = zodAstToTs(valNode);
2767
+ const isOpt = isOptionalChain(valNode);
2768
+ lines.push(`${key}${isOpt ? "?" : ""}: ${tsType}`);
2769
+ }
2770
+ return `{ ${lines.join("; ")} }`;
2771
+ }
2772
+ case "union": {
2773
+ const arrArg = args[0];
2774
+ if (!arrArg || !import_ts_morph9.Node.isArrayLiteralExpression(arrArg)) return "unknown";
2775
+ return arrArg.getElements().map(zodAstToTs).join(" | ");
2776
+ }
2777
+ case "record": {
2778
+ const valArg = args.length === 1 ? args[0] : args[1];
2779
+ if (!valArg) return "unknown";
2780
+ return `Record<string, ${zodAstToTs(valArg)}>`;
2781
+ }
2782
+ case "tuple": {
2783
+ const arrArg = args[0];
2784
+ if (!arrArg || !import_ts_morph9.Node.isArrayLiteralExpression(arrArg)) return "unknown";
2785
+ return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
2786
+ }
2787
+ default:
2788
+ return "unknown";
2789
+ }
2790
+ }
2791
+ return "unknown";
2792
+ }
2793
+ function isOptionalChain(node) {
2794
+ if (!import_ts_morph9.Node.isCallExpression(node)) return false;
2795
+ const expr = node.getExpression();
2796
+ return import_ts_morph9.Node.isPropertyAccessExpression(expr) && expr.getName() === "optional";
2797
+ }
2798
+ function memberType(val, position, project) {
2799
+ if (project) {
2800
+ const inferred = inferSchema(val, project);
2801
+ if (inferred.kind === "schema") {
2802
+ return position === "request" ? requestTypeOf(inferred.types) : responseTypeOf(inferred.types);
2803
+ }
2804
+ }
2805
+ return zodAstToTs(val);
2806
+ }
2807
+ function parseDefineContractCall(callExpr, project) {
2808
+ if (!import_ts_morph9.Node.isCallExpression(callExpr)) return null;
2809
+ const callee = callExpr.getExpression();
2810
+ const calleeName = import_ts_morph9.Node.isIdentifier(callee) ? callee.getText() : import_ts_morph9.Node.isPropertyAccessExpression(callee) ? callee.getName() : "";
2811
+ if (calleeName !== "defineContract") return null;
2812
+ const args = callExpr.getArguments();
2813
+ const optsArg = args[0];
2814
+ if (!optsArg || !import_ts_morph9.Node.isObjectLiteralExpression(optsArg)) return null;
2815
+ let query = null;
2816
+ let body = null;
2817
+ let response = "unknown";
2818
+ let error = null;
2819
+ let bodyZodText = null;
2820
+ let queryZodText = null;
2821
+ for (const prop of optsArg.getProperties()) {
2822
+ if (!import_ts_morph9.Node.isPropertyAssignment(prop)) continue;
2823
+ const propName = prop.getName();
2824
+ const val = prop.getInitializer();
2825
+ if (!val) continue;
2826
+ if (propName === "query") {
2827
+ query = memberType(val, "request", project);
2828
+ queryZodText = val.getText();
2829
+ } else if (propName === "body") {
2830
+ body = memberType(val, "request", project);
2831
+ bodyZodText = val.getText();
2832
+ } else if (propName === "response") {
2833
+ response = memberType(val, "response", project);
2834
+ } else if (propName === "error") {
2835
+ error = memberType(val, "response", project);
2836
+ }
2837
+ }
2838
+ return { query, body, response, error, bodyZodText, queryZodText };
2839
+ }
2840
+
2841
+ // src/discovery/pipe-schema.ts
2842
+ function pipeSchemaOf(decorator, project) {
2843
+ for (const pipe of decorator.getArguments()) {
2844
+ if (!import_ts_morph10.Node.isNewExpression(pipe) && !import_ts_morph10.Node.isCallExpression(pipe)) continue;
2845
+ for (const arg of pipe.getArguments()) {
2846
+ if (!couldBeSchema(arg)) continue;
2847
+ const inferred = inferSchema(arg, project);
2848
+ if (inferred.kind === "schema") {
2849
+ return {
2850
+ type: requestTypeOf(inferred.types),
2851
+ optional: acceptsUndefined(inferred.types),
2852
+ fields: requestFieldsOf(inferred.types)
2853
+ };
2854
+ }
2855
+ if (inferred.kind === "unresolved") {
2856
+ const fallback = syntacticZodType(arg, project);
2857
+ if (fallback) {
2858
+ return { type: fallback, optional: fallback.endsWith("| undefined"), fields: null };
2859
+ }
2860
+ }
2861
+ }
2862
+ }
2863
+ return null;
2864
+ }
2865
+ function couldBeSchema(arg) {
2866
+ return import_ts_morph10.Node.isIdentifier(arg) || import_ts_morph10.Node.isPropertyAccessExpression(arg) || import_ts_morph10.Node.isCallExpression(arg) || import_ts_morph10.Node.isAsExpression(arg) || import_ts_morph10.Node.isSatisfiesExpression(arg) || import_ts_morph10.Node.isParenthesizedExpression(arg);
2867
+ }
2868
+ function syntacticZodType(arg, project) {
2869
+ let expr = arg;
2870
+ if (import_ts_morph10.Node.isIdentifier(arg)) {
2871
+ const resolved = resolveImportedVariable(arg.getText(), arg.getSourceFile(), project);
2872
+ expr = resolved?.decl.getInitializer();
2873
+ }
2874
+ if (!expr || !import_ts_morph10.Node.isCallExpression(expr)) return null;
2875
+ const type = zodAstToTs(expr);
2876
+ return type === "unknown" ? null : type;
2877
+ }
2878
+
2124
2879
  // src/discovery/dto-type-resolver.ts
2125
2880
  var WRAPPER_TYPES = {
2126
2881
  // MikroORM Ref/Reference/LoadedReference/IdentifiedReference are server-side
@@ -2152,22 +2907,22 @@ var PASSTHROUGH_UTILITY = /* @__PURE__ */ new Set([
2152
2907
  ]);
2153
2908
  function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /* @__PURE__ */ new Map()) {
2154
2909
  if (depth <= 0) return "unknown";
2155
- if (import_ts_morph7.Node.isArrayTypeNode(typeNode)) {
2910
+ if (import_ts_morph11.Node.isArrayTypeNode(typeNode)) {
2156
2911
  const elementType = typeNode.getElementTypeNode();
2157
2912
  return `Array<${resolveTypeNodeToString(elementType, sourceFile, project, depth, subst)}>`;
2158
2913
  }
2159
- if (import_ts_morph7.Node.isUnionTypeNode(typeNode)) {
2914
+ if (import_ts_morph11.Node.isUnionTypeNode(typeNode)) {
2160
2915
  return typeNode.getTypeNodes().map((t) => resolveTypeNodeToString(t, sourceFile, project, depth, subst)).join(" | ");
2161
2916
  }
2162
- if (import_ts_morph7.Node.isIntersectionTypeNode(typeNode)) {
2917
+ if (import_ts_morph11.Node.isIntersectionTypeNode(typeNode)) {
2163
2918
  return typeNode.getTypeNodes().map((t) => resolveTypeNodeToString(t, sourceFile, project, depth, subst)).join(" & ");
2164
2919
  }
2165
- if (import_ts_morph7.Node.isParenthesizedTypeNode(typeNode)) {
2920
+ if (import_ts_morph11.Node.isParenthesizedTypeNode(typeNode)) {
2166
2921
  return `(${resolveTypeNodeToString(typeNode.getTypeNode(), sourceFile, project, depth, subst)})`;
2167
2922
  }
2168
- if (import_ts_morph7.Node.isTypeReference(typeNode)) {
2923
+ if (import_ts_morph11.Node.isTypeReference(typeNode)) {
2169
2924
  const typeName = typeNode.getTypeName();
2170
- const name = import_ts_morph7.Node.isIdentifier(typeName) ? typeName.getText() : typeNode.getText();
2925
+ const name = import_ts_morph11.Node.isIdentifier(typeName) ? typeName.getText() : typeNode.getText();
2171
2926
  const bound = subst.get(name);
2172
2927
  if (bound !== void 0) return bound;
2173
2928
  if (name === "string" || name === "number" || name === "boolean") return name;
@@ -2190,13 +2945,13 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /
2190
2945
  dbg("unresolvable type:", name, "in", sourceFile.getFilePath());
2191
2946
  return "unknown";
2192
2947
  }
2193
- if (import_ts_morph7.Node.isTypeLiteral(typeNode)) {
2948
+ if (import_ts_morph11.Node.isTypeLiteral(typeNode)) {
2194
2949
  const members = [];
2195
2950
  for (const member of typeNode.getMembers()) {
2196
- if (import_ts_morph7.Node.isPropertySignature(member)) {
2951
+ if (import_ts_morph11.Node.isPropertySignature(member)) {
2197
2952
  const memberTypeNode = member.getTypeNode();
2198
- const memberType = memberTypeNode ? resolveTypeNodeToString(memberTypeNode, sourceFile, project, depth, subst) : "unknown";
2199
- members.push(`${member.getName()}${member.hasQuestionToken() ? "?" : ""}: ${memberType}`);
2953
+ const memberType2 = memberTypeNode ? resolveTypeNodeToString(memberTypeNode, sourceFile, project, depth, subst) : "unknown";
2954
+ members.push(`${member.getName()}${member.hasQuestionToken() ? "?" : ""}: ${memberType2}`);
2200
2955
  } else {
2201
2956
  members.push(member.getText());
2202
2957
  }
@@ -2204,11 +2959,11 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /
2204
2959
  return members.length > 0 ? `{ ${members.join("; ")} }` : "{}";
2205
2960
  }
2206
2961
  const kind = typeNode.getKind();
2207
- if (kind === import_ts_morph7.SyntaxKind.StringKeyword) return "string";
2208
- if (kind === import_ts_morph7.SyntaxKind.NumberKeyword) return "number";
2209
- if (kind === import_ts_morph7.SyntaxKind.BooleanKeyword) return "boolean";
2210
- if (kind === import_ts_morph7.SyntaxKind.UnknownKeyword) return "unknown";
2211
- if (kind === import_ts_morph7.SyntaxKind.AnyKeyword) return "unknown";
2962
+ if (kind === import_ts_morph11.SyntaxKind.StringKeyword) return "string";
2963
+ if (kind === import_ts_morph11.SyntaxKind.NumberKeyword) return "number";
2964
+ if (kind === import_ts_morph11.SyntaxKind.BooleanKeyword) return "boolean";
2965
+ if (kind === import_ts_morph11.SyntaxKind.UnknownKeyword) return "unknown";
2966
+ if (kind === import_ts_morph11.SyntaxKind.AnyKeyword) return "unknown";
2212
2967
  return typeNode.getText();
2213
2968
  }
2214
2969
  function unwrapFirstTypeArg(typeNode, sourceFile, project, depth, mode, subst = /* @__PURE__ */ new Map()) {
@@ -2256,20 +3011,24 @@ function resolvePropertied(decl, sourceFile, project, depth, subst = /* @__PURE_
2256
3011
  const propName = prop.getName();
2257
3012
  const isOptional = prop.hasQuestionToken();
2258
3013
  const propTypeNode = prop.getTypeNode();
2259
- let propType = "unknown";
3014
+ let propType2 = "unknown";
2260
3015
  if (propTypeNode) {
2261
- propType = resolveTypeNodeToString(propTypeNode, sourceFile, project, depth, subst);
3016
+ propType2 = resolveTypeNodeToString(propTypeNode, sourceFile, project, depth, subst);
2262
3017
  }
2263
- lines.push(`${propName}${isOptional ? "?" : ""}: ${propType}`);
3018
+ lines.push(`${propName}${isOptional ? "?" : ""}: ${propType2}`);
2264
3019
  }
2265
3020
  return `{ ${lines.join("; ")} }`;
2266
3021
  }
3022
+ function namedField(decorator) {
3023
+ const first = decorator.getArguments()[0];
3024
+ return first && import_ts_morph11.Node.isStringLiteral(first) ? first.getLiteralValue() : null;
3025
+ }
2267
3026
  function extractBodyType(method, sourceFile, project) {
2268
3027
  for (const param of method.getParameters()) {
2269
3028
  const bodyDecorator = param.getDecorators().find((d) => d.getName() === "Body");
2270
- if (!bodyDecorator) continue;
2271
- const bodyArgs = bodyDecorator.getArguments();
2272
- if (bodyArgs.length > 0) continue;
3029
+ if (!bodyDecorator || namedField(bodyDecorator) !== null) continue;
3030
+ const piped = pipeSchemaOf(bodyDecorator, project);
3031
+ if (piped) return piped.type;
2273
3032
  const typeNode = param.getTypeNode();
2274
3033
  if (typeNode) {
2275
3034
  return resolveTypeNodeToString(typeNode, sourceFile, project, 3);
@@ -2277,11 +3036,16 @@ function extractBodyType(method, sourceFile, project) {
2277
3036
  }
2278
3037
  return null;
2279
3038
  }
3039
+ function hasPipeSchema(param, decoratorName, project) {
3040
+ const decorator = param.getDecorators().find((d) => d.getName() === decoratorName);
3041
+ return !!decorator && pipeSchemaOf(decorator, project) !== null;
3042
+ }
2280
3043
  function extractQueryType(method, sourceFile, project) {
2281
3044
  for (const param of method.getParameters()) {
2282
3045
  const queryDecorator = param.getDecorators().find((d) => d.getName() === "Query");
2283
- if (!queryDecorator) continue;
2284
- if (queryDecorator.getArguments().length > 0) continue;
3046
+ if (!queryDecorator || namedField(queryDecorator) !== null) continue;
3047
+ const piped = pipeSchemaOf(queryDecorator, project);
3048
+ if (piped) return piped.type;
2285
3049
  const typeNode = param.getTypeNode();
2286
3050
  if (typeNode) {
2287
3051
  return resolveTypeNodeToString(typeNode, sourceFile, project, 3);
@@ -2291,10 +3055,13 @@ function extractQueryType(method, sourceFile, project) {
2291
3055
  for (const param of method.getParameters()) {
2292
3056
  const queryDecorator = param.getDecorators().find((d) => d.getName() === "Query");
2293
3057
  if (!queryDecorator) continue;
2294
- const queryArgs = queryDecorator.getArguments();
2295
- const nameArg = queryArgs[0];
2296
- if (!nameArg || !import_ts_morph7.Node.isStringLiteral(nameArg)) continue;
2297
- const queryName = nameArg.getLiteralValue();
3058
+ const queryName = namedField(queryDecorator);
3059
+ if (queryName === null) continue;
3060
+ const piped = pipeSchemaOf(queryDecorator, project);
3061
+ if (piped) {
3062
+ entries.push(`${queryName}${piped.optional ? "?" : ""}: ${piped.type}`);
3063
+ continue;
3064
+ }
2298
3065
  const typeNode = param.getTypeNode();
2299
3066
  const queryType = typeNode ? resolveTypeNodeToString(typeNode, sourceFile, project, 3) : "string";
2300
3067
  entries.push(`${queryName}${isParamOptional(param) ? "?" : ""}: ${queryType}`);
@@ -2304,8 +3071,8 @@ function extractQueryType(method, sourceFile, project) {
2304
3071
  function isParamOptional(param) {
2305
3072
  if (param.hasQuestionToken() || param.hasInitializer()) return true;
2306
3073
  const typeNode = param.getTypeNode();
2307
- if (typeNode && import_ts_morph7.Node.isUnionTypeNode(typeNode)) {
2308
- return typeNode.getTypeNodes().some((t) => t.getKind() === import_ts_morph7.SyntaxKind.UndefinedKeyword);
3074
+ if (typeNode && import_ts_morph11.Node.isUnionTypeNode(typeNode)) {
3075
+ return typeNode.getTypeNodes().some((t) => t.getKind() === import_ts_morph11.SyntaxKind.UndefinedKeyword);
2309
3076
  }
2310
3077
  return false;
2311
3078
  }
@@ -2317,7 +3084,7 @@ function extractParamsType(method, sourceFile, project) {
2317
3084
  const paramArgs = paramDecorator.getArguments();
2318
3085
  if (paramArgs.length === 0) continue;
2319
3086
  const nameArg = paramArgs[0];
2320
- if (!import_ts_morph7.Node.isStringLiteral(nameArg)) continue;
3087
+ if (!import_ts_morph11.Node.isStringLiteral(nameArg)) continue;
2321
3088
  const paramName = nameArg.getLiteralValue();
2322
3089
  const typeNode = param.getTypeNode();
2323
3090
  const paramType = typeNode ? resolveTypeNodeToString(typeNode, sourceFile, project, 3) : "string";
@@ -2325,6 +3092,22 @@ function extractParamsType(method, sourceFile, project) {
2325
3092
  }
2326
3093
  return entries.length > 0 ? `{ ${entries.join("; ")} }` : null;
2327
3094
  }
3095
+ function extractPipedParamTypes(method, project) {
3096
+ const types = {};
3097
+ for (const param of method.getParameters()) {
3098
+ const paramDecorator = param.getDecorators().find((d) => d.getName() === "Param");
3099
+ if (!paramDecorator) continue;
3100
+ const piped = pipeSchemaOf(paramDecorator, project);
3101
+ if (!piped) continue;
3102
+ const name = namedField(paramDecorator);
3103
+ if (name !== null) {
3104
+ types[name] = piped.type;
3105
+ } else {
3106
+ for (const field of piped.fields ?? []) types[field.name] = field.type;
3107
+ }
3108
+ }
3109
+ return Object.keys(types).length > 0 ? types : null;
3110
+ }
2328
3111
  function extractUploadedFiles(method) {
2329
3112
  const FILE = "File | Blob";
2330
3113
  const entries = [];
@@ -2338,28 +3121,28 @@ function extractUploadedFiles(method) {
2338
3121
  for (const decorator of method.getDecorators()) {
2339
3122
  if (decorator.getName() !== "UseInterceptors") continue;
2340
3123
  for (const arg of decorator.getArguments()) {
2341
- if (!import_ts_morph7.Node.isCallExpression(arg)) continue;
3124
+ if (!import_ts_morph11.Node.isCallExpression(arg)) continue;
2342
3125
  const interceptor = arg.getExpression().getText();
2343
3126
  const callArgs = arg.getArguments();
2344
3127
  const firstArg2 = callArgs[0];
2345
3128
  if (interceptor === "FileInterceptor") {
2346
- if (firstArg2 && import_ts_morph7.Node.isStringLiteral(firstArg2)) {
3129
+ if (firstArg2 && import_ts_morph11.Node.isStringLiteral(firstArg2)) {
2347
3130
  entries.push(`${firstArg2.getLiteralValue()}: ${FILE}`);
2348
3131
  multipart = true;
2349
3132
  }
2350
3133
  } else if (interceptor === "FilesInterceptor") {
2351
- if (firstArg2 && import_ts_morph7.Node.isStringLiteral(firstArg2)) {
3134
+ if (firstArg2 && import_ts_morph11.Node.isStringLiteral(firstArg2)) {
2352
3135
  entries.push(`${firstArg2.getLiteralValue()}: Array<${FILE}>`);
2353
3136
  multipart = true;
2354
3137
  }
2355
3138
  } else if (interceptor === "FileFieldsInterceptor") {
2356
- if (firstArg2 && import_ts_morph7.Node.isArrayLiteralExpression(firstArg2)) {
3139
+ if (firstArg2 && import_ts_morph11.Node.isArrayLiteralExpression(firstArg2)) {
2357
3140
  for (const el of firstArg2.getElements()) {
2358
- if (!import_ts_morph7.Node.isObjectLiteralExpression(el)) continue;
3141
+ if (!import_ts_morph11.Node.isObjectLiteralExpression(el)) continue;
2359
3142
  const nameProp = el.getProperty("name");
2360
- if (nameProp && import_ts_morph7.Node.isPropertyAssignment(nameProp)) {
3143
+ if (nameProp && import_ts_morph11.Node.isPropertyAssignment(nameProp)) {
2361
3144
  const init = nameProp.getInitializer();
2362
- if (init && import_ts_morph7.Node.isStringLiteral(init)) {
3145
+ if (init && import_ts_morph11.Node.isStringLiteral(init)) {
2363
3146
  entries.push(`${init.getLiteralValue()}: Array<${FILE}>`);
2364
3147
  }
2365
3148
  }
@@ -2379,13 +3162,13 @@ function extractResponseType(method, sourceFile, project) {
2379
3162
  if (apiResponseDecorator) {
2380
3163
  const args = apiResponseDecorator.getArguments();
2381
3164
  const optsArg = args[0];
2382
- if (optsArg && import_ts_morph7.Node.isObjectLiteralExpression(optsArg)) {
3165
+ if (optsArg && import_ts_morph11.Node.isObjectLiteralExpression(optsArg)) {
2383
3166
  for (const prop of optsArg.getProperties()) {
2384
- if (!import_ts_morph7.Node.isPropertyAssignment(prop)) continue;
3167
+ if (!import_ts_morph11.Node.isPropertyAssignment(prop)) continue;
2385
3168
  if (prop.getName() !== "type") continue;
2386
3169
  const val = prop.getInitializer();
2387
3170
  if (!val) continue;
2388
- if (import_ts_morph7.Node.isArrayLiteralExpression(val)) {
3171
+ if (import_ts_morph11.Node.isArrayLiteralExpression(val)) {
2389
3172
  const elements = val.getElements();
2390
3173
  const firstEl = elements[0];
2391
3174
  if (elements.length > 0 && firstEl !== void 0) {
@@ -2406,24 +3189,24 @@ function extractResponseType(method, sourceFile, project) {
2406
3189
  }
2407
3190
  function apiResponseStatus(decorator) {
2408
3191
  const optsArg = decorator.getArguments()[0];
2409
- if (!optsArg || !import_ts_morph7.Node.isObjectLiteralExpression(optsArg)) return null;
3192
+ if (!optsArg || !import_ts_morph11.Node.isObjectLiteralExpression(optsArg)) return null;
2410
3193
  for (const prop of optsArg.getProperties()) {
2411
- if (!import_ts_morph7.Node.isPropertyAssignment(prop)) continue;
3194
+ if (!import_ts_morph11.Node.isPropertyAssignment(prop)) continue;
2412
3195
  if (prop.getName() !== "status") continue;
2413
3196
  const val = prop.getInitializer();
2414
- if (val && import_ts_morph7.Node.isNumericLiteral(val)) return Number(val.getLiteralValue());
3197
+ if (val && import_ts_morph11.Node.isNumericLiteral(val)) return Number(val.getLiteralValue());
2415
3198
  }
2416
3199
  return null;
2417
3200
  }
2418
3201
  function apiResponseTypeNode(decorator) {
2419
3202
  const optsArg = decorator.getArguments()[0];
2420
- if (!optsArg || !import_ts_morph7.Node.isObjectLiteralExpression(optsArg)) return null;
3203
+ if (!optsArg || !import_ts_morph11.Node.isObjectLiteralExpression(optsArg)) return null;
2421
3204
  for (const prop of optsArg.getProperties()) {
2422
- if (!import_ts_morph7.Node.isPropertyAssignment(prop)) continue;
3205
+ if (!import_ts_morph11.Node.isPropertyAssignment(prop)) continue;
2423
3206
  if (prop.getName() !== "type") continue;
2424
3207
  const val = prop.getInitializer();
2425
3208
  if (!val) return null;
2426
- if (import_ts_morph7.Node.isArrayLiteralExpression(val)) {
3209
+ if (import_ts_morph11.Node.isArrayLiteralExpression(val)) {
2427
3210
  const first = val.getElements()[0];
2428
3211
  return first ? { node: first, isArray: true } : null;
2429
3212
  }
@@ -2441,7 +3224,7 @@ function extractErrorType(method, sourceFile, project) {
2441
3224
  const inner = resolveIdentifierToClassType(typeInfo.node, sourceFile, project, 3);
2442
3225
  const type = typeInfo.isArray ? `Array<${inner}>` : inner;
2443
3226
  let ref = null;
2444
- if (import_ts_morph7.Node.isIdentifier(typeInfo.node)) {
3227
+ if (import_ts_morph11.Node.isIdentifier(typeInfo.node)) {
2445
3228
  const name = typeInfo.node.getText();
2446
3229
  const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
2447
3230
  if (localDecl?.isExported()) {
@@ -2458,7 +3241,7 @@ function extractErrorType(method, sourceFile, project) {
2458
3241
  return null;
2459
3242
  }
2460
3243
  function resolveIdentifierToClassType(node, sourceFile, project, depth) {
2461
- if (!import_ts_morph7.Node.isIdentifier(node)) return "unknown";
3244
+ if (!import_ts_morph11.Node.isIdentifier(node)) return "unknown";
2462
3245
  const name = node.getText();
2463
3246
  const resolved = findType(name, sourceFile, project);
2464
3247
  if (resolved) {
@@ -2478,9 +3261,9 @@ var STREAM_ENVELOPES = /* @__PURE__ */ new Set(["MessageEvent", "MessageEventLik
2478
3261
  var BINARY_RESPONSE_TYPES = /* @__PURE__ */ new Set(["StreamableFile", "Buffer"]);
2479
3262
  function detectBinaryResponse(method) {
2480
3263
  const node = unwrapNamedContainer(method.getReturnTypeNode(), /* @__PURE__ */ new Set(["Promise"]));
2481
- if (!node || !import_ts_morph7.Node.isTypeReference(node)) return false;
3264
+ if (!node || !import_ts_morph11.Node.isTypeReference(node)) return false;
2482
3265
  const typeName = node.getTypeName();
2483
- const name = import_ts_morph7.Node.isIdentifier(typeName) ? typeName.getText() : "";
3266
+ const name = import_ts_morph11.Node.isIdentifier(typeName) ? typeName.getText() : "";
2484
3267
  return BINARY_RESPONSE_TYPES.has(name);
2485
3268
  }
2486
3269
  function detectStreamElement(method) {
@@ -2495,9 +3278,9 @@ function detectStreamElement(method) {
2495
3278
  return null;
2496
3279
  }
2497
3280
  function streamContainerElement(node) {
2498
- if (!node || !import_ts_morph7.Node.isTypeReference(node)) return null;
3281
+ if (!node || !import_ts_morph11.Node.isTypeReference(node)) return null;
2499
3282
  const typeName = node.getTypeName();
2500
- const name = import_ts_morph7.Node.isIdentifier(typeName) ? typeName.getText() : "";
3283
+ const name = import_ts_morph11.Node.isIdentifier(typeName) ? typeName.getText() : "";
2501
3284
  if (STREAM_CONTAINERS.has(name) || STREAM_CONTAINERS_GENERATOR.has(name)) {
2502
3285
  return node.getTypeArguments()[0] ?? null;
2503
3286
  }
@@ -2507,9 +3290,9 @@ function hasAsQueryDecorator(method) {
2507
3290
  return method.getDecorators().some((d) => d.getName() === "AsQuery");
2508
3291
  }
2509
3292
  function unwrapNamedContainer(node, names) {
2510
- if (!node || !import_ts_morph7.Node.isTypeReference(node)) return node;
3293
+ if (!node || !import_ts_morph11.Node.isTypeReference(node)) return node;
2511
3294
  const typeName = node.getTypeName();
2512
- const name = import_ts_morph7.Node.isIdentifier(typeName) ? typeName.getText() : "";
3295
+ const name = import_ts_morph11.Node.isIdentifier(typeName) ? typeName.getText() : "";
2513
3296
  if (names.has(name)) {
2514
3297
  return node.getTypeArguments()[0] ?? node;
2515
3298
  }
@@ -2530,19 +3313,20 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2530
3313
  body = body ?? bodyType;
2531
3314
  }
2532
3315
  const paramsType = extractParamsType(method, sourceFile, project);
3316
+ const paramTypes = extractPipedParamTypes(method, project);
2533
3317
  const response = isStream ? resolveTypeNodeToString(streamElement, sourceFile, project, 3) : extractResponseType(method, sourceFile, project);
2534
3318
  const errorInfo = extractErrorType(method, sourceFile, project);
2535
- if (body === null && query === null && paramsType === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream && !uploads.multipart && !binaryResponse && !asQuery) {
3319
+ if (body === null && query === null && paramsType === null && paramTypes === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream && !uploads.multipart && !binaryResponse && !asQuery) {
2536
3320
  return null;
2537
3321
  }
2538
3322
  let bodyRef = null;
2539
3323
  let queryRef = null;
2540
3324
  let responseRef = null;
2541
3325
  for (const param of method.getParameters()) {
2542
- if (param.getDecorators().some((d) => d.getName() === "Body") && param.getTypeNode()) {
3326
+ if (param.getDecorators().some((d) => d.getName() === "Body") && param.getTypeNode() && !hasPipeSchema(param, "Body", project)) {
2543
3327
  bodyRef = resolveBodyQueryResponseRef(param.getTypeNode(), sourceFile, project);
2544
3328
  }
2545
- if (param.getDecorators().some((d) => d.getName() === "Query") && param.getTypeNode()) {
3329
+ if (param.getDecorators().some((d) => d.getName() === "Query") && param.getTypeNode() && !hasPipeSchema(param, "Query", project)) {
2546
3330
  queryRef = resolveBodyQueryResponseRef(param.getTypeNode(), sourceFile, project);
2547
3331
  }
2548
3332
  }
@@ -2555,11 +3339,11 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2555
3339
  if (apiResp) {
2556
3340
  const args = apiResp.getArguments();
2557
3341
  const optsArg = args[0];
2558
- if (optsArg && import_ts_morph7.Node.isObjectLiteralExpression(optsArg)) {
3342
+ if (optsArg && import_ts_morph11.Node.isObjectLiteralExpression(optsArg)) {
2559
3343
  for (const prop of optsArg.getProperties()) {
2560
- if (import_ts_morph7.Node.isPropertyAssignment(prop) && prop.getName() === "type") {
3344
+ if (import_ts_morph11.Node.isPropertyAssignment(prop) && prop.getName() === "type") {
2561
3345
  const val = prop.getInitializer();
2562
- if (val && import_ts_morph7.Node.isIdentifier(val)) {
3346
+ if (val && import_ts_morph11.Node.isIdentifier(val)) {
2563
3347
  const name = val.getText();
2564
3348
  const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
2565
3349
  if (localDecl?.isExported()) {
@@ -2595,6 +3379,7 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2595
3379
  response,
2596
3380
  error: errorInfo?.type ?? null,
2597
3381
  params: paramsType,
3382
+ paramTypes,
2598
3383
  queryRef,
2599
3384
  bodyRef,
2600
3385
  responseRef,
@@ -2615,6 +3400,7 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2615
3400
  function resolveParamClass(method, decoratorName, sourceFile, project) {
2616
3401
  for (const param of method.getParameters()) {
2617
3402
  if (!param.getDecorators().some((d) => d.getName() === decoratorName)) continue;
3403
+ if (hasPipeSchema(param, decoratorName, project)) continue;
2618
3404
  const typeNode = param.getTypeNode();
2619
3405
  if (!typeNode) continue;
2620
3406
  const text = typeNode.getText().replace(/\[\]$/, "");
@@ -2627,129 +3413,6 @@ function resolveParamClass(method, decoratorName, sourceFile, project) {
2627
3413
  return null;
2628
3414
  }
2629
3415
 
2630
- // src/discovery/zod-ast-to-ts.ts
2631
- var import_ts_morph8 = require("ts-morph");
2632
- function zodAstToTs(node) {
2633
- if (!import_ts_morph8.Node.isCallExpression(node)) return "unknown";
2634
- const expr = node.getExpression();
2635
- if (import_ts_morph8.Node.isPropertyAccessExpression(expr)) {
2636
- const methodName = expr.getName();
2637
- const receiver = expr.getExpression();
2638
- if (methodName === "optional") {
2639
- return `${zodAstToTs(receiver)} | undefined`;
2640
- }
2641
- if (methodName === "nullable") {
2642
- return `${zodAstToTs(receiver)} | null`;
2643
- }
2644
- const args = node.getArguments();
2645
- switch (methodName) {
2646
- case "string":
2647
- return "string";
2648
- case "number":
2649
- return "number";
2650
- case "boolean":
2651
- return "boolean";
2652
- case "unknown":
2653
- return "unknown";
2654
- case "any":
2655
- return "unknown";
2656
- case "literal": {
2657
- const lit = args[0];
2658
- if (!lit) return "unknown";
2659
- if (import_ts_morph8.Node.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
2660
- if (import_ts_morph8.Node.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
2661
- if (lit.getKind() === import_ts_morph8.SyntaxKind.TrueKeyword) return "true";
2662
- if (lit.getKind() === import_ts_morph8.SyntaxKind.FalseKeyword) return "false";
2663
- return "unknown";
2664
- }
2665
- case "enum": {
2666
- const arrArg = args[0];
2667
- if (!arrArg || !import_ts_morph8.Node.isArrayLiteralExpression(arrArg)) return "unknown";
2668
- const members = arrArg.getElements().map(
2669
- (el) => import_ts_morph8.Node.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
2670
- );
2671
- return members.join(" | ");
2672
- }
2673
- case "array": {
2674
- const inner = args[0];
2675
- if (!inner) return "unknown";
2676
- return `Array<${zodAstToTs(inner)}>`;
2677
- }
2678
- case "object": {
2679
- const objArg = args[0];
2680
- if (!objArg || !import_ts_morph8.Node.isObjectLiteralExpression(objArg)) return "unknown";
2681
- const lines = [];
2682
- for (const prop of objArg.getProperties()) {
2683
- if (!import_ts_morph8.Node.isPropertyAssignment(prop)) continue;
2684
- const key = prop.getName();
2685
- const valNode = prop.getInitializer();
2686
- if (!valNode) continue;
2687
- const tsType = zodAstToTs(valNode);
2688
- const isOpt = isOptionalChain(valNode);
2689
- lines.push(`${key}${isOpt ? "?" : ""}: ${tsType}`);
2690
- }
2691
- return `{ ${lines.join("; ")} }`;
2692
- }
2693
- case "union": {
2694
- const arrArg = args[0];
2695
- if (!arrArg || !import_ts_morph8.Node.isArrayLiteralExpression(arrArg)) return "unknown";
2696
- return arrArg.getElements().map(zodAstToTs).join(" | ");
2697
- }
2698
- case "record": {
2699
- const valArg = args.length === 1 ? args[0] : args[1];
2700
- if (!valArg) return "unknown";
2701
- return `Record<string, ${zodAstToTs(valArg)}>`;
2702
- }
2703
- case "tuple": {
2704
- const arrArg = args[0];
2705
- if (!arrArg || !import_ts_morph8.Node.isArrayLiteralExpression(arrArg)) return "unknown";
2706
- return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
2707
- }
2708
- default:
2709
- return "unknown";
2710
- }
2711
- }
2712
- return "unknown";
2713
- }
2714
- function isOptionalChain(node) {
2715
- if (!import_ts_morph8.Node.isCallExpression(node)) return false;
2716
- const expr = node.getExpression();
2717
- return import_ts_morph8.Node.isPropertyAccessExpression(expr) && expr.getName() === "optional";
2718
- }
2719
- function parseDefineContractCall(callExpr) {
2720
- if (!import_ts_morph8.Node.isCallExpression(callExpr)) return null;
2721
- const callee = callExpr.getExpression();
2722
- const calleeName = import_ts_morph8.Node.isIdentifier(callee) ? callee.getText() : import_ts_morph8.Node.isPropertyAccessExpression(callee) ? callee.getName() : "";
2723
- if (calleeName !== "defineContract") return null;
2724
- const args = callExpr.getArguments();
2725
- const optsArg = args[0];
2726
- if (!optsArg || !import_ts_morph8.Node.isObjectLiteralExpression(optsArg)) return null;
2727
- let query = null;
2728
- let body = null;
2729
- let response = "unknown";
2730
- let error = null;
2731
- let bodyZodText = null;
2732
- let queryZodText = null;
2733
- for (const prop of optsArg.getProperties()) {
2734
- if (!import_ts_morph8.Node.isPropertyAssignment(prop)) continue;
2735
- const propName = prop.getName();
2736
- const val = prop.getInitializer();
2737
- if (!val) continue;
2738
- if (propName === "query") {
2739
- query = zodAstToTs(val);
2740
- queryZodText = val.getText();
2741
- } else if (propName === "body") {
2742
- body = zodAstToTs(val);
2743
- bodyZodText = val.getText();
2744
- } else if (propName === "response") {
2745
- response = zodAstToTs(val);
2746
- } else if (propName === "error") {
2747
- error = zodAstToTs(val);
2748
- }
2749
- }
2750
- return { query, body, response, error, bodyZodText, queryZodText };
2751
- }
2752
-
2753
3416
  // src/discovery/contracts-fast.ts
2754
3417
  async function discoverContractsFast(opts) {
2755
3418
  const { cwd, glob, tsconfig } = opts;
@@ -2762,7 +3425,9 @@ async function discoverContractsFast(opts) {
2762
3425
  }
2763
3426
  bindDiscoveryContext(project, cwd, tsconfigPath, loaded);
2764
3427
  clearMixinTypeProject();
2765
- return extractAllRoutes(project);
3428
+ const routes = extractAllRoutes(project);
3429
+ clearSchemaTypeProject(project);
3430
+ return routes;
2766
3431
  }
2767
3432
  function resolveTsconfigPath(cwd, tsconfig) {
2768
3433
  return tsconfig ? (0, import_node_path5.resolve)(tsconfig) : (0, import_node_path5.join)(cwd, "tsconfig.json");
@@ -2774,25 +3439,25 @@ var NO_TSCONFIG_OPTIONS = {
2774
3439
  };
2775
3440
  function loadDiscoveryTsconfig(tsconfigPath) {
2776
3441
  if (!(0, import_node_fs.existsSync)(tsconfigPath)) return { options: null, files: [] };
2777
- const read = import_ts_morph9.ts.readConfigFile(tsconfigPath, (path) => import_ts_morph9.ts.sys.readFile(path));
3442
+ const read = import_ts_morph12.ts.readConfigFile(tsconfigPath, (path) => import_ts_morph12.ts.sys.readFile(path));
2778
3443
  if (read.error) {
2779
3444
  return {
2780
3445
  options: null,
2781
3446
  files: [tsconfigPath],
2782
- error: import_ts_morph9.ts.flattenDiagnosticMessageText(read.error.messageText, " ")
3447
+ error: import_ts_morph12.ts.flattenDiagnosticMessageText(read.error.messageText, " ")
2783
3448
  };
2784
3449
  }
2785
3450
  const host = {
2786
- useCaseSensitiveFileNames: import_ts_morph9.ts.sys.useCaseSensitiveFileNames,
3451
+ useCaseSensitiveFileNames: import_ts_morph12.ts.sys.useCaseSensitiveFileNames,
2787
3452
  // The one line that keeps a tsconfig from being a filesystem walk.
2788
3453
  readDirectory: () => [],
2789
- fileExists: (path) => import_ts_morph9.ts.sys.fileExists(path),
3454
+ fileExists: (path) => import_ts_morph12.ts.sys.fileExists(path),
2790
3455
  // `extends` is resolved through the host, so a consumer whose `paths` live
2791
3456
  // in a base tsconfig keeps working.
2792
- readFile: (path) => import_ts_morph9.ts.sys.readFile(path)
3457
+ readFile: (path) => import_ts_morph12.ts.sys.readFile(path)
2793
3458
  };
2794
- const sourceFile = import_ts_morph9.ts.readJsonConfigFile(tsconfigPath, (path) => import_ts_morph9.ts.sys.readFile(path));
2795
- const parsed = import_ts_morph9.ts.parseJsonSourceFileConfigFileContent(
3459
+ const sourceFile = import_ts_morph12.ts.readJsonConfigFile(tsconfigPath, (path) => import_ts_morph12.ts.sys.readFile(path));
3460
+ const parsed = import_ts_morph12.ts.parseJsonSourceFileConfigFileContent(
2796
3461
  sourceFile,
2797
3462
  host,
2798
3463
  (0, import_node_path5.dirname)(tsconfigPath),
@@ -2815,7 +3480,7 @@ function createDiscoveryProject(tsconfigPath, tsconfig = loadDiscoveryTsconfig(t
2815
3480
  `[nestjs-codegen/fast] Could not load ${tsconfigPath}: ${tsconfig.error} \u2014 continuing WITHOUT its compiler options, so path alias imports (e.g. '@/...') will not resolve and controllers extending an alias-imported factory will contribute NO routes to the generated client.`
2816
3481
  );
2817
3482
  }
2818
- return new import_ts_morph9.Project({
3483
+ return new import_ts_morph12.Project({
2819
3484
  compilerOptions: tsconfig.options ?? { ...NO_TSCONFIG_OPTIONS },
2820
3485
  skipAddingFilesFromTsConfig: true,
2821
3486
  skipLoadingLibFiles: true,
@@ -2927,15 +3592,16 @@ var PersistentDiscovery = class _PersistentDiscovery {
2927
3592
  clearTypeResolutionCaches(this.project);
2928
3593
  clearEnumCache(this.project);
2929
3594
  clearMixinTypeProject();
3595
+ clearSchemaTypeProject(this.project);
2930
3596
  return extractRoutesFrom(this.project, this.controllerPaths);
2931
3597
  }
2932
3598
  };
2933
3599
  function decoratorStringArg(decoratorExpr) {
2934
3600
  if (!decoratorExpr) return void 0;
2935
- if (import_ts_morph9.Node.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
2936
- if (import_ts_morph9.Node.isArrayLiteralExpression(decoratorExpr)) {
3601
+ if (import_ts_morph12.Node.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
3602
+ if (import_ts_morph12.Node.isArrayLiteralExpression(decoratorExpr)) {
2937
3603
  const first = decoratorExpr.getElements()[0];
2938
- if (first && import_ts_morph9.Node.isStringLiteral(first)) return first.getLiteralValue();
3604
+ if (first && import_ts_morph12.Node.isStringLiteral(first)) return first.getLiteralValue();
2939
3605
  }
2940
3606
  return void 0;
2941
3607
  }
@@ -3056,9 +3722,9 @@ function extractContractRoute(args) {
3056
3722
  let contractDef = null;
3057
3723
  let bodyZodRef = null;
3058
3724
  let queryZodRef = null;
3059
- if (import_ts_morph9.Node.isCallExpression(firstDecoratorArg)) {
3060
- contractDef = parseDefineContractCall(firstDecoratorArg);
3061
- } else if (import_ts_morph9.Node.isIdentifier(firstDecoratorArg)) {
3725
+ if (import_ts_morph12.Node.isCallExpression(firstDecoratorArg)) {
3726
+ contractDef = parseDefineContractCall(firstDecoratorArg, project);
3727
+ } else if (import_ts_morph12.Node.isIdentifier(firstDecoratorArg)) {
3062
3728
  const identName = firstDecoratorArg.getText();
3063
3729
  const resolvedVar = resolveImportedVariable(identName, sourceFile, project);
3064
3730
  if (!resolvedVar) {
@@ -3070,7 +3736,7 @@ function extractContractRoute(args) {
3070
3736
  const { decl: varDecl, file: declFile } = resolvedVar;
3071
3737
  const initializer = varDecl.getInitializer();
3072
3738
  if (!initializer) return null;
3073
- contractDef = parseDefineContractCall(initializer);
3739
+ contractDef = parseDefineContractCall(initializer, project);
3074
3740
  if (contractDef && varDecl.isExported()) {
3075
3741
  const filePath = declFile.getFilePath();
3076
3742
  if (contractDef.body !== null) {
@@ -3141,6 +3807,7 @@ function extractDtoRoute(args) {
3141
3807
  body: dtoContract?.body ?? null,
3142
3808
  response: mixinResponse ?? dtoContract?.response ?? "unknown",
3143
3809
  error: dtoContract?.error ?? null,
3810
+ paramTypes: dtoContract?.paramTypes ?? null,
3144
3811
  queryRef: dtoContract?.queryRef ?? null,
3145
3812
  bodyRef: dtoContract?.bodyRef ?? null,
3146
3813
  responseRef: dtoContract?.responseRef ?? null,
@@ -3263,7 +3930,7 @@ function createExtensionContext(config, getRoutes, trackedInputs) {
3263
3930
  },
3264
3931
  project() {
3265
3932
  if (!project) {
3266
- project = new import_ts_morph10.Project({
3933
+ project = new import_ts_morph13.Project({
3267
3934
  skipAddingFilesFromTsConfig: true,
3268
3935
  skipLoadingLibFiles: true,
3269
3936
  skipFileDependencyResolution: true,
@@ -3381,10 +4048,11 @@ function insertIntoTree(tree, segments, leaf, fullName) {
3381
4048
  insertIntoTree(branch.children, rest, leaf, fullName);
3382
4049
  }
3383
4050
  }
3384
- function buildParamsType(params) {
4051
+ function buildParamsType(params, paramTypes) {
3385
4052
  const pathParams = params.filter((p) => p.source === "path");
3386
4053
  if (pathParams.length === 0) return "never";
3387
- return `{ ${pathParams.map((p) => `${p.name}: string`).join("; ")} }`;
4054
+ const typeOf = (name) => paramTypes && Object.hasOwn(paramTypes, name) && paramTypes[name] || "string";
4055
+ return `{ ${pathParams.map((p) => `${p.name}: ${typeOf(p.name)}`).join("; ")} }`;
3388
4056
  }
3389
4057
  function hasPathParams(params) {
3390
4058
  return params.some((p) => p.source === "path");
@@ -3478,7 +4146,7 @@ function emitRouterTypeBlock(tree, indent, outDir, serialization) {
3478
4146
  }
3479
4147
  const response = buildResponseType(c, outDir, serialization);
3480
4148
  const error = buildErrorType(c);
3481
- const params = buildParamsType(c.params);
4149
+ const params = buildParamsType(c.params, c.contractSource.paramTypes);
3482
4150
  const safeMethod = JSON.stringify(method);
3483
4151
  const safeUrl = JSON.stringify(c.path);
3484
4152
  const filterLiterals = filterFieldLiterals(c.contractSource.filterFields);
@@ -3566,28 +4234,28 @@ function renderFetcherRequest(req, binaryResponse) {
3566
4234
  }
3567
4235
  function emitReqHelper() {
3568
4236
  return [
3569
- "/** Awaitable request handle. `await api.x.y({...})` runs the fetch; extensions add query/mutation helpers. */",
3570
- "type __Req<R> = {",
3571
- " then<T1 = R, T2 = never>(",
4237
+ "/** An awaitable request handle: a lazy, memoized `Promise` that also carries `fetch()` and the members extensions add. */",
4238
+ "export type RequestHandle<R, M = {}> = Promise<R> & { fetch(): Promise<R> } & M;",
4239
+ "class __Request<R> extends Promise<R> {",
4240
+ " static override get [Symbol.species](): PromiseConstructor {",
4241
+ " return Promise;",
4242
+ " }",
4243
+ " private __run: () => Promise<R>;",
4244
+ " private __p: Promise<R> | undefined;",
4245
+ " constructor(run: () => Promise<R>) {",
4246
+ " super(() => {});",
4247
+ " this.__run = run;",
4248
+ " }",
4249
+ " override then<T1 = R, T2 = never>(",
3572
4250
  " onfulfilled?: ((value: R) => T1 | PromiseLike<T1>) | null,",
3573
4251
  " onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null,",
3574
- " ): Promise<T1 | T2>;",
3575
- " catch<T = never>(onrejected?: ((reason: unknown) => T | PromiseLike<T>) | null): Promise<R | T>;",
3576
- " finally(onfinally?: (() => void) | null): Promise<R>;",
3577
- " fetch(): Promise<R>;",
3578
- "};",
3579
- "function __req<R>(run: () => Promise<R>): __Req<R> {",
3580
- " let __p: Promise<R> | undefined;",
3581
- " const __promise = () => {",
3582
- " __p ??= run();",
3583
- " return __p;",
3584
- " };",
3585
- " return {",
3586
- " then: (onfulfilled, onrejected) => __promise().then(onfulfilled, onrejected),",
3587
- " catch: (onrejected) => __promise().catch(onrejected),",
3588
- " finally: (onfinally) => __promise().finally(onfinally),",
3589
- " fetch: run,",
3590
- " };",
4252
+ " ): Promise<T1 | T2> {",
4253
+ " this.__p ??= this.__run();",
4254
+ " return this.__p.then(onfulfilled, onrejected);",
4255
+ " }",
4256
+ "}",
4257
+ "function __req<R, M extends object = {}>(run: () => Promise<R>, members?: M): RequestHandle<R, M> {",
4258
+ " return Object.assign(new __Request<R>(run), { fetch: run }, members) as RequestHandle<R, M>;",
3591
4259
  "}",
3592
4260
  ""
3593
4261
  ];
@@ -3605,18 +4273,26 @@ function emitFilterFieldGuard() {
3605
4273
  ];
3606
4274
  }
3607
4275
  function renderLeaf(pad, objKey, req, requestExpr, members, streamExpr) {
3608
- const lines = [`${pad}${objKey}: (input?: ${req.inputType}) => ({`];
3609
- lines.push(`${pad} ...__req<${req.responseType}>(() => ${requestExpr}),`);
4276
+ const memberLines = [];
3610
4277
  if (req.filterFieldsExpr) {
3611
- lines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
4278
+ memberLines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
3612
4279
  }
3613
4280
  if (streamExpr) {
3614
- lines.push(`${pad} stream: () => ${streamExpr},`);
4281
+ memberLines.push(`${pad} stream: () => ${streamExpr},`);
3615
4282
  }
3616
4283
  for (const [name, value] of Object.entries(members)) {
3617
- lines.push(`${pad} ${name}: ${value},`);
3618
- }
3619
- lines.push(`${pad}}),`);
4284
+ memberLines.push(`${pad} ${name}: ${value},`);
4285
+ }
4286
+ const body = [requestExpr, ...memberLines].join("\n");
4287
+ const param = /\binput\b/.test(body) ? `input?: ${req.inputType}` : "";
4288
+ const lines = [`${pad}${objKey}: (${param}) =>`];
4289
+ if (memberLines.length === 0) {
4290
+ lines.push(`${pad} __req<${req.responseType}>(() => ${requestExpr}),`);
4291
+ return lines;
4292
+ }
4293
+ lines.push(`${pad} __req(() => ${requestExpr}, {`);
4294
+ lines.push(...memberLines);
4295
+ lines.push(`${pad} }),`);
3620
4296
  return lines;
3621
4297
  }
3622
4298
  function renderStreamExpr(req) {
@@ -3747,6 +4423,26 @@ var EMPTY_PATH_NAMESPACE = [
3747
4423
  "}",
3748
4424
  ""
3749
4425
  ];
4426
+ function isClientCallable(route) {
4427
+ return route.method.toUpperCase() !== "ALL";
4428
+ }
4429
+ var ROUTES_IMPORT_PLACEHOLDER = "/* @@routes-import@@ */";
4430
+ var ROUTES_EXPORTS = [
4431
+ // Called, never mentioned in prose: match the call so a comment saying "route" doesn't count.
4432
+ { name: "route", typeOnly: false },
4433
+ { name: "ROUTES", typeOnly: false },
4434
+ { name: "RouteName", typeOnly: true },
4435
+ { name: "ExtractParams", typeOnly: true },
4436
+ { name: "RouteParams", typeOnly: true }
4437
+ ];
4438
+ function finishRoutesImport(lines) {
4439
+ const body = lines.filter((l) => l !== ROUTES_IMPORT_PLACEHOLDER).join("\n");
4440
+ const used = ROUTES_EXPORTS.filter(
4441
+ ({ name }) => new RegExp(name === "route" ? "\\broute\\(" : `\\b${name}\\b`).test(body)
4442
+ ).map(({ name, typeOnly }) => typeOnly ? `type ${name}` : name);
4443
+ const importLine = used.length ? `import { ${used.join(", ")} } from './routes.js';` : null;
4444
+ return lines.flatMap((l) => l === ROUTES_IMPORT_PLACEHOLDER ? importLine ? [importLine] : [] : [l]).join("\n");
4445
+ }
3750
4446
  function buildApiFile(routes, outDir, opts = {}) {
3751
4447
  const fetcherImportPath = opts.fetcherImportPath;
3752
4448
  const serialization = opts.serialization ?? "json";
@@ -3754,7 +4450,7 @@ function buildApiFile(routes, outDir, opts = {}) {
3754
4450
  const { layer } = resolveApiSlots(extensions);
3755
4451
  const memberExts = extensions.filter((e) => e.apiMembers);
3756
4452
  const headerExts = extensions.filter((e) => e.apiHeader);
3757
- const contracted = routes.filter((r) => r.contract);
4453
+ const contracted = routes.filter((r) => r.contract && isClientCallable(r));
3758
4454
  const ctx = opts.ctx ?? {
3759
4455
  cwd: outDir ?? "",
3760
4456
  outDir: outDir ?? "",
@@ -3806,9 +4502,7 @@ function buildApiFile(routes, outDir, opts = {}) {
3806
4502
  for (const imp of ext.apiHeader?.(ctx)?.imports ?? []) pushImport(imp);
3807
4503
  }
3808
4504
  lines.push(...extImports);
3809
- lines.push(
3810
- "import { route, ROUTES, type RouteName, type ExtractParams, type RouteParams } from './routes.js';"
3811
- );
4505
+ lines.push(ROUTES_IMPORT_PLACEHOLDER);
3812
4506
  const runtimeImport = fetcherImportPath ?? "@dudousxd/nestjs-client";
3813
4507
  lines.push(`import type { Fetcher } from '${runtimeImport}';`);
3814
4508
  if (serialization === "json" && contracted.length > 0) {
@@ -3859,7 +4553,7 @@ function buildApiFile(routes, outDir, opts = {}) {
3859
4553
  lines.push(...statements, "");
3860
4554
  }
3861
4555
  }
3862
- return lines.join("\n");
4556
+ return finishRoutesImport(lines);
3863
4557
  }
3864
4558
  const tree = /* @__PURE__ */ new Map();
3865
4559
  for (const r of contracted) {
@@ -3912,7 +4606,7 @@ function buildApiFile(routes, outDir, opts = {}) {
3912
4606
  lines.push(...statements, "");
3913
4607
  }
3914
4608
  }
3915
- return lines.join("\n");
4609
+ return finishRoutesImport(lines);
3916
4610
  }
3917
4611
 
3918
4612
  // src/emit/emit-cache.ts
@@ -3925,6 +4619,7 @@ async function emitCache(pages, outDir) {
3925
4619
  const s = await (0, import_promises4.stat)(p.absolutePath);
3926
4620
  return {
3927
4621
  name: p.name,
4622
+ scope: p.scope ?? "default",
3928
4623
  relativePath: p.relativePath,
3929
4624
  mtime: s.mtime.toISOString()
3930
4625
  };
@@ -4675,6 +5370,7 @@ function buildOpenApiSpec(routes, opts = {}) {
4675
5370
  const paths = {};
4676
5371
  for (const route of routes) {
4677
5372
  if (!route.contract) continue;
5373
+ if (route.method.toUpperCase() === "ALL") continue;
4678
5374
  const oaPath = toOpenApiPath(route.path);
4679
5375
  const method = route.method.toLowerCase();
4680
5376
  let pathItem = paths[oaPath];
@@ -4718,10 +5414,11 @@ async function emitPages(pages, outDir, _options = {}) {
4718
5414
  }).join("\n");
4719
5415
  const propsHelper = "\nexport type InertiaProps<K extends InertiaPageName> = import('@dudousxd/nestjs-inertia').InertiaPages[K];\n";
4720
5416
  const sharedPropsBlock = buildSharedPropsBlock(_options.sharedProps ?? null);
5417
+ const scopesBlock = buildScopesBlock(pages);
4721
5418
  const content = `// Generated by @dudousxd/nestjs-codegen. Do not edit.
4722
5419
 
4723
5420
  export type InertiaPageName = ${pageNameUnion};
4724
- ${propsHelper}
5421
+ ${propsHelper}${scopesBlock}
4725
5422
  declare module '@dudousxd/nestjs-inertia' {
4726
5423
  interface InertiaPages {
4727
5424
  ${augBody}
@@ -4730,6 +5427,31 @@ ${sharedPropsBlock}}
4730
5427
  `;
4731
5428
  await (0, import_promises9.writeFile)((0, import_node_path13.join)(outDir, "pages.d.ts"), content, "utf8");
4732
5429
  }
5430
+ function buildScopesBlock(pages) {
5431
+ const byScope = /* @__PURE__ */ new Map();
5432
+ for (const page of pages) {
5433
+ const scope = page.scope ?? "default";
5434
+ const names = byScope.get(scope) ?? [];
5435
+ names.push(JSON.stringify(page.name));
5436
+ byScope.set(scope, names);
5437
+ }
5438
+ if (![...byScope.keys()].some((scope) => scope !== "default")) return "";
5439
+ if (!byScope.has("default")) byScope.set("default", []);
5440
+ const scopes = ["default", ...[...byScope.keys()].filter((s) => s !== "default")];
5441
+ const body = scopes.map((scope) => {
5442
+ const key = needsQuotes(scope) ? JSON.stringify(scope) : scope;
5443
+ const names = byScope.get(scope) ?? [];
5444
+ return ` ${key}: ${names.length ? names.join(" | ") : "never"};`;
5445
+ }).join("\n");
5446
+ return `
5447
+ /** The page names of each Inertia app: \`default\` (forRoot) and every \`pages.scopes\` entry. */
5448
+ export interface InertiaScopePages {
5449
+ ${body}
5450
+ }
5451
+
5452
+ export type InertiaScopePageName<S extends keyof InertiaScopePages> = InertiaScopePages[S];
5453
+ `;
5454
+ }
4733
5455
  function buildSharedPropsBlock(sharedProps) {
4734
5456
  if (!sharedProps) return "";
4735
5457
  if (sharedProps.isImportRef) {
@@ -4937,8 +5659,7 @@ function diffConfigKeyHashes(previous, current) {
4937
5659
  return [...keys].filter((key) => previous[key] !== current[key]).sort();
4938
5660
  }
4939
5661
  async function discoverInputFiles(config) {
4940
- const globs = [config.contracts.glob, config.forms.watch];
4941
- if (config.pages) globs.push(config.pages.glob);
5662
+ const globs = [config.contracts.glob, config.forms.watch, ...allPageGlobs(config)];
4942
5663
  const cwd = config.codegen.cwd;
4943
5664
  const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
4944
5665
  return [...new Set(matched)].sort();
@@ -5069,12 +5790,7 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
5069
5790
  }
5070
5791
  if (config.pages) {
5071
5792
  const pagesConfig = config.pages;
5072
- const pages = await discoverPages({
5073
- glob: pagesConfig.glob,
5074
- cwd: config.codegen.cwd,
5075
- propsExport: pagesConfig.propsExport,
5076
- componentNameStrategy: pagesConfig.componentNameStrategy
5077
- });
5793
+ const pages = await discoverPageScopes(config);
5078
5794
  const sharedProps = discoverSharedPropsFromConfig(config);
5079
5795
  await emitPages(pages, config.codegen.outDir, {
5080
5796
  propsExport: pagesConfig.propsExport,
@@ -5249,12 +5965,17 @@ async function watch(config, onChange, options = {}) {
5249
5965
  await runInitialPass();
5250
5966
  }
5251
5967
  let pagesDebounceTimer;
5252
- const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
5253
- const pagesWatcher = import_chokidar.default.watch((0, import_node_path18.join)(config.codegen.cwd, pagesGlob), {
5254
- ignoreInitial: true,
5255
- persistent: true,
5256
- awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
5257
- });
5968
+ const pageGlobs = allPageGlobs(config);
5969
+ const pagesWatcher = import_chokidar.default.watch(
5970
+ (pageGlobs.length ? pageGlobs : [".nestjs-codegen-no-pages"]).map(
5971
+ (glob) => (0, import_node_path18.join)(config.codegen.cwd, glob)
5972
+ ),
5973
+ {
5974
+ ignoreInitial: true,
5975
+ persistent: true,
5976
+ awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
5977
+ }
5978
+ );
5258
5979
  function schedulePagesRegenerate() {
5259
5980
  if (pagesDebounceTimer !== void 0) {
5260
5981
  clearTimeout(pagesDebounceTimer);
@@ -5390,7 +6111,7 @@ function toObjectKey2(name) {
5390
6111
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
5391
6112
  }
5392
6113
  function createChainModuleRenderer(opts) {
5393
- const { render, recursiveAnnotation } = opts;
6114
+ const { render: render2, recursiveAnnotation } = opts;
5394
6115
  return (mod) => {
5395
6116
  const ctx = { named: mod.named };
5396
6117
  const recursive = mod.recursive ?? /* @__PURE__ */ new Set();
@@ -5399,7 +6120,7 @@ function createChainModuleRenderer(opts) {
5399
6120
  const namedTypeAliases = /* @__PURE__ */ new Map();
5400
6121
  const namedAnnotations = /* @__PURE__ */ new Map();
5401
6122
  for (const [name, node] of mod.named) {
5402
- namedNestedSchemas.set(name, render(node, ctx));
6123
+ namedNestedSchemas.set(name, render2(node, ctx));
5403
6124
  if (recursive.has(name)) {
5404
6125
  const typeName = typeNameFor(name);
5405
6126
  namedTypeAliases.set(name, `type ${typeName} = ${renderTsType(node, tctx)}`);
@@ -5407,7 +6128,7 @@ function createChainModuleRenderer(opts) {
5407
6128
  }
5408
6129
  }
5409
6130
  return {
5410
- schemaText: render(mod.root, ctx),
6131
+ schemaText: render2(mod.root, ctx),
5411
6132
  namedNestedSchemas,
5412
6133
  namedTypeAliases,
5413
6134
  namedAnnotations,
@@ -5417,7 +6138,7 @@ function createChainModuleRenderer(opts) {
5417
6138
  }
5418
6139
 
5419
6140
  // src/index.ts
5420
- var VERSION = "0.25.2";
6141
+ var VERSION = "0.27.0";
5421
6142
  // Annotate the CommonJS export names for ESM import in node:
5422
6143
  0 && (module.exports = {
5423
6144
  CodegenError,