@dudousxd/nestjs-codegen 0.25.1 → 0.26.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.
@@ -149,15 +149,15 @@ import { existsSync } from "fs";
149
149
  import { dirname as dirname2, join as join2, resolve as resolve3 } from "path";
150
150
  import fg from "fast-glob";
151
151
  import {
152
- Node as Node8,
153
- Project as Project2,
154
- ts
152
+ Node as Node10,
153
+ Project as Project3,
154
+ ts as ts3
155
155
  } from "ts-morph";
156
156
 
157
157
  // src/discovery/dto-type-resolver.ts
158
158
  import {
159
- Node as Node6,
160
- SyntaxKind as SyntaxKind2
159
+ Node as Node9,
160
+ SyntaxKind as SyntaxKind3
161
161
  } from "ts-morph";
162
162
 
163
163
  // src/discovery/dto-to-ir.ts
@@ -1695,6 +1695,674 @@ function extractFilterableEntityFields(filterClass, project, entityOverride, pre
1695
1695
  return fields;
1696
1696
  }
1697
1697
 
1698
+ // src/discovery/pipe-schema.ts
1699
+ import { Node as Node8 } from "ts-morph";
1700
+
1701
+ // src/discovery/schema-type-inference.ts
1702
+ import {
1703
+ ts as ts2
1704
+ } from "ts-morph";
1705
+
1706
+ // src/discovery/schema-type-program.ts
1707
+ import { Node as Node6, Project as Project2, ts } from "ts-morph";
1708
+ var PARAM_DECORATORS = /* @__PURE__ */ new Set(["Body", "Query", "Param"]);
1709
+ var SchemaTypeProgram = class {
1710
+ constructor(discovery) {
1711
+ this.discovery = discovery;
1712
+ const base = discovery.getCompilerOptions();
1713
+ this.options = {
1714
+ ...base,
1715
+ // A tsconfig-less consumer gets ES5 by default, whose lib has no `Map`/`Set`/
1716
+ // `Promise` for the schema libraries' declarations to lean on.
1717
+ target: base.target ?? ts.ScriptTarget.ES2022,
1718
+ // With neither set, resolve the way a bundler does: package `exports`
1719
+ // (`zod/v4`) and extensionless or `.js` relative imports all resolve.
1720
+ ...base.module === void 0 && base.moduleResolution === void 0 ? { module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler } : {},
1721
+ // Without it `.nullable()` and `.optional()` would erase to the bare type.
1722
+ strictNullChecks: true,
1723
+ // No ambient `@types/*` (a tsconfig's `types: ['node']`): a schema does not
1724
+ // need them, and they are a hundred-odd files of program to build.
1725
+ types: [],
1726
+ noEmit: true
1727
+ };
1728
+ this.project = new Project2({
1729
+ skipAddingFilesFromTsConfig: true,
1730
+ compilerOptions: this.options
1731
+ });
1732
+ for (const sf of discovery.getSourceFiles()) this.request(sf.getFilePath(), { schema: true });
1733
+ this.flush();
1734
+ }
1735
+ project;
1736
+ options;
1737
+ /** Parses a file that is not in discovery's Project, without adding it there. */
1738
+ scratch = new Project2({
1739
+ skipAddingFilesFromTsConfig: true,
1740
+ skipLoadingLibFiles: true,
1741
+ skipFileDependencyResolution: true
1742
+ });
1743
+ needs = /* @__PURE__ */ new Map();
1744
+ /** Pruned text per file, as last written into {@link project}. */
1745
+ written = /* @__PURE__ */ new Map();
1746
+ /**
1747
+ * The typed copy of a discovery file, with its schema positions kept. Adding one
1748
+ * that was not there yet (a contract file discovery reached lazily) rebuilds the
1749
+ * program once.
1750
+ */
1751
+ sourceFileFor(sf) {
1752
+ this.request(sf.getFilePath(), { schema: true });
1753
+ this.flush();
1754
+ return this.project.getSourceFile(sf.getFilePath());
1755
+ }
1756
+ // -------------------------------------------------------------------------
1757
+ queue = [];
1758
+ request(path, want) {
1759
+ let needs = this.needs.get(path);
1760
+ const isNew = !needs;
1761
+ needs ??= { schema: false, all: false, names: /* @__PURE__ */ new Set() };
1762
+ let grew = isNew;
1763
+ if (want.schema && !needs.schema) {
1764
+ needs.schema = true;
1765
+ grew = true;
1766
+ }
1767
+ if (want.all && !needs.all) {
1768
+ needs.all = true;
1769
+ grew = true;
1770
+ }
1771
+ for (const name of want.names ?? []) {
1772
+ if (!needs.names.has(name)) {
1773
+ needs.names.add(name);
1774
+ grew = true;
1775
+ }
1776
+ }
1777
+ this.needs.set(path, needs);
1778
+ if (grew) this.queue.push(path);
1779
+ }
1780
+ /** Run the worklist to a fixpoint, then write every changed file into the program. */
1781
+ flush() {
1782
+ const changed = /* @__PURE__ */ new Map();
1783
+ while (this.queue.length > 0) {
1784
+ const path = this.queue.pop();
1785
+ const original = this.original(path);
1786
+ if (!original) continue;
1787
+ const needs = this.needs.get(path);
1788
+ const text = this.prune(original, needs);
1789
+ if (this.written.get(path) !== text) changed.set(path, text);
1790
+ }
1791
+ for (const [path, text] of changed) {
1792
+ this.project.createSourceFile(path, text, { overwrite: true });
1793
+ this.written.set(path, text);
1794
+ }
1795
+ }
1796
+ /** The file as discovery sees it (its in-memory text), else as it is on disk. */
1797
+ original(path) {
1798
+ return this.discovery.getSourceFile(path) ?? this.scratch.getSourceFile(path) ?? this.scratch.addSourceFileAtPathIfExists(path);
1799
+ }
1800
+ /**
1801
+ * `sf`'s text with every import/re-export nothing in `needs` references blanked,
1802
+ * requesting from each kept one's target the names it brings in.
1803
+ */
1804
+ prune(sf, needs) {
1805
+ const locals = topLevelDeclarations(sf);
1806
+ const roots = [];
1807
+ if (needs.all) roots.push(...sf.getStatements());
1808
+ if (needs.schema) roots.push(...schemaPositions(sf));
1809
+ const reexported = /* @__PURE__ */ new Map();
1810
+ for (const exp of sf.getExportDeclarations()) {
1811
+ const spec = exp.getModuleSpecifierValue();
1812
+ if (spec === void 0) {
1813
+ for (const named of exp.getNamedExports()) {
1814
+ const exposed = (named.getAliasNode() ?? named.getNameNode()).getText();
1815
+ if (needs.all || needs.names.has(exposed)) roots.push(named.getNameNode());
1816
+ }
1817
+ continue;
1818
+ }
1819
+ if (exp.isNamespaceExport() || exp.getNamedExports().length === 0) continue;
1820
+ for (const named of exp.getNamedExports()) {
1821
+ const exposed = (named.getAliasNode() ?? named.getNameNode()).getText();
1822
+ const list = reexported.get(exposed) ?? [];
1823
+ list.push({ from: spec, name: named.getNameNode().getText() });
1824
+ reexported.set(exposed, list);
1825
+ }
1826
+ }
1827
+ const unresolvedNames = [];
1828
+ for (const name of needs.names) {
1829
+ const decls = name === "default" ? defaultExport(sf) : locals.get(name) ?? [];
1830
+ if (decls.length > 0) roots.push(...decls);
1831
+ else if (!reexported.has(name)) unresolvedNames.push(name);
1832
+ }
1833
+ const referenced = /* @__PURE__ */ new Set();
1834
+ const queue = [...roots];
1835
+ const seen = new Set(queue);
1836
+ while (queue.length > 0) {
1837
+ const node = queue.pop();
1838
+ const ids = Node6.isIdentifier(node) ? [node] : node.getDescendantsOfKind(ts.SyntaxKind.Identifier);
1839
+ for (const id of ids) {
1840
+ const name = id.getText();
1841
+ if (referenced.has(name)) continue;
1842
+ referenced.add(name);
1843
+ for (const local of locals.get(name) ?? []) {
1844
+ if (seen.has(local)) continue;
1845
+ seen.add(local);
1846
+ queue.push(local);
1847
+ }
1848
+ }
1849
+ }
1850
+ const chars = sf.getFullText().split("");
1851
+ const blank = (node) => {
1852
+ for (let i = node.getStart(); i < node.getEnd(); i++) {
1853
+ if (chars[i] !== "\n" && chars[i] !== "\r") chars[i] = " ";
1854
+ }
1855
+ };
1856
+ for (const decl of sf.getImportDeclarations()) {
1857
+ const target = this.resolve(decl.getModuleSpecifierValue(), sf);
1858
+ const namespace = decl.getNamespaceImport()?.getText();
1859
+ const def = decl.getDefaultImport()?.getText();
1860
+ const named = decl.getNamedImports().map((n) => ({
1861
+ local: (n.getAliasNode() ?? n.getNameNode()).getText(),
1862
+ imported: n.getName()
1863
+ })).filter((n) => referenced.has(n.local));
1864
+ const wantsNamespace = namespace !== void 0 && referenced.has(namespace);
1865
+ const wantsDefault = def !== void 0 && referenced.has(def);
1866
+ if (!wantsNamespace && !wantsDefault && named.length === 0) {
1867
+ blank(decl);
1868
+ continue;
1869
+ }
1870
+ if (target) {
1871
+ this.request(target, {
1872
+ all: wantsNamespace,
1873
+ names: [...wantsDefault ? ["default"] : [], ...named.map((n) => n.imported)]
1874
+ });
1875
+ }
1876
+ }
1877
+ for (const exp of sf.getExportDeclarations()) {
1878
+ const spec = exp.getModuleSpecifierValue();
1879
+ if (spec === void 0) continue;
1880
+ const target = this.resolve(spec, sf);
1881
+ if (exp.isNamespaceExport() || exp.getNamedExports().length === 0) {
1882
+ if (!needs.all && unresolvedNames.length === 0) {
1883
+ blank(exp);
1884
+ } else if (target) {
1885
+ this.request(target, { all: needs.all, names: unresolvedNames });
1886
+ }
1887
+ continue;
1888
+ }
1889
+ const wanted = exp.getNamedExports().filter(
1890
+ (n) => needs.all || needs.names.has((n.getAliasNode() ?? n.getNameNode()).getText())
1891
+ ).map((n) => n.getNameNode().getText());
1892
+ if (wanted.length === 0) blank(exp);
1893
+ else if (target) this.request(target, { names: wanted });
1894
+ }
1895
+ return chars.join("");
1896
+ }
1897
+ /**
1898
+ * The project source file a module specifier resolves to, or undefined for a
1899
+ * package (read unpruned by the program itself) or an unresolvable one.
1900
+ */
1901
+ resolve(specifier, from) {
1902
+ const resolved = ts.resolveModuleName(
1903
+ specifier,
1904
+ from.getFilePath(),
1905
+ this.options,
1906
+ ts.sys
1907
+ ).resolvedModule;
1908
+ if (!resolved || resolved.isExternalLibraryImport) return void 0;
1909
+ const file = resolved.resolvedFileName;
1910
+ if (file.endsWith(".d.ts") || !/\.(m|c)?tsx?$/.test(file)) return void 0;
1911
+ return file;
1912
+ }
1913
+ };
1914
+ function schemaPositions(sf) {
1915
+ const roots = [];
1916
+ sf.forEachDescendant((node) => {
1917
+ if (Node6.isDecorator(node)) {
1918
+ const name = node.getName();
1919
+ if (name === "ApplyContract") {
1920
+ roots.push(...node.getArguments());
1921
+ } else if (PARAM_DECORATORS.has(name)) {
1922
+ for (const arg of node.getArguments()) {
1923
+ if (Node6.isNewExpression(arg) || Node6.isCallExpression(arg)) {
1924
+ roots.push(...arg.getArguments());
1925
+ }
1926
+ }
1927
+ }
1928
+ } else if (Node6.isCallExpression(node)) {
1929
+ const callee = node.getExpression();
1930
+ const name = Node6.isIdentifier(callee) ? callee.getText() : Node6.isPropertyAccessExpression(callee) ? callee.getName() : void 0;
1931
+ if (name === "defineContract") roots.push(...node.getArguments());
1932
+ }
1933
+ });
1934
+ return roots;
1935
+ }
1936
+ function topLevelDeclarations(sf) {
1937
+ const byName = /* @__PURE__ */ new Map();
1938
+ const add = (name, node) => {
1939
+ if (!name) return;
1940
+ const list = byName.get(name);
1941
+ if (list) list.push(node);
1942
+ else byName.set(name, [node]);
1943
+ };
1944
+ for (const decl of sf.getVariableDeclarations()) add(decl.getName(), decl);
1945
+ for (const decl of sf.getFunctions()) add(decl.getName(), decl);
1946
+ for (const decl of sf.getClasses()) add(decl.getName(), decl);
1947
+ for (const decl of sf.getEnums()) add(decl.getName(), decl);
1948
+ for (const decl of sf.getInterfaces()) add(decl.getName(), decl);
1949
+ for (const decl of sf.getTypeAliases()) add(decl.getName(), decl);
1950
+ for (const decl of sf.getModules()) add(decl.getName(), decl);
1951
+ return byName;
1952
+ }
1953
+ function defaultExport(sf) {
1954
+ const nodes = [];
1955
+ for (const assignment of sf.getExportAssignments()) nodes.push(assignment);
1956
+ for (const fn of sf.getFunctions()) if (fn.isDefaultExport()) nodes.push(fn);
1957
+ for (const cls of sf.getClasses()) if (cls.isDefaultExport()) nodes.push(cls);
1958
+ return nodes;
1959
+ }
1960
+
1961
+ // src/discovery/schema-type-inference.ts
1962
+ var programs = /* @__PURE__ */ new WeakMap();
1963
+ function programFor(discovery) {
1964
+ let program = programs.get(discovery);
1965
+ if (!program) {
1966
+ program = new SchemaTypeProgram(discovery);
1967
+ programs.set(discovery, program);
1968
+ }
1969
+ return program;
1970
+ }
1971
+ function clearSchemaTypeProject(discovery) {
1972
+ programs.delete(discovery);
1973
+ }
1974
+ function counterpart(typedSf, node) {
1975
+ const start = node.getStart();
1976
+ const end = node.getEnd();
1977
+ const kind = node.getKind();
1978
+ let candidate = typedSf.getDescendantAtPos(start);
1979
+ while (candidate) {
1980
+ if (candidate.getStart() === start && candidate.getEnd() === end && candidate.getKind() === kind) {
1981
+ return candidate;
1982
+ }
1983
+ if (candidate.getStart() < start || candidate.getEnd() > end) return void 0;
1984
+ candidate = candidate.getParent();
1985
+ }
1986
+ return void 0;
1987
+ }
1988
+ function propType(type, name, at) {
1989
+ return type.getProperty(name)?.getTypeAtLocation(at);
1990
+ }
1991
+ function isAnyOrUnknown(type) {
1992
+ return type.isAny() || type.isUnknown();
1993
+ }
1994
+ function inferSchema(expr, discovery) {
1995
+ try {
1996
+ const typedSf = programFor(discovery).sourceFileFor(expr.getSourceFile());
1997
+ const at = typedSf && counterpart(typedSf, expr);
1998
+ if (!at) return { kind: "unresolved" };
1999
+ const schemaType = at.getType();
2000
+ if (isAnyOrUnknown(schemaType)) return { kind: "unresolved" };
2001
+ const standard = propType(schemaType, "~standard", at);
2002
+ const stdTypes = standard ? propType(standard, "types", at)?.getNonNullableType() : void 0;
2003
+ const stdInput = stdTypes ? propType(stdTypes, "input", at) : void 0;
2004
+ const stdOutput = stdTypes ? propType(stdTypes, "output", at) : void 0;
2005
+ if (stdInput && stdOutput) {
2006
+ return { kind: "schema", types: { input: stdInput, output: stdOutput, at } };
2007
+ }
2008
+ const zodInput = propType(schemaType, "_input", at);
2009
+ const zodOutput = propType(schemaType, "_output", at);
2010
+ if (zodInput && zodOutput) {
2011
+ return { kind: "schema", types: { input: zodInput, output: zodOutput, at } };
2012
+ }
2013
+ return { kind: "not-schema" };
2014
+ } catch (err) {
2015
+ dbg("schema inference failed:", err);
2016
+ return { kind: "unresolved" };
2017
+ }
2018
+ }
2019
+ var GLOBAL_NAMED_TYPES = /* @__PURE__ */ new Set([
2020
+ "Date",
2021
+ "File",
2022
+ "Blob",
2023
+ "FormData",
2024
+ "URL",
2025
+ "RegExp",
2026
+ "Map",
2027
+ "Set",
2028
+ "ArrayBuffer",
2029
+ "Uint8Array"
2030
+ ]);
2031
+ var MAX_DEPTH = 12;
2032
+ function objectKey(name) {
2033
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
2034
+ }
2035
+ function isOptionalSymbol(sym) {
2036
+ return (sym.getFlags() & ts2.SymbolFlags.Optional) !== 0;
2037
+ }
2038
+ function isSymbolKeyed(sym) {
2039
+ return sym.getName().startsWith("__@");
2040
+ }
2041
+ function orderedProperties(type) {
2042
+ const position = (sym) => {
2043
+ const decl = sym.getDeclarations()[0];
2044
+ return decl ? [decl.getSourceFile().getFilePath(), decl.getStart()] : void 0;
2045
+ };
2046
+ return type.getProperties().map((sym, index) => ({ sym, index, at: position(sym) })).sort((a, b) => {
2047
+ if (a.at && b.at) {
2048
+ if (a.at[0] !== b.at[0]) return a.at[0] < b.at[0] ? -1 : 1;
2049
+ if (a.at[1] !== b.at[1]) return a.at[1] - b.at[1];
2050
+ } else if (a.at || b.at) {
2051
+ return a.at ? -1 : 1;
2052
+ }
2053
+ return a.index - b.index;
2054
+ }).map((entry) => entry.sym);
2055
+ }
2056
+ function isFromDeclarationFile(sym) {
2057
+ const decl = sym?.getDeclarations()[0];
2058
+ return !!decl && decl.getSourceFile().isDeclarationFile();
2059
+ }
2060
+ function render(type, state, paired) {
2061
+ if (state.depth > MAX_DEPTH) return "unknown";
2062
+ if (isAnyOrUnknown(type)) {
2063
+ return paired && !isAnyOrUnknown(paired) ? render(paired, state) : "unknown";
2064
+ }
2065
+ if (type.isNever()) return "never";
2066
+ if (type.isString() || type.isTemplateLiteral()) return "string";
2067
+ if (type.isNumber()) return "number";
2068
+ if (type.isBoolean()) return "boolean";
2069
+ if (type.isBigInt()) return "bigint";
2070
+ if (type.isNull()) return "null";
2071
+ if (type.isUndefined() || type.isVoid()) return "undefined";
2072
+ if (type.isBooleanLiteral()) return type.getText();
2073
+ if (type.isStringLiteral() || type.isNumberLiteral() || type.isEnumLiteral()) {
2074
+ const value = type.getLiteralValue();
2075
+ return typeof value === "string" ? JSON.stringify(value) : String(value);
2076
+ }
2077
+ if (type.isBigIntLiteral()) return type.getText();
2078
+ if (type.isTypeParameter()) return "unknown";
2079
+ if (type.isUnion()) return renderUnion(type, state, paired);
2080
+ if (type.isIntersection()) return renderIntersection(type, state);
2081
+ const next = { ...state, depth: state.depth + 1 };
2082
+ if (type.isArray() || type.isReadonlyArray()) {
2083
+ const element = type.getArrayElementType() ?? type.getTypeArguments()[0];
2084
+ const pairedElement = paired?.getArrayElementType() ?? paired?.getTypeArguments()[0];
2085
+ return element ? `Array<${render(element, next, pairedElement)}>` : "Array<unknown>";
2086
+ }
2087
+ if (type.isTuple()) {
2088
+ const elements = type.getTupleElements();
2089
+ const pairedElements = paired?.isTuple() ? paired.getTupleElements() : [];
2090
+ return `[${elements.map((e, i) => render(e, next, pairedElements[i])).join(", ")}]`;
2091
+ }
2092
+ if (type.isObject()) return renderObject(type, next, paired);
2093
+ return "unknown";
2094
+ }
2095
+ function renderUnion(type, state, paired) {
2096
+ const members = type.getUnionTypes();
2097
+ const hasTrue = members.some((m) => m.isBooleanLiteral() && m.getText() === "true");
2098
+ const hasFalse = members.some((m) => m.isBooleanLiteral() && m.getText() === "false");
2099
+ const pairedNonNull = paired?.getNonNullableType();
2100
+ const arms = [];
2101
+ let sawBoolean = false;
2102
+ let hasNull = false;
2103
+ let hasUndefined = false;
2104
+ for (const member of members) {
2105
+ if (member.isNull()) {
2106
+ hasNull = true;
2107
+ continue;
2108
+ }
2109
+ if (member.isUndefined()) {
2110
+ hasUndefined = true;
2111
+ continue;
2112
+ }
2113
+ if (member.isBooleanLiteral() && hasTrue && hasFalse) {
2114
+ if (!sawBoolean) arms.push("boolean");
2115
+ sawBoolean = true;
2116
+ continue;
2117
+ }
2118
+ arms.push(render(member, state, members.length === 1 ? paired : pairedNonNull));
2119
+ }
2120
+ if (hasNull) arms.push("null");
2121
+ if (hasUndefined) arms.push("undefined");
2122
+ const unique = [...new Set(arms)];
2123
+ if (unique.includes("unknown")) return "unknown";
2124
+ return unique.join(" | ");
2125
+ }
2126
+ function renderIntersection(type, state) {
2127
+ const members = type.getIntersectionTypes();
2128
+ const primitive = members.find((m) => !m.isObject());
2129
+ if (primitive) return render(primitive, state);
2130
+ return renderObject(type, { ...state, depth: state.depth + 1 }, void 0);
2131
+ }
2132
+ function renderObject(type, state, paired) {
2133
+ const symbol = type.getSymbol() ?? type.getAliasSymbol();
2134
+ const name = symbol?.getName();
2135
+ if (name && GLOBAL_NAMED_TYPES.has(name) && isFromDeclarationFile(symbol)) {
2136
+ const args = type.getTypeArguments();
2137
+ return args.length ? `${name}<${args.map((a) => render(a, state)).join(", ")}>` : name;
2138
+ }
2139
+ if (type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0) {
2140
+ return "unknown";
2141
+ }
2142
+ if (type.isClassOrInterface() && isFromDeclarationFile(symbol)) return "unknown";
2143
+ if (state.stack.has(type.compilerType)) return "unknown";
2144
+ const stack = new Set(state.stack).add(type.compilerType);
2145
+ const inner = { ...state, stack };
2146
+ const fields = [];
2147
+ for (const prop of orderedProperties(type)) {
2148
+ if (isSymbolKeyed(prop)) continue;
2149
+ const propName = prop.getName();
2150
+ const propT = prop.getTypeAtLocation(state.at);
2151
+ if (propT.getCallSignatures().length > 0 && !propT.isUnion()) continue;
2152
+ const pairedProp = paired?.getProperty(propName)?.getTypeAtLocation(state.at);
2153
+ const optional = isOptionalSymbol(prop) ? "?" : "";
2154
+ fields.push(`${objectKey(propName)}${optional}: ${render(propT, inner, pairedProp)}`);
2155
+ }
2156
+ const stringIndex = type.getStringIndexType();
2157
+ if (stringIndex) {
2158
+ const pairedIndex = paired?.getStringIndexType();
2159
+ const value = render(stringIndex, inner, pairedIndex);
2160
+ if (fields.length === 0) return `Record<string, ${value}>`;
2161
+ fields.push(`[key: string]: ${value}`);
2162
+ }
2163
+ return fields.length ? `{ ${fields.join("; ")} }` : "{}";
2164
+ }
2165
+ function stateAt(at) {
2166
+ return { at, stack: /* @__PURE__ */ new Set(), depth: 0 };
2167
+ }
2168
+ function requestTypeOf(types) {
2169
+ return render(types.input, stateAt(types.at), types.output);
2170
+ }
2171
+ function responseTypeOf(types) {
2172
+ return render(types.output, stateAt(types.at));
2173
+ }
2174
+ function requestFieldsOf(types) {
2175
+ const { input, output, at } = types;
2176
+ const objectInput = input.getNonNullableType();
2177
+ if (!objectInput.isObject() || objectInput.isArray() || objectInput.isTuple()) return null;
2178
+ const state = stateAt(at);
2179
+ return orderedProperties(objectInput).filter((prop) => !isSymbolKeyed(prop)).map((prop) => ({
2180
+ name: prop.getName(),
2181
+ type: render(
2182
+ prop.getTypeAtLocation(at),
2183
+ state,
2184
+ output.getProperty(prop.getName())?.getTypeAtLocation(at)
2185
+ ),
2186
+ optional: isOptionalSymbol(prop)
2187
+ }));
2188
+ }
2189
+ function acceptsUndefined(types) {
2190
+ const { input, output } = types;
2191
+ const accepted = isAnyOrUnknown(input) ? output : input;
2192
+ if (isAnyOrUnknown(accepted) || accepted.isUndefined()) return true;
2193
+ return accepted.isUnion() && accepted.getUnionTypes().some((t) => t.isUndefined());
2194
+ }
2195
+
2196
+ // src/discovery/zod-ast-to-ts.ts
2197
+ import { Node as Node7, SyntaxKind as SyntaxKind2 } from "ts-morph";
2198
+ function zodAstToTs(node) {
2199
+ if (!Node7.isCallExpression(node)) return "unknown";
2200
+ const expr = node.getExpression();
2201
+ if (Node7.isPropertyAccessExpression(expr)) {
2202
+ const methodName = expr.getName();
2203
+ const receiver = expr.getExpression();
2204
+ if (methodName === "optional") {
2205
+ return `${zodAstToTs(receiver)} | undefined`;
2206
+ }
2207
+ if (methodName === "nullable") {
2208
+ return `${zodAstToTs(receiver)} | null`;
2209
+ }
2210
+ const args = node.getArguments();
2211
+ switch (methodName) {
2212
+ case "string":
2213
+ return "string";
2214
+ case "number":
2215
+ return "number";
2216
+ case "boolean":
2217
+ return "boolean";
2218
+ case "unknown":
2219
+ return "unknown";
2220
+ case "any":
2221
+ return "unknown";
2222
+ case "literal": {
2223
+ const lit = args[0];
2224
+ if (!lit) return "unknown";
2225
+ if (Node7.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
2226
+ if (Node7.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
2227
+ if (lit.getKind() === SyntaxKind2.TrueKeyword) return "true";
2228
+ if (lit.getKind() === SyntaxKind2.FalseKeyword) return "false";
2229
+ return "unknown";
2230
+ }
2231
+ case "enum": {
2232
+ const arrArg = args[0];
2233
+ if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
2234
+ const members = arrArg.getElements().map(
2235
+ (el) => Node7.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
2236
+ );
2237
+ return members.join(" | ");
2238
+ }
2239
+ case "array": {
2240
+ const inner = args[0];
2241
+ if (!inner) return "unknown";
2242
+ return `Array<${zodAstToTs(inner)}>`;
2243
+ }
2244
+ case "object": {
2245
+ const objArg = args[0];
2246
+ if (!objArg || !Node7.isObjectLiteralExpression(objArg)) return "unknown";
2247
+ const lines = [];
2248
+ for (const prop of objArg.getProperties()) {
2249
+ if (!Node7.isPropertyAssignment(prop)) continue;
2250
+ const key = prop.getName();
2251
+ const valNode = prop.getInitializer();
2252
+ if (!valNode) continue;
2253
+ const tsType = zodAstToTs(valNode);
2254
+ const isOpt = isOptionalChain(valNode);
2255
+ lines.push(`${key}${isOpt ? "?" : ""}: ${tsType}`);
2256
+ }
2257
+ return `{ ${lines.join("; ")} }`;
2258
+ }
2259
+ case "union": {
2260
+ const arrArg = args[0];
2261
+ if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
2262
+ return arrArg.getElements().map(zodAstToTs).join(" | ");
2263
+ }
2264
+ case "record": {
2265
+ const valArg = args.length === 1 ? args[0] : args[1];
2266
+ if (!valArg) return "unknown";
2267
+ return `Record<string, ${zodAstToTs(valArg)}>`;
2268
+ }
2269
+ case "tuple": {
2270
+ const arrArg = args[0];
2271
+ if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
2272
+ return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
2273
+ }
2274
+ default:
2275
+ return "unknown";
2276
+ }
2277
+ }
2278
+ return "unknown";
2279
+ }
2280
+ function isOptionalChain(node) {
2281
+ if (!Node7.isCallExpression(node)) return false;
2282
+ const expr = node.getExpression();
2283
+ return Node7.isPropertyAccessExpression(expr) && expr.getName() === "optional";
2284
+ }
2285
+ function memberType(val, position, project) {
2286
+ if (project) {
2287
+ const inferred = inferSchema(val, project);
2288
+ if (inferred.kind === "schema") {
2289
+ return position === "request" ? requestTypeOf(inferred.types) : responseTypeOf(inferred.types);
2290
+ }
2291
+ }
2292
+ return zodAstToTs(val);
2293
+ }
2294
+ function parseDefineContractCall(callExpr, project) {
2295
+ if (!Node7.isCallExpression(callExpr)) return null;
2296
+ const callee = callExpr.getExpression();
2297
+ const calleeName = Node7.isIdentifier(callee) ? callee.getText() : Node7.isPropertyAccessExpression(callee) ? callee.getName() : "";
2298
+ if (calleeName !== "defineContract") return null;
2299
+ const args = callExpr.getArguments();
2300
+ const optsArg = args[0];
2301
+ if (!optsArg || !Node7.isObjectLiteralExpression(optsArg)) return null;
2302
+ let query = null;
2303
+ let body = null;
2304
+ let response = "unknown";
2305
+ let error = null;
2306
+ let bodyZodText = null;
2307
+ let queryZodText = null;
2308
+ for (const prop of optsArg.getProperties()) {
2309
+ if (!Node7.isPropertyAssignment(prop)) continue;
2310
+ const propName = prop.getName();
2311
+ const val = prop.getInitializer();
2312
+ if (!val) continue;
2313
+ if (propName === "query") {
2314
+ query = memberType(val, "request", project);
2315
+ queryZodText = val.getText();
2316
+ } else if (propName === "body") {
2317
+ body = memberType(val, "request", project);
2318
+ bodyZodText = val.getText();
2319
+ } else if (propName === "response") {
2320
+ response = memberType(val, "response", project);
2321
+ } else if (propName === "error") {
2322
+ error = memberType(val, "response", project);
2323
+ }
2324
+ }
2325
+ return { query, body, response, error, bodyZodText, queryZodText };
2326
+ }
2327
+
2328
+ // src/discovery/pipe-schema.ts
2329
+ function pipeSchemaOf(decorator, project) {
2330
+ for (const pipe of decorator.getArguments()) {
2331
+ if (!Node8.isNewExpression(pipe) && !Node8.isCallExpression(pipe)) continue;
2332
+ for (const arg of pipe.getArguments()) {
2333
+ if (!couldBeSchema(arg)) continue;
2334
+ const inferred = inferSchema(arg, project);
2335
+ if (inferred.kind === "schema") {
2336
+ return {
2337
+ type: requestTypeOf(inferred.types),
2338
+ optional: acceptsUndefined(inferred.types),
2339
+ fields: requestFieldsOf(inferred.types)
2340
+ };
2341
+ }
2342
+ if (inferred.kind === "unresolved") {
2343
+ const fallback = syntacticZodType(arg, project);
2344
+ if (fallback) {
2345
+ return { type: fallback, optional: fallback.endsWith("| undefined"), fields: null };
2346
+ }
2347
+ }
2348
+ }
2349
+ }
2350
+ return null;
2351
+ }
2352
+ function couldBeSchema(arg) {
2353
+ return Node8.isIdentifier(arg) || Node8.isPropertyAccessExpression(arg) || Node8.isCallExpression(arg) || Node8.isAsExpression(arg) || Node8.isSatisfiesExpression(arg) || Node8.isParenthesizedExpression(arg);
2354
+ }
2355
+ function syntacticZodType(arg, project) {
2356
+ let expr = arg;
2357
+ if (Node8.isIdentifier(arg)) {
2358
+ const resolved = resolveImportedVariable(arg.getText(), arg.getSourceFile(), project);
2359
+ expr = resolved?.decl.getInitializer();
2360
+ }
2361
+ if (!expr || !Node8.isCallExpression(expr)) return null;
2362
+ const type = zodAstToTs(expr);
2363
+ return type === "unknown" ? null : type;
2364
+ }
2365
+
1698
2366
  // src/discovery/dto-type-resolver.ts
1699
2367
  var WRAPPER_TYPES = {
1700
2368
  // MikroORM Ref/Reference/LoadedReference/IdentifiedReference are server-side
@@ -1726,22 +2394,22 @@ var PASSTHROUGH_UTILITY = /* @__PURE__ */ new Set([
1726
2394
  ]);
1727
2395
  function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /* @__PURE__ */ new Map()) {
1728
2396
  if (depth <= 0) return "unknown";
1729
- if (Node6.isArrayTypeNode(typeNode)) {
2397
+ if (Node9.isArrayTypeNode(typeNode)) {
1730
2398
  const elementType = typeNode.getElementTypeNode();
1731
2399
  return `Array<${resolveTypeNodeToString(elementType, sourceFile, project, depth, subst)}>`;
1732
2400
  }
1733
- if (Node6.isUnionTypeNode(typeNode)) {
2401
+ if (Node9.isUnionTypeNode(typeNode)) {
1734
2402
  return typeNode.getTypeNodes().map((t) => resolveTypeNodeToString(t, sourceFile, project, depth, subst)).join(" | ");
1735
2403
  }
1736
- if (Node6.isIntersectionTypeNode(typeNode)) {
2404
+ if (Node9.isIntersectionTypeNode(typeNode)) {
1737
2405
  return typeNode.getTypeNodes().map((t) => resolveTypeNodeToString(t, sourceFile, project, depth, subst)).join(" & ");
1738
2406
  }
1739
- if (Node6.isParenthesizedTypeNode(typeNode)) {
2407
+ if (Node9.isParenthesizedTypeNode(typeNode)) {
1740
2408
  return `(${resolveTypeNodeToString(typeNode.getTypeNode(), sourceFile, project, depth, subst)})`;
1741
2409
  }
1742
- if (Node6.isTypeReference(typeNode)) {
2410
+ if (Node9.isTypeReference(typeNode)) {
1743
2411
  const typeName = typeNode.getTypeName();
1744
- const name = Node6.isIdentifier(typeName) ? typeName.getText() : typeNode.getText();
2412
+ const name = Node9.isIdentifier(typeName) ? typeName.getText() : typeNode.getText();
1745
2413
  const bound = subst.get(name);
1746
2414
  if (bound !== void 0) return bound;
1747
2415
  if (name === "string" || name === "number" || name === "boolean") return name;
@@ -1764,13 +2432,13 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /
1764
2432
  dbg("unresolvable type:", name, "in", sourceFile.getFilePath());
1765
2433
  return "unknown";
1766
2434
  }
1767
- if (Node6.isTypeLiteral(typeNode)) {
2435
+ if (Node9.isTypeLiteral(typeNode)) {
1768
2436
  const members = [];
1769
2437
  for (const member of typeNode.getMembers()) {
1770
- if (Node6.isPropertySignature(member)) {
2438
+ if (Node9.isPropertySignature(member)) {
1771
2439
  const memberTypeNode = member.getTypeNode();
1772
- const memberType = memberTypeNode ? resolveTypeNodeToString(memberTypeNode, sourceFile, project, depth, subst) : "unknown";
1773
- members.push(`${member.getName()}${member.hasQuestionToken() ? "?" : ""}: ${memberType}`);
2440
+ const memberType2 = memberTypeNode ? resolveTypeNodeToString(memberTypeNode, sourceFile, project, depth, subst) : "unknown";
2441
+ members.push(`${member.getName()}${member.hasQuestionToken() ? "?" : ""}: ${memberType2}`);
1774
2442
  } else {
1775
2443
  members.push(member.getText());
1776
2444
  }
@@ -1778,11 +2446,11 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth, subst = /
1778
2446
  return members.length > 0 ? `{ ${members.join("; ")} }` : "{}";
1779
2447
  }
1780
2448
  const kind = typeNode.getKind();
1781
- if (kind === SyntaxKind2.StringKeyword) return "string";
1782
- if (kind === SyntaxKind2.NumberKeyword) return "number";
1783
- if (kind === SyntaxKind2.BooleanKeyword) return "boolean";
1784
- if (kind === SyntaxKind2.UnknownKeyword) return "unknown";
1785
- if (kind === SyntaxKind2.AnyKeyword) return "unknown";
2449
+ if (kind === SyntaxKind3.StringKeyword) return "string";
2450
+ if (kind === SyntaxKind3.NumberKeyword) return "number";
2451
+ if (kind === SyntaxKind3.BooleanKeyword) return "boolean";
2452
+ if (kind === SyntaxKind3.UnknownKeyword) return "unknown";
2453
+ if (kind === SyntaxKind3.AnyKeyword) return "unknown";
1786
2454
  return typeNode.getText();
1787
2455
  }
1788
2456
  function unwrapFirstTypeArg(typeNode, sourceFile, project, depth, mode, subst = /* @__PURE__ */ new Map()) {
@@ -1830,20 +2498,24 @@ function resolvePropertied(decl, sourceFile, project, depth, subst = /* @__PURE_
1830
2498
  const propName = prop.getName();
1831
2499
  const isOptional = prop.hasQuestionToken();
1832
2500
  const propTypeNode = prop.getTypeNode();
1833
- let propType = "unknown";
2501
+ let propType2 = "unknown";
1834
2502
  if (propTypeNode) {
1835
- propType = resolveTypeNodeToString(propTypeNode, sourceFile, project, depth, subst);
2503
+ propType2 = resolveTypeNodeToString(propTypeNode, sourceFile, project, depth, subst);
1836
2504
  }
1837
- lines.push(`${propName}${isOptional ? "?" : ""}: ${propType}`);
2505
+ lines.push(`${propName}${isOptional ? "?" : ""}: ${propType2}`);
1838
2506
  }
1839
2507
  return `{ ${lines.join("; ")} }`;
1840
2508
  }
2509
+ function namedField(decorator) {
2510
+ const first = decorator.getArguments()[0];
2511
+ return first && Node9.isStringLiteral(first) ? first.getLiteralValue() : null;
2512
+ }
1841
2513
  function extractBodyType(method, sourceFile, project) {
1842
2514
  for (const param of method.getParameters()) {
1843
2515
  const bodyDecorator = param.getDecorators().find((d) => d.getName() === "Body");
1844
- if (!bodyDecorator) continue;
1845
- const bodyArgs = bodyDecorator.getArguments();
1846
- if (bodyArgs.length > 0) continue;
2516
+ if (!bodyDecorator || namedField(bodyDecorator) !== null) continue;
2517
+ const piped = pipeSchemaOf(bodyDecorator, project);
2518
+ if (piped) return piped.type;
1847
2519
  const typeNode = param.getTypeNode();
1848
2520
  if (typeNode) {
1849
2521
  return resolveTypeNodeToString(typeNode, sourceFile, project, 3);
@@ -1851,11 +2523,16 @@ function extractBodyType(method, sourceFile, project) {
1851
2523
  }
1852
2524
  return null;
1853
2525
  }
2526
+ function hasPipeSchema(param, decoratorName, project) {
2527
+ const decorator = param.getDecorators().find((d) => d.getName() === decoratorName);
2528
+ return !!decorator && pipeSchemaOf(decorator, project) !== null;
2529
+ }
1854
2530
  function extractQueryType(method, sourceFile, project) {
1855
2531
  for (const param of method.getParameters()) {
1856
2532
  const queryDecorator = param.getDecorators().find((d) => d.getName() === "Query");
1857
- if (!queryDecorator) continue;
1858
- if (queryDecorator.getArguments().length > 0) continue;
2533
+ if (!queryDecorator || namedField(queryDecorator) !== null) continue;
2534
+ const piped = pipeSchemaOf(queryDecorator, project);
2535
+ if (piped) return piped.type;
1859
2536
  const typeNode = param.getTypeNode();
1860
2537
  if (typeNode) {
1861
2538
  return resolveTypeNodeToString(typeNode, sourceFile, project, 3);
@@ -1865,10 +2542,13 @@ function extractQueryType(method, sourceFile, project) {
1865
2542
  for (const param of method.getParameters()) {
1866
2543
  const queryDecorator = param.getDecorators().find((d) => d.getName() === "Query");
1867
2544
  if (!queryDecorator) continue;
1868
- const queryArgs = queryDecorator.getArguments();
1869
- const nameArg = queryArgs[0];
1870
- if (!nameArg || !Node6.isStringLiteral(nameArg)) continue;
1871
- const queryName = nameArg.getLiteralValue();
2545
+ const queryName = namedField(queryDecorator);
2546
+ if (queryName === null) continue;
2547
+ const piped = pipeSchemaOf(queryDecorator, project);
2548
+ if (piped) {
2549
+ entries.push(`${queryName}${piped.optional ? "?" : ""}: ${piped.type}`);
2550
+ continue;
2551
+ }
1872
2552
  const typeNode = param.getTypeNode();
1873
2553
  const queryType = typeNode ? resolveTypeNodeToString(typeNode, sourceFile, project, 3) : "string";
1874
2554
  entries.push(`${queryName}${isParamOptional(param) ? "?" : ""}: ${queryType}`);
@@ -1878,8 +2558,8 @@ function extractQueryType(method, sourceFile, project) {
1878
2558
  function isParamOptional(param) {
1879
2559
  if (param.hasQuestionToken() || param.hasInitializer()) return true;
1880
2560
  const typeNode = param.getTypeNode();
1881
- if (typeNode && Node6.isUnionTypeNode(typeNode)) {
1882
- return typeNode.getTypeNodes().some((t) => t.getKind() === SyntaxKind2.UndefinedKeyword);
2561
+ if (typeNode && Node9.isUnionTypeNode(typeNode)) {
2562
+ return typeNode.getTypeNodes().some((t) => t.getKind() === SyntaxKind3.UndefinedKeyword);
1883
2563
  }
1884
2564
  return false;
1885
2565
  }
@@ -1891,7 +2571,7 @@ function extractParamsType(method, sourceFile, project) {
1891
2571
  const paramArgs = paramDecorator.getArguments();
1892
2572
  if (paramArgs.length === 0) continue;
1893
2573
  const nameArg = paramArgs[0];
1894
- if (!Node6.isStringLiteral(nameArg)) continue;
2574
+ if (!Node9.isStringLiteral(nameArg)) continue;
1895
2575
  const paramName = nameArg.getLiteralValue();
1896
2576
  const typeNode = param.getTypeNode();
1897
2577
  const paramType = typeNode ? resolveTypeNodeToString(typeNode, sourceFile, project, 3) : "string";
@@ -1899,6 +2579,22 @@ function extractParamsType(method, sourceFile, project) {
1899
2579
  }
1900
2580
  return entries.length > 0 ? `{ ${entries.join("; ")} }` : null;
1901
2581
  }
2582
+ function extractPipedParamTypes(method, project) {
2583
+ const types = {};
2584
+ for (const param of method.getParameters()) {
2585
+ const paramDecorator = param.getDecorators().find((d) => d.getName() === "Param");
2586
+ if (!paramDecorator) continue;
2587
+ const piped = pipeSchemaOf(paramDecorator, project);
2588
+ if (!piped) continue;
2589
+ const name = namedField(paramDecorator);
2590
+ if (name !== null) {
2591
+ types[name] = piped.type;
2592
+ } else {
2593
+ for (const field of piped.fields ?? []) types[field.name] = field.type;
2594
+ }
2595
+ }
2596
+ return Object.keys(types).length > 0 ? types : null;
2597
+ }
1902
2598
  function extractUploadedFiles(method) {
1903
2599
  const FILE = "File | Blob";
1904
2600
  const entries = [];
@@ -1912,28 +2608,28 @@ function extractUploadedFiles(method) {
1912
2608
  for (const decorator of method.getDecorators()) {
1913
2609
  if (decorator.getName() !== "UseInterceptors") continue;
1914
2610
  for (const arg of decorator.getArguments()) {
1915
- if (!Node6.isCallExpression(arg)) continue;
2611
+ if (!Node9.isCallExpression(arg)) continue;
1916
2612
  const interceptor = arg.getExpression().getText();
1917
2613
  const callArgs = arg.getArguments();
1918
2614
  const firstArg2 = callArgs[0];
1919
2615
  if (interceptor === "FileInterceptor") {
1920
- if (firstArg2 && Node6.isStringLiteral(firstArg2)) {
2616
+ if (firstArg2 && Node9.isStringLiteral(firstArg2)) {
1921
2617
  entries.push(`${firstArg2.getLiteralValue()}: ${FILE}`);
1922
2618
  multipart = true;
1923
2619
  }
1924
2620
  } else if (interceptor === "FilesInterceptor") {
1925
- if (firstArg2 && Node6.isStringLiteral(firstArg2)) {
2621
+ if (firstArg2 && Node9.isStringLiteral(firstArg2)) {
1926
2622
  entries.push(`${firstArg2.getLiteralValue()}: Array<${FILE}>`);
1927
2623
  multipart = true;
1928
2624
  }
1929
2625
  } else if (interceptor === "FileFieldsInterceptor") {
1930
- if (firstArg2 && Node6.isArrayLiteralExpression(firstArg2)) {
2626
+ if (firstArg2 && Node9.isArrayLiteralExpression(firstArg2)) {
1931
2627
  for (const el of firstArg2.getElements()) {
1932
- if (!Node6.isObjectLiteralExpression(el)) continue;
2628
+ if (!Node9.isObjectLiteralExpression(el)) continue;
1933
2629
  const nameProp = el.getProperty("name");
1934
- if (nameProp && Node6.isPropertyAssignment(nameProp)) {
2630
+ if (nameProp && Node9.isPropertyAssignment(nameProp)) {
1935
2631
  const init = nameProp.getInitializer();
1936
- if (init && Node6.isStringLiteral(init)) {
2632
+ if (init && Node9.isStringLiteral(init)) {
1937
2633
  entries.push(`${init.getLiteralValue()}: Array<${FILE}>`);
1938
2634
  }
1939
2635
  }
@@ -1953,13 +2649,13 @@ function extractResponseType(method, sourceFile, project) {
1953
2649
  if (apiResponseDecorator) {
1954
2650
  const args = apiResponseDecorator.getArguments();
1955
2651
  const optsArg = args[0];
1956
- if (optsArg && Node6.isObjectLiteralExpression(optsArg)) {
2652
+ if (optsArg && Node9.isObjectLiteralExpression(optsArg)) {
1957
2653
  for (const prop of optsArg.getProperties()) {
1958
- if (!Node6.isPropertyAssignment(prop)) continue;
2654
+ if (!Node9.isPropertyAssignment(prop)) continue;
1959
2655
  if (prop.getName() !== "type") continue;
1960
2656
  const val = prop.getInitializer();
1961
2657
  if (!val) continue;
1962
- if (Node6.isArrayLiteralExpression(val)) {
2658
+ if (Node9.isArrayLiteralExpression(val)) {
1963
2659
  const elements = val.getElements();
1964
2660
  const firstEl = elements[0];
1965
2661
  if (elements.length > 0 && firstEl !== void 0) {
@@ -1980,24 +2676,24 @@ function extractResponseType(method, sourceFile, project) {
1980
2676
  }
1981
2677
  function apiResponseStatus(decorator) {
1982
2678
  const optsArg = decorator.getArguments()[0];
1983
- if (!optsArg || !Node6.isObjectLiteralExpression(optsArg)) return null;
2679
+ if (!optsArg || !Node9.isObjectLiteralExpression(optsArg)) return null;
1984
2680
  for (const prop of optsArg.getProperties()) {
1985
- if (!Node6.isPropertyAssignment(prop)) continue;
2681
+ if (!Node9.isPropertyAssignment(prop)) continue;
1986
2682
  if (prop.getName() !== "status") continue;
1987
2683
  const val = prop.getInitializer();
1988
- if (val && Node6.isNumericLiteral(val)) return Number(val.getLiteralValue());
2684
+ if (val && Node9.isNumericLiteral(val)) return Number(val.getLiteralValue());
1989
2685
  }
1990
2686
  return null;
1991
2687
  }
1992
2688
  function apiResponseTypeNode(decorator) {
1993
2689
  const optsArg = decorator.getArguments()[0];
1994
- if (!optsArg || !Node6.isObjectLiteralExpression(optsArg)) return null;
2690
+ if (!optsArg || !Node9.isObjectLiteralExpression(optsArg)) return null;
1995
2691
  for (const prop of optsArg.getProperties()) {
1996
- if (!Node6.isPropertyAssignment(prop)) continue;
2692
+ if (!Node9.isPropertyAssignment(prop)) continue;
1997
2693
  if (prop.getName() !== "type") continue;
1998
2694
  const val = prop.getInitializer();
1999
2695
  if (!val) return null;
2000
- if (Node6.isArrayLiteralExpression(val)) {
2696
+ if (Node9.isArrayLiteralExpression(val)) {
2001
2697
  const first = val.getElements()[0];
2002
2698
  return first ? { node: first, isArray: true } : null;
2003
2699
  }
@@ -2015,7 +2711,7 @@ function extractErrorType(method, sourceFile, project) {
2015
2711
  const inner = resolveIdentifierToClassType(typeInfo.node, sourceFile, project, 3);
2016
2712
  const type = typeInfo.isArray ? `Array<${inner}>` : inner;
2017
2713
  let ref = null;
2018
- if (Node6.isIdentifier(typeInfo.node)) {
2714
+ if (Node9.isIdentifier(typeInfo.node)) {
2019
2715
  const name = typeInfo.node.getText();
2020
2716
  const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
2021
2717
  if (localDecl?.isExported()) {
@@ -2032,7 +2728,7 @@ function extractErrorType(method, sourceFile, project) {
2032
2728
  return null;
2033
2729
  }
2034
2730
  function resolveIdentifierToClassType(node, sourceFile, project, depth) {
2035
- if (!Node6.isIdentifier(node)) return "unknown";
2731
+ if (!Node9.isIdentifier(node)) return "unknown";
2036
2732
  const name = node.getText();
2037
2733
  const resolved = findType(name, sourceFile, project);
2038
2734
  if (resolved) {
@@ -2052,9 +2748,9 @@ var STREAM_ENVELOPES = /* @__PURE__ */ new Set(["MessageEvent", "MessageEventLik
2052
2748
  var BINARY_RESPONSE_TYPES = /* @__PURE__ */ new Set(["StreamableFile", "Buffer"]);
2053
2749
  function detectBinaryResponse(method) {
2054
2750
  const node = unwrapNamedContainer(method.getReturnTypeNode(), /* @__PURE__ */ new Set(["Promise"]));
2055
- if (!node || !Node6.isTypeReference(node)) return false;
2751
+ if (!node || !Node9.isTypeReference(node)) return false;
2056
2752
  const typeName = node.getTypeName();
2057
- const name = Node6.isIdentifier(typeName) ? typeName.getText() : "";
2753
+ const name = Node9.isIdentifier(typeName) ? typeName.getText() : "";
2058
2754
  return BINARY_RESPONSE_TYPES.has(name);
2059
2755
  }
2060
2756
  function detectStreamElement(method) {
@@ -2069,9 +2765,9 @@ function detectStreamElement(method) {
2069
2765
  return null;
2070
2766
  }
2071
2767
  function streamContainerElement(node) {
2072
- if (!node || !Node6.isTypeReference(node)) return null;
2768
+ if (!node || !Node9.isTypeReference(node)) return null;
2073
2769
  const typeName = node.getTypeName();
2074
- const name = Node6.isIdentifier(typeName) ? typeName.getText() : "";
2770
+ const name = Node9.isIdentifier(typeName) ? typeName.getText() : "";
2075
2771
  if (STREAM_CONTAINERS.has(name) || STREAM_CONTAINERS_GENERATOR.has(name)) {
2076
2772
  return node.getTypeArguments()[0] ?? null;
2077
2773
  }
@@ -2081,9 +2777,9 @@ function hasAsQueryDecorator(method) {
2081
2777
  return method.getDecorators().some((d) => d.getName() === "AsQuery");
2082
2778
  }
2083
2779
  function unwrapNamedContainer(node, names) {
2084
- if (!node || !Node6.isTypeReference(node)) return node;
2780
+ if (!node || !Node9.isTypeReference(node)) return node;
2085
2781
  const typeName = node.getTypeName();
2086
- const name = Node6.isIdentifier(typeName) ? typeName.getText() : "";
2782
+ const name = Node9.isIdentifier(typeName) ? typeName.getText() : "";
2087
2783
  if (names.has(name)) {
2088
2784
  return node.getTypeArguments()[0] ?? node;
2089
2785
  }
@@ -2104,19 +2800,20 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2104
2800
  body = body ?? bodyType;
2105
2801
  }
2106
2802
  const paramsType = extractParamsType(method, sourceFile, project);
2803
+ const paramTypes = extractPipedParamTypes(method, project);
2107
2804
  const response = isStream ? resolveTypeNodeToString(streamElement, sourceFile, project, 3) : extractResponseType(method, sourceFile, project);
2108
2805
  const errorInfo = extractErrorType(method, sourceFile, project);
2109
- if (body === null && query === null && paramsType === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream && !uploads.multipart && !binaryResponse && !asQuery) {
2806
+ if (body === null && query === null && paramsType === null && paramTypes === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream && !uploads.multipart && !binaryResponse && !asQuery) {
2110
2807
  return null;
2111
2808
  }
2112
2809
  let bodyRef = null;
2113
2810
  let queryRef = null;
2114
2811
  let responseRef = null;
2115
2812
  for (const param of method.getParameters()) {
2116
- if (param.getDecorators().some((d) => d.getName() === "Body") && param.getTypeNode()) {
2813
+ if (param.getDecorators().some((d) => d.getName() === "Body") && param.getTypeNode() && !hasPipeSchema(param, "Body", project)) {
2117
2814
  bodyRef = resolveBodyQueryResponseRef(param.getTypeNode(), sourceFile, project);
2118
2815
  }
2119
- if (param.getDecorators().some((d) => d.getName() === "Query") && param.getTypeNode()) {
2816
+ if (param.getDecorators().some((d) => d.getName() === "Query") && param.getTypeNode() && !hasPipeSchema(param, "Query", project)) {
2120
2817
  queryRef = resolveBodyQueryResponseRef(param.getTypeNode(), sourceFile, project);
2121
2818
  }
2122
2819
  }
@@ -2129,11 +2826,11 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2129
2826
  if (apiResp) {
2130
2827
  const args = apiResp.getArguments();
2131
2828
  const optsArg = args[0];
2132
- if (optsArg && Node6.isObjectLiteralExpression(optsArg)) {
2829
+ if (optsArg && Node9.isObjectLiteralExpression(optsArg)) {
2133
2830
  for (const prop of optsArg.getProperties()) {
2134
- if (Node6.isPropertyAssignment(prop) && prop.getName() === "type") {
2831
+ if (Node9.isPropertyAssignment(prop) && prop.getName() === "type") {
2135
2832
  const val = prop.getInitializer();
2136
- if (val && Node6.isIdentifier(val)) {
2833
+ if (val && Node9.isIdentifier(val)) {
2137
2834
  const name = val.getText();
2138
2835
  const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
2139
2836
  if (localDecl?.isExported()) {
@@ -2169,6 +2866,7 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2169
2866
  response,
2170
2867
  error: errorInfo?.type ?? null,
2171
2868
  params: paramsType,
2869
+ paramTypes,
2172
2870
  queryRef,
2173
2871
  bodyRef,
2174
2872
  responseRef,
@@ -2189,6 +2887,7 @@ function extractDtoContract(method, sourceFile, project, mixin, controllerClass)
2189
2887
  function resolveParamClass(method, decoratorName, sourceFile, project) {
2190
2888
  for (const param of method.getParameters()) {
2191
2889
  if (!param.getDecorators().some((d) => d.getName() === decoratorName)) continue;
2890
+ if (hasPipeSchema(param, decoratorName, project)) continue;
2192
2891
  const typeNode = param.getTypeNode();
2193
2892
  if (!typeNode) continue;
2194
2893
  const text = typeNode.getText().replace(/\[\]$/, "");
@@ -2201,129 +2900,6 @@ function resolveParamClass(method, decoratorName, sourceFile, project) {
2201
2900
  return null;
2202
2901
  }
2203
2902
 
2204
- // src/discovery/zod-ast-to-ts.ts
2205
- import { Node as Node7, SyntaxKind as SyntaxKind3 } from "ts-morph";
2206
- function zodAstToTs(node) {
2207
- if (!Node7.isCallExpression(node)) return "unknown";
2208
- const expr = node.getExpression();
2209
- if (Node7.isPropertyAccessExpression(expr)) {
2210
- const methodName = expr.getName();
2211
- const receiver = expr.getExpression();
2212
- if (methodName === "optional") {
2213
- return `${zodAstToTs(receiver)} | undefined`;
2214
- }
2215
- if (methodName === "nullable") {
2216
- return `${zodAstToTs(receiver)} | null`;
2217
- }
2218
- const args = node.getArguments();
2219
- switch (methodName) {
2220
- case "string":
2221
- return "string";
2222
- case "number":
2223
- return "number";
2224
- case "boolean":
2225
- return "boolean";
2226
- case "unknown":
2227
- return "unknown";
2228
- case "any":
2229
- return "unknown";
2230
- case "literal": {
2231
- const lit = args[0];
2232
- if (!lit) return "unknown";
2233
- if (Node7.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
2234
- if (Node7.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
2235
- if (lit.getKind() === SyntaxKind3.TrueKeyword) return "true";
2236
- if (lit.getKind() === SyntaxKind3.FalseKeyword) return "false";
2237
- return "unknown";
2238
- }
2239
- case "enum": {
2240
- const arrArg = args[0];
2241
- if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
2242
- const members = arrArg.getElements().map(
2243
- (el) => Node7.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
2244
- );
2245
- return members.join(" | ");
2246
- }
2247
- case "array": {
2248
- const inner = args[0];
2249
- if (!inner) return "unknown";
2250
- return `Array<${zodAstToTs(inner)}>`;
2251
- }
2252
- case "object": {
2253
- const objArg = args[0];
2254
- if (!objArg || !Node7.isObjectLiteralExpression(objArg)) return "unknown";
2255
- const lines = [];
2256
- for (const prop of objArg.getProperties()) {
2257
- if (!Node7.isPropertyAssignment(prop)) continue;
2258
- const key = prop.getName();
2259
- const valNode = prop.getInitializer();
2260
- if (!valNode) continue;
2261
- const tsType = zodAstToTs(valNode);
2262
- const isOpt = isOptionalChain(valNode);
2263
- lines.push(`${key}${isOpt ? "?" : ""}: ${tsType}`);
2264
- }
2265
- return `{ ${lines.join("; ")} }`;
2266
- }
2267
- case "union": {
2268
- const arrArg = args[0];
2269
- if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
2270
- return arrArg.getElements().map(zodAstToTs).join(" | ");
2271
- }
2272
- case "record": {
2273
- const valArg = args.length === 1 ? args[0] : args[1];
2274
- if (!valArg) return "unknown";
2275
- return `Record<string, ${zodAstToTs(valArg)}>`;
2276
- }
2277
- case "tuple": {
2278
- const arrArg = args[0];
2279
- if (!arrArg || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
2280
- return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
2281
- }
2282
- default:
2283
- return "unknown";
2284
- }
2285
- }
2286
- return "unknown";
2287
- }
2288
- function isOptionalChain(node) {
2289
- if (!Node7.isCallExpression(node)) return false;
2290
- const expr = node.getExpression();
2291
- return Node7.isPropertyAccessExpression(expr) && expr.getName() === "optional";
2292
- }
2293
- function parseDefineContractCall(callExpr) {
2294
- if (!Node7.isCallExpression(callExpr)) return null;
2295
- const callee = callExpr.getExpression();
2296
- const calleeName = Node7.isIdentifier(callee) ? callee.getText() : Node7.isPropertyAccessExpression(callee) ? callee.getName() : "";
2297
- if (calleeName !== "defineContract") return null;
2298
- const args = callExpr.getArguments();
2299
- const optsArg = args[0];
2300
- if (!optsArg || !Node7.isObjectLiteralExpression(optsArg)) return null;
2301
- let query = null;
2302
- let body = null;
2303
- let response = "unknown";
2304
- let error = null;
2305
- let bodyZodText = null;
2306
- let queryZodText = null;
2307
- for (const prop of optsArg.getProperties()) {
2308
- if (!Node7.isPropertyAssignment(prop)) continue;
2309
- const propName = prop.getName();
2310
- const val = prop.getInitializer();
2311
- if (!val) continue;
2312
- if (propName === "query") {
2313
- query = zodAstToTs(val);
2314
- queryZodText = val.getText();
2315
- } else if (propName === "body") {
2316
- body = zodAstToTs(val);
2317
- bodyZodText = val.getText();
2318
- } else if (propName === "response") {
2319
- response = zodAstToTs(val);
2320
- } else if (propName === "error") {
2321
- error = zodAstToTs(val);
2322
- }
2323
- }
2324
- return { query, body, response, error, bodyZodText, queryZodText };
2325
- }
2326
-
2327
2903
  // src/discovery/contracts-fast.ts
2328
2904
  function resolveTsconfigPath(cwd, tsconfig) {
2329
2905
  return tsconfig ? resolve3(tsconfig) : join2(cwd, "tsconfig.json");
@@ -2335,25 +2911,25 @@ var NO_TSCONFIG_OPTIONS = {
2335
2911
  };
2336
2912
  function loadDiscoveryTsconfig(tsconfigPath) {
2337
2913
  if (!existsSync(tsconfigPath)) return { options: null, files: [] };
2338
- const read = ts.readConfigFile(tsconfigPath, (path) => ts.sys.readFile(path));
2914
+ const read = ts3.readConfigFile(tsconfigPath, (path) => ts3.sys.readFile(path));
2339
2915
  if (read.error) {
2340
2916
  return {
2341
2917
  options: null,
2342
2918
  files: [tsconfigPath],
2343
- error: ts.flattenDiagnosticMessageText(read.error.messageText, " ")
2919
+ error: ts3.flattenDiagnosticMessageText(read.error.messageText, " ")
2344
2920
  };
2345
2921
  }
2346
2922
  const host = {
2347
- useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
2923
+ useCaseSensitiveFileNames: ts3.sys.useCaseSensitiveFileNames,
2348
2924
  // The one line that keeps a tsconfig from being a filesystem walk.
2349
2925
  readDirectory: () => [],
2350
- fileExists: (path) => ts.sys.fileExists(path),
2926
+ fileExists: (path) => ts3.sys.fileExists(path),
2351
2927
  // `extends` is resolved through the host, so a consumer whose `paths` live
2352
2928
  // in a base tsconfig keeps working.
2353
- readFile: (path) => ts.sys.readFile(path)
2929
+ readFile: (path) => ts3.sys.readFile(path)
2354
2930
  };
2355
- const sourceFile = ts.readJsonConfigFile(tsconfigPath, (path) => ts.sys.readFile(path));
2356
- const parsed = ts.parseJsonSourceFileConfigFileContent(
2931
+ const sourceFile = ts3.readJsonConfigFile(tsconfigPath, (path) => ts3.sys.readFile(path));
2932
+ const parsed = ts3.parseJsonSourceFileConfigFileContent(
2357
2933
  sourceFile,
2358
2934
  host,
2359
2935
  dirname2(tsconfigPath),
@@ -2376,7 +2952,7 @@ function createDiscoveryProject(tsconfigPath, tsconfig = loadDiscoveryTsconfig(t
2376
2952
  `[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.`
2377
2953
  );
2378
2954
  }
2379
- return new Project2({
2955
+ return new Project3({
2380
2956
  compilerOptions: tsconfig.options ?? { ...NO_TSCONFIG_OPTIONS },
2381
2957
  skipAddingFilesFromTsConfig: true,
2382
2958
  skipLoadingLibFiles: true,
@@ -2481,15 +3057,16 @@ var PersistentDiscovery = class _PersistentDiscovery {
2481
3057
  clearTypeResolutionCaches(this.project);
2482
3058
  clearEnumCache(this.project);
2483
3059
  clearMixinTypeProject();
3060
+ clearSchemaTypeProject(this.project);
2484
3061
  return extractRoutesFrom(this.project, this.controllerPaths);
2485
3062
  }
2486
3063
  };
2487
3064
  function decoratorStringArg(decoratorExpr) {
2488
3065
  if (!decoratorExpr) return void 0;
2489
- if (Node8.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
2490
- if (Node8.isArrayLiteralExpression(decoratorExpr)) {
3066
+ if (Node10.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
3067
+ if (Node10.isArrayLiteralExpression(decoratorExpr)) {
2491
3068
  const first = decoratorExpr.getElements()[0];
2492
- if (first && Node8.isStringLiteral(first)) return first.getLiteralValue();
3069
+ if (first && Node10.isStringLiteral(first)) return first.getLiteralValue();
2493
3070
  }
2494
3071
  return void 0;
2495
3072
  }
@@ -2610,9 +3187,9 @@ function extractContractRoute(args) {
2610
3187
  let contractDef = null;
2611
3188
  let bodyZodRef = null;
2612
3189
  let queryZodRef = null;
2613
- if (Node8.isCallExpression(firstDecoratorArg)) {
2614
- contractDef = parseDefineContractCall(firstDecoratorArg);
2615
- } else if (Node8.isIdentifier(firstDecoratorArg)) {
3190
+ if (Node10.isCallExpression(firstDecoratorArg)) {
3191
+ contractDef = parseDefineContractCall(firstDecoratorArg, project);
3192
+ } else if (Node10.isIdentifier(firstDecoratorArg)) {
2616
3193
  const identName = firstDecoratorArg.getText();
2617
3194
  const resolvedVar = resolveImportedVariable(identName, sourceFile, project);
2618
3195
  if (!resolvedVar) {
@@ -2624,7 +3201,7 @@ function extractContractRoute(args) {
2624
3201
  const { decl: varDecl, file: declFile } = resolvedVar;
2625
3202
  const initializer = varDecl.getInitializer();
2626
3203
  if (!initializer) return null;
2627
- contractDef = parseDefineContractCall(initializer);
3204
+ contractDef = parseDefineContractCall(initializer, project);
2628
3205
  if (contractDef && varDecl.isExported()) {
2629
3206
  const filePath = declFile.getFilePath();
2630
3207
  if (contractDef.body !== null) {
@@ -2695,6 +3272,7 @@ function extractDtoRoute(args) {
2695
3272
  body: dtoContract?.body ?? null,
2696
3273
  response: mixinResponse ?? dtoContract?.response ?? "unknown",
2697
3274
  error: dtoContract?.error ?? null,
3275
+ paramTypes: dtoContract?.paramTypes ?? null,
2698
3276
  queryRef: dtoContract?.queryRef ?? null,
2699
3277
  bodyRef: dtoContract?.bodyRef ?? null,
2700
3278
  responseRef: dtoContract?.responseRef ?? null,
@@ -2824,7 +3402,7 @@ function extractPropsSource(source, exportName) {
2824
3402
 
2825
3403
  // src/discovery/shared-props.ts
2826
3404
  import { join as join4 } from "path";
2827
- import { Node as Node9, Project as Project3, SyntaxKind as SyntaxKind4 } from "ts-morph";
3405
+ import { Node as Node11, Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
2828
3406
  function discoverSharedProps(project, moduleEntry) {
2829
3407
  try {
2830
3408
  let sourceFile = project.getSourceFile(moduleEntry);
@@ -2850,14 +3428,14 @@ function discoverSharedPropsFromConfig(config) {
2850
3428
  const tsconfigPath = config.app.tsconfig ?? join4(config.codegen.cwd, "tsconfig.json");
2851
3429
  let project;
2852
3430
  try {
2853
- project = new Project3({
3431
+ project = new Project4({
2854
3432
  tsConfigFilePath: tsconfigPath,
2855
3433
  skipAddingFilesFromTsConfig: true,
2856
3434
  skipLoadingLibFiles: true,
2857
3435
  skipFileDependencyResolution: true
2858
3436
  });
2859
3437
  } catch {
2860
- project = new Project3({
3438
+ project = new Project4({
2861
3439
  skipAddingFilesFromTsConfig: true,
2862
3440
  skipLoadingLibFiles: true,
2863
3441
  skipFileDependencyResolution: true,
@@ -2873,10 +3451,10 @@ function findForRootCall(sourceFile) {
2873
3451
  const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind4.CallExpression);
2874
3452
  for (const call of callExpressions) {
2875
3453
  const expr = call.getExpression();
2876
- if (!Node9.isPropertyAccessExpression(expr)) continue;
3454
+ if (!Node11.isPropertyAccessExpression(expr)) continue;
2877
3455
  const methodName = expr.getName();
2878
3456
  const objectExpr = expr.getExpression();
2879
- if (methodName === "forRoot" && Node9.isIdentifier(objectExpr)) {
3457
+ if (methodName === "forRoot" && Node11.isIdentifier(objectExpr)) {
2880
3458
  const name = objectExpr.getText();
2881
3459
  if (name === "InertiaModule") {
2882
3460
  return call;
@@ -2886,19 +3464,19 @@ function findForRootCall(sourceFile) {
2886
3464
  return null;
2887
3465
  }
2888
3466
  function findShareInitializer(forRootCall) {
2889
- if (!Node9.isCallExpression(forRootCall)) return null;
3467
+ if (!Node11.isCallExpression(forRootCall)) return null;
2890
3468
  const args = forRootCall.getArguments();
2891
3469
  const firstArg2 = args[0];
2892
- if (!firstArg2 || !Node9.isObjectLiteralExpression(firstArg2)) return null;
3470
+ if (!firstArg2 || !Node11.isObjectLiteralExpression(firstArg2)) return null;
2893
3471
  for (const prop of firstArg2.getProperties()) {
2894
- if (Node9.isPropertyAssignment(prop) && prop.getName() === "share") {
3472
+ if (Node11.isPropertyAssignment(prop) && prop.getName() === "share") {
2895
3473
  return prop.getInitializer() ?? null;
2896
3474
  }
2897
3475
  }
2898
3476
  return null;
2899
3477
  }
2900
3478
  function extractShareType(node, sourceFile, project) {
2901
- if (Node9.isIdentifier(node)) {
3479
+ if (Node11.isIdentifier(node)) {
2902
3480
  const ref = resolveIdentifierToImportRef(node, sourceFile, project);
2903
3481
  if (ref) {
2904
3482
  return {
@@ -2908,22 +3486,22 @@ function extractShareType(node, sourceFile, project) {
2908
3486
  };
2909
3487
  }
2910
3488
  }
2911
- if (Node9.isArrowFunction(node)) {
3489
+ if (Node11.isArrowFunction(node)) {
2912
3490
  const result = extractFromFunctionLike(node, sourceFile);
2913
3491
  return result ? { ...result, isImportRef: false } : null;
2914
3492
  }
2915
- if (Node9.isFunctionExpression(node)) {
3493
+ if (Node11.isFunctionExpression(node)) {
2916
3494
  const result = extractFromFunctionLike(node, sourceFile);
2917
3495
  return result ? { ...result, isImportRef: false } : null;
2918
3496
  }
2919
- if (Node9.isObjectLiteralExpression(node)) {
3497
+ if (Node11.isObjectLiteralExpression(node)) {
2920
3498
  const result = extractFromObjectLiteral(node);
2921
3499
  return result ? { ...result, isImportRef: false } : null;
2922
3500
  }
2923
3501
  return null;
2924
3502
  }
2925
3503
  function resolveIdentifierToImportRef(id, sourceFile, project) {
2926
- if (!Node9.isIdentifier(id)) return null;
3504
+ if (!Node11.isIdentifier(id)) return null;
2927
3505
  const name = id.getText();
2928
3506
  const localFunc = sourceFile.getFunction(name);
2929
3507
  if (localFunc?.isExported()) {
@@ -2957,37 +3535,37 @@ function resolveIdentifierToImportRef(id, sourceFile, project) {
2957
3535
  return null;
2958
3536
  }
2959
3537
  function extractFromFunctionLike(node, _sourceFile) {
2960
- const returnTypeNode = Node9.isArrowFunction(node) || Node9.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
3538
+ const returnTypeNode = Node11.isArrowFunction(node) || Node11.isFunctionExpression(node) ? node.getReturnTypeNode() : null;
2961
3539
  if (returnTypeNode) {
2962
3540
  return extractFromReturnTypeAnnotation(returnTypeNode);
2963
3541
  }
2964
- if (Node9.isArrowFunction(node)) {
3542
+ if (Node11.isArrowFunction(node)) {
2965
3543
  const body = node.getBody();
2966
- if (Node9.isParenthesizedExpression(body)) {
3544
+ if (Node11.isParenthesizedExpression(body)) {
2967
3545
  const inner = body.getExpression();
2968
- if (Node9.isObjectLiteralExpression(inner)) {
3546
+ if (Node11.isObjectLiteralExpression(inner)) {
2969
3547
  return extractFromObjectLiteral(inner);
2970
3548
  }
2971
3549
  }
2972
- if (Node9.isObjectLiteralExpression(body)) {
3550
+ if (Node11.isObjectLiteralExpression(body)) {
2973
3551
  return extractFromObjectLiteral(body);
2974
3552
  }
2975
- if (Node9.isBlock(body)) {
3553
+ if (Node11.isBlock(body)) {
2976
3554
  return extractFromBlockReturn(body);
2977
3555
  }
2978
3556
  }
2979
- if (Node9.isFunctionExpression(node)) {
3557
+ if (Node11.isFunctionExpression(node)) {
2980
3558
  const body = node.getBody();
2981
- if (Node9.isBlock(body)) {
3559
+ if (Node11.isBlock(body)) {
2982
3560
  return extractFromBlockReturn(body);
2983
3561
  }
2984
3562
  }
2985
3563
  return null;
2986
3564
  }
2987
3565
  function extractFromReturnTypeAnnotation(typeNode) {
2988
- if (Node9.isTypeReference(typeNode)) {
3566
+ if (Node11.isTypeReference(typeNode)) {
2989
3567
  const typeName = typeNode.getTypeName();
2990
- if (Node9.isIdentifier(typeName) && typeName.getText() === "Promise") {
3568
+ if (Node11.isIdentifier(typeName) && typeName.getText() === "Promise") {
2991
3569
  const typeArgs = typeNode.getTypeArguments();
2992
3570
  const firstArg2 = typeArgs[0];
2993
3571
  if (firstArg2) {
@@ -2996,10 +3574,10 @@ function extractFromReturnTypeAnnotation(typeNode) {
2996
3574
  return null;
2997
3575
  }
2998
3576
  }
2999
- if (Node9.isTypeLiteral(typeNode)) {
3577
+ if (Node11.isTypeLiteral(typeNode)) {
3000
3578
  const properties = [];
3001
3579
  for (const member of typeNode.getMembers()) {
3002
- if (Node9.isPropertySignature(member)) {
3580
+ if (Node11.isPropertySignature(member)) {
3003
3581
  const name = member.getName();
3004
3582
  const memberTypeNode = member.getTypeNode();
3005
3583
  const type = memberTypeNode ? memberTypeNode.getText() : "unknown";
@@ -3013,19 +3591,19 @@ function extractFromReturnTypeAnnotation(typeNode) {
3013
3591
  return null;
3014
3592
  }
3015
3593
  function extractFromBlockReturn(block) {
3016
- if (!Node9.isBlock(block)) return null;
3594
+ if (!Node11.isBlock(block)) return null;
3017
3595
  const statements = block.getStatements();
3018
3596
  for (let i = statements.length - 1; i >= 0; i--) {
3019
3597
  const stmt = statements[i];
3020
- if (!Node9.isReturnStatement(stmt)) continue;
3598
+ if (!Node11.isReturnStatement(stmt)) continue;
3021
3599
  const expr = stmt.getExpression();
3022
3600
  if (!expr) continue;
3023
- if (Node9.isObjectLiteralExpression(expr)) {
3601
+ if (Node11.isObjectLiteralExpression(expr)) {
3024
3602
  return extractFromObjectLiteral(expr);
3025
3603
  }
3026
- if (Node9.isParenthesizedExpression(expr)) {
3604
+ if (Node11.isParenthesizedExpression(expr)) {
3027
3605
  const inner = expr.getExpression();
3028
- if (Node9.isObjectLiteralExpression(inner)) {
3606
+ if (Node11.isObjectLiteralExpression(inner)) {
3029
3607
  return extractFromObjectLiteral(inner);
3030
3608
  }
3031
3609
  }
@@ -3034,10 +3612,10 @@ function extractFromBlockReturn(block) {
3034
3612
  return null;
3035
3613
  }
3036
3614
  function extractFromObjectLiteral(objLiteral) {
3037
- if (!Node9.isObjectLiteralExpression(objLiteral)) return null;
3615
+ if (!Node11.isObjectLiteralExpression(objLiteral)) return null;
3038
3616
  const properties = [];
3039
3617
  for (const prop of objLiteral.getProperties()) {
3040
- if (!Node9.isPropertyAssignment(prop)) continue;
3618
+ if (!Node11.isPropertyAssignment(prop)) continue;
3041
3619
  const name = prop.getName();
3042
3620
  const initializer = prop.getInitializer();
3043
3621
  if (!initializer) continue;
@@ -3049,21 +3627,21 @@ function extractFromObjectLiteral(objLiteral) {
3049
3627
  return { typeString, properties, isImportRef: false };
3050
3628
  }
3051
3629
  function inferExpressionType(node) {
3052
- if (Node9.isStringLiteral(node)) return "string";
3053
- if (Node9.isTemplateExpression(node) || Node9.isNoSubstitutionTemplateLiteral(node))
3630
+ if (Node11.isStringLiteral(node)) return "string";
3631
+ if (Node11.isTemplateExpression(node) || Node11.isNoSubstitutionTemplateLiteral(node))
3054
3632
  return "string";
3055
- if (Node9.isNumericLiteral(node)) return "number";
3633
+ if (Node11.isNumericLiteral(node)) return "number";
3056
3634
  if (node.getKind() === SyntaxKind4.TrueKeyword || node.getKind() === SyntaxKind4.FalseKeyword) {
3057
3635
  return "boolean";
3058
3636
  }
3059
3637
  if (node.getKind() === SyntaxKind4.NullKeyword) return "null";
3060
- if (Node9.isIdentifier(node) && node.getText() === "undefined") return "undefined";
3061
- if (Node9.isObjectLiteralExpression(node)) {
3638
+ if (Node11.isIdentifier(node) && node.getText() === "undefined") return "undefined";
3639
+ if (Node11.isObjectLiteralExpression(node)) {
3062
3640
  const props = node.getProperties();
3063
3641
  if (props.length === 0) return "Record<string, unknown>";
3064
3642
  const entries = [];
3065
3643
  for (const prop of props) {
3066
- if (!Node9.isPropertyAssignment(prop)) continue;
3644
+ if (!Node11.isPropertyAssignment(prop)) continue;
3067
3645
  const key = prop.getName();
3068
3646
  const init = prop.getInitializer();
3069
3647
  if (!init) continue;
@@ -3072,23 +3650,23 @@ function inferExpressionType(node) {
3072
3650
  if (entries.length === 0) return "Record<string, unknown>";
3073
3651
  return `{ ${entries.join("; ")} }`;
3074
3652
  }
3075
- if (Node9.isArrayLiteralExpression(node)) {
3653
+ if (Node11.isArrayLiteralExpression(node)) {
3076
3654
  const elements = node.getElements();
3077
3655
  if (elements.length === 0) return "Array<unknown>";
3078
3656
  const first = elements[0];
3079
3657
  if (first) return `Array<${inferExpressionType(first)}>`;
3080
3658
  return "Array<unknown>";
3081
3659
  }
3082
- if (Node9.isConditionalExpression(node)) {
3660
+ if (Node11.isConditionalExpression(node)) {
3083
3661
  const whenTrue = inferExpressionType(node.getWhenTrue());
3084
3662
  const whenFalse = inferExpressionType(node.getWhenFalse());
3085
3663
  if (whenTrue === whenFalse) return whenTrue;
3086
3664
  return `${whenTrue} | ${whenFalse}`;
3087
3665
  }
3088
- if (Node9.isParenthesizedExpression(node)) {
3666
+ if (Node11.isParenthesizedExpression(node)) {
3089
3667
  return inferExpressionType(node.getExpression());
3090
3668
  }
3091
- if (Node9.isAsExpression(node)) {
3669
+ if (Node11.isAsExpression(node)) {
3092
3670
  const typeNode = node.getTypeNode();
3093
3671
  if (typeNode) return typeNode.getText();
3094
3672
  }
@@ -3101,7 +3679,7 @@ import { isAbsolute as isAbsolute2, join as join5, relative as relative4 } from
3101
3679
 
3102
3680
  // src/extension/registry.ts
3103
3681
  import { relative as relative3, resolve as resolve4 } from "path";
3104
- import { Project as Project4 } from "ts-morph";
3682
+ import { Project as Project5 } from "ts-morph";
3105
3683
  function resolveApiSlots(extensions) {
3106
3684
  let layer;
3107
3685
  let layerOwner;
@@ -3152,7 +3730,7 @@ function createExtensionContext(config, getRoutes, trackedInputs) {
3152
3730
  },
3153
3731
  project() {
3154
3732
  if (!project) {
3155
- project = new Project4({
3733
+ project = new Project5({
3156
3734
  skipAddingFilesFromTsConfig: true,
3157
3735
  skipLoadingLibFiles: true,
3158
3736
  skipFileDependencyResolution: true,
@@ -3270,10 +3848,11 @@ function insertIntoTree(tree, segments, leaf, fullName) {
3270
3848
  insertIntoTree(branch.children, rest, leaf, fullName);
3271
3849
  }
3272
3850
  }
3273
- function buildParamsType(params) {
3851
+ function buildParamsType(params, paramTypes) {
3274
3852
  const pathParams = params.filter((p) => p.source === "path");
3275
3853
  if (pathParams.length === 0) return "never";
3276
- return `{ ${pathParams.map((p) => `${p.name}: string`).join("; ")} }`;
3854
+ const typeOf = (name) => paramTypes && Object.hasOwn(paramTypes, name) && paramTypes[name] || "string";
3855
+ return `{ ${pathParams.map((p) => `${p.name}: ${typeOf(p.name)}`).join("; ")} }`;
3277
3856
  }
3278
3857
  function hasPathParams(params) {
3279
3858
  return params.some((p) => p.source === "path");
@@ -3367,7 +3946,7 @@ function emitRouterTypeBlock(tree, indent, outDir, serialization) {
3367
3946
  }
3368
3947
  const response = buildResponseType(c, outDir, serialization);
3369
3948
  const error = buildErrorType(c);
3370
- const params = buildParamsType(c.params);
3949
+ const params = buildParamsType(c.params, c.contractSource.paramTypes);
3371
3950
  const safeMethod = JSON.stringify(method);
3372
3951
  const safeUrl = JSON.stringify(c.path);
3373
3952
  const filterLiterals = filterFieldLiterals(c.contractSource.filterFields);
@@ -3636,6 +4215,9 @@ var EMPTY_PATH_NAMESPACE = [
3636
4215
  "}",
3637
4216
  ""
3638
4217
  ];
4218
+ function isClientCallable(route) {
4219
+ return route.method.toUpperCase() !== "ALL";
4220
+ }
3639
4221
  function buildApiFile(routes, outDir, opts = {}) {
3640
4222
  const fetcherImportPath = opts.fetcherImportPath;
3641
4223
  const serialization = opts.serialization ?? "json";
@@ -3643,7 +4225,7 @@ function buildApiFile(routes, outDir, opts = {}) {
3643
4225
  const { layer } = resolveApiSlots(extensions);
3644
4226
  const memberExts = extensions.filter((e) => e.apiMembers);
3645
4227
  const headerExts = extensions.filter((e) => e.apiHeader);
3646
- const contracted = routes.filter((r) => r.contract);
4228
+ const contracted = routes.filter((r) => r.contract && isClientCallable(r));
3647
4229
  const ctx = opts.ctx ?? {
3648
4230
  cwd: outDir ?? "",
3649
4231
  outDir: outDir ?? "",
@@ -4561,6 +5143,7 @@ function buildOpenApiSpec(routes, opts = {}) {
4561
5143
  const paths = {};
4562
5144
  for (const route of routes) {
4563
5145
  if (!route.contract) continue;
5146
+ if (route.method.toUpperCase() === "ALL") continue;
4564
5147
  const oaPath = toOpenApiPath(route.path);
4565
5148
  const method = route.method.toLowerCase();
4566
5149
  let pathItem = paths[oaPath];
@@ -5062,7 +5645,7 @@ async function watch(config, onChange, options = {}) {
5062
5645
  }
5063
5646
 
5064
5647
  // src/index.ts
5065
- var VERSION = "0.25.1";
5648
+ var VERSION = "0.26.0";
5066
5649
 
5067
5650
  // src/generate-manifest.ts
5068
5651
  var MANIFEST_FILE = ".codegen-manifest.json";