@trpc/openapi 11.17.1-canary.2 → 11.18.0-alpha

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/README.md CHANGED
@@ -25,10 +25,11 @@ pnpm exec trpc-openapi ./src/server/router.ts
25
25
  ```ts
26
26
  import { generateOpenAPIDocument } from '@trpc/openapi';
27
27
 
28
- const doc = generateOpenAPIDocument('./src/server/router.ts', {
28
+ const doc = await generateOpenAPIDocument('./src/server/router.ts', {
29
29
  exportName: 'AppRouter',
30
30
  title: 'My API',
31
31
  version: '1.0.0',
32
+ servers: [{ url: 'https://api.example.com/trpc' }],
32
33
  });
33
34
  ```
34
35
 
package/dist/cli.js CHANGED
@@ -937,6 +937,7 @@ function buildOpenAPIDocument(procedures, options, meta = { errorSchema: null })
937
937
  title: options.title ?? "tRPC API",
938
938
  version: options.version ?? "0.0.0"
939
939
  },
940
+ ...options.servers?.length ? { servers: options.servers } : {},
940
941
  paths,
941
942
  components: {
942
943
  ...hasNamedSchemas && meta.schemas ? { schemas: meta.schemas } : {},
@@ -1035,7 +1036,8 @@ function parseArgs$1(argv) {
1035
1036
  version: {
1036
1037
  type: "string",
1037
1038
  default: "0.0.0"
1038
- }
1039
+ },
1040
+ "server-url": { type: "string" }
1039
1041
  },
1040
1042
  strict: true,
1041
1043
  allowPositionals: true
@@ -1051,6 +1053,7 @@ function parseArgs$1(argv) {
1051
1053
  output: parsed.values.output,
1052
1054
  title: parsed.values.title,
1053
1055
  version: parsed.values.version,
1056
+ serverUrl: parsed.values["server-url"],
1054
1057
  help: parsed.values.help
1055
1058
  };
1056
1059
  }
@@ -1068,11 +1071,13 @@ Options:
1068
1071
  -o, --output <file> Output file path [default: openapi.json]
1069
1072
  --title <text> OpenAPI info.title [default: tRPC API]
1070
1073
  --version <ver> OpenAPI info.version [default: 0.0.0]
1074
+ --server-url <url> OpenAPI servers[].url (include any tRPC mount prefix)
1071
1075
  -h, --help Show this help message
1072
1076
 
1073
1077
  Examples:
1074
1078
  trpc-openapi ./src/server/router.ts
1075
1079
  trpc-openapi ./src/server/router.ts --output api.json --title "My API" --version 1.0.0
1080
+ trpc-openapi ./src/server/router.ts --server-url https://api.example.com/trpc
1076
1081
  trpc-openapi ./src/server/router.ts --export appRouter
1077
1082
  `.trim();
1078
1083
  async function main() {
@@ -1097,7 +1102,8 @@ async function main() {
1097
1102
  doc = await generateOpenAPIDocument(routerFile, {
1098
1103
  exportName: args.exportName,
1099
1104
  title: args.title,
1100
- version: args.version
1105
+ version: args.version,
1106
+ servers: args.serverUrl ? [{ url: args.serverUrl }] : void 0
1101
1107
  });
1102
1108
  } catch (err) {
1103
1109
  const message = err instanceof Error ? err.message : String(err);
package/dist/index.cjs CHANGED
@@ -935,7 +935,7 @@ function buildProcedureOperation(proc, method) {
935
935
  return operation;
936
936
  }
937
937
  function buildOpenAPIDocument(procedures, options, meta = { errorSchema: null }) {
938
- var _options$title, _options$version, _meta$errorSchema;
938
+ var _options$title, _options$version, _options$servers, _meta$errorSchema;
939
939
  const paths = {};
940
940
  for (const proc of procedures) {
941
941
  var _paths$opPath;
@@ -947,13 +947,14 @@ function buildOpenAPIDocument(procedures, options, meta = { errorSchema: null })
947
947
  pathItem[method] = buildProcedureOperation(proc, method);
948
948
  }
949
949
  const hasNamedSchemas = meta.schemas !== void 0 && Object.keys(meta.schemas).length > 0;
950
- return {
950
+ return (0, import_objectSpread2.default)((0, import_objectSpread2.default)({
951
951
  openapi: "3.1.1",
952
952
  jsonSchemaDialect: "https://spec.openapis.org/oas/3.1/dialect/base",
953
953
  info: {
954
954
  title: (_options$title = options.title) !== null && _options$title !== void 0 ? _options$title : "tRPC API",
955
955
  version: (_options$version = options.version) !== null && _options$version !== void 0 ? _options$version : "0.0.0"
956
- },
956
+ }
957
+ }, ((_options$servers = options.servers) === null || _options$servers === void 0 ? void 0 : _options$servers.length) ? { servers: options.servers } : {}), {}, {
957
958
  paths,
958
959
  components: (0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, hasNamedSchemas && meta.schemas ? { schemas: meta.schemas } : {}), {}, { responses: { Error: {
959
960
  description: "Error response",
@@ -963,7 +964,7 @@ function buildOpenAPIDocument(procedures, options, meta = { errorSchema: null })
963
964
  required: ["error"]
964
965
  } } }
965
966
  } } })
966
- };
967
+ });
967
968
  }
968
969
  /**
969
970
  * Analyse the given TypeScript router file using the TypeScript compiler and
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@ import { OpenAPIV3_1 } from "openapi-types";
2
2
 
3
3
  //#region rolldown:runtime
4
4
  declare namespace types_d_exports {
5
- export { ArraySchemaObject, CallbackObject, ComponentsObject, DiscriminatorObject, Document, ExampleObject, ExternalDocumentationObject, HeaderObject, HttpMethods, LinkObject, MediaTypeObject, OperationObject, ParameterBaseObject, ParameterObject, PathItemObject, PathsObject, PrimitiveSchemaType, ReferenceObject, Replace, RequestBodyObject, ResponseObject, ResponsesObject, SchemaLike, SchemaObject, SchemaType, SecuritySchemeObject, XMLObject };
5
+ export { ArraySchemaObject, CallbackObject, ComponentsObject, DiscriminatorObject, Document, ExampleObject, ExternalDocumentationObject, HeaderObject, HttpMethods, LinkObject, MediaTypeObject, OperationObject, ParameterBaseObject, ParameterObject, PathItemObject, PathsObject, PrimitiveSchemaType, ReferenceObject, Replace, RequestBodyObject, ResponseObject, ResponsesObject, SchemaLike, SchemaObject, SchemaType, SecuritySchemeObject, ServerObject, XMLObject };
6
6
  }
7
7
  type Replace<TTarget, TReplaceWith> = Omit<TTarget, keyof TReplaceWith> & TReplaceWith;
8
8
  type SchemaType = 'array' | 'boolean' | 'integer' | 'null' | 'number' | 'object' | 'string';
@@ -15,6 +15,7 @@ type ExternalDocumentationObject = OpenAPIV3_1.ExternalDocumentationObject;
15
15
  type XMLObject = OpenAPIV3_1.XMLObject;
16
16
  type LinkObject = OpenAPIV3_1.LinkObject;
17
17
  type SecuritySchemeObject = OpenAPIV3_1.SecuritySchemeObject;
18
+ type ServerObject = OpenAPIV3_1.ServerObject;
18
19
  type SchemaObject = Replace<OpenAPIV3_1.BaseSchemaObject, {
19
20
  $ref?: string;
20
21
  $defs?: Record<string, SchemaObject>;
@@ -104,6 +105,13 @@ interface GenerateOptions {
104
105
  title?: string;
105
106
  /** Version string for the generated OpenAPI `info` object. */
106
107
  version?: string;
108
+ /**
109
+ * OpenAPI `servers` array, passed through to the generated document. Each
110
+ * `url` should include any tRPC mount prefix, since the generated paths
111
+ * (`/user.create`, …) are relative to it — e.g.
112
+ * `https://api.example.com/trpc`. When omitted, no `servers` entry is added.
113
+ */
114
+ servers?: ServerObject[];
107
115
  }
108
116
  /**
109
117
  * Analyse the given TypeScript router file using the TypeScript compiler and
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -3,7 +3,7 @@ import { OpenAPIV3_1 } from "openapi-types";
3
3
 
4
4
  //#region src/types.d.ts
5
5
  declare namespace types_d_exports {
6
- export { ArraySchemaObject, CallbackObject, ComponentsObject, DiscriminatorObject, Document, ExampleObject, ExternalDocumentationObject, HeaderObject, HttpMethods, LinkObject, MediaTypeObject, OperationObject, ParameterBaseObject, ParameterObject, PathItemObject, PathsObject, PrimitiveSchemaType, ReferenceObject, Replace, RequestBodyObject, ResponseObject, ResponsesObject, SchemaLike, SchemaObject, SchemaType, SecuritySchemeObject, XMLObject };
6
+ export { ArraySchemaObject, CallbackObject, ComponentsObject, DiscriminatorObject, Document, ExampleObject, ExternalDocumentationObject, HeaderObject, HttpMethods, LinkObject, MediaTypeObject, OperationObject, ParameterBaseObject, ParameterObject, PathItemObject, PathsObject, PrimitiveSchemaType, ReferenceObject, Replace, RequestBodyObject, ResponseObject, ResponsesObject, SchemaLike, SchemaObject, SchemaType, SecuritySchemeObject, ServerObject, XMLObject };
7
7
  }
8
8
  type Replace<TTarget, TReplaceWith> = Omit<TTarget, keyof TReplaceWith> & TReplaceWith;
9
9
  type SchemaType = 'array' | 'boolean' | 'integer' | 'null' | 'number' | 'object' | 'string';
@@ -16,6 +16,7 @@ type ExternalDocumentationObject = OpenAPIV3_1.ExternalDocumentationObject;
16
16
  type XMLObject = OpenAPIV3_1.XMLObject;
17
17
  type LinkObject = OpenAPIV3_1.LinkObject;
18
18
  type SecuritySchemeObject = OpenAPIV3_1.SecuritySchemeObject;
19
+ type ServerObject = OpenAPIV3_1.ServerObject;
19
20
  type SchemaObject = Replace<OpenAPIV3_1.BaseSchemaObject, {
20
21
  $ref?: string;
21
22
  $defs?: Record<string, SchemaObject>;
@@ -105,6 +106,13 @@ interface GenerateOptions {
105
106
  title?: string;
106
107
  /** Version string for the generated OpenAPI `info` object. */
107
108
  version?: string;
109
+ /**
110
+ * OpenAPI `servers` array, passed through to the generated document. Each
111
+ * `url` should include any tRPC mount prefix, since the generated paths
112
+ * (`/user.create`, …) are relative to it — e.g.
113
+ * `https://api.example.com/trpc`. When omitted, no `servers` entry is added.
114
+ */
115
+ servers?: ServerObject[];
108
116
  }
109
117
  /**
110
118
  * Analyse the given TypeScript router file using the TypeScript compiler and
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -936,7 +936,7 @@ function buildProcedureOperation(proc, method) {
936
936
  return operation;
937
937
  }
938
938
  function buildOpenAPIDocument(procedures, options, meta = { errorSchema: null }) {
939
- var _options$title, _options$version, _meta$errorSchema;
939
+ var _options$title, _options$version, _options$servers, _meta$errorSchema;
940
940
  const paths = {};
941
941
  for (const proc of procedures) {
942
942
  var _paths$opPath;
@@ -948,13 +948,14 @@ function buildOpenAPIDocument(procedures, options, meta = { errorSchema: null })
948
948
  pathItem[method] = buildProcedureOperation(proc, method);
949
949
  }
950
950
  const hasNamedSchemas = meta.schemas !== void 0 && Object.keys(meta.schemas).length > 0;
951
- return {
951
+ return (0, import_objectSpread2.default)((0, import_objectSpread2.default)({
952
952
  openapi: "3.1.1",
953
953
  jsonSchemaDialect: "https://spec.openapis.org/oas/3.1/dialect/base",
954
954
  info: {
955
955
  title: (_options$title = options.title) !== null && _options$title !== void 0 ? _options$title : "tRPC API",
956
956
  version: (_options$version = options.version) !== null && _options$version !== void 0 ? _options$version : "0.0.0"
957
- },
957
+ }
958
+ }, ((_options$servers = options.servers) === null || _options$servers === void 0 ? void 0 : _options$servers.length) ? { servers: options.servers } : {}), {}, {
958
959
  paths,
959
960
  components: (0, import_objectSpread2.default)((0, import_objectSpread2.default)({}, hasNamedSchemas && meta.schemas ? { schemas: meta.schemas } : {}), {}, { responses: { Error: {
960
961
  description: "Error response",
@@ -964,7 +965,7 @@ function buildOpenAPIDocument(procedures, options, meta = { errorSchema: null })
964
965
  required: ["error"]
965
966
  } } }
966
967
  } } })
967
- };
968
+ });
968
969
  }
969
970
  /**
970
971
  * Analyse the given TypeScript router file using the TypeScript compiler and
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["value: unknown","schema: $ZodType","wrapperDefTypes: ReadonlySet<$ZodTypeDef['type']>","def: $ZodTypeDef","current: $ZodType","schema: unknown","map: DescriptionMap","prefix: string","ctx: {\n registry: $ZodRegistry<GlobalMeta>;\n map: DescriptionMap;\n seenLazy: Set<$ZodType>;\n }","path","mod: Record<string, unknown>","exportName: string","resolvedPath: string","routerOrRecord: AnyTRPCRouter | TRPCRouterRecord","result: Map<string, RuntimeDescriptions>","record: TRPCRouterRecord","inputDescs: DescriptionMap | null","outputDescs: DescriptionMap | null","value: AnyTRPCProcedure | TRPCRouterRecord","schema: SchemaObject","descs: DescriptionMap","schemas?: Record<string, SchemaObject>","propertyName: string","description: string","type: ts.Type","flag: ts.TypeFlags","sym: ts.Symbol","prop: ts.Symbol","schema: SchemaObject | null","schemas: Record<string, SchemaObject>","name: string","existing: Record<string, unknown>","schema: SchemaObject","s: SchemaObject","ctx: SchemaCtx","schema","flags: ts.TypeFlags","checker: ts.TypeChecker","type: ts.UnionType","depth: number","schemas: SchemaObject[]","nonNull: ts.Type[]","hasNull: boolean","type: ts.IntersectionType","properties: Record<string, SchemaObject>","required: string[]","additionalProperties: SchemaObject | boolean | undefined","result: SchemaObject","autoRegName: string | null","defType: ts.Type","inputType: ts.Type | null","type: ProcedureInfo['type']","path: string","def: ProcedureDef","initializer: ts.Expression | null","recovered: ts.Type | null","expr: ts.Expression","ctx: WalkCtx","inputSchema: SchemaObject | null","outputSchema: SchemaObject | null","filePath: string","opts: WalkTypeOpts","recordType: ts.Type","prefix: string","startDir: string","options: ts.CompilerOptions","routerType: ts.Type","schemaCtx: SchemaCtx","keys: string[]","DEFAULT_ERROR_SCHEMA: SchemaObject","resultSchema: SchemaObject","proc: ProcedureInfo","method: 'get' | 'post'","operation: OperationObject","procedures: ProcedureInfo[]","options: GenerateOptions","meta: RouterMeta","paths: PathsObject","pathItem: PathItemObject","routerFilePath: string","walkCtx: WalkCtx"],"sources":["../src/schemaExtraction.ts","../src/generate.ts","../src/types.ts"],"sourcesContent":["import { pathToFileURL } from 'node:url';\nimport type {\n AnyTRPCProcedure,\n AnyTRPCRouter,\n TRPCRouterRecord,\n} from '@trpc/server';\nimport type {\n $ZodArrayDef,\n $ZodObjectDef,\n $ZodRegistry,\n $ZodShape,\n $ZodType,\n $ZodTypeDef,\n GlobalMeta,\n} from 'zod/v4/core';\nimport type { SchemaObject } from './types';\n\n/** Description strings extracted from Zod `.describe()` calls, keyed by dot-delimited property path. */\nexport interface DescriptionMap {\n /** Top-level description on the schema itself (empty-string key). */\n self?: string;\n /** Property-path → description, e.g. `\"name\"` or `\"address.street\"`. */\n properties: Map<string, string>;\n}\n\nexport interface RuntimeDescriptions {\n input: DescriptionMap | null;\n output: DescriptionMap | null;\n}\n\n// ---------------------------------------------------------------------------\n// Zod shape walking — extract .describe() strings\n// ---------------------------------------------------------------------------\n\n/**\n * Zod v4 stores `.describe()` strings in `globalThis.__zod_globalRegistry`,\n * a WeakMap-backed `$ZodRegistry<GlobalMeta>`. We access it via globalThis\n * because zod is an optional peer dependency.\n */\nfunction getZodGlobalRegistry(): $ZodRegistry<GlobalMeta> | null {\n const reg = (\n globalThis as { __zod_globalRegistry?: $ZodRegistry<GlobalMeta> }\n ).__zod_globalRegistry;\n return reg && typeof reg.get === 'function' ? reg : null;\n}\n\n/** Runtime check: does this value look like a `$ZodType` (has `_zod.def`)? */\nfunction isZodSchema(value: unknown): value is $ZodType {\n if (value == null || typeof value !== 'object') return false;\n const zod = (value as { _zod?: unknown })._zod;\n return zod != null && typeof zod === 'object' && 'def' in zod;\n}\n\n/** Get the object shape from a Zod object schema, if applicable. */\nfunction zodObjectShape(schema: $ZodType): $ZodShape | null {\n const def = schema._zod.def;\n if (def.type === 'object' && 'shape' in def) {\n return (def as $ZodObjectDef).shape;\n }\n return null;\n}\n\n/** Get the element schema from a Zod array schema, if applicable. */\nfunction zodArrayElement(schema: $ZodType): $ZodType | null {\n const def = schema._zod.def;\n if (def.type === 'array' && 'element' in def) {\n return (def as $ZodArrayDef).element;\n }\n return null;\n}\n\n/** Wrapper def types whose inner schema is accessible via `innerType` or `in`. */\nconst wrapperDefTypes: ReadonlySet<$ZodTypeDef['type']> = new Set([\n 'optional',\n 'nullable',\n 'nonoptional',\n 'default',\n 'prefault',\n 'catch',\n 'readonly',\n 'pipe',\n 'transform',\n 'promise',\n]);\n\n/**\n * Extract the wrapped inner schema from a wrapper def.\n * Most wrappers use `innerType`; `pipe` uses `in`.\n */\nfunction getWrappedInner(def: $ZodTypeDef): $ZodType | null {\n if ('innerType' in def) return (def as { innerType: $ZodType }).innerType;\n if ('in' in def) return (def as { in: $ZodType }).in;\n return null;\n}\n\n/** Unwrap wrapper types (optional, nullable, default, readonly, etc.) to get the inner schema. */\nfunction unwrapZodSchema(schema: $ZodType): $ZodType {\n let current: $ZodType = schema;\n const seen = new Set<$ZodType>();\n while (!seen.has(current)) {\n seen.add(current);\n const def = current._zod.def;\n if (!wrapperDefTypes.has(def.type)) break;\n const inner = getWrappedInner(def);\n if (!inner) break;\n current = inner;\n }\n return current;\n}\n\n/**\n * Walk a Zod schema and collect description strings at each property path.\n * Returns `null` if the value is not a Zod schema or has no descriptions.\n */\nexport function extractZodDescriptions(schema: unknown): DescriptionMap | null {\n if (!isZodSchema(schema)) return null;\n const registry = getZodGlobalRegistry();\n if (!registry) return null;\n\n const map: DescriptionMap = { properties: new Map() };\n let hasAny = false;\n\n // Check top-level description\n const topMeta = registry.get(schema);\n if (topMeta?.description) {\n map.self = topMeta.description;\n hasAny = true;\n }\n\n // Walk object shape\n walkZodShape(schema, '', { registry, map, seenLazy: new Set() });\n if (map.properties.size > 0) hasAny = true;\n\n return hasAny ? map : null;\n}\n\nfunction walkZodShape(\n schema: $ZodType,\n prefix: string,\n ctx: {\n registry: $ZodRegistry<GlobalMeta>;\n map: DescriptionMap;\n seenLazy: Set<$ZodType>;\n },\n): void {\n const unwrapped = unwrapZodSchema(schema);\n const def = unwrapped._zod.def;\n\n if (def.type === 'lazy' && 'getter' in def) {\n if (ctx.seenLazy.has(unwrapped)) {\n return;\n }\n ctx.seenLazy.add(unwrapped);\n const inner = (def as { getter: () => unknown }).getter();\n if (isZodSchema(inner)) {\n walkZodShape(inner, prefix, ctx);\n }\n return;\n }\n\n // If this is an array, check for a description on the element schema itself\n // (stored as `[]` in the path) and recurse into the element's shape.\n const element = zodArrayElement(unwrapped);\n if (element) {\n const unwrappedElement = unwrapZodSchema(element);\n const elemMeta = ctx.registry.get(element);\n const innerElemMeta =\n unwrappedElement !== element\n ? ctx.registry.get(unwrappedElement)\n : undefined;\n const elemDesc = elemMeta?.description ?? innerElemMeta?.description;\n if (elemDesc) {\n const itemsPath = prefix ? `${prefix}.[]` : '[]';\n ctx.map.properties.set(itemsPath, elemDesc);\n }\n walkZodShape(element, prefix, ctx);\n return;\n }\n\n const shape = zodObjectShape(unwrapped);\n if (!shape) return;\n\n for (const [key, fieldSchema] of Object.entries(shape)) {\n const path = prefix ? `${prefix}.${key}` : key;\n\n // Check for description on the field — may be on the wrapper or inner schema\n const meta = ctx.registry.get(fieldSchema);\n const unwrappedField = unwrapZodSchema(fieldSchema);\n const innerMeta =\n unwrappedField !== fieldSchema\n ? ctx.registry.get(unwrappedField)\n : undefined;\n const description = meta?.description ?? innerMeta?.description;\n if (description) {\n ctx.map.properties.set(path, description);\n }\n\n // Recurse into nested objects and arrays\n walkZodShape(unwrappedField, path, ctx);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Router detection & dynamic import\n// ---------------------------------------------------------------------------\n\n/** Check whether a value looks like a tRPC router instance at runtime. */\nfunction isRouterInstance(value: unknown): value is AnyTRPCRouter {\n if (value == null) return false;\n const obj = value as Record<string, unknown>;\n const def = obj['_def'];\n return (\n typeof obj === 'object' &&\n def != null &&\n typeof def === 'object' &&\n (def as Record<string, unknown>)['record'] != null &&\n typeof (def as Record<string, unknown>)['record'] === 'object'\n );\n}\n\n/**\n * Search a module's exports for a tRPC router instance.\n *\n * Tries (in order):\n * 1. Exact `exportName` match\n * 2. lcfirst variant (`AppRouter` → `appRouter`)\n * 3. First export that looks like a router\n */\nexport function findRouterExport(\n mod: Record<string, unknown>,\n exportName: string,\n): AnyTRPCRouter | null {\n // 1. Exact match\n if (isRouterInstance(mod[exportName])) {\n return mod[exportName];\n }\n\n // 2. lcfirst variant (e.g. AppRouter → appRouter)\n const lcFirst = exportName.charAt(0).toLowerCase() + exportName.slice(1);\n if (lcFirst !== exportName && isRouterInstance(mod[lcFirst])) {\n return mod[lcFirst];\n }\n\n // 3. Any export that looks like a router\n for (const value of Object.values(mod)) {\n if (isRouterInstance(value)) {\n return value;\n }\n }\n\n return null;\n}\n\n/**\n * Try to dynamically import the router file and extract a tRPC router\n * instance. Returns `null` if the import fails (e.g. no TS loader) or\n * no router export is found.\n */\nexport async function tryImportRouter(\n resolvedPath: string,\n exportName: string,\n): Promise<AnyTRPCRouter | null> {\n try {\n const mod = await import(pathToFileURL(resolvedPath).href);\n return findRouterExport(mod as Record<string, unknown>, exportName);\n } catch {\n // Dynamic import not available (no TS loader registered) — that's fine,\n // we fall back to type-checker-only schemas.\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Router walker — collect descriptions per procedure\n// ---------------------------------------------------------------------------\n\n/**\n * Walk a runtime tRPC router/record and collect Zod `.describe()` strings\n * keyed by procedure path.\n */\nexport function collectRuntimeDescriptions(\n routerOrRecord: AnyTRPCRouter | TRPCRouterRecord,\n prefix: string,\n result: Map<string, RuntimeDescriptions>,\n): void {\n // Unwrap router to its record; plain RouterRecords are used as-is.\n const record: TRPCRouterRecord = isRouterInstance(routerOrRecord)\n ? routerOrRecord._def.record\n : routerOrRecord;\n\n for (const [key, value] of Object.entries(record)) {\n const fullPath = prefix ? `${prefix}.${key}` : key;\n\n if (isProcedure(value)) {\n // Procedure — extract descriptions from input and output Zod schemas\n const def = value._def;\n let inputDescs: DescriptionMap | null = null;\n for (const input of def.inputs) {\n const descs = extractZodDescriptions(input);\n if (descs) {\n // Merge multiple .input() descriptions (last wins for conflicts)\n inputDescs ??= { properties: new Map() };\n inputDescs.self = descs.self ?? inputDescs.self;\n for (const [p, d] of descs.properties) {\n inputDescs.properties.set(p, d);\n }\n }\n }\n\n let outputDescs: DescriptionMap | null = null;\n // `output` exists at runtime on the procedure def (from the builder)\n // but is not part of the public Procedure type.\n const outputParser = (def as Record<string, unknown>)['output'];\n if (outputParser) {\n outputDescs = extractZodDescriptions(outputParser);\n }\n\n if (inputDescs || outputDescs) {\n result.set(fullPath, { input: inputDescs, output: outputDescs });\n }\n } else {\n // Sub-router or nested RouterRecord — recurse\n collectRuntimeDescriptions(value, fullPath, result);\n }\n }\n}\n\n/** Type guard: check if a RouterRecord value is a procedure (callable). */\nfunction isProcedure(\n value: AnyTRPCProcedure | TRPCRouterRecord,\n): value is AnyTRPCProcedure {\n return typeof value === 'function';\n}\n\n// ---------------------------------------------------------------------------\n// Apply descriptions to JSON schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Overlay description strings from a `DescriptionMap` onto an existing\n * JSON schema produced by the TypeScript type checker. Mutates in place.\n */\nexport function applyDescriptions(\n schema: SchemaObject,\n descs: DescriptionMap,\n schemas?: Record<string, SchemaObject>,\n): void {\n if (descs.self) {\n schema.description = descs.self;\n }\n\n for (const [propPath, description] of descs.properties) {\n setNestedDescription({\n schema,\n pathParts: propPath.split('.'),\n description,\n schemas,\n });\n }\n}\n\nfunction resolveSchemaRef(\n schema: SchemaObject,\n schemas?: Record<string, SchemaObject>,\n): SchemaObject | null {\n const ref = schema.$ref;\n if (!ref) {\n return schema;\n }\n if (!schemas || !ref.startsWith('#/components/schemas/')) {\n return null;\n }\n\n const refName = ref.slice('#/components/schemas/'.length);\n return refName ? (schemas[refName] ?? null) : null;\n}\n\nfunction getArrayItemsSchema(schema: SchemaObject): SchemaObject | null {\n const items = schema.items;\n if (schema.type !== 'array' || items == null || items === false) {\n return null;\n }\n return items;\n}\n\nfunction getPropertySchema(\n schema: SchemaObject,\n propertyName: string,\n): SchemaObject | null {\n return schema.properties?.[propertyName] ?? null;\n}\n\nfunction setLeafDescription(schema: SchemaObject, description: string): void {\n if (schema.$ref) {\n const ref = schema.$ref;\n delete schema.$ref;\n schema.allOf = [{ $ref: ref }, ...(schema.allOf ?? [])];\n }\n schema.description = description;\n}\n\nfunction setNestedDescription({\n schema,\n pathParts,\n description,\n schemas,\n}: {\n schema: SchemaObject;\n pathParts: string[];\n description: string;\n schemas?: Record<string, SchemaObject>;\n}): void {\n if (pathParts.length === 0) return;\n\n const [head, ...rest] = pathParts;\n if (!head) return;\n\n // `[]` means \"array items\" — navigate to the `items` sub-schema\n if (head === '[]') {\n const items = getArrayItemsSchema(schema);\n if (!items) return;\n if (rest.length === 0) {\n setLeafDescription(items, description);\n } else {\n const target = resolveSchemaRef(items, schemas) ?? items;\n setNestedDescription({\n schema: target,\n pathParts: rest,\n description,\n schemas,\n });\n }\n return;\n }\n\n const propSchema = getPropertySchema(schema, head);\n if (!propSchema) return;\n\n if (rest.length === 0) {\n // Leaf — Zod .describe() takes priority over JSDoc\n setLeafDescription(propSchema, description);\n } else {\n // For arrays, step through `items` transparently\n const target = getArrayItemsSchema(propSchema) ?? propSchema;\n const resolvedTarget = resolveSchemaRef(target, schemas) ?? target;\n setNestedDescription({\n schema: resolvedTarget,\n pathParts: rest,\n description,\n schemas,\n });\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as ts from 'typescript';\nimport {\n applyDescriptions,\n collectRuntimeDescriptions,\n tryImportRouter,\n type RuntimeDescriptions,\n} from './schemaExtraction';\nimport type {\n Document,\n OperationObject,\n PathItemObject,\n PathsObject,\n SchemaObject,\n} from './types';\n\ninterface ProcedureInfo {\n path: string;\n type: 'query' | 'mutation' | 'subscription';\n inputSchema: SchemaObject | null;\n outputSchema: SchemaObject | null;\n description?: string;\n}\n\n/** State extracted from the router's root config. */\ninterface RouterMeta {\n errorSchema: SchemaObject | null;\n schemas?: Record<string, SchemaObject>;\n}\n\nexport interface GenerateOptions {\n /**\n * The name of the exported router symbol.\n * @default 'AppRouter'\n */\n exportName?: string;\n /** Title for the generated OpenAPI `info` object. */\n title?: string;\n /** Version string for the generated OpenAPI `info` object. */\n version?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Flag helpers\n// ---------------------------------------------------------------------------\n\nconst PRIMITIVE_FLAGS =\n ts.TypeFlags.String |\n ts.TypeFlags.Number |\n ts.TypeFlags.Boolean |\n ts.TypeFlags.StringLiteral |\n ts.TypeFlags.NumberLiteral |\n ts.TypeFlags.BooleanLiteral;\n\nfunction hasFlag(type: ts.Type, flag: ts.TypeFlags): boolean {\n return (type.getFlags() & flag) !== 0;\n}\n\nfunction isPrimitive(type: ts.Type): boolean {\n return hasFlag(type, PRIMITIVE_FLAGS);\n}\n\nfunction isObjectType(type: ts.Type): boolean {\n return hasFlag(type, ts.TypeFlags.Object);\n}\n\nfunction isOptionalSymbol(sym: ts.Symbol): boolean {\n return (sym.flags & ts.SymbolFlags.Optional) !== 0;\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema conversion — shared state\n// ---------------------------------------------------------------------------\n\n/** Shared state threaded through the type-to-schema recursion. */\ninterface SchemaCtx {\n checker: ts.TypeChecker;\n visited: Set<ts.Type>;\n /** Collected named schemas for components/schemas. */\n schemas: Record<string, SchemaObject>;\n /** Map from TS type identity to its registered schema name. */\n typeToRef: Map<ts.Type, string>;\n}\n\n// ---------------------------------------------------------------------------\n// Brand unwrapping\n// ---------------------------------------------------------------------------\n\n/**\n * If `type` is a branded intersection (primitive & object), return just the\n * primitive part. Otherwise return the type as-is.\n */\nfunction unwrapBrand(type: ts.Type): ts.Type {\n if (!type.isIntersection()) {\n return type;\n }\n const primitives = type.types.filter(isPrimitive);\n const hasObject = type.types.some(isObjectType);\n const [first] = primitives;\n if (first && hasObject) {\n return first;\n }\n return type;\n}\n\n// ---------------------------------------------------------------------------\n// Schema naming helpers\n// ---------------------------------------------------------------------------\n\nconst ANONYMOUS_NAMES = new Set(['__type', '__object', 'Object', '']);\nconst INTERNAL_COMPUTED_PROPERTY_SYMBOL = /^__@.*@\\d+$/;\n\n/** Try to determine a meaningful name for a TS type (type alias or interface). */\nfunction getTypeName(type: ts.Type): string | null {\n const aliasName = type.aliasSymbol?.getName();\n if (aliasName && !ANONYMOUS_NAMES.has(aliasName)) {\n return aliasName;\n }\n const symName = type.getSymbol()?.getName();\n if (symName && !ANONYMOUS_NAMES.has(symName) && !symName.startsWith('__')) {\n return symName;\n }\n return null;\n}\n\n// Skips asyncGenerator and branded symbols etc when creating types\n// Symbols can't be serialised\nfunction shouldSkipPropertySymbol(prop: ts.Symbol): boolean {\n return (\n prop.declarations?.some((declaration) => {\n const declarationName = ts.getNameOfDeclaration(declaration);\n if (!declarationName || !ts.isComputedPropertyName(declarationName)) {\n return false;\n }\n\n return INTERNAL_COMPUTED_PROPERTY_SYMBOL.test(prop.getName());\n }) ?? false\n );\n}\n\nfunction getReferencedSchema(\n schema: SchemaObject | null,\n schemas: Record<string, SchemaObject>,\n): SchemaObject | null {\n const ref = schema?.$ref;\n if (!ref?.startsWith('#/components/schemas/')) {\n return schema;\n }\n\n const refName = ref.slice('#/components/schemas/'.length);\n return refName ? (schemas[refName] ?? null) : schema;\n}\n\nfunction ensureUniqueName(\n name: string,\n existing: Record<string, unknown>,\n): string {\n if (!(name in existing)) {\n return name;\n }\n let i = 2;\n while (`${name}${i}` in existing) {\n i++;\n }\n return `${name}${i}`;\n}\n\nfunction schemaRef(name: string): SchemaObject {\n return { $ref: `#/components/schemas/${name}` };\n}\n\nfunction isSelfSchemaRef(schema: SchemaObject, name: string): boolean {\n return schema.$ref === schemaRef(name).$ref;\n}\n\nfunction isNonEmptySchema(s: SchemaObject): boolean {\n for (const _ in s) return true;\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Type → JSON Schema (with component extraction)\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a TS type to a JSON Schema. If the type has been pre-registered\n * (or has a meaningful TS name), it is stored in `ctx.schemas` and a `$ref`\n * is returned instead of an inline schema.\n *\n * Named types (type aliases, interfaces) are auto-registered before conversion\n * so that recursive references (including through unions and intersections)\n * resolve to a `$ref` instead of causing infinite recursion.\n */\nfunction typeToJsonSchema(\n type: ts.Type,\n ctx: SchemaCtx,\n depth = 0,\n): SchemaObject {\n // If this type is already registered as a named schema, return a $ref.\n const existingRef = ctx.typeToRef.get(type);\n if (existingRef) {\n const storedSchema = ctx.schemas[existingRef];\n if (\n storedSchema &&\n (isNonEmptySchema(storedSchema) || ctx.visited.has(type))\n ) {\n return schemaRef(existingRef);\n }\n\n // First encounter for a pre-registered placeholder: convert once, but keep\n // returning $ref for recursive edges while the type is actively visiting.\n ctx.schemas[existingRef] = storedSchema ?? {};\n const schema = convertTypeToSchema(type, ctx, depth);\n if (!isSelfSchemaRef(schema, existingRef)) {\n ctx.schemas[existingRef] = schema;\n }\n return schemaRef(existingRef);\n }\n\n const schema = convertTypeToSchema(type, ctx, depth);\n\n // If a recursive reference was detected during conversion (via handleCyclicRef\n // or convertPlainObject's auto-registration), the type is now registered in\n // typeToRef. If the stored schema is still the empty placeholder, fill it in\n // with the actual converted schema. Either way, return a $ref.\n const postConvertRef = ctx.typeToRef.get(type);\n if (postConvertRef) {\n const stored = ctx.schemas[postConvertRef];\n if (\n stored &&\n !isNonEmptySchema(stored) &&\n !isSelfSchemaRef(schema, postConvertRef)\n ) {\n ctx.schemas[postConvertRef] = schema;\n }\n return schemaRef(postConvertRef);\n }\n\n // Extract JSDoc from type alias symbol (e.g. `/** desc */ type Foo = string`)\n if (!schema.description && !schema.$ref && type.aliasSymbol) {\n const aliasJsDoc = getJsDocComment(type.aliasSymbol, ctx.checker);\n if (aliasJsDoc) {\n schema.description = aliasJsDoc;\n }\n }\n\n return schema;\n}\n\n// ---------------------------------------------------------------------------\n// Cyclic reference handling\n// ---------------------------------------------------------------------------\n\n/**\n * When we encounter a type we're already visiting, it's recursive.\n * Register it as a named schema and return a $ref.\n */\nfunction handleCyclicRef(type: ts.Type, ctx: SchemaCtx): SchemaObject {\n let refName = ctx.typeToRef.get(type);\n if (!refName) {\n const name = getTypeName(type) ?? 'RecursiveType';\n refName = ensureUniqueName(name, ctx.schemas);\n ctx.typeToRef.set(type, refName);\n ctx.schemas[refName] = {}; // placeholder — filled by the outer call\n }\n return schemaRef(refName);\n}\n\n// ---------------------------------------------------------------------------\n// Primitive & literal type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertPrimitiveOrLiteral(\n type: ts.Type,\n flags: ts.TypeFlags,\n checker: ts.TypeChecker,\n): SchemaObject | null {\n if (flags & ts.TypeFlags.String) {\n return { type: 'string' };\n }\n if (flags & ts.TypeFlags.Number) {\n return { type: 'number' };\n }\n if (flags & ts.TypeFlags.Boolean) {\n return { type: 'boolean' };\n }\n if (flags & ts.TypeFlags.Null) {\n return { type: 'null' };\n }\n if (flags & ts.TypeFlags.Undefined) {\n return {};\n }\n if (flags & ts.TypeFlags.Void) {\n return {};\n }\n if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) {\n return {};\n }\n if (flags & ts.TypeFlags.Never) {\n return { not: {} };\n }\n if (flags & ts.TypeFlags.BigInt || flags & ts.TypeFlags.BigIntLiteral) {\n return { type: 'integer', format: 'bigint' };\n }\n\n if (flags & ts.TypeFlags.StringLiteral) {\n return { type: 'string', const: (type as ts.StringLiteralType).value };\n }\n if (flags & ts.TypeFlags.NumberLiteral) {\n return { type: 'number', const: (type as ts.NumberLiteralType).value };\n }\n if (flags & ts.TypeFlags.BooleanLiteral) {\n const isTrue = checker.typeToString(type) === 'true';\n return { type: 'boolean', const: isTrue };\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Union type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertUnionType(\n type: ts.UnionType,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const members = type.types;\n\n // Strip undefined / void members (they make the field optional, not typed)\n const defined = members.filter(\n (m) => !hasFlag(m, ts.TypeFlags.Undefined | ts.TypeFlags.Void),\n );\n if (defined.length === 0) {\n return {};\n }\n\n const hasNull = defined.some((m) => hasFlag(m, ts.TypeFlags.Null));\n const nonNull = defined.filter((m) => !hasFlag(m, ts.TypeFlags.Null));\n\n // TypeScript represents `boolean` as `true | false`. Collapse boolean\n // literal pairs back into a single boolean, even when mixed with other types.\n // e.g. `string | true | false` → treat as `string | boolean`\n const boolLiterals = nonNull.filter((m) =>\n hasFlag(unwrapBrand(m), ts.TypeFlags.BooleanLiteral),\n );\n const hasBoolPair =\n boolLiterals.length === 2 &&\n boolLiterals.some(\n (m) => ctx.checker.typeToString(unwrapBrand(m)) === 'true',\n ) &&\n boolLiterals.some(\n (m) => ctx.checker.typeToString(unwrapBrand(m)) === 'false',\n );\n\n // Build the effective non-null members, collapsing boolean literal pairs\n const effective = hasBoolPair\n ? nonNull.filter(\n (m) => !hasFlag(unwrapBrand(m), ts.TypeFlags.BooleanLiteral),\n )\n : nonNull;\n\n // Pure boolean (or boolean | null) — no other types\n if (hasBoolPair && effective.length === 0) {\n return hasNull ? { type: ['boolean', 'null'] } : { type: 'boolean' };\n }\n\n // Collapse unions of same-type literals into a single `enum` array.\n // e.g. \"FOO\" | \"BAR\" → { type: \"string\", enum: [\"FOO\", \"BAR\"] }\n const collapsedEnum = tryCollapseLiteralUnion(effective, hasNull);\n if (collapsedEnum) {\n return collapsedEnum;\n }\n\n const schemas = effective\n .map((m) => typeToJsonSchema(m, ctx, depth + 1))\n .filter(isNonEmptySchema);\n\n // Re-inject the collapsed boolean\n if (hasBoolPair) {\n schemas.push({ type: 'boolean' });\n }\n\n if (hasNull) {\n schemas.push({ type: 'null' });\n }\n\n if (schemas.length === 0) {\n return {};\n }\n\n const [firstSchema] = schemas;\n if (schemas.length === 1 && firstSchema !== undefined) {\n return firstSchema;\n }\n\n // When all schemas are simple type-only schemas (no other properties),\n // collapse into a single `type` array. e.g. string | null → type: [\"string\", \"null\"]\n if (schemas.every(isSimpleTypeSchema)) {\n return { type: schemas.map((s) => s.type as string) };\n }\n\n // Detect discriminated unions: all oneOf members are objects sharing a common\n // required property whose value is a `const`. If found, add a `discriminator`.\n const discriminatorProp = detectDiscriminatorProperty(schemas);\n if (discriminatorProp) {\n return {\n oneOf: schemas,\n discriminator: { propertyName: discriminatorProp },\n };\n }\n\n return { oneOf: schemas };\n}\n\n/**\n * If every schema in a oneOf is an object with a common required property\n * whose value is a `const`, return that property name. Otherwise return null.\n */\nfunction detectDiscriminatorProperty(schemas: SchemaObject[]): string | null {\n if (schemas.length < 2) {\n return null;\n }\n\n // All schemas must be object types with properties\n if (!schemas.every((s) => s.type === 'object' && s.properties)) {\n return null;\n }\n\n // Find properties that exist in every schema, are required, and have a `const` value\n const first = schemas[0];\n if (!first?.properties) {\n return null;\n }\n const firstProps = Object.keys(first.properties);\n for (const prop of firstProps) {\n const allHaveConst = schemas.every((s) => {\n const propSchema = s.properties?.[prop];\n return (\n propSchema !== undefined &&\n propSchema.const !== undefined &&\n s.required?.includes(prop)\n );\n });\n if (allHaveConst) {\n return prop;\n }\n }\n\n return null;\n}\n\n/** A schema that is just `{ type: \"somePrimitive\" }` with no other keys. */\nfunction isSimpleTypeSchema(s: SchemaObject): boolean {\n const keys = Object.keys(s);\n return keys.length === 1 && keys[0] === 'type' && typeof s.type === 'string';\n}\n\n/**\n * If every non-null member is a string or number literal of the same kind,\n * collapse them into a single `{ type, enum }` schema.\n */\nfunction tryCollapseLiteralUnion(\n nonNull: ts.Type[],\n hasNull: boolean,\n): SchemaObject | null {\n if (nonNull.length <= 1) {\n return null;\n }\n\n const allLiterals = nonNull.every((m) =>\n hasFlag(m, ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral),\n );\n if (!allLiterals) {\n return null;\n }\n\n const [first] = nonNull;\n if (!first) {\n return null;\n }\n\n const isString = hasFlag(first, ts.TypeFlags.StringLiteral);\n const targetFlag = isString\n ? ts.TypeFlags.StringLiteral\n : ts.TypeFlags.NumberLiteral;\n const allSameKind = nonNull.every((m) => hasFlag(m, targetFlag));\n if (!allSameKind) {\n return null;\n }\n\n const values = nonNull.map((m) =>\n isString\n ? (m as ts.StringLiteralType).value\n : (m as ts.NumberLiteralType).value,\n );\n const baseType = isString ? 'string' : 'number';\n return {\n type: hasNull ? [baseType, 'null'] : baseType,\n enum: values,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Intersection type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertIntersectionType(\n type: ts.IntersectionType,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n // Branded types (e.g. z.string().brand<'X'>()) appear as an intersection of\n // a primitive with a phantom object. Strip the object members — they are\n // always brand metadata.\n const hasPrimitiveMember = type.types.some(isPrimitive);\n const nonBrand = hasPrimitiveMember\n ? type.types.filter((m) => !isObjectType(m))\n : type.types;\n\n const schemas = nonBrand\n .map((m) => typeToJsonSchema(m, ctx, depth + 1))\n .filter(isNonEmptySchema);\n\n if (schemas.length === 0) {\n return {};\n }\n const [onlySchema] = schemas;\n if (schemas.length === 1 && onlySchema !== undefined) {\n return onlySchema;\n }\n\n // When all members are plain inline object schemas (no $ref), merge them\n // into a single object instead of wrapping in allOf.\n if (schemas.every(isInlineObjectSchema)) {\n return mergeObjectSchemas(schemas);\n }\n\n return { allOf: schemas };\n}\n\n/** True when the schema is an inline `{ type: \"object\", ... }` (not a $ref). */\nfunction isInlineObjectSchema(s: SchemaObject): boolean {\n return s.type === 'object' && !s.$ref;\n}\n\n/**\n * Merge multiple `{ type: \"object\" }` schemas into one.\n * Falls back to `allOf` if any property names conflict across schemas.\n */\nfunction mergeObjectSchemas(schemas: SchemaObject[]): SchemaObject {\n // Check for property name conflicts before merging.\n const seen = new Set<string>();\n for (const s of schemas) {\n if (s.properties) {\n for (const prop of Object.keys(s.properties)) {\n if (seen.has(prop)) {\n // Conflicting property — fall back to allOf to preserve both definitions.\n return { allOf: schemas };\n }\n seen.add(prop);\n }\n }\n }\n\n const properties: Record<string, SchemaObject> = {};\n const required: string[] = [];\n let additionalProperties: SchemaObject | boolean | undefined;\n\n for (const s of schemas) {\n if (s.properties) {\n Object.assign(properties, s.properties);\n }\n if (s.required) {\n required.push(...s.required);\n }\n if (s.additionalProperties !== undefined) {\n additionalProperties = s.additionalProperties;\n }\n }\n\n const result: SchemaObject = { type: 'object' };\n if (Object.keys(properties).length > 0) {\n result.properties = properties;\n }\n if (required.length > 0) {\n result.required = required;\n }\n if (additionalProperties !== undefined) {\n result.additionalProperties = additionalProperties;\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Object type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertWellKnownType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject | null {\n const symName = type.getSymbol()?.getName();\n if (symName === 'Date') {\n return { type: 'string', format: 'date-time' };\n }\n if (symName === 'Uint8Array' || symName === 'Buffer') {\n return { type: 'string', format: 'binary' };\n }\n\n // Unwrap Promise<T>\n if (symName === 'Promise') {\n const [inner] = ctx.checker.getTypeArguments(type as ts.TypeReference);\n return inner ? typeToJsonSchema(inner, ctx, depth + 1) : {};\n }\n\n return null;\n}\n\nfunction convertArrayType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const [elem] = ctx.checker.getTypeArguments(type as ts.TypeReference);\n const schema: SchemaObject = { type: 'array' };\n if (elem) {\n schema.items = typeToJsonSchema(elem, ctx, depth + 1);\n }\n return schema;\n}\n\nfunction convertTupleType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const args = ctx.checker.getTypeArguments(type as ts.TypeReference);\n const schemas = args.map((a) => typeToJsonSchema(a, ctx, depth + 1));\n return {\n type: 'array',\n prefixItems: schemas,\n items: false,\n minItems: args.length,\n maxItems: args.length,\n };\n}\n\nfunction convertPlainObject(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const { checker } = ctx;\n const stringIndexType = type.getStringIndexType();\n const typeProps = type.getProperties();\n\n // Pure index-signature Record type (no named props)\n if (typeProps.length === 0 && stringIndexType) {\n return {\n type: 'object',\n additionalProperties: typeToJsonSchema(stringIndexType, ctx, depth + 1),\n };\n }\n\n // Auto-register types with a meaningful TS name BEFORE converting\n // properties, so that circular or shared refs discovered during recursion\n // resolve to a $ref via the `typeToJsonSchema` wrapper.\n let autoRegName: string | null = null;\n const tsName = getTypeName(type);\n const isNamedUnregisteredType =\n tsName !== null && typeProps.length > 0 && !ctx.typeToRef.has(type);\n if (isNamedUnregisteredType) {\n autoRegName = ensureUniqueName(tsName, ctx.schemas);\n ctx.typeToRef.set(type, autoRegName);\n ctx.schemas[autoRegName] = {}; // placeholder for circular ref guard\n }\n\n ctx.visited.add(type);\n const properties: Record<string, SchemaObject> = {};\n const required: string[] = [];\n\n for (const prop of typeProps) {\n if (shouldSkipPropertySymbol(prop)) {\n continue;\n }\n\n const propType = checker.getTypeOfSymbol(prop);\n const propSchema = typeToJsonSchema(propType, ctx, depth + 1);\n\n // Extract JSDoc comment from the property symbol as a description\n const jsDoc = getJsDocComment(prop, checker);\n if (jsDoc && !propSchema.description && !propSchema.$ref) {\n propSchema.description = jsDoc;\n }\n\n properties[prop.name] = propSchema;\n if (!isOptionalSymbol(prop)) {\n required.push(prop.name);\n }\n }\n\n ctx.visited.delete(type);\n\n const result: SchemaObject = { type: 'object' };\n if (Object.keys(properties).length > 0) {\n result.properties = properties;\n }\n if (required.length > 0) {\n result.required = required;\n }\n if (stringIndexType) {\n result.additionalProperties = typeToJsonSchema(\n stringIndexType,\n ctx,\n depth + 1,\n );\n } else if (Object.keys(properties).length > 0) {\n result.additionalProperties = false;\n }\n\n // autoRegName covers named types (early-registered). For anonymous\n // recursive types, a recursive call may have registered this type during\n // property conversion — check typeToRef as a fallback.\n const registeredName = autoRegName ?? ctx.typeToRef.get(type);\n if (registeredName) {\n ctx.schemas[registeredName] = result;\n return schemaRef(registeredName);\n }\n\n return result;\n}\n\nfunction convertObjectType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const wellKnown = convertWellKnownType(type, ctx, depth);\n if (wellKnown) {\n return wellKnown;\n }\n\n if (ctx.checker.isArrayType(type)) {\n return convertArrayType(type, ctx, depth);\n }\n if (ctx.checker.isTupleType(type)) {\n return convertTupleType(type, ctx, depth);\n }\n\n return convertPlainObject(type, ctx, depth);\n}\n\n// ---------------------------------------------------------------------------\n// Core dispatcher\n// ---------------------------------------------------------------------------\n\n/** Core type-to-schema conversion (no ref handling). */\nfunction convertTypeToSchema(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n if (ctx.visited.has(type)) {\n return handleCyclicRef(type, ctx);\n }\n\n const flags = type.getFlags();\n\n const primitive = convertPrimitiveOrLiteral(type, flags, ctx.checker);\n if (primitive) {\n return primitive;\n }\n\n if (type.isUnion()) {\n ctx.visited.add(type);\n const result = convertUnionType(type, ctx, depth);\n ctx.visited.delete(type);\n return result;\n }\n if (type.isIntersection()) {\n ctx.visited.add(type);\n const result = convertIntersectionType(type, ctx, depth);\n ctx.visited.delete(type);\n return result;\n }\n if (isObjectType(type)) {\n return convertObjectType(type, ctx, depth);\n }\n\n return {};\n}\n\n// ---------------------------------------------------------------------------\n// Router / procedure type walker\n// ---------------------------------------------------------------------------\n\n/** State shared across the router-walk recursion. */\ninterface WalkCtx {\n procedures: ProcedureInfo[];\n seen: Set<ts.Type>;\n schemaCtx: SchemaCtx;\n /** Runtime descriptions keyed by procedure path (when a router instance is available). */\n runtimeDescriptions: Map<string, RuntimeDescriptions>;\n}\n\n/**\n * Inspect `_def.type` and return the procedure type string, or null if this is\n * not a procedure (e.g. a nested router).\n */\nfunction getProcedureTypeName(\n defType: ts.Type,\n checker: ts.TypeChecker,\n): ProcedureInfo['type'] | null {\n const typeSym = defType.getProperty('type');\n if (!typeSym) {\n return null;\n }\n const typeType = checker.getTypeOfSymbol(typeSym);\n const raw = checker.typeToString(typeType).replace(/['\"]/g, '');\n if (raw === 'query' || raw === 'mutation' || raw === 'subscription') {\n return raw;\n }\n return null;\n}\n\nfunction isVoidLikeInput(inputType: ts.Type | null): boolean {\n if (!inputType) {\n return true;\n }\n\n const isVoidOrUndefinedOrNever = hasFlag(\n inputType,\n ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never,\n );\n if (isVoidOrUndefinedOrNever) {\n return true;\n }\n\n const isUnionOfVoids =\n inputType.isUnion() &&\n inputType.types.every((t) =>\n hasFlag(t, ts.TypeFlags.Void | ts.TypeFlags.Undefined),\n );\n return isUnionOfVoids;\n}\n\ninterface ProcedureDef {\n defType: ts.Type;\n typeName: string;\n path: string;\n description?: string;\n symbol: ts.Symbol;\n}\n\nfunction shouldIncludeProcedureInOpenAPI(type: ProcedureInfo['type']): boolean {\n return type !== 'subscription';\n}\n\nfunction getProcedureInputTypeName(type: ts.Type, path: string): string {\n const directName = getTypeName(type);\n if (directName) {\n return directName;\n }\n\n for (const sym of [type.aliasSymbol, type.getSymbol()].filter(\n (candidate): candidate is ts.Symbol => !!candidate,\n )) {\n for (const declaration of sym.declarations ?? []) {\n const declarationName = ts.getNameOfDeclaration(declaration)?.getText();\n if (\n declarationName &&\n !ANONYMOUS_NAMES.has(declarationName) &&\n !declarationName.startsWith('__')\n ) {\n return declarationName;\n }\n }\n }\n\n const fallbackName = path\n .split('.')\n .filter(Boolean)\n .map((segment) =>\n segment\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(''),\n )\n .join('');\n\n return `${fallbackName || 'Procedure'}Input`;\n}\n\nfunction isUnknownLikeType(type: ts.Type): boolean {\n return hasFlag(type, ts.TypeFlags.Unknown | ts.TypeFlags.Any);\n}\n\nfunction isCollapsedProcedureInputType(type: ts.Type): boolean {\n return (\n isUnknownLikeType(type) ||\n (isObjectType(type) &&\n type.getProperties().length === 0 &&\n !type.getStringIndexType())\n );\n}\n\nfunction recoverProcedureInputType(\n def: ProcedureDef,\n checker: ts.TypeChecker,\n): ts.Type | null {\n let initializer: ts.Expression | null = null;\n for (const declaration of def.symbol.declarations ?? []) {\n if (ts.isPropertyAssignment(declaration)) {\n initializer = declaration.initializer;\n break;\n }\n if (ts.isVariableDeclaration(declaration) && declaration.initializer) {\n initializer = declaration.initializer;\n break;\n }\n }\n if (!initializer) {\n return null;\n }\n\n let recovered: ts.Type | null = null;\n // Walk the builder chain and keep the last `.input(...)` parser output type.\n const visit = (expr: ts.Expression): void => {\n if (!ts.isCallExpression(expr)) {\n return;\n }\n\n const callee = expr.expression;\n if (!ts.isPropertyAccessExpression(callee)) {\n return;\n }\n\n visit(callee.expression);\n if (callee.name.text !== 'input') {\n return;\n }\n\n const [parserExpr] = expr.arguments;\n if (!parserExpr) {\n return;\n }\n\n const parserType = checker.getTypeAtLocation(parserExpr);\n const standardSym = parserType.getProperty('~standard');\n if (!standardSym) {\n return;\n }\n\n const standardType = checker.getTypeOfSymbolAtLocation(\n standardSym,\n parserExpr,\n );\n const typesSym = standardType.getProperty('types');\n if (!typesSym) {\n return;\n }\n\n const typesType = checker.getNonNullableType(\n checker.getTypeOfSymbolAtLocation(typesSym, parserExpr),\n );\n const outputSym = typesType.getProperty('output');\n if (!outputSym) {\n return;\n }\n\n const outputType = checker.getTypeOfSymbolAtLocation(outputSym, parserExpr);\n if (!isUnknownLikeType(outputType)) {\n recovered = outputType;\n }\n };\n visit(initializer);\n\n return recovered;\n}\n\nfunction extractProcedure(def: ProcedureDef, ctx: WalkCtx): void {\n const { schemaCtx } = ctx;\n const { checker } = schemaCtx;\n\n const $typesSym = def.defType.getProperty('$types');\n if (!$typesSym) {\n return;\n }\n const $typesType = checker.getTypeOfSymbol($typesSym);\n\n const inputSym = $typesType.getProperty('input');\n const outputSym = $typesType.getProperty('output');\n\n const inputType = inputSym ? checker.getTypeOfSymbol(inputSym) : null;\n const outputType = outputSym ? checker.getTypeOfSymbol(outputSym) : null;\n const resolvedInputType =\n inputType && isCollapsedProcedureInputType(inputType)\n ? (recoverProcedureInputType(def, checker) ?? inputType)\n : inputType;\n\n let inputSchema: SchemaObject | null = null;\n if (!resolvedInputType || isVoidLikeInput(resolvedInputType)) {\n // null is fine\n } else {\n // Pre-register recovered parser output types so recursive edges resolve to a\n // stable component ref instead of collapsing into `{}`.\n const ensureRecoveredInputRegistration = (type: ts.Type): void => {\n if (schemaCtx.typeToRef.has(type)) {\n return;\n }\n\n const refName = ensureUniqueName(\n getProcedureInputTypeName(type, def.path),\n schemaCtx.schemas,\n );\n schemaCtx.typeToRef.set(type, refName);\n schemaCtx.schemas[refName] = {};\n };\n\n if (resolvedInputType !== inputType) {\n ensureRecoveredInputRegistration(resolvedInputType);\n }\n\n const initialSchema = typeToJsonSchema(resolvedInputType, schemaCtx);\n if (\n !isNonEmptySchema(initialSchema) &&\n !schemaCtx.typeToRef.has(resolvedInputType)\n ) {\n ensureRecoveredInputRegistration(resolvedInputType);\n inputSchema = typeToJsonSchema(resolvedInputType, schemaCtx);\n } else {\n inputSchema = initialSchema;\n }\n }\n\n const outputSchema: SchemaObject | null = outputType\n ? typeToJsonSchema(outputType, schemaCtx)\n : null;\n\n // Overlay extracted schema descriptions onto the type-checker-generated schemas.\n const runtimeDescs = ctx.runtimeDescriptions.get(def.path);\n if (runtimeDescs) {\n const resolvedInputSchema = getReferencedSchema(\n inputSchema,\n schemaCtx.schemas,\n );\n const resolvedOutputSchema = getReferencedSchema(\n outputSchema,\n schemaCtx.schemas,\n );\n\n if (resolvedInputSchema && runtimeDescs.input) {\n applyDescriptions(\n resolvedInputSchema,\n runtimeDescs.input,\n schemaCtx.schemas,\n );\n }\n if (resolvedOutputSchema && runtimeDescs.output) {\n applyDescriptions(\n resolvedOutputSchema,\n runtimeDescs.output,\n schemaCtx.schemas,\n );\n }\n }\n\n ctx.procedures.push({\n path: def.path,\n type: def.typeName as 'query' | 'mutation' | 'subscription',\n inputSchema,\n outputSchema,\n description: def.description,\n });\n}\n\n/** Extract the JSDoc comment text from a symbol, if any. */\nfunction getJsDocComment(\n sym: ts.Symbol,\n checker: ts.TypeChecker,\n): string | undefined {\n const normalize = (filePath: string): string => filePath.replace(/\\\\/g, '/');\n\n const declarations = sym.declarations ?? [];\n const isExternalNodeModulesDeclaration =\n declarations.length > 0 &&\n declarations.every((declaration) => {\n const sourceFile = declaration.getSourceFile();\n if (!sourceFile.isDeclarationFile) {\n return false;\n }\n\n const declarationPath = normalize(sourceFile.fileName);\n if (!declarationPath.includes('/node_modules/')) {\n return false;\n }\n\n try {\n const realPath = normalize(fs.realpathSync.native(sourceFile.fileName));\n // Keep JSDoc for workspace packages linked into node_modules\n // (e.g. monorepos using pnpm/yarn workspaces). The resolved target\n // may sit outside the current cwd, so avoid cwd-based checks here.\n if (!realPath.includes('/node_modules/')) {\n return false;\n }\n } catch {\n // Fall back to treating the declaration as external.\n }\n\n return true;\n });\n if (isExternalNodeModulesDeclaration) {\n return undefined;\n }\n\n const parts = sym.getDocumentationComment(checker);\n if (parts.length === 0) {\n return undefined;\n }\n const text = parts.map((p) => p.text).join('');\n return text || undefined;\n}\n\ninterface WalkTypeOpts {\n type: ts.Type;\n ctx: WalkCtx;\n currentPath: string;\n description?: string;\n symbol?: ts.Symbol;\n}\n\nfunction walkType(opts: WalkTypeOpts): void {\n const { type, ctx, currentPath, description, symbol } = opts;\n if (ctx.seen.has(type)) {\n return;\n }\n\n const defSym = type.getProperty('_def');\n\n if (!defSym) {\n // No `_def` — this is a plain RouterRecord or an unrecognised type.\n // Walk its own properties so nested procedures are found.\n if (isObjectType(type)) {\n ctx.seen.add(type);\n walkRecord(type, ctx, currentPath);\n ctx.seen.delete(type);\n }\n return;\n }\n\n const { checker } = ctx.schemaCtx;\n const defType = checker.getTypeOfSymbol(defSym);\n\n const procedureTypeName = getProcedureTypeName(defType, checker);\n if (procedureTypeName) {\n if (!shouldIncludeProcedureInOpenAPI(procedureTypeName)) {\n return;\n }\n\n extractProcedure(\n {\n defType,\n typeName: procedureTypeName,\n path: currentPath,\n description,\n symbol: symbol ?? type.getSymbol() ?? defSym,\n },\n ctx,\n );\n return;\n }\n\n // Router? (_def.router === true)\n const routerSym = defType.getProperty('router');\n if (!routerSym) {\n return;\n }\n\n const isRouter =\n checker.typeToString(checker.getTypeOfSymbol(routerSym)) === 'true';\n if (!isRouter) {\n return;\n }\n\n const recordSym = defType.getProperty('record');\n if (!recordSym) {\n return;\n }\n\n ctx.seen.add(type);\n const recordType = checker.getTypeOfSymbol(recordSym);\n walkRecord(recordType, ctx, currentPath);\n ctx.seen.delete(type);\n}\n\nfunction walkRecord(recordType: ts.Type, ctx: WalkCtx, prefix: string): void {\n for (const prop of recordType.getProperties()) {\n const propType = ctx.schemaCtx.checker.getTypeOfSymbol(prop);\n const fullPath = prefix ? `${prefix}.${prop.name}` : prop.name;\n const description = getJsDocComment(prop, ctx.schemaCtx.checker);\n walkType({\n type: propType,\n ctx,\n currentPath: fullPath,\n description,\n symbol: prop,\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// TypeScript program helpers\n// ---------------------------------------------------------------------------\n\nfunction loadCompilerOptions(startDir: string): ts.CompilerOptions {\n const configPath = ts.findConfigFile(\n startDir,\n (f) => ts.sys.fileExists(f),\n 'tsconfig.json',\n );\n if (!configPath) {\n return {\n target: ts.ScriptTarget.ES2020,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n skipLibCheck: true,\n noEmit: true,\n };\n }\n\n const configFile = ts.readConfigFile(configPath, (f) => ts.sys.readFile(f));\n const parsed = ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n path.dirname(configPath),\n );\n const options: ts.CompilerOptions = { ...parsed.options, noEmit: true };\n\n // `parseJsonConfigFileContent` only returns explicitly-set values. TypeScript\n // itself infers moduleResolution from `module` at compile time, but we have to\n // do it manually here for the compiler host to resolve imports correctly.\n if (options.moduleResolution === undefined) {\n const mod = options.module;\n if (mod === ts.ModuleKind.Node16 || mod === ts.ModuleKind.NodeNext) {\n options.moduleResolution = ts.ModuleResolutionKind.NodeNext;\n } else if (\n mod === ts.ModuleKind.Preserve ||\n mod === ts.ModuleKind.ES2022 ||\n mod === ts.ModuleKind.ESNext\n ) {\n options.moduleResolution = ts.ModuleResolutionKind.Bundler;\n } else {\n options.moduleResolution = ts.ModuleResolutionKind.Node10;\n }\n }\n\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Error shape extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Walk `_def._config.$types.errorShape` on the router type and convert\n * it to a JSON Schema. Returns `null` when the path cannot be resolved\n * (e.g. older tRPC versions or missing type info).\n */\nfunction extractErrorSchema(\n routerType: ts.Type,\n checker: ts.TypeChecker,\n schemaCtx: SchemaCtx,\n): SchemaObject | null {\n const walk = (type: ts.Type, keys: string[]): ts.Type | null => {\n const [head, ...rest] = keys;\n if (!head) {\n return type;\n }\n const sym = type.getProperty(head);\n if (!sym) {\n return null;\n }\n return walk(checker.getTypeOfSymbol(sym), rest);\n };\n\n const errorShapeType = walk(routerType, [\n '_def',\n '_config',\n '$types',\n 'errorShape',\n ]);\n if (!errorShapeType) {\n return null;\n }\n\n if (hasFlag(errorShapeType, ts.TypeFlags.Any)) {\n return null;\n }\n\n return typeToJsonSchema(errorShapeType, schemaCtx);\n}\n\n// ---------------------------------------------------------------------------\n// OpenAPI document builder\n// ---------------------------------------------------------------------------\n\n/** Fallback error schema when the router type doesn't expose an error shape. */\nconst DEFAULT_ERROR_SCHEMA: SchemaObject = {\n type: 'object',\n properties: {\n message: { type: 'string' },\n code: { type: 'string' },\n data: { type: 'object' },\n },\n required: ['message', 'code'],\n};\n\n/**\n * Wrap a procedure's output schema in the tRPC success envelope.\n *\n * tRPC HTTP responses are always serialised as:\n * `{ result: { data: T } }`\n *\n * When the procedure has no output the envelope is still present but\n * the `data` property is omitted.\n */\nfunction wrapInSuccessEnvelope(\n outputSchema: SchemaObject | null,\n): SchemaObject {\n const hasOutput = outputSchema !== null && isNonEmptySchema(outputSchema);\n const resultSchema: SchemaObject = {\n type: 'object',\n properties: {\n ...(hasOutput ? { data: outputSchema } : {}),\n },\n ...(hasOutput ? { required: ['data'] } : {}),\n };\n return {\n type: 'object',\n properties: {\n result: resultSchema,\n },\n required: ['result'],\n };\n}\n\nfunction buildProcedureOperation(\n proc: ProcedureInfo,\n method: 'get' | 'post',\n): OperationObject {\n const [tag = proc.path] = proc.path.split('.');\n const operation: OperationObject = {\n operationId: proc.path,\n ...(proc.description ? { description: proc.description } : {}),\n tags: [tag],\n responses: {\n '200': {\n description: 'Successful response',\n content: {\n 'application/json': {\n schema: wrapInSuccessEnvelope(proc.outputSchema),\n },\n },\n },\n default: { $ref: '#/components/responses/Error' },\n },\n };\n\n if (proc.inputSchema === null) {\n return operation;\n }\n\n if (method === 'get') {\n operation.parameters = [\n {\n name: 'input',\n in: 'query',\n required: true,\n // FIXME: OAS 3.1.1 says a parameter MUST use either schema+style OR content, not both.\n // style should be removed here, but hey-api requires it to generate a correct query serializer.\n style: 'deepObject',\n content: { 'application/json': { schema: proc.inputSchema } },\n },\n ];\n } else {\n operation.requestBody = {\n required: true,\n content: { 'application/json': { schema: proc.inputSchema } },\n };\n }\n\n return operation;\n}\n\nfunction buildOpenAPIDocument(\n procedures: ProcedureInfo[],\n options: GenerateOptions,\n meta: RouterMeta = { errorSchema: null },\n): Document {\n const paths: PathsObject = {};\n\n for (const proc of procedures) {\n if (!shouldIncludeProcedureInOpenAPI(proc.type)) {\n continue;\n }\n\n const opPath = `/${proc.path}`;\n const method = proc.type === 'query' ? 'get' : 'post';\n\n const pathItem: PathItemObject = paths[opPath] ?? {};\n paths[opPath] = pathItem;\n pathItem[method] = buildProcedureOperation(\n proc,\n method,\n ) as PathItemObject[typeof method];\n }\n\n const hasNamedSchemas =\n meta.schemas !== undefined && Object.keys(meta.schemas).length > 0;\n\n return {\n openapi: '3.1.1',\n jsonSchemaDialect: 'https://spec.openapis.org/oas/3.1/dialect/base',\n info: {\n title: options.title ?? 'tRPC API',\n version: options.version ?? '0.0.0',\n },\n paths,\n components: {\n ...(hasNamedSchemas && meta.schemas ? { schemas: meta.schemas } : {}),\n responses: {\n Error: {\n description: 'Error response',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: meta.errorSchema ?? DEFAULT_ERROR_SCHEMA,\n },\n required: ['error'],\n },\n },\n },\n },\n },\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Analyse the given TypeScript router file using the TypeScript compiler and\n * return an OpenAPI 3.1 document describing all query and mutation procedures.\n *\n * @param routerFilePath - Absolute or relative path to the file that exports\n * the AppRouter.\n * @param options - Optional generation settings (export name, title, version).\n */\nexport async function generateOpenAPIDocument(\n routerFilePath: string,\n options: GenerateOptions = {},\n): Promise<Document> {\n const resolvedPath = path.resolve(routerFilePath);\n const exportName = options.exportName ?? 'AppRouter';\n\n const compilerOptions = loadCompilerOptions(path.dirname(resolvedPath));\n const program = ts.createProgram([resolvedPath], compilerOptions);\n const checker = program.getTypeChecker();\n const sourceFile = program.getSourceFile(resolvedPath);\n\n if (!sourceFile) {\n throw new Error(`Could not load TypeScript file: ${resolvedPath}`);\n }\n\n const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n if (!moduleSymbol) {\n throw new Error(`No module exports found in: ${resolvedPath}`);\n }\n\n const tsExports = checker.getExportsOfModule(moduleSymbol);\n const routerSymbol = tsExports.find((sym) => sym.getName() === exportName);\n\n if (!routerSymbol) {\n const available = tsExports.map((e) => e.getName()).join(', ');\n throw new Error(\n `No export named '${exportName}' found in: ${resolvedPath}\\n` +\n `Available exports: ${available || '(none)'}`,\n );\n }\n\n // Prefer the value declaration for value exports; fall back to the declared\n // type for `export type AppRouter = …` aliases.\n let routerType: ts.Type;\n if (routerSymbol.valueDeclaration) {\n routerType = checker.getTypeOfSymbolAtLocation(\n routerSymbol,\n routerSymbol.valueDeclaration,\n );\n } else {\n routerType = checker.getDeclaredTypeOfSymbol(routerSymbol);\n }\n\n const schemaCtx: SchemaCtx = {\n checker,\n visited: new Set(),\n schemas: {},\n typeToRef: new Map(),\n };\n\n // Try to dynamically import the router to extract schema descriptions\n const runtimeDescriptions = new Map<string, RuntimeDescriptions>();\n const router = await tryImportRouter(resolvedPath, exportName);\n if (router) {\n collectRuntimeDescriptions(router, '', runtimeDescriptions);\n }\n\n const walkCtx: WalkCtx = {\n procedures: [],\n seen: new Set(),\n schemaCtx,\n runtimeDescriptions,\n };\n walkType({ type: routerType, ctx: walkCtx, currentPath: '' });\n\n const errorSchema = extractErrorSchema(routerType, checker, schemaCtx);\n return buildOpenAPIDocument(walkCtx.procedures, options, {\n errorSchema,\n schemas: schemaCtx.schemas,\n });\n}\n","import type { OpenAPIV3_1 as BaseOpenAPIV3_1 } from 'openapi-types';\n\nexport type Replace<TTarget, TReplaceWith> = Omit<TTarget, keyof TReplaceWith> &\n TReplaceWith;\n\nexport type SchemaType =\n | 'array'\n | 'boolean'\n | 'integer'\n | 'null'\n | 'number'\n | 'object'\n | 'string';\n\nexport type PrimitiveSchemaType = SchemaType;\n\nexport type HttpMethods = BaseOpenAPIV3_1.HttpMethods;\nexport type ReferenceObject = BaseOpenAPIV3_1.ReferenceObject;\nexport type ExampleObject = BaseOpenAPIV3_1.ExampleObject;\nexport type DiscriminatorObject = BaseOpenAPIV3_1.DiscriminatorObject;\nexport type ExternalDocumentationObject =\n BaseOpenAPIV3_1.ExternalDocumentationObject;\nexport type XMLObject = BaseOpenAPIV3_1.XMLObject;\nexport type LinkObject = BaseOpenAPIV3_1.LinkObject;\nexport type SecuritySchemeObject = BaseOpenAPIV3_1.SecuritySchemeObject;\n\nexport type SchemaObject = Replace<\n BaseOpenAPIV3_1.BaseSchemaObject,\n {\n $ref?: string;\n $defs?: Record<string, SchemaObject>;\n $schema?: string;\n type?: string | string[];\n properties?: Record<string, SchemaObject>;\n required?: string[];\n items?: SchemaObject | false;\n prefixItems?: SchemaObject[];\n const?: string | number | boolean | null;\n enum?: (string | number | boolean | null)[];\n oneOf?: SchemaObject[];\n anyOf?: SchemaObject[];\n allOf?: SchemaObject[];\n not?: SchemaObject;\n additionalProperties?: boolean | SchemaObject;\n discriminator?: DiscriminatorObject;\n externalDocs?: ExternalDocumentationObject;\n xml?: XMLObject;\n contentMediaType?: string;\n exclusiveMinimum?: boolean | number;\n exclusiveMaximum?: boolean | number;\n }\n>;\n\nexport type SchemaLike = SchemaObject;\n\nexport interface ArraySchemaObject extends SchemaObject {\n type: 'array';\n items: SchemaObject | false;\n}\n\nexport type MediaTypeObject = Replace<\n BaseOpenAPIV3_1.MediaTypeObject,\n {\n schema?: SchemaObject | ReferenceObject;\n examples?: Record<string, ReferenceObject | ExampleObject>;\n }\n>;\n\nexport interface ParameterBaseObject\n extends Replace<\n BaseOpenAPIV3_1.ParameterBaseObject,\n {\n schema?: SchemaObject | ReferenceObject;\n examples?: Record<string, ReferenceObject | ExampleObject>;\n content?: Record<string, MediaTypeObject>;\n }\n > {}\n\nexport interface ParameterObject extends ParameterBaseObject {\n name: string;\n in: string;\n}\n\nexport type HeaderObject = ParameterBaseObject;\n\nexport type RequestBodyObject = Replace<\n BaseOpenAPIV3_1.RequestBodyObject,\n {\n content: Record<string, MediaTypeObject>;\n }\n>;\n\nexport type ResponseObject = Replace<\n BaseOpenAPIV3_1.ResponseObject,\n {\n headers?: Record<string, ReferenceObject | HeaderObject>;\n content?: Record<string, MediaTypeObject>;\n links?: Record<string, ReferenceObject | LinkObject>;\n }\n>;\n\nexport type ResponsesObject = Record<string, ReferenceObject | ResponseObject>;\n\nexport type OperationObject<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.OperationObject<T>,\n {\n parameters?: (ReferenceObject | ParameterObject)[];\n requestBody?: ReferenceObject | RequestBodyObject;\n responses?: ResponsesObject;\n callbacks?: Record<string, ReferenceObject | CallbackObject>;\n }\n> &\n T;\n\nexport type PathItemObject<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.PathItemObject<T>,\n {\n parameters?: (ReferenceObject | ParameterObject)[];\n }\n> & {\n [method in HttpMethods]?: OperationObject<T>;\n};\n\nexport type PathsObject<T extends {} = {}, TPath extends {} = {}> = Record<\n string,\n (PathItemObject<T> & TPath) | undefined\n>;\n\nexport type CallbackObject = Record<string, PathItemObject | ReferenceObject>;\n\nexport type ComponentsObject = Replace<\n BaseOpenAPIV3_1.ComponentsObject,\n {\n schemas?: Record<string, SchemaObject>;\n responses?: Record<string, ReferenceObject | ResponseObject>;\n parameters?: Record<string, ReferenceObject | ParameterObject>;\n requestBodies?: Record<string, ReferenceObject | RequestBodyObject>;\n headers?: Record<string, ReferenceObject | HeaderObject>;\n links?: Record<string, ReferenceObject | LinkObject>;\n callbacks?: Record<string, ReferenceObject | CallbackObject>;\n pathItems?: Record<string, ReferenceObject | PathItemObject>;\n }\n>;\n\nexport type Document<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.Document<T>,\n {\n paths?: PathsObject<T>;\n components?: ComponentsObject;\n }\n>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["value: unknown","schema: $ZodType","wrapperDefTypes: ReadonlySet<$ZodTypeDef['type']>","def: $ZodTypeDef","current: $ZodType","schema: unknown","map: DescriptionMap","prefix: string","ctx: {\n registry: $ZodRegistry<GlobalMeta>;\n map: DescriptionMap;\n seenLazy: Set<$ZodType>;\n }","path","mod: Record<string, unknown>","exportName: string","resolvedPath: string","routerOrRecord: AnyTRPCRouter | TRPCRouterRecord","result: Map<string, RuntimeDescriptions>","record: TRPCRouterRecord","inputDescs: DescriptionMap | null","outputDescs: DescriptionMap | null","value: AnyTRPCProcedure | TRPCRouterRecord","schema: SchemaObject","descs: DescriptionMap","schemas?: Record<string, SchemaObject>","propertyName: string","description: string","type: ts.Type","flag: ts.TypeFlags","sym: ts.Symbol","prop: ts.Symbol","schema: SchemaObject | null","schemas: Record<string, SchemaObject>","name: string","existing: Record<string, unknown>","schema: SchemaObject","s: SchemaObject","ctx: SchemaCtx","schema","flags: ts.TypeFlags","checker: ts.TypeChecker","type: ts.UnionType","depth: number","schemas: SchemaObject[]","nonNull: ts.Type[]","hasNull: boolean","type: ts.IntersectionType","properties: Record<string, SchemaObject>","required: string[]","additionalProperties: SchemaObject | boolean | undefined","result: SchemaObject","autoRegName: string | null","defType: ts.Type","inputType: ts.Type | null","type: ProcedureInfo['type']","path: string","def: ProcedureDef","initializer: ts.Expression | null","recovered: ts.Type | null","expr: ts.Expression","ctx: WalkCtx","inputSchema: SchemaObject | null","outputSchema: SchemaObject | null","filePath: string","opts: WalkTypeOpts","recordType: ts.Type","prefix: string","startDir: string","options: ts.CompilerOptions","routerType: ts.Type","schemaCtx: SchemaCtx","keys: string[]","DEFAULT_ERROR_SCHEMA: SchemaObject","resultSchema: SchemaObject","proc: ProcedureInfo","method: 'get' | 'post'","operation: OperationObject","procedures: ProcedureInfo[]","options: GenerateOptions","meta: RouterMeta","paths: PathsObject","pathItem: PathItemObject","routerFilePath: string","walkCtx: WalkCtx"],"sources":["../src/schemaExtraction.ts","../src/generate.ts","../src/types.ts"],"sourcesContent":["import { pathToFileURL } from 'node:url';\nimport type {\n AnyTRPCProcedure,\n AnyTRPCRouter,\n TRPCRouterRecord,\n} from '@trpc/server';\nimport type {\n $ZodArrayDef,\n $ZodObjectDef,\n $ZodRegistry,\n $ZodShape,\n $ZodType,\n $ZodTypeDef,\n GlobalMeta,\n} from 'zod/v4/core';\nimport type { SchemaObject } from './types';\n\n/** Description strings extracted from Zod `.describe()` calls, keyed by dot-delimited property path. */\nexport interface DescriptionMap {\n /** Top-level description on the schema itself (empty-string key). */\n self?: string;\n /** Property-path → description, e.g. `\"name\"` or `\"address.street\"`. */\n properties: Map<string, string>;\n}\n\nexport interface RuntimeDescriptions {\n input: DescriptionMap | null;\n output: DescriptionMap | null;\n}\n\n// ---------------------------------------------------------------------------\n// Zod shape walking — extract .describe() strings\n// ---------------------------------------------------------------------------\n\n/**\n * Zod v4 stores `.describe()` strings in `globalThis.__zod_globalRegistry`,\n * a WeakMap-backed `$ZodRegistry<GlobalMeta>`. We access it via globalThis\n * because zod is an optional peer dependency.\n */\nfunction getZodGlobalRegistry(): $ZodRegistry<GlobalMeta> | null {\n const reg = (\n globalThis as { __zod_globalRegistry?: $ZodRegistry<GlobalMeta> }\n ).__zod_globalRegistry;\n return reg && typeof reg.get === 'function' ? reg : null;\n}\n\n/** Runtime check: does this value look like a `$ZodType` (has `_zod.def`)? */\nfunction isZodSchema(value: unknown): value is $ZodType {\n if (value == null || typeof value !== 'object') return false;\n const zod = (value as { _zod?: unknown })._zod;\n return zod != null && typeof zod === 'object' && 'def' in zod;\n}\n\n/** Get the object shape from a Zod object schema, if applicable. */\nfunction zodObjectShape(schema: $ZodType): $ZodShape | null {\n const def = schema._zod.def;\n if (def.type === 'object' && 'shape' in def) {\n return (def as $ZodObjectDef).shape;\n }\n return null;\n}\n\n/** Get the element schema from a Zod array schema, if applicable. */\nfunction zodArrayElement(schema: $ZodType): $ZodType | null {\n const def = schema._zod.def;\n if (def.type === 'array' && 'element' in def) {\n return (def as $ZodArrayDef).element;\n }\n return null;\n}\n\n/** Wrapper def types whose inner schema is accessible via `innerType` or `in`. */\nconst wrapperDefTypes: ReadonlySet<$ZodTypeDef['type']> = new Set([\n 'optional',\n 'nullable',\n 'nonoptional',\n 'default',\n 'prefault',\n 'catch',\n 'readonly',\n 'pipe',\n 'transform',\n 'promise',\n]);\n\n/**\n * Extract the wrapped inner schema from a wrapper def.\n * Most wrappers use `innerType`; `pipe` uses `in`.\n */\nfunction getWrappedInner(def: $ZodTypeDef): $ZodType | null {\n if ('innerType' in def) return (def as { innerType: $ZodType }).innerType;\n if ('in' in def) return (def as { in: $ZodType }).in;\n return null;\n}\n\n/** Unwrap wrapper types (optional, nullable, default, readonly, etc.) to get the inner schema. */\nfunction unwrapZodSchema(schema: $ZodType): $ZodType {\n let current: $ZodType = schema;\n const seen = new Set<$ZodType>();\n while (!seen.has(current)) {\n seen.add(current);\n const def = current._zod.def;\n if (!wrapperDefTypes.has(def.type)) break;\n const inner = getWrappedInner(def);\n if (!inner) break;\n current = inner;\n }\n return current;\n}\n\n/**\n * Walk a Zod schema and collect description strings at each property path.\n * Returns `null` if the value is not a Zod schema or has no descriptions.\n */\nexport function extractZodDescriptions(schema: unknown): DescriptionMap | null {\n if (!isZodSchema(schema)) return null;\n const registry = getZodGlobalRegistry();\n if (!registry) return null;\n\n const map: DescriptionMap = { properties: new Map() };\n let hasAny = false;\n\n // Check top-level description\n const topMeta = registry.get(schema);\n if (topMeta?.description) {\n map.self = topMeta.description;\n hasAny = true;\n }\n\n // Walk object shape\n walkZodShape(schema, '', { registry, map, seenLazy: new Set() });\n if (map.properties.size > 0) hasAny = true;\n\n return hasAny ? map : null;\n}\n\nfunction walkZodShape(\n schema: $ZodType,\n prefix: string,\n ctx: {\n registry: $ZodRegistry<GlobalMeta>;\n map: DescriptionMap;\n seenLazy: Set<$ZodType>;\n },\n): void {\n const unwrapped = unwrapZodSchema(schema);\n const def = unwrapped._zod.def;\n\n if (def.type === 'lazy' && 'getter' in def) {\n if (ctx.seenLazy.has(unwrapped)) {\n return;\n }\n ctx.seenLazy.add(unwrapped);\n const inner = (def as { getter: () => unknown }).getter();\n if (isZodSchema(inner)) {\n walkZodShape(inner, prefix, ctx);\n }\n return;\n }\n\n // If this is an array, check for a description on the element schema itself\n // (stored as `[]` in the path) and recurse into the element's shape.\n const element = zodArrayElement(unwrapped);\n if (element) {\n const unwrappedElement = unwrapZodSchema(element);\n const elemMeta = ctx.registry.get(element);\n const innerElemMeta =\n unwrappedElement !== element\n ? ctx.registry.get(unwrappedElement)\n : undefined;\n const elemDesc = elemMeta?.description ?? innerElemMeta?.description;\n if (elemDesc) {\n const itemsPath = prefix ? `${prefix}.[]` : '[]';\n ctx.map.properties.set(itemsPath, elemDesc);\n }\n walkZodShape(element, prefix, ctx);\n return;\n }\n\n const shape = zodObjectShape(unwrapped);\n if (!shape) return;\n\n for (const [key, fieldSchema] of Object.entries(shape)) {\n const path = prefix ? `${prefix}.${key}` : key;\n\n // Check for description on the field — may be on the wrapper or inner schema\n const meta = ctx.registry.get(fieldSchema);\n const unwrappedField = unwrapZodSchema(fieldSchema);\n const innerMeta =\n unwrappedField !== fieldSchema\n ? ctx.registry.get(unwrappedField)\n : undefined;\n const description = meta?.description ?? innerMeta?.description;\n if (description) {\n ctx.map.properties.set(path, description);\n }\n\n // Recurse into nested objects and arrays\n walkZodShape(unwrappedField, path, ctx);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Router detection & dynamic import\n// ---------------------------------------------------------------------------\n\n/** Check whether a value looks like a tRPC router instance at runtime. */\nfunction isRouterInstance(value: unknown): value is AnyTRPCRouter {\n if (value == null) return false;\n const obj = value as Record<string, unknown>;\n const def = obj['_def'];\n return (\n typeof obj === 'object' &&\n def != null &&\n typeof def === 'object' &&\n (def as Record<string, unknown>)['record'] != null &&\n typeof (def as Record<string, unknown>)['record'] === 'object'\n );\n}\n\n/**\n * Search a module's exports for a tRPC router instance.\n *\n * Tries (in order):\n * 1. Exact `exportName` match\n * 2. lcfirst variant (`AppRouter` → `appRouter`)\n * 3. First export that looks like a router\n */\nexport function findRouterExport(\n mod: Record<string, unknown>,\n exportName: string,\n): AnyTRPCRouter | null {\n // 1. Exact match\n if (isRouterInstance(mod[exportName])) {\n return mod[exportName];\n }\n\n // 2. lcfirst variant (e.g. AppRouter → appRouter)\n const lcFirst = exportName.charAt(0).toLowerCase() + exportName.slice(1);\n if (lcFirst !== exportName && isRouterInstance(mod[lcFirst])) {\n return mod[lcFirst];\n }\n\n // 3. Any export that looks like a router\n for (const value of Object.values(mod)) {\n if (isRouterInstance(value)) {\n return value;\n }\n }\n\n return null;\n}\n\n/**\n * Try to dynamically import the router file and extract a tRPC router\n * instance. Returns `null` if the import fails (e.g. no TS loader) or\n * no router export is found.\n */\nexport async function tryImportRouter(\n resolvedPath: string,\n exportName: string,\n): Promise<AnyTRPCRouter | null> {\n try {\n const mod = await import(pathToFileURL(resolvedPath).href);\n return findRouterExport(mod as Record<string, unknown>, exportName);\n } catch {\n // Dynamic import not available (no TS loader registered) — that's fine,\n // we fall back to type-checker-only schemas.\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Router walker — collect descriptions per procedure\n// ---------------------------------------------------------------------------\n\n/**\n * Walk a runtime tRPC router/record and collect Zod `.describe()` strings\n * keyed by procedure path.\n */\nexport function collectRuntimeDescriptions(\n routerOrRecord: AnyTRPCRouter | TRPCRouterRecord,\n prefix: string,\n result: Map<string, RuntimeDescriptions>,\n): void {\n // Unwrap router to its record; plain RouterRecords are used as-is.\n const record: TRPCRouterRecord = isRouterInstance(routerOrRecord)\n ? routerOrRecord._def.record\n : routerOrRecord;\n\n for (const [key, value] of Object.entries(record)) {\n const fullPath = prefix ? `${prefix}.${key}` : key;\n\n if (isProcedure(value)) {\n // Procedure — extract descriptions from input and output Zod schemas\n const def = value._def;\n let inputDescs: DescriptionMap | null = null;\n for (const input of def.inputs) {\n const descs = extractZodDescriptions(input);\n if (descs) {\n // Merge multiple .input() descriptions (last wins for conflicts)\n inputDescs ??= { properties: new Map() };\n inputDescs.self = descs.self ?? inputDescs.self;\n for (const [p, d] of descs.properties) {\n inputDescs.properties.set(p, d);\n }\n }\n }\n\n let outputDescs: DescriptionMap | null = null;\n // `output` exists at runtime on the procedure def (from the builder)\n // but is not part of the public Procedure type.\n const outputParser = (def as Record<string, unknown>)['output'];\n if (outputParser) {\n outputDescs = extractZodDescriptions(outputParser);\n }\n\n if (inputDescs || outputDescs) {\n result.set(fullPath, { input: inputDescs, output: outputDescs });\n }\n } else {\n // Sub-router or nested RouterRecord — recurse\n collectRuntimeDescriptions(value, fullPath, result);\n }\n }\n}\n\n/** Type guard: check if a RouterRecord value is a procedure (callable). */\nfunction isProcedure(\n value: AnyTRPCProcedure | TRPCRouterRecord,\n): value is AnyTRPCProcedure {\n return typeof value === 'function';\n}\n\n// ---------------------------------------------------------------------------\n// Apply descriptions to JSON schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Overlay description strings from a `DescriptionMap` onto an existing\n * JSON schema produced by the TypeScript type checker. Mutates in place.\n */\nexport function applyDescriptions(\n schema: SchemaObject,\n descs: DescriptionMap,\n schemas?: Record<string, SchemaObject>,\n): void {\n if (descs.self) {\n schema.description = descs.self;\n }\n\n for (const [propPath, description] of descs.properties) {\n setNestedDescription({\n schema,\n pathParts: propPath.split('.'),\n description,\n schemas,\n });\n }\n}\n\nfunction resolveSchemaRef(\n schema: SchemaObject,\n schemas?: Record<string, SchemaObject>,\n): SchemaObject | null {\n const ref = schema.$ref;\n if (!ref) {\n return schema;\n }\n if (!schemas || !ref.startsWith('#/components/schemas/')) {\n return null;\n }\n\n const refName = ref.slice('#/components/schemas/'.length);\n return refName ? (schemas[refName] ?? null) : null;\n}\n\nfunction getArrayItemsSchema(schema: SchemaObject): SchemaObject | null {\n const items = schema.items;\n if (schema.type !== 'array' || items == null || items === false) {\n return null;\n }\n return items;\n}\n\nfunction getPropertySchema(\n schema: SchemaObject,\n propertyName: string,\n): SchemaObject | null {\n return schema.properties?.[propertyName] ?? null;\n}\n\nfunction setLeafDescription(schema: SchemaObject, description: string): void {\n if (schema.$ref) {\n const ref = schema.$ref;\n delete schema.$ref;\n schema.allOf = [{ $ref: ref }, ...(schema.allOf ?? [])];\n }\n schema.description = description;\n}\n\nfunction setNestedDescription({\n schema,\n pathParts,\n description,\n schemas,\n}: {\n schema: SchemaObject;\n pathParts: string[];\n description: string;\n schemas?: Record<string, SchemaObject>;\n}): void {\n if (pathParts.length === 0) return;\n\n const [head, ...rest] = pathParts;\n if (!head) return;\n\n // `[]` means \"array items\" — navigate to the `items` sub-schema\n if (head === '[]') {\n const items = getArrayItemsSchema(schema);\n if (!items) return;\n if (rest.length === 0) {\n setLeafDescription(items, description);\n } else {\n const target = resolveSchemaRef(items, schemas) ?? items;\n setNestedDescription({\n schema: target,\n pathParts: rest,\n description,\n schemas,\n });\n }\n return;\n }\n\n const propSchema = getPropertySchema(schema, head);\n if (!propSchema) return;\n\n if (rest.length === 0) {\n // Leaf — Zod .describe() takes priority over JSDoc\n setLeafDescription(propSchema, description);\n } else {\n // For arrays, step through `items` transparently\n const target = getArrayItemsSchema(propSchema) ?? propSchema;\n const resolvedTarget = resolveSchemaRef(target, schemas) ?? target;\n setNestedDescription({\n schema: resolvedTarget,\n pathParts: rest,\n description,\n schemas,\n });\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as ts from 'typescript';\nimport {\n applyDescriptions,\n collectRuntimeDescriptions,\n tryImportRouter,\n type RuntimeDescriptions,\n} from './schemaExtraction';\nimport type {\n Document,\n OperationObject,\n PathItemObject,\n PathsObject,\n SchemaObject,\n ServerObject,\n} from './types';\n\ninterface ProcedureInfo {\n path: string;\n type: 'query' | 'mutation' | 'subscription';\n inputSchema: SchemaObject | null;\n outputSchema: SchemaObject | null;\n description?: string;\n}\n\n/** State extracted from the router's root config. */\ninterface RouterMeta {\n errorSchema: SchemaObject | null;\n schemas?: Record<string, SchemaObject>;\n}\n\nexport interface GenerateOptions {\n /**\n * The name of the exported router symbol.\n * @default 'AppRouter'\n */\n exportName?: string;\n /** Title for the generated OpenAPI `info` object. */\n title?: string;\n /** Version string for the generated OpenAPI `info` object. */\n version?: string;\n /**\n * OpenAPI `servers` array, passed through to the generated document. Each\n * `url` should include any tRPC mount prefix, since the generated paths\n * (`/user.create`, …) are relative to it — e.g.\n * `https://api.example.com/trpc`. When omitted, no `servers` entry is added.\n */\n servers?: ServerObject[];\n}\n\n// ---------------------------------------------------------------------------\n// Flag helpers\n// ---------------------------------------------------------------------------\n\nconst PRIMITIVE_FLAGS =\n ts.TypeFlags.String |\n ts.TypeFlags.Number |\n ts.TypeFlags.Boolean |\n ts.TypeFlags.StringLiteral |\n ts.TypeFlags.NumberLiteral |\n ts.TypeFlags.BooleanLiteral;\n\nfunction hasFlag(type: ts.Type, flag: ts.TypeFlags): boolean {\n return (type.getFlags() & flag) !== 0;\n}\n\nfunction isPrimitive(type: ts.Type): boolean {\n return hasFlag(type, PRIMITIVE_FLAGS);\n}\n\nfunction isObjectType(type: ts.Type): boolean {\n return hasFlag(type, ts.TypeFlags.Object);\n}\n\nfunction isOptionalSymbol(sym: ts.Symbol): boolean {\n return (sym.flags & ts.SymbolFlags.Optional) !== 0;\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema conversion — shared state\n// ---------------------------------------------------------------------------\n\n/** Shared state threaded through the type-to-schema recursion. */\ninterface SchemaCtx {\n checker: ts.TypeChecker;\n visited: Set<ts.Type>;\n /** Collected named schemas for components/schemas. */\n schemas: Record<string, SchemaObject>;\n /** Map from TS type identity to its registered schema name. */\n typeToRef: Map<ts.Type, string>;\n}\n\n// ---------------------------------------------------------------------------\n// Brand unwrapping\n// ---------------------------------------------------------------------------\n\n/**\n * If `type` is a branded intersection (primitive & object), return just the\n * primitive part. Otherwise return the type as-is.\n */\nfunction unwrapBrand(type: ts.Type): ts.Type {\n if (!type.isIntersection()) {\n return type;\n }\n const primitives = type.types.filter(isPrimitive);\n const hasObject = type.types.some(isObjectType);\n const [first] = primitives;\n if (first && hasObject) {\n return first;\n }\n return type;\n}\n\n// ---------------------------------------------------------------------------\n// Schema naming helpers\n// ---------------------------------------------------------------------------\n\nconst ANONYMOUS_NAMES = new Set(['__type', '__object', 'Object', '']);\nconst INTERNAL_COMPUTED_PROPERTY_SYMBOL = /^__@.*@\\d+$/;\n\n/** Try to determine a meaningful name for a TS type (type alias or interface). */\nfunction getTypeName(type: ts.Type): string | null {\n const aliasName = type.aliasSymbol?.getName();\n if (aliasName && !ANONYMOUS_NAMES.has(aliasName)) {\n return aliasName;\n }\n const symName = type.getSymbol()?.getName();\n if (symName && !ANONYMOUS_NAMES.has(symName) && !symName.startsWith('__')) {\n return symName;\n }\n return null;\n}\n\n// Skips asyncGenerator and branded symbols etc when creating types\n// Symbols can't be serialised\nfunction shouldSkipPropertySymbol(prop: ts.Symbol): boolean {\n return (\n prop.declarations?.some((declaration) => {\n const declarationName = ts.getNameOfDeclaration(declaration);\n if (!declarationName || !ts.isComputedPropertyName(declarationName)) {\n return false;\n }\n\n return INTERNAL_COMPUTED_PROPERTY_SYMBOL.test(prop.getName());\n }) ?? false\n );\n}\n\nfunction getReferencedSchema(\n schema: SchemaObject | null,\n schemas: Record<string, SchemaObject>,\n): SchemaObject | null {\n const ref = schema?.$ref;\n if (!ref?.startsWith('#/components/schemas/')) {\n return schema;\n }\n\n const refName = ref.slice('#/components/schemas/'.length);\n return refName ? (schemas[refName] ?? null) : schema;\n}\n\nfunction ensureUniqueName(\n name: string,\n existing: Record<string, unknown>,\n): string {\n if (!(name in existing)) {\n return name;\n }\n let i = 2;\n while (`${name}${i}` in existing) {\n i++;\n }\n return `${name}${i}`;\n}\n\nfunction schemaRef(name: string): SchemaObject {\n return { $ref: `#/components/schemas/${name}` };\n}\n\nfunction isSelfSchemaRef(schema: SchemaObject, name: string): boolean {\n return schema.$ref === schemaRef(name).$ref;\n}\n\nfunction isNonEmptySchema(s: SchemaObject): boolean {\n for (const _ in s) return true;\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Type → JSON Schema (with component extraction)\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a TS type to a JSON Schema. If the type has been pre-registered\n * (or has a meaningful TS name), it is stored in `ctx.schemas` and a `$ref`\n * is returned instead of an inline schema.\n *\n * Named types (type aliases, interfaces) are auto-registered before conversion\n * so that recursive references (including through unions and intersections)\n * resolve to a `$ref` instead of causing infinite recursion.\n */\nfunction typeToJsonSchema(\n type: ts.Type,\n ctx: SchemaCtx,\n depth = 0,\n): SchemaObject {\n // If this type is already registered as a named schema, return a $ref.\n const existingRef = ctx.typeToRef.get(type);\n if (existingRef) {\n const storedSchema = ctx.schemas[existingRef];\n if (\n storedSchema &&\n (isNonEmptySchema(storedSchema) || ctx.visited.has(type))\n ) {\n return schemaRef(existingRef);\n }\n\n // First encounter for a pre-registered placeholder: convert once, but keep\n // returning $ref for recursive edges while the type is actively visiting.\n ctx.schemas[existingRef] = storedSchema ?? {};\n const schema = convertTypeToSchema(type, ctx, depth);\n if (!isSelfSchemaRef(schema, existingRef)) {\n ctx.schemas[existingRef] = schema;\n }\n return schemaRef(existingRef);\n }\n\n const schema = convertTypeToSchema(type, ctx, depth);\n\n // If a recursive reference was detected during conversion (via handleCyclicRef\n // or convertPlainObject's auto-registration), the type is now registered in\n // typeToRef. If the stored schema is still the empty placeholder, fill it in\n // with the actual converted schema. Either way, return a $ref.\n const postConvertRef = ctx.typeToRef.get(type);\n if (postConvertRef) {\n const stored = ctx.schemas[postConvertRef];\n if (\n stored &&\n !isNonEmptySchema(stored) &&\n !isSelfSchemaRef(schema, postConvertRef)\n ) {\n ctx.schemas[postConvertRef] = schema;\n }\n return schemaRef(postConvertRef);\n }\n\n // Extract JSDoc from type alias symbol (e.g. `/** desc */ type Foo = string`)\n if (!schema.description && !schema.$ref && type.aliasSymbol) {\n const aliasJsDoc = getJsDocComment(type.aliasSymbol, ctx.checker);\n if (aliasJsDoc) {\n schema.description = aliasJsDoc;\n }\n }\n\n return schema;\n}\n\n// ---------------------------------------------------------------------------\n// Cyclic reference handling\n// ---------------------------------------------------------------------------\n\n/**\n * When we encounter a type we're already visiting, it's recursive.\n * Register it as a named schema and return a $ref.\n */\nfunction handleCyclicRef(type: ts.Type, ctx: SchemaCtx): SchemaObject {\n let refName = ctx.typeToRef.get(type);\n if (!refName) {\n const name = getTypeName(type) ?? 'RecursiveType';\n refName = ensureUniqueName(name, ctx.schemas);\n ctx.typeToRef.set(type, refName);\n ctx.schemas[refName] = {}; // placeholder — filled by the outer call\n }\n return schemaRef(refName);\n}\n\n// ---------------------------------------------------------------------------\n// Primitive & literal type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertPrimitiveOrLiteral(\n type: ts.Type,\n flags: ts.TypeFlags,\n checker: ts.TypeChecker,\n): SchemaObject | null {\n if (flags & ts.TypeFlags.String) {\n return { type: 'string' };\n }\n if (flags & ts.TypeFlags.Number) {\n return { type: 'number' };\n }\n if (flags & ts.TypeFlags.Boolean) {\n return { type: 'boolean' };\n }\n if (flags & ts.TypeFlags.Null) {\n return { type: 'null' };\n }\n if (flags & ts.TypeFlags.Undefined) {\n return {};\n }\n if (flags & ts.TypeFlags.Void) {\n return {};\n }\n if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) {\n return {};\n }\n if (flags & ts.TypeFlags.Never) {\n return { not: {} };\n }\n if (flags & ts.TypeFlags.BigInt || flags & ts.TypeFlags.BigIntLiteral) {\n return { type: 'integer', format: 'bigint' };\n }\n\n if (flags & ts.TypeFlags.StringLiteral) {\n return { type: 'string', const: (type as ts.StringLiteralType).value };\n }\n if (flags & ts.TypeFlags.NumberLiteral) {\n return { type: 'number', const: (type as ts.NumberLiteralType).value };\n }\n if (flags & ts.TypeFlags.BooleanLiteral) {\n const isTrue = checker.typeToString(type) === 'true';\n return { type: 'boolean', const: isTrue };\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Union type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertUnionType(\n type: ts.UnionType,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const members = type.types;\n\n // Strip undefined / void members (they make the field optional, not typed)\n const defined = members.filter(\n (m) => !hasFlag(m, ts.TypeFlags.Undefined | ts.TypeFlags.Void),\n );\n if (defined.length === 0) {\n return {};\n }\n\n const hasNull = defined.some((m) => hasFlag(m, ts.TypeFlags.Null));\n const nonNull = defined.filter((m) => !hasFlag(m, ts.TypeFlags.Null));\n\n // TypeScript represents `boolean` as `true | false`. Collapse boolean\n // literal pairs back into a single boolean, even when mixed with other types.\n // e.g. `string | true | false` → treat as `string | boolean`\n const boolLiterals = nonNull.filter((m) =>\n hasFlag(unwrapBrand(m), ts.TypeFlags.BooleanLiteral),\n );\n const hasBoolPair =\n boolLiterals.length === 2 &&\n boolLiterals.some(\n (m) => ctx.checker.typeToString(unwrapBrand(m)) === 'true',\n ) &&\n boolLiterals.some(\n (m) => ctx.checker.typeToString(unwrapBrand(m)) === 'false',\n );\n\n // Build the effective non-null members, collapsing boolean literal pairs\n const effective = hasBoolPair\n ? nonNull.filter(\n (m) => !hasFlag(unwrapBrand(m), ts.TypeFlags.BooleanLiteral),\n )\n : nonNull;\n\n // Pure boolean (or boolean | null) — no other types\n if (hasBoolPair && effective.length === 0) {\n return hasNull ? { type: ['boolean', 'null'] } : { type: 'boolean' };\n }\n\n // Collapse unions of same-type literals into a single `enum` array.\n // e.g. \"FOO\" | \"BAR\" → { type: \"string\", enum: [\"FOO\", \"BAR\"] }\n const collapsedEnum = tryCollapseLiteralUnion(effective, hasNull);\n if (collapsedEnum) {\n return collapsedEnum;\n }\n\n const schemas = effective\n .map((m) => typeToJsonSchema(m, ctx, depth + 1))\n .filter(isNonEmptySchema);\n\n // Re-inject the collapsed boolean\n if (hasBoolPair) {\n schemas.push({ type: 'boolean' });\n }\n\n if (hasNull) {\n schemas.push({ type: 'null' });\n }\n\n if (schemas.length === 0) {\n return {};\n }\n\n const [firstSchema] = schemas;\n if (schemas.length === 1 && firstSchema !== undefined) {\n return firstSchema;\n }\n\n // When all schemas are simple type-only schemas (no other properties),\n // collapse into a single `type` array. e.g. string | null → type: [\"string\", \"null\"]\n if (schemas.every(isSimpleTypeSchema)) {\n return { type: schemas.map((s) => s.type as string) };\n }\n\n // Detect discriminated unions: all oneOf members are objects sharing a common\n // required property whose value is a `const`. If found, add a `discriminator`.\n const discriminatorProp = detectDiscriminatorProperty(schemas);\n if (discriminatorProp) {\n return {\n oneOf: schemas,\n discriminator: { propertyName: discriminatorProp },\n };\n }\n\n return { oneOf: schemas };\n}\n\n/**\n * If every schema in a oneOf is an object with a common required property\n * whose value is a `const`, return that property name. Otherwise return null.\n */\nfunction detectDiscriminatorProperty(schemas: SchemaObject[]): string | null {\n if (schemas.length < 2) {\n return null;\n }\n\n // All schemas must be object types with properties\n if (!schemas.every((s) => s.type === 'object' && s.properties)) {\n return null;\n }\n\n // Find properties that exist in every schema, are required, and have a `const` value\n const first = schemas[0];\n if (!first?.properties) {\n return null;\n }\n const firstProps = Object.keys(first.properties);\n for (const prop of firstProps) {\n const allHaveConst = schemas.every((s) => {\n const propSchema = s.properties?.[prop];\n return (\n propSchema !== undefined &&\n propSchema.const !== undefined &&\n s.required?.includes(prop)\n );\n });\n if (allHaveConst) {\n return prop;\n }\n }\n\n return null;\n}\n\n/** A schema that is just `{ type: \"somePrimitive\" }` with no other keys. */\nfunction isSimpleTypeSchema(s: SchemaObject): boolean {\n const keys = Object.keys(s);\n return keys.length === 1 && keys[0] === 'type' && typeof s.type === 'string';\n}\n\n/**\n * If every non-null member is a string or number literal of the same kind,\n * collapse them into a single `{ type, enum }` schema.\n */\nfunction tryCollapseLiteralUnion(\n nonNull: ts.Type[],\n hasNull: boolean,\n): SchemaObject | null {\n if (nonNull.length <= 1) {\n return null;\n }\n\n const allLiterals = nonNull.every((m) =>\n hasFlag(m, ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral),\n );\n if (!allLiterals) {\n return null;\n }\n\n const [first] = nonNull;\n if (!first) {\n return null;\n }\n\n const isString = hasFlag(first, ts.TypeFlags.StringLiteral);\n const targetFlag = isString\n ? ts.TypeFlags.StringLiteral\n : ts.TypeFlags.NumberLiteral;\n const allSameKind = nonNull.every((m) => hasFlag(m, targetFlag));\n if (!allSameKind) {\n return null;\n }\n\n const values = nonNull.map((m) =>\n isString\n ? (m as ts.StringLiteralType).value\n : (m as ts.NumberLiteralType).value,\n );\n const baseType = isString ? 'string' : 'number';\n return {\n type: hasNull ? [baseType, 'null'] : baseType,\n enum: values,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Intersection type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertIntersectionType(\n type: ts.IntersectionType,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n // Branded types (e.g. z.string().brand<'X'>()) appear as an intersection of\n // a primitive with a phantom object. Strip the object members — they are\n // always brand metadata.\n const hasPrimitiveMember = type.types.some(isPrimitive);\n const nonBrand = hasPrimitiveMember\n ? type.types.filter((m) => !isObjectType(m))\n : type.types;\n\n const schemas = nonBrand\n .map((m) => typeToJsonSchema(m, ctx, depth + 1))\n .filter(isNonEmptySchema);\n\n if (schemas.length === 0) {\n return {};\n }\n const [onlySchema] = schemas;\n if (schemas.length === 1 && onlySchema !== undefined) {\n return onlySchema;\n }\n\n // When all members are plain inline object schemas (no $ref), merge them\n // into a single object instead of wrapping in allOf.\n if (schemas.every(isInlineObjectSchema)) {\n return mergeObjectSchemas(schemas);\n }\n\n return { allOf: schemas };\n}\n\n/** True when the schema is an inline `{ type: \"object\", ... }` (not a $ref). */\nfunction isInlineObjectSchema(s: SchemaObject): boolean {\n return s.type === 'object' && !s.$ref;\n}\n\n/**\n * Merge multiple `{ type: \"object\" }` schemas into one.\n * Falls back to `allOf` if any property names conflict across schemas.\n */\nfunction mergeObjectSchemas(schemas: SchemaObject[]): SchemaObject {\n // Check for property name conflicts before merging.\n const seen = new Set<string>();\n for (const s of schemas) {\n if (s.properties) {\n for (const prop of Object.keys(s.properties)) {\n if (seen.has(prop)) {\n // Conflicting property — fall back to allOf to preserve both definitions.\n return { allOf: schemas };\n }\n seen.add(prop);\n }\n }\n }\n\n const properties: Record<string, SchemaObject> = {};\n const required: string[] = [];\n let additionalProperties: SchemaObject | boolean | undefined;\n\n for (const s of schemas) {\n if (s.properties) {\n Object.assign(properties, s.properties);\n }\n if (s.required) {\n required.push(...s.required);\n }\n if (s.additionalProperties !== undefined) {\n additionalProperties = s.additionalProperties;\n }\n }\n\n const result: SchemaObject = { type: 'object' };\n if (Object.keys(properties).length > 0) {\n result.properties = properties;\n }\n if (required.length > 0) {\n result.required = required;\n }\n if (additionalProperties !== undefined) {\n result.additionalProperties = additionalProperties;\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Object type conversion\n// ---------------------------------------------------------------------------\n\nfunction convertWellKnownType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject | null {\n const symName = type.getSymbol()?.getName();\n if (symName === 'Date') {\n return { type: 'string', format: 'date-time' };\n }\n if (symName === 'Uint8Array' || symName === 'Buffer') {\n return { type: 'string', format: 'binary' };\n }\n\n // Unwrap Promise<T>\n if (symName === 'Promise') {\n const [inner] = ctx.checker.getTypeArguments(type as ts.TypeReference);\n return inner ? typeToJsonSchema(inner, ctx, depth + 1) : {};\n }\n\n return null;\n}\n\nfunction convertArrayType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const [elem] = ctx.checker.getTypeArguments(type as ts.TypeReference);\n const schema: SchemaObject = { type: 'array' };\n if (elem) {\n schema.items = typeToJsonSchema(elem, ctx, depth + 1);\n }\n return schema;\n}\n\nfunction convertTupleType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const args = ctx.checker.getTypeArguments(type as ts.TypeReference);\n const schemas = args.map((a) => typeToJsonSchema(a, ctx, depth + 1));\n return {\n type: 'array',\n prefixItems: schemas,\n items: false,\n minItems: args.length,\n maxItems: args.length,\n };\n}\n\nfunction convertPlainObject(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const { checker } = ctx;\n const stringIndexType = type.getStringIndexType();\n const typeProps = type.getProperties();\n\n // Pure index-signature Record type (no named props)\n if (typeProps.length === 0 && stringIndexType) {\n return {\n type: 'object',\n additionalProperties: typeToJsonSchema(stringIndexType, ctx, depth + 1),\n };\n }\n\n // Auto-register types with a meaningful TS name BEFORE converting\n // properties, so that circular or shared refs discovered during recursion\n // resolve to a $ref via the `typeToJsonSchema` wrapper.\n let autoRegName: string | null = null;\n const tsName = getTypeName(type);\n const isNamedUnregisteredType =\n tsName !== null && typeProps.length > 0 && !ctx.typeToRef.has(type);\n if (isNamedUnregisteredType) {\n autoRegName = ensureUniqueName(tsName, ctx.schemas);\n ctx.typeToRef.set(type, autoRegName);\n ctx.schemas[autoRegName] = {}; // placeholder for circular ref guard\n }\n\n ctx.visited.add(type);\n const properties: Record<string, SchemaObject> = {};\n const required: string[] = [];\n\n for (const prop of typeProps) {\n if (shouldSkipPropertySymbol(prop)) {\n continue;\n }\n\n const propType = checker.getTypeOfSymbol(prop);\n const propSchema = typeToJsonSchema(propType, ctx, depth + 1);\n\n // Extract JSDoc comment from the property symbol as a description\n const jsDoc = getJsDocComment(prop, checker);\n if (jsDoc && !propSchema.description && !propSchema.$ref) {\n propSchema.description = jsDoc;\n }\n\n properties[prop.name] = propSchema;\n if (!isOptionalSymbol(prop)) {\n required.push(prop.name);\n }\n }\n\n ctx.visited.delete(type);\n\n const result: SchemaObject = { type: 'object' };\n if (Object.keys(properties).length > 0) {\n result.properties = properties;\n }\n if (required.length > 0) {\n result.required = required;\n }\n if (stringIndexType) {\n result.additionalProperties = typeToJsonSchema(\n stringIndexType,\n ctx,\n depth + 1,\n );\n } else if (Object.keys(properties).length > 0) {\n result.additionalProperties = false;\n }\n\n // autoRegName covers named types (early-registered). For anonymous\n // recursive types, a recursive call may have registered this type during\n // property conversion — check typeToRef as a fallback.\n const registeredName = autoRegName ?? ctx.typeToRef.get(type);\n if (registeredName) {\n ctx.schemas[registeredName] = result;\n return schemaRef(registeredName);\n }\n\n return result;\n}\n\nfunction convertObjectType(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n const wellKnown = convertWellKnownType(type, ctx, depth);\n if (wellKnown) {\n return wellKnown;\n }\n\n if (ctx.checker.isArrayType(type)) {\n return convertArrayType(type, ctx, depth);\n }\n if (ctx.checker.isTupleType(type)) {\n return convertTupleType(type, ctx, depth);\n }\n\n return convertPlainObject(type, ctx, depth);\n}\n\n// ---------------------------------------------------------------------------\n// Core dispatcher\n// ---------------------------------------------------------------------------\n\n/** Core type-to-schema conversion (no ref handling). */\nfunction convertTypeToSchema(\n type: ts.Type,\n ctx: SchemaCtx,\n depth: number,\n): SchemaObject {\n if (ctx.visited.has(type)) {\n return handleCyclicRef(type, ctx);\n }\n\n const flags = type.getFlags();\n\n const primitive = convertPrimitiveOrLiteral(type, flags, ctx.checker);\n if (primitive) {\n return primitive;\n }\n\n if (type.isUnion()) {\n ctx.visited.add(type);\n const result = convertUnionType(type, ctx, depth);\n ctx.visited.delete(type);\n return result;\n }\n if (type.isIntersection()) {\n ctx.visited.add(type);\n const result = convertIntersectionType(type, ctx, depth);\n ctx.visited.delete(type);\n return result;\n }\n if (isObjectType(type)) {\n return convertObjectType(type, ctx, depth);\n }\n\n return {};\n}\n\n// ---------------------------------------------------------------------------\n// Router / procedure type walker\n// ---------------------------------------------------------------------------\n\n/** State shared across the router-walk recursion. */\ninterface WalkCtx {\n procedures: ProcedureInfo[];\n seen: Set<ts.Type>;\n schemaCtx: SchemaCtx;\n /** Runtime descriptions keyed by procedure path (when a router instance is available). */\n runtimeDescriptions: Map<string, RuntimeDescriptions>;\n}\n\n/**\n * Inspect `_def.type` and return the procedure type string, or null if this is\n * not a procedure (e.g. a nested router).\n */\nfunction getProcedureTypeName(\n defType: ts.Type,\n checker: ts.TypeChecker,\n): ProcedureInfo['type'] | null {\n const typeSym = defType.getProperty('type');\n if (!typeSym) {\n return null;\n }\n const typeType = checker.getTypeOfSymbol(typeSym);\n const raw = checker.typeToString(typeType).replace(/['\"]/g, '');\n if (raw === 'query' || raw === 'mutation' || raw === 'subscription') {\n return raw;\n }\n return null;\n}\n\nfunction isVoidLikeInput(inputType: ts.Type | null): boolean {\n if (!inputType) {\n return true;\n }\n\n const isVoidOrUndefinedOrNever = hasFlag(\n inputType,\n ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never,\n );\n if (isVoidOrUndefinedOrNever) {\n return true;\n }\n\n const isUnionOfVoids =\n inputType.isUnion() &&\n inputType.types.every((t) =>\n hasFlag(t, ts.TypeFlags.Void | ts.TypeFlags.Undefined),\n );\n return isUnionOfVoids;\n}\n\ninterface ProcedureDef {\n defType: ts.Type;\n typeName: string;\n path: string;\n description?: string;\n symbol: ts.Symbol;\n}\n\nfunction shouldIncludeProcedureInOpenAPI(type: ProcedureInfo['type']): boolean {\n return type !== 'subscription';\n}\n\nfunction getProcedureInputTypeName(type: ts.Type, path: string): string {\n const directName = getTypeName(type);\n if (directName) {\n return directName;\n }\n\n for (const sym of [type.aliasSymbol, type.getSymbol()].filter(\n (candidate): candidate is ts.Symbol => !!candidate,\n )) {\n for (const declaration of sym.declarations ?? []) {\n const declarationName = ts.getNameOfDeclaration(declaration)?.getText();\n if (\n declarationName &&\n !ANONYMOUS_NAMES.has(declarationName) &&\n !declarationName.startsWith('__')\n ) {\n return declarationName;\n }\n }\n }\n\n const fallbackName = path\n .split('.')\n .filter(Boolean)\n .map((segment) =>\n segment\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(''),\n )\n .join('');\n\n return `${fallbackName || 'Procedure'}Input`;\n}\n\nfunction isUnknownLikeType(type: ts.Type): boolean {\n return hasFlag(type, ts.TypeFlags.Unknown | ts.TypeFlags.Any);\n}\n\nfunction isCollapsedProcedureInputType(type: ts.Type): boolean {\n return (\n isUnknownLikeType(type) ||\n (isObjectType(type) &&\n type.getProperties().length === 0 &&\n !type.getStringIndexType())\n );\n}\n\nfunction recoverProcedureInputType(\n def: ProcedureDef,\n checker: ts.TypeChecker,\n): ts.Type | null {\n let initializer: ts.Expression | null = null;\n for (const declaration of def.symbol.declarations ?? []) {\n if (ts.isPropertyAssignment(declaration)) {\n initializer = declaration.initializer;\n break;\n }\n if (ts.isVariableDeclaration(declaration) && declaration.initializer) {\n initializer = declaration.initializer;\n break;\n }\n }\n if (!initializer) {\n return null;\n }\n\n let recovered: ts.Type | null = null;\n // Walk the builder chain and keep the last `.input(...)` parser output type.\n const visit = (expr: ts.Expression): void => {\n if (!ts.isCallExpression(expr)) {\n return;\n }\n\n const callee = expr.expression;\n if (!ts.isPropertyAccessExpression(callee)) {\n return;\n }\n\n visit(callee.expression);\n if (callee.name.text !== 'input') {\n return;\n }\n\n const [parserExpr] = expr.arguments;\n if (!parserExpr) {\n return;\n }\n\n const parserType = checker.getTypeAtLocation(parserExpr);\n const standardSym = parserType.getProperty('~standard');\n if (!standardSym) {\n return;\n }\n\n const standardType = checker.getTypeOfSymbolAtLocation(\n standardSym,\n parserExpr,\n );\n const typesSym = standardType.getProperty('types');\n if (!typesSym) {\n return;\n }\n\n const typesType = checker.getNonNullableType(\n checker.getTypeOfSymbolAtLocation(typesSym, parserExpr),\n );\n const outputSym = typesType.getProperty('output');\n if (!outputSym) {\n return;\n }\n\n const outputType = checker.getTypeOfSymbolAtLocation(outputSym, parserExpr);\n if (!isUnknownLikeType(outputType)) {\n recovered = outputType;\n }\n };\n visit(initializer);\n\n return recovered;\n}\n\nfunction extractProcedure(def: ProcedureDef, ctx: WalkCtx): void {\n const { schemaCtx } = ctx;\n const { checker } = schemaCtx;\n\n const $typesSym = def.defType.getProperty('$types');\n if (!$typesSym) {\n return;\n }\n const $typesType = checker.getTypeOfSymbol($typesSym);\n\n const inputSym = $typesType.getProperty('input');\n const outputSym = $typesType.getProperty('output');\n\n const inputType = inputSym ? checker.getTypeOfSymbol(inputSym) : null;\n const outputType = outputSym ? checker.getTypeOfSymbol(outputSym) : null;\n const resolvedInputType =\n inputType && isCollapsedProcedureInputType(inputType)\n ? (recoverProcedureInputType(def, checker) ?? inputType)\n : inputType;\n\n let inputSchema: SchemaObject | null = null;\n if (!resolvedInputType || isVoidLikeInput(resolvedInputType)) {\n // null is fine\n } else {\n // Pre-register recovered parser output types so recursive edges resolve to a\n // stable component ref instead of collapsing into `{}`.\n const ensureRecoveredInputRegistration = (type: ts.Type): void => {\n if (schemaCtx.typeToRef.has(type)) {\n return;\n }\n\n const refName = ensureUniqueName(\n getProcedureInputTypeName(type, def.path),\n schemaCtx.schemas,\n );\n schemaCtx.typeToRef.set(type, refName);\n schemaCtx.schemas[refName] = {};\n };\n\n if (resolvedInputType !== inputType) {\n ensureRecoveredInputRegistration(resolvedInputType);\n }\n\n const initialSchema = typeToJsonSchema(resolvedInputType, schemaCtx);\n if (\n !isNonEmptySchema(initialSchema) &&\n !schemaCtx.typeToRef.has(resolvedInputType)\n ) {\n ensureRecoveredInputRegistration(resolvedInputType);\n inputSchema = typeToJsonSchema(resolvedInputType, schemaCtx);\n } else {\n inputSchema = initialSchema;\n }\n }\n\n const outputSchema: SchemaObject | null = outputType\n ? typeToJsonSchema(outputType, schemaCtx)\n : null;\n\n // Overlay extracted schema descriptions onto the type-checker-generated schemas.\n const runtimeDescs = ctx.runtimeDescriptions.get(def.path);\n if (runtimeDescs) {\n const resolvedInputSchema = getReferencedSchema(\n inputSchema,\n schemaCtx.schemas,\n );\n const resolvedOutputSchema = getReferencedSchema(\n outputSchema,\n schemaCtx.schemas,\n );\n\n if (resolvedInputSchema && runtimeDescs.input) {\n applyDescriptions(\n resolvedInputSchema,\n runtimeDescs.input,\n schemaCtx.schemas,\n );\n }\n if (resolvedOutputSchema && runtimeDescs.output) {\n applyDescriptions(\n resolvedOutputSchema,\n runtimeDescs.output,\n schemaCtx.schemas,\n );\n }\n }\n\n ctx.procedures.push({\n path: def.path,\n type: def.typeName as 'query' | 'mutation' | 'subscription',\n inputSchema,\n outputSchema,\n description: def.description,\n });\n}\n\n/** Extract the JSDoc comment text from a symbol, if any. */\nfunction getJsDocComment(\n sym: ts.Symbol,\n checker: ts.TypeChecker,\n): string | undefined {\n const normalize = (filePath: string): string => filePath.replace(/\\\\/g, '/');\n\n const declarations = sym.declarations ?? [];\n const isExternalNodeModulesDeclaration =\n declarations.length > 0 &&\n declarations.every((declaration) => {\n const sourceFile = declaration.getSourceFile();\n if (!sourceFile.isDeclarationFile) {\n return false;\n }\n\n const declarationPath = normalize(sourceFile.fileName);\n if (!declarationPath.includes('/node_modules/')) {\n return false;\n }\n\n try {\n const realPath = normalize(fs.realpathSync.native(sourceFile.fileName));\n // Keep JSDoc for workspace packages linked into node_modules\n // (e.g. monorepos using pnpm/yarn workspaces). The resolved target\n // may sit outside the current cwd, so avoid cwd-based checks here.\n if (!realPath.includes('/node_modules/')) {\n return false;\n }\n } catch {\n // Fall back to treating the declaration as external.\n }\n\n return true;\n });\n if (isExternalNodeModulesDeclaration) {\n return undefined;\n }\n\n const parts = sym.getDocumentationComment(checker);\n if (parts.length === 0) {\n return undefined;\n }\n const text = parts.map((p) => p.text).join('');\n return text || undefined;\n}\n\ninterface WalkTypeOpts {\n type: ts.Type;\n ctx: WalkCtx;\n currentPath: string;\n description?: string;\n symbol?: ts.Symbol;\n}\n\nfunction walkType(opts: WalkTypeOpts): void {\n const { type, ctx, currentPath, description, symbol } = opts;\n if (ctx.seen.has(type)) {\n return;\n }\n\n const defSym = type.getProperty('_def');\n\n if (!defSym) {\n // No `_def` — this is a plain RouterRecord or an unrecognised type.\n // Walk its own properties so nested procedures are found.\n if (isObjectType(type)) {\n ctx.seen.add(type);\n walkRecord(type, ctx, currentPath);\n ctx.seen.delete(type);\n }\n return;\n }\n\n const { checker } = ctx.schemaCtx;\n const defType = checker.getTypeOfSymbol(defSym);\n\n const procedureTypeName = getProcedureTypeName(defType, checker);\n if (procedureTypeName) {\n if (!shouldIncludeProcedureInOpenAPI(procedureTypeName)) {\n return;\n }\n\n extractProcedure(\n {\n defType,\n typeName: procedureTypeName,\n path: currentPath,\n description,\n symbol: symbol ?? type.getSymbol() ?? defSym,\n },\n ctx,\n );\n return;\n }\n\n // Router? (_def.router === true)\n const routerSym = defType.getProperty('router');\n if (!routerSym) {\n return;\n }\n\n const isRouter =\n checker.typeToString(checker.getTypeOfSymbol(routerSym)) === 'true';\n if (!isRouter) {\n return;\n }\n\n const recordSym = defType.getProperty('record');\n if (!recordSym) {\n return;\n }\n\n ctx.seen.add(type);\n const recordType = checker.getTypeOfSymbol(recordSym);\n walkRecord(recordType, ctx, currentPath);\n ctx.seen.delete(type);\n}\n\nfunction walkRecord(recordType: ts.Type, ctx: WalkCtx, prefix: string): void {\n for (const prop of recordType.getProperties()) {\n const propType = ctx.schemaCtx.checker.getTypeOfSymbol(prop);\n const fullPath = prefix ? `${prefix}.${prop.name}` : prop.name;\n const description = getJsDocComment(prop, ctx.schemaCtx.checker);\n walkType({\n type: propType,\n ctx,\n currentPath: fullPath,\n description,\n symbol: prop,\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// TypeScript program helpers\n// ---------------------------------------------------------------------------\n\nfunction loadCompilerOptions(startDir: string): ts.CompilerOptions {\n const configPath = ts.findConfigFile(\n startDir,\n (f) => ts.sys.fileExists(f),\n 'tsconfig.json',\n );\n if (!configPath) {\n return {\n target: ts.ScriptTarget.ES2020,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n skipLibCheck: true,\n noEmit: true,\n };\n }\n\n const configFile = ts.readConfigFile(configPath, (f) => ts.sys.readFile(f));\n const parsed = ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n path.dirname(configPath),\n );\n const options: ts.CompilerOptions = { ...parsed.options, noEmit: true };\n\n // `parseJsonConfigFileContent` only returns explicitly-set values. TypeScript\n // itself infers moduleResolution from `module` at compile time, but we have to\n // do it manually here for the compiler host to resolve imports correctly.\n if (options.moduleResolution === undefined) {\n const mod = options.module;\n if (mod === ts.ModuleKind.Node16 || mod === ts.ModuleKind.NodeNext) {\n options.moduleResolution = ts.ModuleResolutionKind.NodeNext;\n } else if (\n mod === ts.ModuleKind.Preserve ||\n mod === ts.ModuleKind.ES2022 ||\n mod === ts.ModuleKind.ESNext\n ) {\n options.moduleResolution = ts.ModuleResolutionKind.Bundler;\n } else {\n options.moduleResolution = ts.ModuleResolutionKind.Node10;\n }\n }\n\n return options;\n}\n\n// ---------------------------------------------------------------------------\n// Error shape extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Walk `_def._config.$types.errorShape` on the router type and convert\n * it to a JSON Schema. Returns `null` when the path cannot be resolved\n * (e.g. older tRPC versions or missing type info).\n */\nfunction extractErrorSchema(\n routerType: ts.Type,\n checker: ts.TypeChecker,\n schemaCtx: SchemaCtx,\n): SchemaObject | null {\n const walk = (type: ts.Type, keys: string[]): ts.Type | null => {\n const [head, ...rest] = keys;\n if (!head) {\n return type;\n }\n const sym = type.getProperty(head);\n if (!sym) {\n return null;\n }\n return walk(checker.getTypeOfSymbol(sym), rest);\n };\n\n const errorShapeType = walk(routerType, [\n '_def',\n '_config',\n '$types',\n 'errorShape',\n ]);\n if (!errorShapeType) {\n return null;\n }\n\n if (hasFlag(errorShapeType, ts.TypeFlags.Any)) {\n return null;\n }\n\n return typeToJsonSchema(errorShapeType, schemaCtx);\n}\n\n// ---------------------------------------------------------------------------\n// OpenAPI document builder\n// ---------------------------------------------------------------------------\n\n/** Fallback error schema when the router type doesn't expose an error shape. */\nconst DEFAULT_ERROR_SCHEMA: SchemaObject = {\n type: 'object',\n properties: {\n message: { type: 'string' },\n code: { type: 'string' },\n data: { type: 'object' },\n },\n required: ['message', 'code'],\n};\n\n/**\n * Wrap a procedure's output schema in the tRPC success envelope.\n *\n * tRPC HTTP responses are always serialised as:\n * `{ result: { data: T } }`\n *\n * When the procedure has no output the envelope is still present but\n * the `data` property is omitted.\n */\nfunction wrapInSuccessEnvelope(\n outputSchema: SchemaObject | null,\n): SchemaObject {\n const hasOutput = outputSchema !== null && isNonEmptySchema(outputSchema);\n const resultSchema: SchemaObject = {\n type: 'object',\n properties: {\n ...(hasOutput ? { data: outputSchema } : {}),\n },\n ...(hasOutput ? { required: ['data'] } : {}),\n };\n return {\n type: 'object',\n properties: {\n result: resultSchema,\n },\n required: ['result'],\n };\n}\n\nfunction buildProcedureOperation(\n proc: ProcedureInfo,\n method: 'get' | 'post',\n): OperationObject {\n const [tag = proc.path] = proc.path.split('.');\n const operation: OperationObject = {\n operationId: proc.path,\n ...(proc.description ? { description: proc.description } : {}),\n tags: [tag],\n responses: {\n '200': {\n description: 'Successful response',\n content: {\n 'application/json': {\n schema: wrapInSuccessEnvelope(proc.outputSchema),\n },\n },\n },\n default: { $ref: '#/components/responses/Error' },\n },\n };\n\n if (proc.inputSchema === null) {\n return operation;\n }\n\n if (method === 'get') {\n operation.parameters = [\n {\n name: 'input',\n in: 'query',\n required: true,\n // FIXME: OAS 3.1.1 says a parameter MUST use either schema+style OR content, not both.\n // style should be removed here, but hey-api requires it to generate a correct query serializer.\n style: 'deepObject',\n content: { 'application/json': { schema: proc.inputSchema } },\n },\n ];\n } else {\n operation.requestBody = {\n required: true,\n content: { 'application/json': { schema: proc.inputSchema } },\n };\n }\n\n return operation;\n}\n\nfunction buildOpenAPIDocument(\n procedures: ProcedureInfo[],\n options: GenerateOptions,\n meta: RouterMeta = { errorSchema: null },\n): Document {\n const paths: PathsObject = {};\n\n for (const proc of procedures) {\n if (!shouldIncludeProcedureInOpenAPI(proc.type)) {\n continue;\n }\n\n const opPath = `/${proc.path}`;\n const method = proc.type === 'query' ? 'get' : 'post';\n\n const pathItem: PathItemObject = paths[opPath] ?? {};\n paths[opPath] = pathItem;\n pathItem[method] = buildProcedureOperation(\n proc,\n method,\n ) as PathItemObject[typeof method];\n }\n\n const hasNamedSchemas =\n meta.schemas !== undefined && Object.keys(meta.schemas).length > 0;\n\n return {\n openapi: '3.1.1',\n jsonSchemaDialect: 'https://spec.openapis.org/oas/3.1/dialect/base',\n info: {\n title: options.title ?? 'tRPC API',\n version: options.version ?? '0.0.0',\n },\n ...(options.servers?.length ? { servers: options.servers } : {}),\n paths,\n components: {\n ...(hasNamedSchemas && meta.schemas ? { schemas: meta.schemas } : {}),\n responses: {\n Error: {\n description: 'Error response',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n error: meta.errorSchema ?? DEFAULT_ERROR_SCHEMA,\n },\n required: ['error'],\n },\n },\n },\n },\n },\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Analyse the given TypeScript router file using the TypeScript compiler and\n * return an OpenAPI 3.1 document describing all query and mutation procedures.\n *\n * @param routerFilePath - Absolute or relative path to the file that exports\n * the AppRouter.\n * @param options - Optional generation settings (export name, title, version).\n */\nexport async function generateOpenAPIDocument(\n routerFilePath: string,\n options: GenerateOptions = {},\n): Promise<Document> {\n const resolvedPath = path.resolve(routerFilePath);\n const exportName = options.exportName ?? 'AppRouter';\n\n const compilerOptions = loadCompilerOptions(path.dirname(resolvedPath));\n const program = ts.createProgram([resolvedPath], compilerOptions);\n const checker = program.getTypeChecker();\n const sourceFile = program.getSourceFile(resolvedPath);\n\n if (!sourceFile) {\n throw new Error(`Could not load TypeScript file: ${resolvedPath}`);\n }\n\n const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n if (!moduleSymbol) {\n throw new Error(`No module exports found in: ${resolvedPath}`);\n }\n\n const tsExports = checker.getExportsOfModule(moduleSymbol);\n const routerSymbol = tsExports.find((sym) => sym.getName() === exportName);\n\n if (!routerSymbol) {\n const available = tsExports.map((e) => e.getName()).join(', ');\n throw new Error(\n `No export named '${exportName}' found in: ${resolvedPath}\\n` +\n `Available exports: ${available || '(none)'}`,\n );\n }\n\n // Prefer the value declaration for value exports; fall back to the declared\n // type for `export type AppRouter = …` aliases.\n let routerType: ts.Type;\n if (routerSymbol.valueDeclaration) {\n routerType = checker.getTypeOfSymbolAtLocation(\n routerSymbol,\n routerSymbol.valueDeclaration,\n );\n } else {\n routerType = checker.getDeclaredTypeOfSymbol(routerSymbol);\n }\n\n const schemaCtx: SchemaCtx = {\n checker,\n visited: new Set(),\n schemas: {},\n typeToRef: new Map(),\n };\n\n // Try to dynamically import the router to extract schema descriptions\n const runtimeDescriptions = new Map<string, RuntimeDescriptions>();\n const router = await tryImportRouter(resolvedPath, exportName);\n if (router) {\n collectRuntimeDescriptions(router, '', runtimeDescriptions);\n }\n\n const walkCtx: WalkCtx = {\n procedures: [],\n seen: new Set(),\n schemaCtx,\n runtimeDescriptions,\n };\n walkType({ type: routerType, ctx: walkCtx, currentPath: '' });\n\n const errorSchema = extractErrorSchema(routerType, checker, schemaCtx);\n return buildOpenAPIDocument(walkCtx.procedures, options, {\n errorSchema,\n schemas: schemaCtx.schemas,\n });\n}\n","import type { OpenAPIV3_1 as BaseOpenAPIV3_1 } from 'openapi-types';\n\nexport type Replace<TTarget, TReplaceWith> = Omit<TTarget, keyof TReplaceWith> &\n TReplaceWith;\n\nexport type SchemaType =\n | 'array'\n | 'boolean'\n | 'integer'\n | 'null'\n | 'number'\n | 'object'\n | 'string';\n\nexport type PrimitiveSchemaType = SchemaType;\n\nexport type HttpMethods = BaseOpenAPIV3_1.HttpMethods;\nexport type ReferenceObject = BaseOpenAPIV3_1.ReferenceObject;\nexport type ExampleObject = BaseOpenAPIV3_1.ExampleObject;\nexport type DiscriminatorObject = BaseOpenAPIV3_1.DiscriminatorObject;\nexport type ExternalDocumentationObject =\n BaseOpenAPIV3_1.ExternalDocumentationObject;\nexport type XMLObject = BaseOpenAPIV3_1.XMLObject;\nexport type LinkObject = BaseOpenAPIV3_1.LinkObject;\nexport type SecuritySchemeObject = BaseOpenAPIV3_1.SecuritySchemeObject;\nexport type ServerObject = BaseOpenAPIV3_1.ServerObject;\n\nexport type SchemaObject = Replace<\n BaseOpenAPIV3_1.BaseSchemaObject,\n {\n $ref?: string;\n $defs?: Record<string, SchemaObject>;\n $schema?: string;\n type?: string | string[];\n properties?: Record<string, SchemaObject>;\n required?: string[];\n items?: SchemaObject | false;\n prefixItems?: SchemaObject[];\n const?: string | number | boolean | null;\n enum?: (string | number | boolean | null)[];\n oneOf?: SchemaObject[];\n anyOf?: SchemaObject[];\n allOf?: SchemaObject[];\n not?: SchemaObject;\n additionalProperties?: boolean | SchemaObject;\n discriminator?: DiscriminatorObject;\n externalDocs?: ExternalDocumentationObject;\n xml?: XMLObject;\n contentMediaType?: string;\n exclusiveMinimum?: boolean | number;\n exclusiveMaximum?: boolean | number;\n }\n>;\n\nexport type SchemaLike = SchemaObject;\n\nexport interface ArraySchemaObject extends SchemaObject {\n type: 'array';\n items: SchemaObject | false;\n}\n\nexport type MediaTypeObject = Replace<\n BaseOpenAPIV3_1.MediaTypeObject,\n {\n schema?: SchemaObject | ReferenceObject;\n examples?: Record<string, ReferenceObject | ExampleObject>;\n }\n>;\n\nexport interface ParameterBaseObject\n extends Replace<\n BaseOpenAPIV3_1.ParameterBaseObject,\n {\n schema?: SchemaObject | ReferenceObject;\n examples?: Record<string, ReferenceObject | ExampleObject>;\n content?: Record<string, MediaTypeObject>;\n }\n > {}\n\nexport interface ParameterObject extends ParameterBaseObject {\n name: string;\n in: string;\n}\n\nexport type HeaderObject = ParameterBaseObject;\n\nexport type RequestBodyObject = Replace<\n BaseOpenAPIV3_1.RequestBodyObject,\n {\n content: Record<string, MediaTypeObject>;\n }\n>;\n\nexport type ResponseObject = Replace<\n BaseOpenAPIV3_1.ResponseObject,\n {\n headers?: Record<string, ReferenceObject | HeaderObject>;\n content?: Record<string, MediaTypeObject>;\n links?: Record<string, ReferenceObject | LinkObject>;\n }\n>;\n\nexport type ResponsesObject = Record<string, ReferenceObject | ResponseObject>;\n\nexport type OperationObject<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.OperationObject<T>,\n {\n parameters?: (ReferenceObject | ParameterObject)[];\n requestBody?: ReferenceObject | RequestBodyObject;\n responses?: ResponsesObject;\n callbacks?: Record<string, ReferenceObject | CallbackObject>;\n }\n> &\n T;\n\nexport type PathItemObject<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.PathItemObject<T>,\n {\n parameters?: (ReferenceObject | ParameterObject)[];\n }\n> & {\n [method in HttpMethods]?: OperationObject<T>;\n};\n\nexport type PathsObject<T extends {} = {}, TPath extends {} = {}> = Record<\n string,\n (PathItemObject<T> & TPath) | undefined\n>;\n\nexport type CallbackObject = Record<string, PathItemObject | ReferenceObject>;\n\nexport type ComponentsObject = Replace<\n BaseOpenAPIV3_1.ComponentsObject,\n {\n schemas?: Record<string, SchemaObject>;\n responses?: Record<string, ReferenceObject | ResponseObject>;\n parameters?: Record<string, ReferenceObject | ParameterObject>;\n requestBodies?: Record<string, ReferenceObject | RequestBodyObject>;\n headers?: Record<string, ReferenceObject | HeaderObject>;\n links?: Record<string, ReferenceObject | LinkObject>;\n callbacks?: Record<string, ReferenceObject | CallbackObject>;\n pathItems?: Record<string, ReferenceObject | PathItemObject>;\n }\n>;\n\nexport type Document<T extends {} = {}> = Replace<\n BaseOpenAPIV3_1.Document<T>,\n {\n paths?: PathsObject<T>;\n components?: ComponentsObject;\n }\n>;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@trpc/openapi",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "11.17.1-canary.2+f8f0c0e39",
5
+ "version": "11.18.0-alpha",
6
6
  "description": "OpenAPI document generator for tRPC routers",
7
7
  "author": "KATT",
8
8
  "license": "MIT",
@@ -80,7 +80,7 @@
80
80
  "@hey-api/openapi-ts": "^0.94.5",
81
81
  "@swagger-api/apidom-ls": "^1.6.0",
82
82
  "@tanstack/intent": "^0.0.27",
83
- "@trpc/server": "11.17.1",
83
+ "@trpc/server": "11.18.0",
84
84
  "@types/node": "^22.13.5",
85
85
  "bson": "^7.2.0",
86
86
  "eslint": "^9.26.0",
@@ -94,7 +94,7 @@
94
94
  },
95
95
  "peerDependencies": {
96
96
  "@hey-api/openapi-ts": ">=0.94.5",
97
- "@trpc/server": "11.17.1",
97
+ "@trpc/server": "11.18.0",
98
98
  "typescript": ">=5.7.2",
99
99
  "zod": ">=4.0.0"
100
100
  },
@@ -112,5 +112,5 @@
112
112
  "keywords": [
113
113
  "tanstack-intent"
114
114
  ],
115
- "gitHead": "f8f0c0e3979ecb980d38e9369fa8c98df95d212b"
115
+ "gitHead": "6aec1578a899df50a17e4e78d5512a099b574c18"
116
116
  }
package/src/cli.ts CHANGED
@@ -12,6 +12,7 @@
12
12
  * --output, -o Output file path (default: openapi.json)
13
13
  * --title OpenAPI info.title (default: tRPC API)
14
14
  * --version OpenAPI info.version (default: 0.0.0)
15
+ * --server-url OpenAPI servers[].url (include any tRPC prefix)
15
16
  * --help, -h Show this help message
16
17
  */
17
18
  import * as fs from 'node:fs';
@@ -29,6 +30,7 @@ interface ParsedArgs {
29
30
  output: string;
30
31
  title: string;
31
32
  version: string;
33
+ serverUrl: string | undefined;
32
34
  help: boolean;
33
35
  }
34
36
 
@@ -43,6 +45,7 @@ function parseArgs(argv: string[]): ParsedArgs {
43
45
  output: { type: 'string', short: 'o', default: 'openapi.json' },
44
46
  title: { type: 'string', default: 'tRPC API' },
45
47
  version: { type: 'string', default: '0.0.0' },
48
+ 'server-url': { type: 'string' },
46
49
  },
47
50
  strict: true,
48
51
  allowPositionals: true,
@@ -59,6 +62,7 @@ function parseArgs(argv: string[]): ParsedArgs {
59
62
  output: parsed.values.output,
60
63
  title: parsed.values.title,
61
64
  version: parsed.values.version,
65
+ serverUrl: parsed.values['server-url'],
62
66
  help: parsed.values.help,
63
67
  };
64
68
  }
@@ -81,11 +85,13 @@ Options:
81
85
  -o, --output <file> Output file path [default: openapi.json]
82
86
  --title <text> OpenAPI info.title [default: tRPC API]
83
87
  --version <ver> OpenAPI info.version [default: 0.0.0]
88
+ --server-url <url> OpenAPI servers[].url (include any tRPC mount prefix)
84
89
  -h, --help Show this help message
85
90
 
86
91
  Examples:
87
92
  trpc-openapi ./src/server/router.ts
88
93
  trpc-openapi ./src/server/router.ts --output api.json --title "My API" --version 1.0.0
94
+ trpc-openapi ./src/server/router.ts --server-url https://api.example.com/trpc
89
95
  trpc-openapi ./src/server/router.ts --export appRouter
90
96
  `.trim();
91
97
 
@@ -118,6 +124,7 @@ async function main(): Promise<void> {
118
124
  exportName: args.exportName,
119
125
  title: args.title,
120
126
  version: args.version,
127
+ servers: args.serverUrl ? [{ url: args.serverUrl }] : undefined,
121
128
  });
122
129
  } catch (err: unknown) {
123
130
  const message = err instanceof Error ? err.message : String(err);
package/src/generate.ts CHANGED
@@ -13,6 +13,7 @@ import type {
13
13
  PathItemObject,
14
14
  PathsObject,
15
15
  SchemaObject,
16
+ ServerObject,
16
17
  } from './types';
17
18
 
18
19
  interface ProcedureInfo {
@@ -39,6 +40,13 @@ export interface GenerateOptions {
39
40
  title?: string;
40
41
  /** Version string for the generated OpenAPI `info` object. */
41
42
  version?: string;
43
+ /**
44
+ * OpenAPI `servers` array, passed through to the generated document. Each
45
+ * `url` should include any tRPC mount prefix, since the generated paths
46
+ * (`/user.create`, …) are relative to it — e.g.
47
+ * `https://api.example.com/trpc`. When omitted, no `servers` entry is added.
48
+ */
49
+ servers?: ServerObject[];
42
50
  }
43
51
 
44
52
  // ---------------------------------------------------------------------------
@@ -1429,6 +1437,7 @@ function buildOpenAPIDocument(
1429
1437
  title: options.title ?? 'tRPC API',
1430
1438
  version: options.version ?? '0.0.0',
1431
1439
  },
1440
+ ...(options.servers?.length ? { servers: options.servers } : {}),
1432
1441
  paths,
1433
1442
  components: {
1434
1443
  ...(hasNamedSchemas && meta.schemas ? { schemas: meta.schemas } : {}),
package/src/types.ts CHANGED
@@ -23,6 +23,7 @@ export type ExternalDocumentationObject =
23
23
  export type XMLObject = BaseOpenAPIV3_1.XMLObject;
24
24
  export type LinkObject = BaseOpenAPIV3_1.LinkObject;
25
25
  export type SecuritySchemeObject = BaseOpenAPIV3_1.SecuritySchemeObject;
26
+ export type ServerObject = BaseOpenAPIV3_1.ServerObject;
26
27
 
27
28
  export type SchemaObject = Replace<
28
29
  BaseOpenAPIV3_1.BaseSchemaObject,