@trpc/openapi 11.22.2-canary.7.c01346ec8 → 11.23.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 +0 -8
- package/dist/heyapi/index.d.cts.map +1 -1
- package/dist/heyapi/index.d.mts.map +1 -1
- package/dist/heyapi/index.mjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -20
- package/skills/openapi/SKILL.md +229 -164
- package/src/cli.ts +1 -1
- package/src/heyapi/index.ts +2 -1
- package/src/types.ts +7 -1
- package/bin/intent.js +0 -20
package/README.md
CHANGED
|
@@ -39,14 +39,6 @@ The generator statically analyses your router's TypeScript types — it never ex
|
|
|
39
39
|
|
|
40
40
|
Full documentation is available at [trpc.io/docs/openapi](https://trpc.io/docs/openapi).
|
|
41
41
|
|
|
42
|
-
## AI Agents
|
|
43
|
-
|
|
44
|
-
If you use an AI coding agent, install tRPC skills for better code generation:
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
npx @tanstack/intent@latest install
|
|
48
|
-
```
|
|
49
|
-
|
|
50
42
|
## TODO
|
|
51
43
|
|
|
52
44
|
- [ ] SSE subscriptions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/heyapi/index.ts"],"mappings":";;;YAMY,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/heyapi/index.ts"],"mappings":";;;YAMY,yBACR,sBACA;iBACa;EACf,cAAc;;YAGJ,kBAAkB,QAAQ,iBAAiB;YAE3C,eAAe,WACzB,QAAQ,kBAAkB;YAGhB,yBAAyB,SACnC,KAAK,oCAEL,KAAK;;;;;;;;;;;;;;;;;;;wBA6BS,iCAAiC;;;;wBAoBjC,6BAA6B,OAAO;WA4BvB,mBAAA;WAIW,wBAAA,kBAAO;WA1BlB,kBAAA,OAAA;;;;;wBA2Cb,2BACd,iBAAiB,0BAGT;;;;;;;;;;;;;;;;;;;;wBA6BM,0BACd,QAAQ,QAAQ,kBAAkB,QAClC,MAAM,0BACJ,KAAK,oBAAoB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/heyapi/index.ts"],"mappings":";;;YAMY,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/heyapi/index.ts"],"mappings":";;;YAMY,yBACR,sBACA;iBACa;EACf,cAAc;;YAGJ,kBAAkB,QAAQ,iBAAiB;YAE3C,eAAe,WACzB,QAAQ,kBAAkB;YAGhB,yBAAyB,SACnC,KAAK,oCAEL,KAAK;;;;;;;;;;;;;;;;;;;wBA6BS,iCAAiC;;;;wBAoBjC,6BAA6B,OAAO;WA4BvB,mBAAA;WAIW,wBAAA,kBAAO;WA1BlB,kBAAA,OAAA;;;;;wBA2Cb,2BACd,iBAAiB,0BAGT;;;;;;;;;;;;;;;;;;;;wBA6BM,0BACd,QAAQ,QAAQ,kBAAkB,QAClC,MAAM,0BACJ,KAAK,oBAAoB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/heyapi/index.ts"],"sourcesContent":["import type { Plugins } from '@hey-api/openapi-ts';\nimport type {\n TRPCCombinedDataTransformer,\n TRPCDataTransformer,\n} from '@trpc/server';\n\nexport type DataTransformerOptions =\n TRPCDataTransformer
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/heyapi/index.ts"],"sourcesContent":["import type { Plugins } from '@hey-api/openapi-ts';\nimport type {\n TRPCCombinedDataTransformer,\n TRPCDataTransformer,\n} from '@trpc/server';\n\nexport type DataTransformerOptions =\n | TRPCDataTransformer\n | TRPCCombinedDataTransformer;\nexport interface TRPCHeyApiClientOptions {\n transformer?: DataTransformerOptions;\n}\n\nexport type HeyAPIResolvers = Plugins.HeyApiTypeScript.Resolvers;\n\nexport type HeyApiConfig = ReturnType<\n Plugins.HeyApiClientFetch.Client['getConfig']\n>;\n\nexport type TRPCHeyApiClientConfig = Required<\n Pick<HeyApiConfig, 'querySerializer'>\n> &\n Pick<HeyApiConfig, 'bodySerializer' | 'responseTransformer'>;\n\nfunction resolveTransformer(\n transformer: DataTransformerOptions,\n): TRPCCombinedDataTransformer {\n if ('input' in transformer) {\n return transformer;\n }\n return { input: transformer, output: transformer };\n}\n\n/**\n * Returns the `~resolvers` object for the `@hey-api/typescript` plugin.\n *\n * Maps `date` and `date-time` string formats to `Date` so that the\n * generated SDK uses `Date` instead of `string` for those fields.\n *\n * @example\n * ```ts\n * import { createClient } from '@hey-api/openapi-ts';\n * import { createTRPCHeyApiTypeResolvers } from '@trpc/openapi/heyapi';\n *\n * await createClient({\n * plugins: [\n * { name: '@hey-api/typescript', '~resolvers': createTRPCHeyApiTypeResolvers() },\n * ],\n * });\n * ```\n */\nexport function createTRPCHeyApiTypeResolvers(): HeyAPIResolvers {\n return {\n string(ctx) {\n if (ctx.schema.format === 'date-time' || ctx.schema.format === 'date') {\n return ctx.$.type('Date');\n }\n return undefined;\n },\n number(ctx) {\n if (ctx.schema.format === 'bigint') {\n return ctx.$.type('bigint');\n }\n return undefined;\n },\n };\n}\n\n/**\n * @internal - Prefer `configureTRPCHeyApiClient`\n */\nexport function createTRPCHeyApiClientConfig(opts?: TRPCHeyApiClientOptions) {\n const transformer = opts?.transformer\n ? resolveTransformer(opts.transformer)\n : undefined;\n\n return {\n querySerializer: (query: Record<string, unknown>) => {\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) {\n continue;\n }\n\n if (key === 'input' && transformer) {\n params.append(\n key,\n JSON.stringify(transformer.input.serialize(value)),\n );\n } else {\n params.append(key, JSON.stringify(value));\n }\n }\n\n return params.toString();\n },\n\n ...(transformer && {\n bodySerializer: (body: unknown) => {\n return JSON.stringify(transformer.input.serialize(body));\n },\n\n responseTransformer: async (data: unknown) => {\n if (!!data && typeof data === 'object' && 'result' in data) {\n const result = (data as any).result;\n if (!result.type || result.type === 'data') {\n result.data = transformer.output.deserialize(result.data);\n }\n }\n\n return data;\n },\n }),\n } as const satisfies TRPCHeyApiClientConfig;\n}\n\n/**\n * @internal - Prefer `configureTRPCHeyApiClient`\n */\nexport function createTRPCErrorInterceptor(\n transformerOpts: DataTransformerOptions,\n) {\n const transformer = resolveTransformer(transformerOpts);\n return (error: unknown) => {\n if (!!error && typeof error === 'object' && 'error' in error) {\n (error as any).error = transformer.output.deserialize(\n (error as any).error,\n );\n }\n return error;\n };\n}\n\n/**\n * Configures a hey-api client for use with a tRPC OpenAPI backend.\n *\n * Sets up querySerializer, bodySerializer, responseTransformer, and\n * an error interceptor (for transformer-based error deserialization)\n * in a single call.\n *\n * @example\n * ```ts\n * import { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';\n * import superjson from 'superjson';\n * import { client } from './generated/client.gen';\n *\n * configureTRPCHeyApiClient(client, {\n * baseUrl: 'http://localhost:3000',\n * transformer: superjson,\n * });\n * ```\n */\nexport function configureTRPCHeyApiClient(\n client: Plugins.HeyApiClientFetch.Client,\n opts: TRPCHeyApiClientOptions &\n Omit<HeyApiConfig, keyof TRPCHeyApiClientConfig>,\n) {\n const { transformer, ...heyConfig } = opts;\n const trpcConfig = createTRPCHeyApiClientConfig({ transformer });\n\n client.setConfig({ ...heyConfig, ...trpcConfig });\n\n if (transformer) {\n client.interceptors.error.use(createTRPCErrorInterceptor(transformer));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA8JU,MAAA,YAAA,CAAA,aAAA;AAtIV,SAAS,mBACP,aAC6B;CAC7B,IAAI,WAAW,aACb,OAAO;CAET,OAAO;EAAE,OAAO;EAAa,QAAQ;CAAY;AACnD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,gCAAiD;CAC/D,OAAO;EACL,OAAO,KAAK;GACV,IAAI,IAAI,OAAO,WAAW,eAAe,IAAI,OAAO,WAAW,QAC7D,OAAO,IAAI,EAAE,KAAK,MAAM;EAG5B;EACA,OAAO,KAAK;GACV,IAAI,IAAI,OAAO,WAAW,UACxB,OAAO,IAAI,EAAE,KAAK,QAAQ;EAG9B;CACF;AACF;;;;AAKA,SAAgB,6BAA6B,MAAgC;CAC3E,MAAM,eAAA,SAAA,QAAA,SAAA,KAAA,IAAA,KAAA,IAAc,KAAM,eACtB,mBAAmB,KAAK,WAAW,IACnC,KAAA;CAEJ,OAAA,eAAA,EACE,kBAAkB,UAAmC;EACnD,MAAM,SAAS,IAAI,gBAAgB;EAEnC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;GAChD,IAAI,UAAU,KAAA,GACZ;GAGF,IAAI,QAAQ,WAAW,aACrB,OAAO,OACL,KACA,KAAK,UAAU,YAAY,MAAM,UAAU,KAAK,CAAC,CACnD;QAEA,OAAO,OAAO,KAAK,KAAK,UAAU,KAAK,CAAC;EAE5C;EAEA,OAAO,OAAO,SAAS;CACzB,EAAA,GAEI,eAAe;EACjB,iBAAiB,SAAkB;GACjC,OAAO,KAAK,UAAU,YAAY,MAAM,UAAU,IAAI,CAAC;EACzD;EAEA,qBAAqB,OAAO,SAAkB;GAC5C,IAAI,CAAC,CAAC,QAAQ,OAAO,SAAS,YAAY,YAAY,MAAM;IAC1D,MAAM,SAAU,KAAa;IAC7B,IAAI,CAAC,OAAO,QAAQ,OAAO,SAAS,QAClC,OAAO,OAAO,YAAY,OAAO,YAAY,OAAO,IAAI;GAE5D;GAEA,OAAO;EACT;CACF,CACF;AACF;;;;AAKA,SAAgB,2BACd,iBACA;CACA,MAAM,cAAc,mBAAmB,eAAe;CACtD,QAAQ,UAAmB;EACzB,IAAI,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,WAAW,OACrD,MAAe,QAAQ,YAAY,OAAO,YACvC,MAAc,KACjB;EAEF,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,0BACd,QACA,MAEA;CACA,MAAM,EAAE,gBAAA,MAAgB,YAAA,yBAAc,MAAA,SAAA;CACtC,MAAM,aAAa,6BAA6B,EAAE,YAAY,CAAC;CAE/D,OAAO,UAAA,eAAA,eAAA,CAAA,GAAe,SAAA,GAAc,UAAW,CAAC;CAEhD,IAAI,aACF,OAAO,aAAa,MAAM,IAAI,2BAA2B,WAAW,CAAC;AAEzE"}
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"mappings":";;;;KAEY,QAAQ,SAAS,gBAAgB,KAAK,eAAe,gBAC/D;KAEU;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"mappings":";;;;KAEY,QAAQ,SAAS,gBAAgB,KAAK,eAAe,gBAC/D;KAEU;KASA,sBAAsB;KAEtB,cAAc,YAAgB;KAC9B,kBAAkB,YAAgB;KAClC,gBAAgB,YAAgB;KAChC,sBAAsB,YAAgB;KACtC,8BACV,YAAgB;KACN,YAAY,YAAgB;KAC5B,aAAa,YAAgB;KAC7B,uBAAuB,YAAgB;KACvC,eAAe,YAAgB;KAE/B,eAAe,QACzB,YAAgB;EAEd;EACA,QAAQ,eAAe;EACvB;EACA;EACA,aAAa,eAAe;EAC5B;EACA,QAAQ;EACR,cAAc;EACd;EACA;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,MAAM;EACN,iCAAiC;EACjC,gBAAgB;EAChB,eAAe;EACf,MAAM;EACN;EACA;EACA;;KAIQ,aAAa;UAER,0BAA0B;EACzC;EACA,OAAO;;KAGG,kBAAkB,QAC5B,YAAgB;EAEd,SAAS,eAAe;EACxB,WAAW,eAAe,kBAAkB;;UAI/B,4BAA4B,QAC3C,YAAgB;EAEd,SAAS,eAAe;EACxB,WAAW,eAAe,kBAAkB;EAC5C,UAAU,eAAe;;UAIZ,wBAAwB;EACvC;EACA;;KAGU,eAAe;KAEf,oBAAoB,QAC9B,YAAgB;EAEd,SAAS,eAAe;;KAIhB,iBAAiB,QAC3B,YAAgB;EAEd,UAAU,eAAe,kBAAkB;EAC3C,UAAU,eAAe;EACzB,QAAQ,eAAe,kBAAkB;;KAIjC,kBAAkB,eAAe,kBAAkB;KAEnD,gBAAgB,qBAAqB,QAC/C,YAAgB,gBAAgB;EAE9B,cAAc,kBAAkB;EAChC,cAAc,kBAAkB;EAChC,YAAY;EACZ,YAAY,eAAe,kBAAkB;KAG/C;KAEU,eAAe,qBAAqB,QAC9C,YAAgB,eAAe;EAE7B,cAAc,kBAAkB;QAGjC,UAAU,eAAe,gBAAgB;KAGhC,YAAY,mBAAmB,yBAAyB,gBAEjE,eAAe,KAAK;KAGX,iBAAiB,eAAe,iBAAiB;KAEjD,mBAAmB,QAC7B,YAAgB;EAEd,UAAU,eAAe;EACzB,YAAY,eAAe,kBAAkB;EAC7C,aAAa,eAAe,kBAAkB;EAC9C,gBAAgB,eAAe,kBAAkB;EACjD,UAAU,eAAe,kBAAkB;EAC3C,QAAQ,eAAe,kBAAkB;EACzC,YAAY,eAAe,kBAAkB;EAC7C,YAAY,eAAe,kBAAkB;;KAIrC,SAAS,qBAAqB,QACxC,YAAgB,SAAS;EAEvB,QAAQ,YAAY;EACpB,aAAa;;;;UClHA;;;;;EAKf;;EAEA;;EAEA;;;;;;;EAOA,UAAU;;;;;;;;;;wBAqoDU,wBACpB,wBACA,UAAS,kBACR,QAAQ"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"mappings":";;;;KAEY,QAAQ,SAAS,gBAAgB,KAAK,eAAe,gBAC/D;KAEU;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/generate.ts"],"mappings":";;;;KAEY,QAAQ,SAAS,gBAAgB,KAAK,eAAe,gBAC/D;KAEU;KASA,sBAAsB;KAEtB,cAAc,YAAgB;KAC9B,kBAAkB,YAAgB;KAClC,gBAAgB,YAAgB;KAChC,sBAAsB,YAAgB;KACtC,8BACV,YAAgB;KACN,YAAY,YAAgB;KAC5B,aAAa,YAAgB;KAC7B,uBAAuB,YAAgB;KACvC,eAAe,YAAgB;KAE/B,eAAe,QACzB,YAAgB;EAEd;EACA,QAAQ,eAAe;EACvB;EACA;EACA,aAAa,eAAe;EAC5B;EACA,QAAQ;EACR,cAAc;EACd;EACA;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,MAAM;EACN,iCAAiC;EACjC,gBAAgB;EAChB,eAAe;EACf,MAAM;EACN;EACA;EACA;;KAIQ,aAAa;UAER,0BAA0B;EACzC;EACA,OAAO;;KAGG,kBAAkB,QAC5B,YAAgB;EAEd,SAAS,eAAe;EACxB,WAAW,eAAe,kBAAkB;;UAI/B,4BAA4B,QAC3C,YAAgB;EAEd,SAAS,eAAe;EACxB,WAAW,eAAe,kBAAkB;EAC5C,UAAU,eAAe;;UAIZ,wBAAwB;EACvC;EACA;;KAGU,eAAe;KAEf,oBAAoB,QAC9B,YAAgB;EAEd,SAAS,eAAe;;KAIhB,iBAAiB,QAC3B,YAAgB;EAEd,UAAU,eAAe,kBAAkB;EAC3C,UAAU,eAAe;EACzB,QAAQ,eAAe,kBAAkB;;KAIjC,kBAAkB,eAAe,kBAAkB;KAEnD,gBAAgB,qBAAqB,QAC/C,YAAgB,gBAAgB;EAE9B,cAAc,kBAAkB;EAChC,cAAc,kBAAkB;EAChC,YAAY;EACZ,YAAY,eAAe,kBAAkB;KAG/C;KAEU,eAAe,qBAAqB,QAC9C,YAAgB,eAAe;EAE7B,cAAc,kBAAkB;QAGjC,UAAU,eAAe,gBAAgB;KAGhC,YAAY,mBAAmB,yBAAyB,gBAEjE,eAAe,KAAK;KAGX,iBAAiB,eAAe,iBAAiB;KAEjD,mBAAmB,QAC7B,YAAgB;EAEd,UAAU,eAAe;EACzB,YAAY,eAAe,kBAAkB;EAC7C,aAAa,eAAe,kBAAkB;EAC9C,gBAAgB,eAAe,kBAAkB;EACjD,UAAU,eAAe,kBAAkB;EAC3C,QAAQ,eAAe,kBAAkB;EACzC,YAAY,eAAe,kBAAkB;EAC7C,YAAY,eAAe,kBAAkB;;KAIrC,SAAS,qBAAqB,QACxC,YAAgB,SAAS;EAEvB,QAAQ,YAAY;EACpB,aAAa;;;;UClHA;;;;;EAKf;;EAEA;;EAEA;;;;;;;EAOA,UAAU;;;;;;;;;;wBAqoDU,wBACpB,wBACA,UAAS,kBACR,QAAQ"}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"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 ResponseObject,\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 errorSchema: 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\nconst STANDARD_FUNCTION_INTERFACES = new Set([\n 'Function',\n 'CallableFunction',\n 'NewableFunction',\n]);\n\nfunction isStandardFunctionInterface(type: ts.Type): boolean {\n const symbol = type.getSymbol();\n const name = symbol?.getName();\n if (!name || !STANDARD_FUNCTION_INTERFACES.has(name)) {\n return false;\n }\n return (\n symbol?.declarations?.some((d) =>\n /(^|[\\\\/])lib\\.[^\\\\/]*\\.d\\.ts$/.test(d.getSourceFile().fileName),\n ) ?? false\n );\n}\n\nfunction isFunctionType(type: ts.Type): boolean {\n return (\n type.getCallSignatures().length > 0 ||\n type.getConstructSignatures().length > 0 ||\n isStandardFunctionInterface(type)\n );\n}\n\nfunction hasFunctionMember(type: ts.Type): boolean {\n if (isFunctionType(type)) {\n return true;\n }\n return type.isUnion() && type.types.some(isFunctionType);\n}\n\nfunction isUnserialisableType(type: ts.Type): boolean {\n if (isFunctionType(type)) {\n return true;\n }\n if (!type.isUnion() || !type.types.some(isFunctionType)) {\n return false;\n }\n // Once callables are dropped, a union of nothing but `null` / `undefined`\n // describes no value worth emitting.\n return !type.types.some(\n (m) =>\n !isFunctionType(m) &&\n !hasFlag(\n m,\n ts.TypeFlags.Undefined | ts.TypeFlags.Void | ts.TypeFlags.Null,\n ),\n );\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) =>\n !hasFlag(m, ts.TypeFlags.Undefined | ts.TypeFlags.Void) &&\n !isFunctionType(m),\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 const distinctSchemas = dedupeSchemas(schemas, ctx.schemas);\n if (distinctSchemas.length === 0) {\n return {};\n }\n\n const [firstSchema] = distinctSchemas;\n if (distinctSchemas.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 (distinctSchemas.every(isSimpleTypeSchema)) {\n return { type: distinctSchemas.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(distinctSchemas);\n if (discriminatorProp) {\n return {\n oneOf: distinctSchemas,\n discriminator: { propertyName: discriminatorProp },\n };\n }\n\n return { oneOf: distinctSchemas };\n}\n\nfunction dedupeSchemas(\n schemas: SchemaObject[],\n components: Record<string, SchemaObject>,\n): SchemaObject[] {\n const seen = new Set<string>();\n\n return schemas.filter((schema) => {\n const key = canonicalize(resolveBareRef(schema, components));\n if (seen.has(key)) {\n return false;\n }\n seen.add(key);\n return true;\n });\n}\n\n/**\n * A `$ref` on its own describes exactly the component it points at, so compare\n * through the component - otherwise the same shape reached both by reference\n * and inline looks like two distinct schemas.\n */\nfunction resolveBareRef(\n schema: SchemaObject,\n components: Record<string, SchemaObject>,\n): SchemaObject {\n if (!isBareRef(schema)) {\n return schema;\n }\n const target = getReferencedSchema(schema, components);\n // A component mid-conversion is still an empty placeholder (cyclic types);\n // compare those by their `$ref` so distinct ones stay distinct.\n return target && isNonEmptySchema(target) ? target : schema;\n}\n\n/** A `$ref` with no sibling keys, i.e. one that stands for its component. */\nfunction isBareRef(schema: SchemaObject): boolean {\n return schema.$ref !== undefined && Object.keys(schema).length === 1;\n}\n\nfunction canonicalize(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map(canonicalize).join(',')}]`;\n }\n\n if (value && typeof value === 'object') {\n const entries = Object.entries(value)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([k, v]) => `${JSON.stringify(k)}:${canonicalize(v)}`);\n return `{${entries.join(',')}}`;\n }\n return JSON.stringify(value) ?? 'undefined';\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 propSchema?.const !== undefined && s.required?.includes(prop);\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 if (isUnserialisableType(propType)) {\n continue;\n }\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) && !hasFunctionMember(propType)) {\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 (typeProps.length > 0) {\n // Closed shape. Stays closed even when every property was filtered out,\n // so the result reads as \"no keys\" rather than \"any keys\".\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 (isFunctionType(type)) {\n return {};\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 /** The router-wide error shape, used to spot procedures that differ from it. */\n routerErrorType: ts.Type | null;\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 return `${pascalCasePath(path) || 'Procedure'}Input`;\n}\n\n/** `user.getById` → `UserGetById`, for naming components after a procedure. */\nfunction pascalCasePath(path: string): string {\n return 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\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 errorSchema: extractProcedureErrorSchema($typesType, ctx),\n description: def.description,\n });\n}\n\nfunction extractProcedureErrorSchema(\n $typesType: ts.Type,\n ctx: WalkCtx,\n): SchemaObject | null {\n const { schemaCtx } = ctx;\n const errorSym = $typesType.getProperty('errorShape');\n if (!errorSym) {\n return null;\n }\n\n const { checker } = schemaCtx;\n const errorType = checker.getTypeOfSymbol(errorSym);\n if (\n hasFlag(errorType, ts.TypeFlags.Any) ||\n isUnknownLikeType(errorType) ||\n addsNothingToRouterErrorType(errorType, ctx.routerErrorType, checker)\n ) {\n return null;\n }\n\n const schema = typeToJsonSchema(errorType, schemaCtx);\n return isNonEmptySchema(schema) ? schema : null;\n}\n\nfunction addsNothingToRouterErrorType(\n errorType: ts.Type,\n routerErrorType: ts.Type | null,\n checker: ts.TypeChecker,\n): boolean {\n if (!routerErrorType) {\n return false;\n }\n if (errorType === routerErrorType) {\n return true;\n }\n\n const describe = (type: ts.Type) =>\n checker.typeToString(\n type,\n undefined,\n ts.TypeFormatFlags.NoTruncation |\n ts.TypeFormatFlags.UseFullyQualifiedType,\n );\n const unionMembers = (type: ts.Type) =>\n type.isUnion() ? type.types : [type];\n\n const routerMembers = new Set(unionMembers(routerErrorType).map(describe));\n\n return unionMembers(errorType).every((member) =>\n routerMembers.has(describe(member)),\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 getRouterErrorType(\n routerType: ts.Type,\n checker: ts.TypeChecker,\n): ts.Type | 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 || hasFlag(errorShapeType, ts.TypeFlags.Any)) {\n return null;\n }\n\n return errorShapeType;\n}\n\nfunction extractErrorSchema(\n routerType: ts.Type,\n checker: ts.TypeChecker,\n schemaCtx: SchemaCtx,\n): SchemaObject | null {\n const errorShapeType = getRouterErrorType(routerType, checker);\n if (!errorShapeType) {\n return null;\n }\n\n return typeToJsonSchema(errorShapeType, schemaCtx);\n}\n\n// ---------------------------------------------------------------------------\n// OpenAPI document builder\n// ---------------------------------------------------------------------------\n\nfunction wrapInErrorEnvelope(errorSchema: SchemaObject): SchemaObject {\n return {\n type: 'object',\n properties: { error: errorSchema },\n required: ['error'],\n };\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 errorResponseRef: string,\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: errorResponseRef },\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 buildErrorResponse(schema: SchemaObject): ResponseObject {\n return {\n description: 'Error response',\n content: {\n 'application/json': { schema: wrapInErrorEnvelope(schema) },\n },\n };\n}\n\nfunction buildErrorResponses(\n procedures: ProcedureInfo[],\n routerErrorSchema: SchemaObject,\n schemas: Record<string, SchemaObject>,\n): {\n responses: Record<string, ResponseObject>;\n refByProcedurePath: Map<string, string>;\n} {\n const responses: Record<string, ResponseObject> = {\n Error: buildErrorResponse(routerErrorSchema),\n };\n const shapeKey = (schema: SchemaObject) =>\n canonicalize(resolveBareRef(schema, schemas));\n const refByShape = new Map<string, string>([\n [shapeKey(routerErrorSchema), '#/components/responses/Error'],\n ]);\n const refByProcedurePath = new Map<string, string>();\n\n for (const proc of procedures) {\n if (!proc.errorSchema) {\n continue;\n }\n\n const key = shapeKey(proc.errorSchema);\n let ref = refByShape.get(key);\n if (!ref) {\n // A shape that already is a component needs no second name for it.\n const name = `${pascalCasePath(proc.path) || 'Procedure'}Error`;\n const shape = isBareRef(proc.errorSchema)\n ? proc.errorSchema\n : registerSchema(`${name}Shape`, proc.errorSchema, schemas);\n const responseName = ensureUniqueName(name, responses);\n responses[responseName] = buildErrorResponse(shape);\n ref = `#/components/responses/${responseName}`;\n refByShape.set(key, ref);\n }\n refByProcedurePath.set(proc.path, ref);\n }\n\n return { responses, refByProcedurePath };\n}\n\nfunction registerSchema(\n name: string,\n schema: SchemaObject,\n schemas: Record<string, SchemaObject>,\n): SchemaObject {\n const refName = ensureUniqueName(name, schemas);\n schemas[refName] = schema;\n return { $ref: `#/components/schemas/${refName}` };\n}\n\nfunction buildOpenAPIDocument(\n procedures: ProcedureInfo[],\n options: GenerateOptions,\n meta: RouterMeta = { errorSchema: null },\n): Document {\n const paths: PathsObject = {};\n const included = procedures.filter((proc) =>\n shouldIncludeProcedureInOpenAPI(proc.type),\n );\n\n const schemas = meta.schemas ?? {};\n const { responses: errorResponses, refByProcedurePath } = buildErrorResponses(\n included,\n meta.errorSchema ?? DEFAULT_ERROR_SCHEMA,\n schemas,\n );\n\n for (const proc of included) {\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 refByProcedurePath.get(proc.path) ?? '#/components/responses/Error',\n ) as PathItemObject[typeof method];\n }\n\n const hasNamedSchemas = Object.keys(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 ? { schemas } : {}),\n responses: errorResponses,\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 routerErrorType: getRouterErrorType(routerType, checker),\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' | 'boolean' | 'integer' | 'null' | 'number' | 'object' | '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 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":";;;;;;;;;;;;AAuCA,SAAS,uBAAwD;CAC/D,MAAM,MACJ,WACA;CACF,OAAO,OAAO,OAAO,IAAI,QAAQ,aAAa,MAAM;AACtD;;AAGA,SAAS,YAAY,OAAmC;CACtD,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU,OAAO;CACvD,MAAM,MAAO,MAA6B;CAC1C,OAAO,OAAO,QAAQ,OAAO,QAAQ,YAAY,SAAS;AAC5D;;AAGA,SAAS,eAAe,QAAoC;CAC1D,MAAM,MAAM,OAAO,KAAK;CACxB,IAAI,IAAI,SAAS,YAAY,WAAW,KACtC,OAAQ,IAAsB;CAEhC,OAAO;AACT;;AAGA,SAAS,gBAAgB,QAAmC;CAC1D,MAAM,MAAM,OAAO,KAAK;CACxB,IAAI,IAAI,SAAS,WAAW,aAAa,KACvC,OAAQ,IAAqB;CAE/B,OAAO;AACT;;AAGA,MAAM,kCAAoD,IAAI,IAAI;CAChE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;AAMD,SAAS,gBAAgB,KAAmC;CAC1D,IAAI,eAAe,KAAK,OAAQ,IAAgC;CAChE,IAAI,QAAQ,KAAK,OAAQ,IAAyB;CAClD,OAAO;AACT;;AAGA,SAAS,gBAAgB,QAA4B;CACnD,IAAI,UAAoB;CACxB,MAAM,uBAAO,IAAI,IAAc;CAC/B,OAAO,CAAC,KAAK,IAAI,OAAO,GAAG;EACzB,KAAK,IAAI,OAAO;EAChB,MAAM,MAAM,QAAQ,KAAK;EACzB,IAAI,CAAC,gBAAgB,IAAI,IAAI,IAAI,GAAG;EACpC,MAAM,QAAQ,gBAAgB,GAAG;EACjC,IAAI,CAAC,OAAO;EACZ,UAAU;CACZ;CACA,OAAO;AACT;;;;;AAMA,SAAgB,uBAAuB,QAAwC;CAC7E,IAAI,CAAC,YAAY,MAAM,GAAG,OAAO;CACjC,MAAM,WAAW,qBAAqB;CACtC,IAAI,CAAC,UAAU,OAAO;CAEtB,MAAM,MAAsB,EAAE,4BAAY,IAAI,IAAI,EAAE;CACpD,IAAI,SAAS;CAGb,MAAM,UAAU,SAAS,IAAI,MAAM;CACnC,IAAA,YAAA,QAAA,YAAA,KAAA,IAAA,KAAA,IAAI,QAAS,aAAa;EACxB,IAAI,OAAO,QAAQ;EACnB,SAAS;CACX;CAGA,aAAa,QAAQ,IAAI;EAAE;EAAU;EAAK,0BAAU,IAAI,IAAI;CAAE,CAAC;CAC/D,IAAI,IAAI,WAAW,OAAO,GAAG,SAAS;CAEtC,OAAO,SAAS,MAAM;AACxB;AAEA,SAAS,aACP,QACA,QACA,KAKM;CACN,MAAM,YAAY,gBAAgB,MAAM;CACxC,MAAM,MAAM,UAAU,KAAK;CAE3B,IAAI,IAAI,SAAS,UAAU,YAAY,KAAK;EAC1C,IAAI,IAAI,SAAS,IAAI,SAAS,GAC5B;EAEF,IAAI,SAAS,IAAI,SAAS;EAC1B,MAAM,QAAS,IAAkC,OAAO;EACxD,IAAI,YAAY,KAAK,GACnB,aAAa,OAAO,QAAQ,GAAG;EAEjC;CACF;CAIA,MAAM,UAAU,gBAAgB,SAAS;CACzC,IAAI,SAAS;;EACX,MAAM,mBAAmB,gBAAgB,OAAO;EAChD,MAAM,WAAW,IAAI,SAAS,IAAI,OAAO;EACzC,MAAM,gBACJ,qBAAqB,UACjB,IAAI,SAAS,IAAI,gBAAgB,IACjC,KAAA;EACN,MAAM,YAAA,wBAAA,aAAA,QAAA,aAAA,KAAA,IAAA,KAAA,IAAW,SAAU,iBAAA,QAAA,0BAAA,KAAA,IAAA,wBAAA,kBAAA,QAAA,kBAAA,KAAA,IAAA,KAAA,IAAe,cAAe;EACzD,IAAI,UAAU;GACZ,MAAM,YAAY,SAAS,GAAG,OAAO,OAAO;GAC5C,IAAI,IAAI,WAAW,IAAI,WAAW,QAAQ;EAC5C;EACA,aAAa,SAAS,QAAQ,GAAG;EACjC;CACF;CAEA,MAAM,QAAQ,eAAe,SAAS;CACtC,IAAI,CAAC,OAAO;CAEZ,KAAK,MAAM,CAAC,KAAK,gBAAgB,OAAO,QAAQ,KAAK,GAAG;;EACtD,MAAM,OAAO,SAAS,GAAG,OAAO,GAAG,QAAQ;EAG3C,MAAM,OAAO,IAAI,SAAS,IAAI,WAAW;EACzC,MAAM,iBAAiB,gBAAgB,WAAW;EAClD,MAAM,YACJ,mBAAmB,cACf,IAAI,SAAS,IAAI,cAAc,IAC/B,KAAA;EACN,MAAM,eAAA,oBAAA,SAAA,QAAA,SAAA,KAAA,IAAA,KAAA,IAAc,KAAM,iBAAA,QAAA,sBAAA,KAAA,IAAA,oBAAA,cAAA,QAAA,cAAA,KAAA,IAAA,KAAA,IAAe,UAAW;EACpD,IAAI,aACF,IAAI,IAAI,WAAW,IAAI,MAAM,WAAW;EAI1C,aAAa,gBAAgB,MAAM,GAAG;CACxC;AACF;;AAOA,SAAS,iBAAiB,OAAwC;CAChE,IAAI,SAAS,MAAM,OAAO;CAC1B,MAAM,MAAM;CACZ,MAAM,MAAM,IAAI;CAChB,OACE,OAAO,QAAQ,YACf,OAAO,QACP,OAAO,QAAQ,YACd,IAAgC,aAAa,QAC9C,OAAQ,IAAgC,cAAc;AAE1D;;;;;;;;;AAUA,SAAgB,iBACd,KACA,YACsB;CAEtB,IAAI,iBAAiB,IAAI,WAAW,GAClC,OAAO,IAAI;CAIb,MAAM,UAAU,WAAW,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,WAAW,MAAM,CAAC;CACvE,IAAI,YAAY,cAAc,iBAAiB,IAAI,QAAQ,GACzD,OAAO,IAAI;CAIb,KAAK,MAAM,SAAS,OAAO,OAAO,GAAG,GACnC,IAAI,iBAAiB,KAAK,GACxB,OAAO;CAIX,OAAO;AACT;;;;;;AAOA,eAAsB,gBACpB,cACA,YAC+B;CAC/B,IAAI;EAEF,OAAO,iBAAiB,MADN,OAAO,cAAc,YAAY,CAAC,CAAC,OACG,UAAU;CACpE,SAAA,SAAQ;EAGN,OAAO;CACT;AACF;;;;;AAUA,SAAgB,2BACd,gBACA,QACA,QACM;CAEN,MAAM,SAA2B,iBAAiB,cAAc,IAC5D,eAAe,KAAK,SACpB;CAEJ,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;EACjD,MAAM,WAAW,SAAS,GAAG,OAAO,GAAG,QAAQ;EAE/C,IAAI,YAAY,KAAK,GAAG;GAEtB,MAAM,MAAM,MAAM;GAClB,IAAI,aAAoC;GACxC,KAAK,MAAM,SAAS,IAAI,QAAQ;IAC9B,MAAM,QAAQ,uBAAuB,KAAK;IAC1C,IAAI,OAAO;;KAET,CAAA,cAAA,gBAAA,QAAA,gBAAA,KAAA,MAAA,aAAe,EAAE,4BAAY,IAAI,IAAI,EAAE;KACvC,WAAW,QAAA,cAAO,MAAM,UAAA,QAAA,gBAAA,KAAA,IAAA,cAAQ,WAAW;KAC3C,KAAK,MAAM,CAAC,GAAG,MAAM,MAAM,YACzB,WAAW,WAAW,IAAI,GAAG,CAAC;IAElC;GACF;GAEA,IAAI,cAAqC;GAGzC,MAAM,eAAgB,IAAgC;GACtD,IAAI,cACF,cAAc,uBAAuB,YAAY;GAGnD,IAAI,cAAc,aAChB,OAAO,IAAI,UAAU;IAAE,OAAO;IAAY,QAAQ;GAAY,CAAC;EAEnE,OAEE,2BAA2B,OAAO,UAAU,MAAM;CAEtD;AACF;;AAGA,SAAS,YACP,OAC2B;CAC3B,OAAO,OAAO,UAAU;AAC1B;;;;;AAUA,SAAgB,kBACd,QACA,OACA,SACM;CACN,IAAI,MAAM,MACR,OAAO,cAAc,MAAM;CAG7B,KAAK,MAAM,CAAC,UAAU,gBAAgB,MAAM,YAC1C,qBAAqB;EACnB;EACA,WAAW,SAAS,MAAM,GAAG;EAC7B;EACA;CACF,CAAC;AAEL;AAEA,SAAS,iBACP,QACA,SACqB;;CACrB,MAAM,MAAM,OAAO;CACnB,IAAI,CAAC,KACH,OAAO;CAET,IAAI,CAAC,WAAW,CAAC,IAAI,WAAW,uBAAuB,GACrD,OAAO;CAGT,MAAM,UAAU,IAAI,MAAM,EAA8B;CACxD,OAAO,WAAA,mBAAW,QAAQ,cAAA,QAAA,qBAAA,KAAA,IAAA,mBAAY,OAAQ;AAChD;AAEA,SAAS,oBAAoB,QAA2C;CACtE,MAAM,QAAQ,OAAO;CACrB,IAAI,OAAO,SAAS,WAAW,SAAS,QAAQ,UAAU,OACxD,OAAO;CAET,OAAO;AACT;AAEA,SAAS,kBACP,QACA,cACqB;;CACrB,QAAA,yBAAA,qBAAO,OAAO,gBAAA,QAAA,uBAAA,KAAA,IAAA,KAAA,IAAA,mBAAa,mBAAA,QAAA,0BAAA,KAAA,IAAA,wBAAiB;AAC9C;AAEA,SAAS,mBAAmB,QAAsB,aAA2B;CAC3E,IAAI,OAAO,MAAM;;EACf,MAAM,MAAM,OAAO;EACnB,OAAO,OAAO;EACd,OAAO,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,IAAA,gBAAI,OAAO,WAAA,QAAA,kBAAA,KAAA,IAAA,gBAAS,CAAC,CAAE;CACxD;CACA,OAAO,cAAc;AACvB;AAEA,SAAS,qBAAqB,EAC5B,QACA,WACA,aACA,WAMO;CACP,IAAI,UAAU,WAAW,GAAG;CAE5B,MAAM,CAAC,MAAM,GAAG,QAAQ;CACxB,IAAI,CAAC,MAAM;CAGX,IAAI,SAAS,MAAM;EACjB,MAAM,QAAQ,oBAAoB,MAAM;EACxC,IAAI,CAAC,OAAO;EACZ,IAAI,KAAK,WAAW,GAClB,mBAAmB,OAAO,WAAW;OAChC;;GAEL,qBAAqB;IACnB,SAAA,oBAFa,iBAAiB,OAAO,OAAO,OAAA,QAAA,sBAAA,KAAA,IAAA,oBAAK;IAGjD,WAAW;IACX;IACA;GACF,CAAC;EACH;EACA;CACF;CAEA,MAAM,aAAa,kBAAkB,QAAQ,IAAI;CACjD,IAAI,CAAC,YAAY;CAEjB,IAAI,KAAK,WAAW,GAElB,mBAAmB,YAAY,WAAW;MACrC;;EAEL,MAAM,UAAA,uBAAS,oBAAoB,UAAU,OAAA,QAAA,yBAAA,KAAA,IAAA,uBAAK;EAElD,qBAAqB;GACnB,SAAA,qBAFqB,iBAAiB,QAAQ,OAAO,OAAA,QAAA,uBAAA,KAAA,IAAA,qBAAK;GAG1D,WAAW;GACX;GACA;EACF,CAAC;CACH;AACF;;;AC3YA,MAAM,kBACJ,GAAG,UAAU,SACb,GAAG,UAAU,SACb,GAAG,UAAU,UACb,GAAG,UAAU,gBACb,GAAG,UAAU,gBACb,GAAG,UAAU;AAEf,SAAS,QAAQ,MAAe,MAA6B;CAC3D,QAAQ,KAAK,SAAS,IAAI,UAAU;AACtC;AAEA,SAAS,YAAY,MAAwB;CAC3C,OAAO,QAAQ,MAAM,eAAe;AACtC;AAEA,SAAS,aAAa,MAAwB;CAC5C,OAAO,QAAQ,MAAM,GAAG,UAAU,MAAM;AAC1C;AAEA,MAAM,+CAA+B,IAAI,IAAI;CAC3C;CACA;CACA;AACF,CAAC;AAED,SAAS,4BAA4B,MAAwB;;CAC3D,MAAM,SAAS,KAAK,UAAU;CAC9B,MAAM,OAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAO,OAAQ,QAAQ;CAC7B,IAAI,CAAC,QAAQ,CAAC,6BAA6B,IAAI,IAAI,GACjD,OAAO;CAET,QAAA,wBAAA,WAAA,QAAA,WAAA,KAAA,MAAA,uBACE,OAAQ,kBAAA,QAAA,yBAAA,KAAA,IAAA,KAAA,IAAA,qBAAc,MAAM,MAC1B,gCAAgC,KAAK,EAAE,cAAc,CAAC,CAAC,QAAQ,CACjE,OAAA,QAAA,0BAAA,KAAA,IAAA,wBAAK;AAET;AAEA,SAAS,eAAe,MAAwB;CAC9C,OACE,KAAK,kBAAkB,CAAC,CAAC,SAAS,KAClC,KAAK,uBAAuB,CAAC,CAAC,SAAS,KACvC,4BAA4B,IAAI;AAEpC;AAEA,SAAS,kBAAkB,MAAwB;CACjD,IAAI,eAAe,IAAI,GACrB,OAAO;CAET,OAAO,KAAK,QAAQ,KAAK,KAAK,MAAM,KAAK,cAAc;AACzD;AAEA,SAAS,qBAAqB,MAAwB;CACpD,IAAI,eAAe,IAAI,GACrB,OAAO;CAET,IAAI,CAAC,KAAK,QAAQ,KAAK,CAAC,KAAK,MAAM,KAAK,cAAc,GACpD,OAAO;CAIT,OAAO,CAAC,KAAK,MAAM,MAChB,MACC,CAAC,eAAe,CAAC,KACjB,CAAC,QACC,GACA,GAAG,UAAU,YAAY,GAAG,UAAU,OAAO,GAAG,UAAU,IAC5D,CACJ;AACF;AAEA,SAAS,iBAAiB,KAAyB;CACjD,QAAQ,IAAI,QAAQ,GAAG,YAAY,cAAc;AACnD;;;;;AAwBA,SAAS,YAAY,MAAwB;CAC3C,IAAI,CAAC,KAAK,eAAe,GACvB,OAAO;CAET,MAAM,aAAa,KAAK,MAAM,OAAO,WAAW;CAChD,MAAM,YAAY,KAAK,MAAM,KAAK,YAAY;CAC9C,MAAM,CAAC,SAAS;CAChB,IAAI,SAAS,WACX,OAAO;CAET,OAAO;AACT;AAMA,MAAM,kCAAkB,IAAI,IAAI;CAAC;CAAU;CAAY;CAAU;AAAE,CAAC;AACpE,MAAM,oCAAoC;;AAG1C,SAAS,YAAY,MAA8B;;CACjD,MAAM,aAAA,oBAAY,KAAK,iBAAA,QAAA,sBAAA,KAAA,IAAA,KAAA,IAAA,kBAAa,QAAQ;CAC5C,IAAI,aAAa,CAAC,gBAAgB,IAAI,SAAS,GAC7C,OAAO;CAET,MAAM,WAAA,kBAAU,KAAK,UAAU,OAAA,QAAA,oBAAA,KAAA,IAAA,KAAA,IAAA,gBAAG,QAAQ;CAC1C,IAAI,WAAW,CAAC,gBAAgB,IAAI,OAAO,KAAK,CAAC,QAAQ,WAAW,IAAI,GACtE,OAAO;CAET,OAAO;AACT;AAIA,SAAS,yBAAyB,MAA0B;;CAC1D,QAAA,yBAAA,qBACE,KAAK,kBAAA,QAAA,uBAAA,KAAA,IAAA,KAAA,IAAA,mBAAc,MAAM,gBAAgB;EACvC,MAAM,kBAAkB,GAAG,qBAAqB,WAAW;EAC3D,IAAI,CAAC,mBAAmB,CAAC,GAAG,uBAAuB,eAAe,GAChE,OAAO;EAGT,OAAO,kCAAkC,KAAK,KAAK,QAAQ,CAAC;CAC9D,CAAC,OAAA,QAAA,0BAAA,KAAA,IAAA,wBAAK;AAEV;AAEA,SAAS,oBACP,QACA,SACqB;;CACrB,MAAM,MAAA,WAAA,QAAA,WAAA,KAAA,IAAA,KAAA,IAAM,OAAQ;CACpB,IAAI,EAAA,QAAA,QAAA,QAAA,KAAA,IAAA,KAAA,IAAC,IAAK,WAAW,uBAAuB,IAC1C,OAAO;CAGT,MAAM,UAAU,IAAI,MAAM,EAA8B;CACxD,OAAO,WAAA,mBAAW,QAAQ,cAAA,QAAA,qBAAA,KAAA,IAAA,mBAAY,OAAQ;AAChD;AAEA,SAAS,iBACP,MACA,UACQ;CACR,IAAI,EAAE,QAAQ,WACZ,OAAO;CAET,IAAI,IAAI;CACR,OAAO,GAAG,OAAO,OAAO,UACtB;CAEF,OAAO,GAAG,OAAO;AACnB;AAEA,SAAS,UAAU,MAA4B;CAC7C,OAAO,EAAE,MAAM,wBAAwB,OAAO;AAChD;AAEA,SAAS,gBAAgB,QAAsB,MAAuB;CACpE,OAAO,OAAO,SAAS,UAAU,IAAI,CAAC,CAAC;AACzC;AAEA,SAAS,iBAAiB,GAA0B;CAClD,KAAK,MAAM,KAAK,GAAG,OAAO;CAC1B,OAAO;AACT;;;;;;;;;;AAeA,SAAS,iBACP,MACA,KACA,QAAQ,GACM;CAEd,MAAM,cAAc,IAAI,UAAU,IAAI,IAAI;CAC1C,IAAI,aAAa;EACf,MAAM,eAAe,IAAI,QAAQ;EACjC,IACE,iBACC,iBAAiB,YAAY,KAAK,IAAI,QAAQ,IAAI,IAAI,IAEvD,OAAO,UAAU,WAAW;EAK9B,IAAI,QAAQ,eAAe,iBAAA,QAAA,iBAAA,KAAA,IAAA,eAAgB,CAAC;EAC5C,MAAM,SAAS,oBAAoB,MAAM,KAAK,KAAK;EACnD,IAAI,CAAC,gBAAgB,QAAQ,WAAW,GACtC,IAAI,QAAQ,eAAe;EAE7B,OAAO,UAAU,WAAW;CAC9B;CAEA,MAAM,SAAS,oBAAoB,MAAM,KAAK,KAAK;CAMnD,MAAM,iBAAiB,IAAI,UAAU,IAAI,IAAI;CAC7C,IAAI,gBAAgB;EAClB,MAAM,SAAS,IAAI,QAAQ;EAC3B,IACE,UACA,CAAC,iBAAiB,MAAM,KACxB,CAAC,gBAAgB,QAAQ,cAAc,GAEvC,IAAI,QAAQ,kBAAkB;EAEhC,OAAO,UAAU,cAAc;CACjC;CAGA,IAAI,CAAC,OAAO,eAAe,CAAC,OAAO,QAAQ,KAAK,aAAa;EAC3D,MAAM,aAAa,gBAAgB,KAAK,aAAa,IAAI,OAAO;EAChE,IAAI,YACF,OAAO,cAAc;CAEzB;CAEA,OAAO;AACT;;;;;AAUA,SAAS,gBAAgB,MAAe,KAA8B;CACpE,IAAI,UAAU,IAAI,UAAU,IAAI,IAAI;CACpC,IAAI,CAAC,SAAS;;EAEZ,UAAU,kBAAA,eADG,YAAY,IAAI,OAAA,QAAA,iBAAA,KAAA,IAAA,eAAK,iBACD,IAAI,OAAO;EAC5C,IAAI,UAAU,IAAI,MAAM,OAAO;EAC/B,IAAI,QAAQ,WAAW,CAAC;CAC1B;CACA,OAAO,UAAU,OAAO;AAC1B;AAMA,SAAS,0BACP,MACA,OACA,SACqB;CACrB,IAAI,QAAQ,GAAG,UAAU,QACvB,OAAO,EAAE,MAAM,SAAS;CAE1B,IAAI,QAAQ,GAAG,UAAU,QACvB,OAAO,EAAE,MAAM,SAAS;CAE1B,IAAI,QAAQ,GAAG,UAAU,SACvB,OAAO,EAAE,MAAM,UAAU;CAE3B,IAAI,QAAQ,GAAG,UAAU,MACvB,OAAO,EAAE,MAAM,OAAO;CAExB,IAAI,QAAQ,GAAG,UAAU,WACvB,OAAO,CAAC;CAEV,IAAI,QAAQ,GAAG,UAAU,MACvB,OAAO,CAAC;CAEV,IAAI,QAAQ,GAAG,UAAU,OAAO,QAAQ,GAAG,UAAU,SACnD,OAAO,CAAC;CAEV,IAAI,QAAQ,GAAG,UAAU,OACvB,OAAO,EAAE,KAAK,CAAC,EAAE;CAEnB,IAAI,QAAQ,GAAG,UAAU,UAAU,QAAQ,GAAG,UAAU,eACtD,OAAO;EAAE,MAAM;EAAW,QAAQ;CAAS;CAG7C,IAAI,QAAQ,GAAG,UAAU,eACvB,OAAO;EAAE,MAAM;EAAU,OAAQ,KAA8B;CAAM;CAEvE,IAAI,QAAQ,GAAG,UAAU,eACvB,OAAO;EAAE,MAAM;EAAU,OAAQ,KAA8B;CAAM;CAEvE,IAAI,QAAQ,GAAG,UAAU,gBAEvB,OAAO;EAAE,MAAM;EAAW,OADX,QAAQ,aAAa,IAAI,MAAM;CACN;CAG1C,OAAO;AACT;AAMA,SAAS,iBACP,MACA,KACA,OACc;CAId,MAAM,UAHU,KAAK,MAGG,QACrB,MACC,CAAC,QAAQ,GAAG,GAAG,UAAU,YAAY,GAAG,UAAU,IAAI,KACtD,CAAC,eAAe,CAAC,CACrB;CACA,IAAI,QAAQ,WAAW,GACrB,OAAO,CAAC;CAGV,MAAM,UAAU,QAAQ,MAAM,MAAM,QAAQ,GAAG,GAAG,UAAU,IAAI,CAAC;CACjE,MAAM,UAAU,QAAQ,QAAQ,MAAM,CAAC,QAAQ,GAAG,GAAG,UAAU,IAAI,CAAC;CAKpE,MAAM,eAAe,QAAQ,QAAQ,MACnC,QAAQ,YAAY,CAAC,GAAG,GAAG,UAAU,cAAc,CACrD;CACA,MAAM,cACJ,aAAa,WAAW,KACxB,aAAa,MACV,MAAM,IAAI,QAAQ,aAAa,YAAY,CAAC,CAAC,MAAM,MACtD,KACA,aAAa,MACV,MAAM,IAAI,QAAQ,aAAa,YAAY,CAAC,CAAC,MAAM,OACtD;CAGF,MAAM,YAAY,cACd,QAAQ,QACL,MAAM,CAAC,QAAQ,YAAY,CAAC,GAAG,GAAG,UAAU,cAAc,CAC7D,IACA;CAGJ,IAAI,eAAe,UAAU,WAAW,GACtC,OAAO,UAAU,EAAE,MAAM,CAAC,WAAW,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU;CAKrE,MAAM,gBAAgB,wBAAwB,WAAW,OAAO;CAChE,IAAI,eACF,OAAO;CAGT,MAAM,UAAU,UACb,KAAK,MAAM,iBAAiB,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAC/C,OAAO,gBAAgB;CAG1B,IAAI,aACF,QAAQ,KAAK,EAAE,MAAM,UAAU,CAAC;CAGlC,IAAI,SACF,QAAQ,KAAK,EAAE,MAAM,OAAO,CAAC;CAG/B,MAAM,kBAAkB,cAAc,SAAS,IAAI,OAAO;CAC1D,IAAI,gBAAgB,WAAW,GAC7B,OAAO,CAAC;CAGV,MAAM,CAAC,eAAe;CACtB,IAAI,gBAAgB,WAAW,KAAK,gBAAgB,KAAA,GAClD,OAAO;CAKT,IAAI,gBAAgB,MAAM,kBAAkB,GAC1C,OAAO,EAAE,MAAM,gBAAgB,KAAK,MAAM,EAAE,IAAc,EAAE;CAK9D,MAAM,oBAAoB,4BAA4B,eAAe;CACrE,IAAI,mBACF,OAAO;EACL,OAAO;EACP,eAAe,EAAE,cAAc,kBAAkB;CACnD;CAGF,OAAO,EAAE,OAAO,gBAAgB;AAClC;AAEA,SAAS,cACP,SACA,YACgB;CAChB,MAAM,uBAAO,IAAI,IAAY;CAE7B,OAAO,QAAQ,QAAQ,WAAW;EAChC,MAAM,MAAM,aAAa,eAAe,QAAQ,UAAU,CAAC;EAC3D,IAAI,KAAK,IAAI,GAAG,GACd,OAAO;EAET,KAAK,IAAI,GAAG;EACZ,OAAO;CACT,CAAC;AACH;;;;;;AAOA,SAAS,eACP,QACA,YACc;CACd,IAAI,CAAC,UAAU,MAAM,GACnB,OAAO;CAET,MAAM,SAAS,oBAAoB,QAAQ,UAAU;CAGrD,OAAO,UAAU,iBAAiB,MAAM,IAAI,SAAS;AACvD;;AAGA,SAAS,UAAU,QAA+B;CAChD,OAAO,OAAO,SAAS,KAAA,KAAa,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW;AACrE;AAEA,SAAS,aAAa,OAAwB;;CAC5C,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,IAAI,MAAM,IAAI,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE;CAG/C,IAAI,SAAS,OAAO,UAAU,UAK5B,OAAO,IAJS,OAAO,QAAQ,KAAK,CAAC,CAClC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC,CAClC,MAAM,CAAC,IAAI,CAAC,OAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE,CAAC,CAChD,KAAK,CAAC,GAAG,OAAO,GAAG,KAAK,UAAU,CAAC,EAAE,GAAG,aAAa,CAAC,GACxC,CAAC,CAAC,KAAK,GAAG,EAAE;CAE/B,QAAA,kBAAO,KAAK,UAAU,KAAK,OAAA,QAAA,oBAAA,KAAA,IAAA,kBAAK;AAClC;;;;;AAMA,SAAS,4BAA4B,SAAwC;CAC3E,IAAI,QAAQ,SAAS,GACnB,OAAO;CAIT,IAAI,CAAC,QAAQ,OAAO,MAAM,EAAE,SAAS,YAAY,EAAE,UAAU,GAC3D,OAAO;CAIT,MAAM,QAAQ,QAAQ;CACtB,IAAI,EAAA,UAAA,QAAA,UAAA,KAAA,IAAA,KAAA,IAAC,MAAO,aACV,OAAO;CAET,MAAM,aAAa,OAAO,KAAK,MAAM,UAAU;CAC/C,KAAK,MAAM,QAAQ,YAKjB,IAJqB,QAAQ,OAAO,MAAM;;EACxC,MAAM,cAAA,gBAAa,EAAE,gBAAA,QAAA,kBAAA,KAAA,IAAA,KAAA,IAAA,cAAa;EAClC,QAAA,eAAA,QAAA,eAAA,KAAA,IAAA,KAAA,IAAO,WAAY,WAAU,KAAA,OAAA,cAAa,EAAE,cAAA,QAAA,gBAAA,KAAA,IAAA,KAAA,IAAA,YAAU,SAAS,IAAI;CACrE,CACe,GACb,OAAO;CAIX,OAAO;AACT;;AAGA,SAAS,mBAAmB,GAA0B;CACpD,MAAM,OAAO,OAAO,KAAK,CAAC;CAC1B,OAAO,KAAK,WAAW,KAAK,KAAK,OAAO,UAAU,OAAO,EAAE,SAAS;AACtE;;;;;AAMA,SAAS,wBACP,SACA,SACqB;CACrB,IAAI,QAAQ,UAAU,GACpB,OAAO;CAMT,IAAI,CAHgB,QAAQ,OAAO,MACjC,QAAQ,GAAG,GAAG,UAAU,gBAAgB,GAAG,UAAU,aAAa,CAErD,GACb,OAAO;CAGT,MAAM,CAAC,SAAS;CAChB,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,WAAW,QAAQ,OAAO,GAAG,UAAU,aAAa;CAC1D,MAAM,aAAa,WACf,GAAG,UAAU,gBACb,GAAG,UAAU;CAEjB,IAAI,CADgB,QAAQ,OAAO,MAAM,QAAQ,GAAG,UAAU,CAC/C,GACb,OAAO;CAGT,MAAM,SAAS,QAAQ,KAAK,MAC1B,WACK,EAA2B,QAC3B,EAA2B,KAClC;CACA,MAAM,WAAW,WAAW,WAAW;CACvC,OAAO;EACL,MAAM,UAAU,CAAC,UAAU,MAAM,IAAI;EACrC,MAAM;CACR;AACF;AAMA,SAAS,wBACP,MACA,KACA,OACc;CASd,MAAM,WALqB,KAAK,MAAM,KAAK,WACT,IAC9B,KAAK,MAAM,QAAQ,MAAM,CAAC,aAAa,CAAC,CAAC,IACzC,KAAK,MAAA,CAGN,KAAK,MAAM,iBAAiB,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAC/C,OAAO,gBAAgB;CAE1B,IAAI,QAAQ,WAAW,GACrB,OAAO,CAAC;CAEV,MAAM,CAAC,cAAc;CACrB,IAAI,QAAQ,WAAW,KAAK,eAAe,KAAA,GACzC,OAAO;CAKT,IAAI,QAAQ,MAAM,oBAAoB,GACpC,OAAO,mBAAmB,OAAO;CAGnC,OAAO,EAAE,OAAO,QAAQ;AAC1B;;AAGA,SAAS,qBAAqB,GAA0B;CACtD,OAAO,EAAE,SAAS,YAAY,CAAC,EAAE;AACnC;;;;;AAMA,SAAS,mBAAmB,SAAuC;CAEjE,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,KAAK,SACd,IAAI,EAAE,YACJ,KAAK,MAAM,QAAQ,OAAO,KAAK,EAAE,UAAU,GAAG;EAC5C,IAAI,KAAK,IAAI,IAAI,GAEf,OAAO,EAAE,OAAO,QAAQ;EAE1B,KAAK,IAAI,IAAI;CACf;CAIJ,MAAM,aAA2C,CAAC;CAClD,MAAM,WAAqB,CAAC;CAC5B,IAAI;CAEJ,KAAK,MAAM,KAAK,SAAS;EACvB,IAAI,EAAE,YACJ,OAAO,OAAO,YAAY,EAAE,UAAU;EAExC,IAAI,EAAE,UACJ,SAAS,KAAK,GAAG,EAAE,QAAQ;EAE7B,IAAI,EAAE,yBAAyB,KAAA,GAC7B,uBAAuB,EAAE;CAE7B;CAEA,MAAM,SAAuB,EAAE,MAAM,SAAS;CAC9C,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GACnC,OAAO,aAAa;CAEtB,IAAI,SAAS,SAAS,GACpB,OAAO,WAAW;CAEpB,IAAI,yBAAyB,KAAA,GAC3B,OAAO,uBAAuB;CAEhC,OAAO;AACT;AAMA,SAAS,qBACP,MACA,KACA,OACqB;;CACrB,MAAM,WAAA,mBAAU,KAAK,UAAU,OAAA,QAAA,qBAAA,KAAA,IAAA,KAAA,IAAA,iBAAG,QAAQ;CAC1C,IAAI,YAAY,QACd,OAAO;EAAE,MAAM;EAAU,QAAQ;CAAY;CAE/C,IAAI,YAAY,gBAAgB,YAAY,UAC1C,OAAO;EAAE,MAAM;EAAU,QAAQ;CAAS;CAI5C,IAAI,YAAY,WAAW;EACzB,MAAM,CAAC,SAAS,IAAI,QAAQ,iBAAiB,IAAwB;EACrE,OAAO,QAAQ,iBAAiB,OAAO,KAAK,QAAQ,CAAC,IAAI,CAAC;CAC5D;CAEA,OAAO;AACT;AAEA,SAAS,iBACP,MACA,KACA,OACc;CACd,MAAM,CAAC,QAAQ,IAAI,QAAQ,iBAAiB,IAAwB;CACpE,MAAM,SAAuB,EAAE,MAAM,QAAQ;CAC7C,IAAI,MACF,OAAO,QAAQ,iBAAiB,MAAM,KAAK,QAAQ,CAAC;CAEtD,OAAO;AACT;AAEA,SAAS,iBACP,MACA,KACA,OACc;CACd,MAAM,OAAO,IAAI,QAAQ,iBAAiB,IAAwB;CAElE,OAAO;EACL,MAAM;EACN,aAHc,KAAK,KAAK,MAAM,iBAAiB,GAAG,KAAK,QAAQ,CAAC,CAG7C;EACnB,OAAO;EACP,UAAU,KAAK;EACf,UAAU,KAAK;CACjB;AACF;AAEA,SAAS,mBACP,MACA,KACA,OACc;;CACd,MAAM,EAAE,YAAY;CACpB,MAAM,kBAAkB,KAAK,mBAAmB;CAChD,MAAM,YAAY,KAAK,cAAc;CAGrC,IAAI,UAAU,WAAW,KAAK,iBAC5B,OAAO;EACL,MAAM;EACN,sBAAsB,iBAAiB,iBAAiB,KAAK,QAAQ,CAAC;CACxE;CAMF,IAAI,cAA6B;CACjC,MAAM,SAAS,YAAY,IAAI;CAG/B,IADE,WAAW,QAAQ,UAAU,SAAS,KAAK,CAAC,IAAI,UAAU,IAAI,IAAI,GACvC;EAC3B,cAAc,iBAAiB,QAAQ,IAAI,OAAO;EAClD,IAAI,UAAU,IAAI,MAAM,WAAW;EACnC,IAAI,QAAQ,eAAe,CAAC;CAC9B;CAEA,IAAI,QAAQ,IAAI,IAAI;CACpB,MAAM,aAA2C,CAAC;CAClD,MAAM,WAAqB,CAAC;CAE5B,KAAK,MAAM,QAAQ,WAAW;EAC5B,IAAI,yBAAyB,IAAI,GAC/B;EAGF,MAAM,WAAW,QAAQ,gBAAgB,IAAI;EAC7C,IAAI,qBAAqB,QAAQ,GAC/B;EAEF,MAAM,aAAa,iBAAiB,UAAU,KAAK,QAAQ,CAAC;EAG5D,MAAM,QAAQ,gBAAgB,MAAM,OAAO;EAC3C,IAAI,SAAS,CAAC,WAAW,eAAe,CAAC,WAAW,MAClD,WAAW,cAAc;EAG3B,WAAW,KAAK,QAAQ;EACxB,IAAI,CAAC,iBAAiB,IAAI,KAAK,CAAC,kBAAkB,QAAQ,GACxD,SAAS,KAAK,KAAK,IAAI;CAE3B;CAEA,IAAI,QAAQ,OAAO,IAAI;CAEvB,MAAM,SAAuB,EAAE,MAAM,SAAS;CAC9C,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GACnC,OAAO,aAAa;CAEtB,IAAI,SAAS,SAAS,GACpB,OAAO,WAAW;CAEpB,IAAI,iBACF,OAAO,uBAAuB,iBAC5B,iBACA,KACA,QAAQ,CACV;MACK,IAAI,UAAU,SAAS,GAG5B,OAAO,uBAAuB;CAMhC,MAAM,kBAAA,eAAiB,iBAAA,QAAA,iBAAA,KAAA,IAAA,eAAe,IAAI,UAAU,IAAI,IAAI;CAC5D,IAAI,gBAAgB;EAClB,IAAI,QAAQ,kBAAkB;EAC9B,OAAO,UAAU,cAAc;CACjC;CAEA,OAAO;AACT;AAEA,SAAS,kBACP,MACA,KACA,OACc;CACd,MAAM,YAAY,qBAAqB,MAAM,KAAK,KAAK;CACvD,IAAI,WACF,OAAO;CAGT,IAAI,IAAI,QAAQ,YAAY,IAAI,GAC9B,OAAO,iBAAiB,MAAM,KAAK,KAAK;CAE1C,IAAI,IAAI,QAAQ,YAAY,IAAI,GAC9B,OAAO,iBAAiB,MAAM,KAAK,KAAK;CAG1C,OAAO,mBAAmB,MAAM,KAAK,KAAK;AAC5C;;AAOA,SAAS,oBACP,MACA,KACA,OACc;CACd,IAAI,IAAI,QAAQ,IAAI,IAAI,GACtB,OAAO,gBAAgB,MAAM,GAAG;CAKlC,MAAM,YAAY,0BAA0B,MAF9B,KAAK,SAEmC,GAAG,IAAI,OAAO;CACpE,IAAI,WACF,OAAO;CAGT,IAAI,KAAK,QAAQ,GAAG;EAClB,IAAI,QAAQ,IAAI,IAAI;EACpB,MAAM,SAAS,iBAAiB,MAAM,KAAK,KAAK;EAChD,IAAI,QAAQ,OAAO,IAAI;EACvB,OAAO;CACT;CACA,IAAI,KAAK,eAAe,GAAG;EACzB,IAAI,QAAQ,IAAI,IAAI;EACpB,MAAM,SAAS,wBAAwB,MAAM,KAAK,KAAK;EACvD,IAAI,QAAQ,OAAO,IAAI;EACvB,OAAO;CACT;CACA,IAAI,eAAe,IAAI,GACrB,OAAO,CAAC;CAEV,IAAI,aAAa,IAAI,GACnB,OAAO,kBAAkB,MAAM,KAAK,KAAK;CAG3C,OAAO,CAAC;AACV;;;;;AAqBA,SAAS,qBACP,SACA,SAC8B;CAC9B,MAAM,UAAU,QAAQ,YAAY,MAAM;CAC1C,IAAI,CAAC,SACH,OAAO;CAET,MAAM,WAAW,QAAQ,gBAAgB,OAAO;CAChD,MAAM,MAAM,QAAQ,aAAa,QAAQ,CAAC,CAAC,QAAQ,SAAS,EAAE;CAC9D,IAAI,QAAQ,WAAW,QAAQ,cAAc,QAAQ,gBACnD,OAAO;CAET,OAAO;AACT;AAEA,SAAS,gBAAgB,WAAoC;CAC3D,IAAI,CAAC,WACH,OAAO;CAOT,IAJiC,QAC/B,WACA,GAAG,UAAU,OAAO,GAAG,UAAU,YAAY,GAAG,UAAU,KAEjC,GACzB,OAAO;CAQT,OAJE,UAAU,QAAQ,KAClB,UAAU,MAAM,OAAO,MACrB,QAAQ,GAAG,GAAG,UAAU,OAAO,GAAG,UAAU,SAAS,CACvD;AAEJ;AAUA,SAAS,gCAAgC,MAAsC;CAC7E,OAAO,SAAS;AAClB;AAEA,SAAS,0BAA0B,MAAe,MAAsB;CACtE,MAAM,aAAa,YAAY,IAAI;CACnC,IAAI,YACF,OAAO;CAGT,KAAK,MAAM,OAAO,CAAC,KAAK,aAAa,KAAK,UAAU,CAAC,CAAC,CAAC,QACpD,cAAsC,CAAC,CAAC,SAC3C,GAAG;;EACD,KAAK,MAAM,gBAAA,oBAAe,IAAI,kBAAA,QAAA,sBAAA,KAAA,IAAA,oBAAgB,CAAC,GAAG;;GAChD,MAAM,mBAAA,wBAAkB,GAAG,qBAAqB,WAAW,OAAA,QAAA,0BAAA,KAAA,IAAA,KAAA,IAAA,sBAAG,QAAQ;GACtE,IACE,mBACA,CAAC,gBAAgB,IAAI,eAAe,KACpC,CAAC,gBAAgB,WAAW,IAAI,GAEhC,OAAO;EAEX;CACF;CAEA,OAAO,GAAG,eAAe,IAAI,KAAK,YAAY;AAChD;;AAGA,SAAS,eAAe,MAAsB;CAC5C,OAAO,KACJ,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CAAC,CACf,KAAK,YACJ,QACG,MAAM,eAAe,CAAC,CACtB,OAAO,OAAO,CAAC,CACf,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAC3D,KAAK,EAAE,CACZ,CAAC,CACA,KAAK,EAAE;AACZ;AAEA,SAAS,kBAAkB,MAAwB;CACjD,OAAO,QAAQ,MAAM,GAAG,UAAU,UAAU,GAAG,UAAU,GAAG;AAC9D;AAEA,SAAS,8BAA8B,MAAwB;CAC7D,OACE,kBAAkB,IAAI,KACrB,aAAa,IAAI,KAChB,KAAK,cAAc,CAAC,CAAC,WAAW,KAChC,CAAC,KAAK,mBAAmB;AAE/B;AAEA,SAAS,0BACP,KACA,SACgB;;CAChB,IAAI,cAAoC;CACxC,KAAK,MAAM,gBAAA,wBAAe,IAAI,OAAO,kBAAA,QAAA,0BAAA,KAAA,IAAA,wBAAgB,CAAC,GAAG;EACvD,IAAI,GAAG,qBAAqB,WAAW,GAAG;GACxC,cAAc,YAAY;GAC1B;EACF;EACA,IAAI,GAAG,sBAAsB,WAAW,KAAK,YAAY,aAAa;GACpE,cAAc,YAAY;GAC1B;EACF;CACF;CACA,IAAI,CAAC,aACH,OAAO;CAGT,IAAI,YAA4B;CAEhC,MAAM,SAAS,SAA8B;EAC3C,IAAI,CAAC,GAAG,iBAAiB,IAAI,GAC3B;EAGF,MAAM,SAAS,KAAK;EACpB,IAAI,CAAC,GAAG,2BAA2B,MAAM,GACvC;EAGF,MAAM,OAAO,UAAU;EACvB,IAAI,OAAO,KAAK,SAAS,SACvB;EAGF,MAAM,CAAC,cAAc,KAAK;EAC1B,IAAI,CAAC,YACH;EAIF,MAAM,cADa,QAAQ,kBAAkB,UAChB,CAAC,CAAC,YAAY,WAAW;EACtD,IAAI,CAAC,aACH;EAOF,MAAM,WAJe,QAAQ,0BAC3B,aACA,UAE0B,CAAC,CAAC,YAAY,OAAO;EACjD,IAAI,CAAC,UACH;EAMF,MAAM,YAHY,QAAQ,mBACxB,QAAQ,0BAA0B,UAAU,UAAU,CAE9B,CAAC,CAAC,YAAY,QAAQ;EAChD,IAAI,CAAC,WACH;EAGF,MAAM,aAAa,QAAQ,0BAA0B,WAAW,UAAU;EAC1E,IAAI,CAAC,kBAAkB,UAAU,GAC/B,YAAY;CAEhB;CACA,MAAM,WAAW;CAEjB,OAAO;AACT;AAEA,SAAS,iBAAiB,KAAmB,KAAoB;;CAC/D,MAAM,EAAE,cAAc;CACtB,MAAM,EAAE,YAAY;CAEpB,MAAM,YAAY,IAAI,QAAQ,YAAY,QAAQ;CAClD,IAAI,CAAC,WACH;CAEF,MAAM,aAAa,QAAQ,gBAAgB,SAAS;CAEpD,MAAM,WAAW,WAAW,YAAY,OAAO;CAC/C,MAAM,YAAY,WAAW,YAAY,QAAQ;CAEjD,MAAM,YAAY,WAAW,QAAQ,gBAAgB,QAAQ,IAAI;CACjE,MAAM,aAAa,YAAY,QAAQ,gBAAgB,SAAS,IAAI;CACpE,MAAM,oBACJ,aAAa,8BAA8B,SAAS,KAAA,wBAC/C,0BAA0B,KAAK,OAAO,OAAA,QAAA,0BAAA,KAAA,IAAA,wBAAK,YAC5C;CAEN,IAAI,cAAmC;CACvC,IAAI,CAAC,qBAAqB,gBAAgB,iBAAiB,GAAG,CAE9D,OAAO;EAGL,MAAM,oCAAoC,SAAwB;GAChE,IAAI,UAAU,UAAU,IAAI,IAAI,GAC9B;GAGF,MAAM,UAAU,iBACd,0BAA0B,MAAM,IAAI,IAAI,GACxC,UAAU,OACZ;GACA,UAAU,UAAU,IAAI,MAAM,OAAO;GACrC,UAAU,QAAQ,WAAW,CAAC;EAChC;EAEA,IAAI,sBAAsB,WACxB,iCAAiC,iBAAiB;EAGpD,MAAM,gBAAgB,iBAAiB,mBAAmB,SAAS;EACnE,IACE,CAAC,iBAAiB,aAAa,KAC/B,CAAC,UAAU,UAAU,IAAI,iBAAiB,GAC1C;GACA,iCAAiC,iBAAiB;GAClD,cAAc,iBAAiB,mBAAmB,SAAS;EAC7D,OACE,cAAc;CAElB;CAEA,MAAM,eAAoC,aACtC,iBAAiB,YAAY,SAAS,IACtC;CAGJ,MAAM,eAAe,IAAI,oBAAoB,IAAI,IAAI,IAAI;CACzD,IAAI,cAAc;EAChB,MAAM,sBAAsB,oBAC1B,aACA,UAAU,OACZ;EACA,MAAM,uBAAuB,oBAC3B,cACA,UAAU,OACZ;EAEA,IAAI,uBAAuB,aAAa,OACtC,kBACE,qBACA,aAAa,OACb,UAAU,OACZ;EAEF,IAAI,wBAAwB,aAAa,QACvC,kBACE,sBACA,aAAa,QACb,UAAU,OACZ;CAEJ;CAEA,IAAI,WAAW,KAAK;EAClB,MAAM,IAAI;EACV,MAAM,IAAI;EACV;EACA;EACA,aAAa,4BAA4B,YAAY,GAAG;EACxD,aAAa,IAAI;CACnB,CAAC;AACH;AAEA,SAAS,4BACP,YACA,KACqB;CACrB,MAAM,EAAE,cAAc;CACtB,MAAM,WAAW,WAAW,YAAY,YAAY;CACpD,IAAI,CAAC,UACH,OAAO;CAGT,MAAM,EAAE,YAAY;CACpB,MAAM,YAAY,QAAQ,gBAAgB,QAAQ;CAClD,IACE,QAAQ,WAAW,GAAG,UAAU,GAAG,KACnC,kBAAkB,SAAS,KAC3B,6BAA6B,WAAW,IAAI,iBAAiB,OAAO,GAEpE,OAAO;CAGT,MAAM,SAAS,iBAAiB,WAAW,SAAS;CACpD,OAAO,iBAAiB,MAAM,IAAI,SAAS;AAC7C;AAEA,SAAS,6BACP,WACA,iBACA,SACS;CACT,IAAI,CAAC,iBACH,OAAO;CAET,IAAI,cAAc,iBAChB,OAAO;CAGT,MAAM,YAAY,SAChB,QAAQ,aACN,MACA,KAAA,GACA,GAAG,gBAAgB,eACjB,GAAG,gBAAgB,qBACvB;CACF,MAAM,gBAAgB,SACpB,KAAK,QAAQ,IAAI,KAAK,QAAQ,CAAC,IAAI;CAErC,MAAM,gBAAgB,IAAI,IAAI,aAAa,eAAe,CAAC,CAAC,IAAI,QAAQ,CAAC;CAEzE,OAAO,aAAa,SAAS,CAAC,CAAC,OAAO,WACpC,cAAc,IAAI,SAAS,MAAM,CAAC,CACpC;AACF;;AAGA,SAAS,gBACP,KACA,SACoB;;CACpB,MAAM,aAAa,aAA6B,SAAS,QAAQ,OAAO,GAAG;CAE3E,MAAM,gBAAA,qBAAe,IAAI,kBAAA,QAAA,uBAAA,KAAA,IAAA,qBAAgB,CAAC;CA4B1C,IA1BE,aAAa,SAAS,KACtB,aAAa,OAAO,gBAAgB;EAClC,MAAM,aAAa,YAAY,cAAc;EAC7C,IAAI,CAAC,WAAW,mBACd,OAAO;EAIT,IAAI,CADoB,UAAU,WAAW,QAC1B,CAAC,CAAC,SAAS,gBAAgB,GAC5C,OAAO;EAGT,IAAI;GAKF,IAAI,CAJa,UAAU,GAAG,aAAa,OAAO,WAAW,QAAQ,CAIzD,CAAC,CAAC,SAAS,gBAAgB,GACrC,OAAO;EAEX,SAAA,SAAQ,CAER;EAEA,OAAO;CACT,CAAC,GAED;CAGF,MAAM,QAAQ,IAAI,wBAAwB,OAAO;CACjD,IAAI,MAAM,WAAW,GACnB;CAGF,OADa,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,EACjC,KAAK,KAAA;AACjB;AAUA,SAAS,SAAS,MAA0B;CAC1C,MAAM,EAAE,MAAM,KAAK,aAAa,aAAa,WAAW;CACxD,IAAI,IAAI,KAAK,IAAI,IAAI,GACnB;CAGF,MAAM,SAAS,KAAK,YAAY,MAAM;CAEtC,IAAI,CAAC,QAAQ;EAGX,IAAI,aAAa,IAAI,GAAG;GACtB,IAAI,KAAK,IAAI,IAAI;GACjB,WAAW,MAAM,KAAK,WAAW;GACjC,IAAI,KAAK,OAAO,IAAI;EACtB;EACA;CACF;CAEA,MAAM,EAAE,YAAY,IAAI;CACxB,MAAM,UAAU,QAAQ,gBAAgB,MAAM;CAE9C,MAAM,oBAAoB,qBAAqB,SAAS,OAAO;CAC/D,IAAI,mBAAmB;;EACrB,IAAI,CAAC,gCAAgC,iBAAiB,GACpD;EAGF,iBACE;GACE;GACA,UAAU;GACV,MAAM;GACN;GACA,SAAA,OAAQ,WAAA,QAAA,WAAA,KAAA,IAAA,SAAU,KAAK,UAAU,OAAA,QAAA,SAAA,KAAA,IAAA,OAAK;EACxC,GACA,GACF;EACA;CACF;CAGA,MAAM,YAAY,QAAQ,YAAY,QAAQ;CAC9C,IAAI,CAAC,WACH;CAKF,IAAI,EADF,QAAQ,aAAa,QAAQ,gBAAgB,SAAS,CAAC,MAAM,SAE7D;CAGF,MAAM,YAAY,QAAQ,YAAY,QAAQ;CAC9C,IAAI,CAAC,WACH;CAGF,IAAI,KAAK,IAAI,IAAI;CAEjB,WADmB,QAAQ,gBAAgB,SACvB,GAAG,KAAK,WAAW;CACvC,IAAI,KAAK,OAAO,IAAI;AACtB;AAEA,SAAS,WAAW,YAAqB,KAAc,QAAsB;CAC3E,KAAK,MAAM,QAAQ,WAAW,cAAc,GAI1C,SAAS;EACP,MAJe,IAAI,UAAU,QAAQ,gBAAgB,IAIxC;EACb;EACA,aALe,SAAS,GAAG,OAAO,GAAG,KAAK,SAAS,KAAK;EAMxD,aALkB,gBAAgB,MAAM,IAAI,UAAU,OAK5C;EACV,QAAQ;CACV,CAAC;AAEL;AAMA,SAAS,oBAAoB,UAAsC;CACjE,MAAM,aAAa,GAAG,eACpB,WACC,MAAM,GAAG,IAAI,WAAW,CAAC,GAC1B,eACF;CACA,IAAI,CAAC,YACH,OAAO;EACL,QAAQ,GAAG,aAAa;EACxB,kBAAkB,GAAG,qBAAqB;EAC1C,cAAc;EACd,QAAQ;CACV;CAGF,MAAM,aAAa,GAAG,eAAe,aAAa,MAAM,GAAG,IAAI,SAAS,CAAC,CAAC;CAC1E,MAAM,SAAS,GAAG,2BAChB,WAAW,QACX,GAAG,KACH,KAAK,QAAQ,UAAU,CACzB;CACA,MAAM,UAAA,eAAA,eAAA,CAAA,GAAmC,OAAO,OAAA,GAAA,CAAA,GAAA,EAAS,QAAQ,KAAA,CAAK;CAKtE,IAAI,QAAQ,qBAAqB,KAAA,GAAW;EAC1C,MAAM,MAAM,QAAQ;EACpB,IAAI,QAAQ,GAAG,WAAW,UAAU,QAAQ,GAAG,WAAW,UACxD,QAAQ,mBAAmB,GAAG,qBAAqB;OAC9C,IACL,QAAQ,GAAG,WAAW,YACtB,QAAQ,GAAG,WAAW,UACtB,QAAQ,GAAG,WAAW,QAEtB,QAAQ,mBAAmB,GAAG,qBAAqB;OAEnD,QAAQ,mBAAmB,GAAG,qBAAqB;CAEvD;CAEA,OAAO;AACT;;;;;;AAWA,SAAS,mBACP,YACA,SACgB;CAChB,MAAM,QAAQ,MAAe,SAAmC;EAC9D,MAAM,CAAC,MAAM,GAAG,QAAQ;EACxB,IAAI,CAAC,MACH,OAAO;EAET,MAAM,MAAM,KAAK,YAAY,IAAI;EACjC,IAAI,CAAC,KACH,OAAO;EAET,OAAO,KAAK,QAAQ,gBAAgB,GAAG,GAAG,IAAI;CAChD;CAEA,MAAM,iBAAiB,KAAK,YAAY;EACtC;EACA;EACA;EACA;CACF,CAAC;CACD,IAAI,CAAC,kBAAkB,QAAQ,gBAAgB,GAAG,UAAU,GAAG,GAC7D,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,mBACP,YACA,SACA,WACqB;CACrB,MAAM,iBAAiB,mBAAmB,YAAY,OAAO;CAC7D,IAAI,CAAC,gBACH,OAAO;CAGT,OAAO,iBAAiB,gBAAgB,SAAS;AACnD;AAMA,SAAS,oBAAoB,aAAyC;CACpE,OAAO;EACL,MAAM;EACN,YAAY,EAAE,OAAO,YAAY;EACjC,UAAU,CAAC,OAAO;CACpB;AACF;;AAGA,MAAM,uBAAqC;CACzC,MAAM;CACN,YAAY;EACV,SAAS,EAAE,MAAM,SAAS;EAC1B,MAAM,EAAE,MAAM,SAAS;EACvB,MAAM,EAAE,MAAM,SAAS;CACzB;CACA,UAAU,CAAC,WAAW,MAAM;AAC9B;;;;;;;;;;AAWA,SAAS,sBACP,cACc;CACd,MAAM,YAAY,iBAAiB,QAAQ,iBAAiB,YAAY;CAQxE,OAAO;EACL,MAAM;EACN,YAAY,EACV,QAAA,eAAA;GATF,MAAM;GACN,YAAA,eAAA,CAAA,GACM,YAAY,EAAE,MAAM,aAAa,IAAI,CAAC,CAC5C;EACI,GAAA,YAAY,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAKrB,EACrB;EACA,UAAU,CAAC,QAAQ;CACrB;AACF;AAEA,SAAS,wBACP,MACA,QACA,kBACiB;CACjB,MAAM,CAAC,MAAM,KAAK,QAAQ,KAAK,KAAK,MAAM,GAAG;CAC7C,MAAM,YAAA,eAAA,eAAA,EACJ,aAAa,KAAK,KAAA,GACd,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC,CAAA,GAAA,CAAA,GAAA;EAC5D,MAAM,CAAC,GAAG;EACV,WAAW;GACT,OAAO;IACL,aAAa;IACb,SAAS,EACP,oBAAoB,EAClB,QAAQ,sBAAsB,KAAK,YAAY,EACjD,EACF;GACF;GACA,SAAS,EAAE,MAAM,iBAAiB;EACpC;CACF,CAAA;CAEA,IAAI,KAAK,gBAAgB,MACvB,OAAO;CAGT,IAAI,WAAW,OACb,UAAU,aAAa,CACrB;EACE,MAAM;EACN,IAAI;EACJ,UAAU;EAGV,OAAO;EACP,SAAS,EAAE,oBAAoB,EAAE,QAAQ,KAAK,YAAY,EAAE;CAC9D,CACF;MAEA,UAAU,cAAc;EACtB,UAAU;EACV,SAAS,EAAE,oBAAoB,EAAE,QAAQ,KAAK,YAAY,EAAE;CAC9D;CAGF,OAAO;AACT;AAEA,SAAS,mBAAmB,QAAsC;CAChE,OAAO;EACL,aAAa;EACb,SAAS,EACP,oBAAoB,EAAE,QAAQ,oBAAoB,MAAM,EAAE,EAC5D;CACF;AACF;AAEA,SAAS,oBACP,YACA,mBACA,SAIA;CACA,MAAM,YAA4C,EAChD,OAAO,mBAAmB,iBAAiB,EAC7C;CACA,MAAM,YAAY,WAChB,aAAa,eAAe,QAAQ,OAAO,CAAC;CAC9C,MAAM,6BAAa,IAAI,IAAoB,CACzC,CAAC,SAAS,iBAAiB,GAAG,8BAA8B,CAC9D,CAAC;CACD,MAAM,qCAAqB,IAAI,IAAoB;CAEnD,KAAK,MAAM,QAAQ,YAAY;EAC7B,IAAI,CAAC,KAAK,aACR;EAGF,MAAM,MAAM,SAAS,KAAK,WAAW;EACrC,IAAI,MAAM,WAAW,IAAI,GAAG;EAC5B,IAAI,CAAC,KAAK;GAER,MAAM,OAAO,GAAG,eAAe,KAAK,IAAI,KAAK,YAAY;GACzD,MAAM,QAAQ,UAAU,KAAK,WAAW,IACpC,KAAK,cACL,eAAe,GAAG,KAAK,QAAQ,KAAK,aAAa,OAAO;GAC5D,MAAM,eAAe,iBAAiB,MAAM,SAAS;GACrD,UAAU,gBAAgB,mBAAmB,KAAK;GAClD,MAAM,0BAA0B;GAChC,WAAW,IAAI,KAAK,GAAG;EACzB;EACA,mBAAmB,IAAI,KAAK,MAAM,GAAG;CACvC;CAEA,OAAO;EAAE;EAAW;CAAmB;AACzC;AAEA,SAAS,eACP,MACA,QACA,SACc;CACd,MAAM,UAAU,iBAAiB,MAAM,OAAO;CAC9C,QAAQ,WAAW;CACnB,OAAO,EAAE,MAAM,wBAAwB,UAAU;AACnD;AAEA,SAAS,qBACP,YACA,SACA,OAAmB,EAAE,aAAa,KAAK,GAC7B;;CACV,MAAM,QAAqB,CAAC;CAC5B,MAAM,WAAW,WAAW,QAAQ,SAClC,gCAAgC,KAAK,IAAI,CAC3C;CAEA,MAAM,WAAA,gBAAU,KAAK,aAAA,QAAA,kBAAA,KAAA,IAAA,gBAAW,CAAC;CACjC,MAAM,EAAE,WAAW,gBAAgB,uBAAuB,oBACxD,WAAA,oBACA,KAAK,iBAAA,QAAA,sBAAA,KAAA,IAAA,oBAAe,sBACpB,OACF;CAEA,KAAK,MAAM,QAAQ,UAAU;;EAC3B,MAAM,SAAS,IAAI,KAAK;EACxB,MAAM,SAAS,KAAK,SAAS,UAAU,QAAQ;EAE/C,MAAM,YAAA,gBAA2B,MAAM,aAAA,QAAA,kBAAA,KAAA,IAAA,gBAAW,CAAC;EACnD,MAAM,UAAU;EAChB,SAAS,UAAU,wBACjB,MACA,SAAA,wBACA,mBAAmB,IAAI,KAAK,IAAI,OAAA,QAAA,0BAAA,KAAA,IAAA,wBAAK,8BACvC;CACF;CAEA,MAAM,kBAAkB,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS;CAEtD,OAAA,eAAA,eAAA;EACE,SAAS;EACT,mBAAmB;EACnB,MAAM;GACJ,QAAA,iBAAO,QAAQ,WAAA,QAAA,mBAAA,KAAA,IAAA,iBAAS;GACxB,UAAA,mBAAS,QAAQ,aAAA,QAAA,qBAAA,KAAA,IAAA,mBAAW;EAC9B;CACI,KAAA,mBAAA,QAAQ,aAAA,QAAA,qBAAA,KAAA,IAAA,KAAA,IAAA,iBAAS,UAAS,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC,CAAA,GAAA,CAAA,GAAA;EAC9D;EACA,YAAA,eAAA,eAAA,CAAA,GACM,kBAAkB,EAAE,QAAQ,IAAI,CAAC,CAAA,GAAA,CAAA,GAAA,EACrC,WAAW,eAAA,CACb;CACF,CAAA;AACF;;;;;;;;;AAcA,eAAsB,wBACpB,gBACA,UAA2B,CAAC,GACT;;CACnB,MAAM,eAAe,KAAK,QAAQ,cAAc;CAChD,MAAM,cAAA,sBAAa,QAAQ,gBAAA,QAAA,wBAAA,KAAA,IAAA,sBAAc;CAEzC,MAAM,kBAAkB,oBAAoB,KAAK,QAAQ,YAAY,CAAC;CACtE,MAAM,UAAU,GAAG,cAAc,CAAC,YAAY,GAAG,eAAe;CAChE,MAAM,UAAU,QAAQ,eAAe;CACvC,MAAM,aAAa,QAAQ,cAAc,YAAY;CAErD,IAAI,CAAC,YACH,MAAM,IAAI,MAAM,mCAAmC,cAAc;CAGnE,MAAM,eAAe,QAAQ,oBAAoB,UAAU;CAC3D,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,+BAA+B,cAAc;CAG/D,MAAM,YAAY,QAAQ,mBAAmB,YAAY;CACzD,MAAM,eAAe,UAAU,MAAM,QAAQ,IAAI,QAAQ,MAAM,UAAU;CAEzE,IAAI,CAAC,cAAc;EACjB,MAAM,YAAY,UAAU,KAAK,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI;EAC7D,MAAM,IAAI,MACR,oBAAoB,WAAW,cAAc,aAAa,uBAClC,aAAa,UACvC;CACF;CAIA,IAAI;CACJ,IAAI,aAAa,kBACf,aAAa,QAAQ,0BACnB,cACA,aAAa,gBACf;MAEA,aAAa,QAAQ,wBAAwB,YAAY;CAG3D,MAAM,YAAuB;EAC3B;EACA,yBAAS,IAAI,IAAI;EACjB,SAAS,CAAC;EACV,2BAAW,IAAI,IAAI;CACrB;CAGA,MAAM,sCAAsB,IAAI,IAAiC;CACjE,MAAM,SAAS,MAAM,gBAAgB,cAAc,UAAU;CAC7D,IAAI,QACF,2BAA2B,QAAQ,IAAI,mBAAmB;CAG5D,MAAM,UAAmB;EACvB,YAAY,CAAC;EACb,sBAAM,IAAI,IAAI;EACd;EACA;EACA,iBAAiB,mBAAmB,YAAY,OAAO;CACzD;CACA,SAAS;EAAE,MAAM;EAAY,KAAK;EAAS,aAAa;CAAG,CAAC;CAE5D,MAAM,cAAc,mBAAmB,YAAY,SAAS,SAAS;CACrE,OAAO,qBAAqB,QAAQ,YAAY,SAAS;EACvD;EACA,SAAS,UAAU;CACrB,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"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 ResponseObject,\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 errorSchema: 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\nconst STANDARD_FUNCTION_INTERFACES = new Set([\n 'Function',\n 'CallableFunction',\n 'NewableFunction',\n]);\n\nfunction isStandardFunctionInterface(type: ts.Type): boolean {\n const symbol = type.getSymbol();\n const name = symbol?.getName();\n if (!name || !STANDARD_FUNCTION_INTERFACES.has(name)) {\n return false;\n }\n return (\n symbol?.declarations?.some((d) =>\n /(^|[\\\\/])lib\\.[^\\\\/]*\\.d\\.ts$/.test(d.getSourceFile().fileName),\n ) ?? false\n );\n}\n\nfunction isFunctionType(type: ts.Type): boolean {\n return (\n type.getCallSignatures().length > 0 ||\n type.getConstructSignatures().length > 0 ||\n isStandardFunctionInterface(type)\n );\n}\n\nfunction hasFunctionMember(type: ts.Type): boolean {\n if (isFunctionType(type)) {\n return true;\n }\n return type.isUnion() && type.types.some(isFunctionType);\n}\n\nfunction isUnserialisableType(type: ts.Type): boolean {\n if (isFunctionType(type)) {\n return true;\n }\n if (!type.isUnion() || !type.types.some(isFunctionType)) {\n return false;\n }\n // Once callables are dropped, a union of nothing but `null` / `undefined`\n // describes no value worth emitting.\n return !type.types.some(\n (m) =>\n !isFunctionType(m) &&\n !hasFlag(\n m,\n ts.TypeFlags.Undefined | ts.TypeFlags.Void | ts.TypeFlags.Null,\n ),\n );\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) =>\n !hasFlag(m, ts.TypeFlags.Undefined | ts.TypeFlags.Void) &&\n !isFunctionType(m),\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 const distinctSchemas = dedupeSchemas(schemas, ctx.schemas);\n if (distinctSchemas.length === 0) {\n return {};\n }\n\n const [firstSchema] = distinctSchemas;\n if (distinctSchemas.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 (distinctSchemas.every(isSimpleTypeSchema)) {\n return { type: distinctSchemas.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(distinctSchemas);\n if (discriminatorProp) {\n return {\n oneOf: distinctSchemas,\n discriminator: { propertyName: discriminatorProp },\n };\n }\n\n return { oneOf: distinctSchemas };\n}\n\nfunction dedupeSchemas(\n schemas: SchemaObject[],\n components: Record<string, SchemaObject>,\n): SchemaObject[] {\n const seen = new Set<string>();\n\n return schemas.filter((schema) => {\n const key = canonicalize(resolveBareRef(schema, components));\n if (seen.has(key)) {\n return false;\n }\n seen.add(key);\n return true;\n });\n}\n\n/**\n * A `$ref` on its own describes exactly the component it points at, so compare\n * through the component - otherwise the same shape reached both by reference\n * and inline looks like two distinct schemas.\n */\nfunction resolveBareRef(\n schema: SchemaObject,\n components: Record<string, SchemaObject>,\n): SchemaObject {\n if (!isBareRef(schema)) {\n return schema;\n }\n const target = getReferencedSchema(schema, components);\n // A component mid-conversion is still an empty placeholder (cyclic types);\n // compare those by their `$ref` so distinct ones stay distinct.\n return target && isNonEmptySchema(target) ? target : schema;\n}\n\n/** A `$ref` with no sibling keys, i.e. one that stands for its component. */\nfunction isBareRef(schema: SchemaObject): boolean {\n return schema.$ref !== undefined && Object.keys(schema).length === 1;\n}\n\nfunction canonicalize(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map(canonicalize).join(',')}]`;\n }\n\n if (value && typeof value === 'object') {\n const entries = Object.entries(value)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n .map(([k, v]) => `${JSON.stringify(k)}:${canonicalize(v)}`);\n return `{${entries.join(',')}}`;\n }\n return JSON.stringify(value) ?? 'undefined';\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 propSchema?.const !== undefined && s.required?.includes(prop);\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 if (isUnserialisableType(propType)) {\n continue;\n }\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) && !hasFunctionMember(propType)) {\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 (typeProps.length > 0) {\n // Closed shape. Stays closed even when every property was filtered out,\n // so the result reads as \"no keys\" rather than \"any keys\".\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 (isFunctionType(type)) {\n return {};\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 /** The router-wide error shape, used to spot procedures that differ from it. */\n routerErrorType: ts.Type | null;\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 return `${pascalCasePath(path) || 'Procedure'}Input`;\n}\n\n/** `user.getById` → `UserGetById`, for naming components after a procedure. */\nfunction pascalCasePath(path: string): string {\n return 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\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 errorSchema: extractProcedureErrorSchema($typesType, ctx),\n description: def.description,\n });\n}\n\nfunction extractProcedureErrorSchema(\n $typesType: ts.Type,\n ctx: WalkCtx,\n): SchemaObject | null {\n const { schemaCtx } = ctx;\n const errorSym = $typesType.getProperty('errorShape');\n if (!errorSym) {\n return null;\n }\n\n const { checker } = schemaCtx;\n const errorType = checker.getTypeOfSymbol(errorSym);\n if (\n hasFlag(errorType, ts.TypeFlags.Any) ||\n isUnknownLikeType(errorType) ||\n addsNothingToRouterErrorType(errorType, ctx.routerErrorType, checker)\n ) {\n return null;\n }\n\n const schema = typeToJsonSchema(errorType, schemaCtx);\n return isNonEmptySchema(schema) ? schema : null;\n}\n\nfunction addsNothingToRouterErrorType(\n errorType: ts.Type,\n routerErrorType: ts.Type | null,\n checker: ts.TypeChecker,\n): boolean {\n if (!routerErrorType) {\n return false;\n }\n if (errorType === routerErrorType) {\n return true;\n }\n\n const describe = (type: ts.Type) =>\n checker.typeToString(\n type,\n undefined,\n ts.TypeFormatFlags.NoTruncation |\n ts.TypeFormatFlags.UseFullyQualifiedType,\n );\n const unionMembers = (type: ts.Type) =>\n type.isUnion() ? type.types : [type];\n\n const routerMembers = new Set(unionMembers(routerErrorType).map(describe));\n\n return unionMembers(errorType).every((member) =>\n routerMembers.has(describe(member)),\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 getRouterErrorType(\n routerType: ts.Type,\n checker: ts.TypeChecker,\n): ts.Type | 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 || hasFlag(errorShapeType, ts.TypeFlags.Any)) {\n return null;\n }\n\n return errorShapeType;\n}\n\nfunction extractErrorSchema(\n routerType: ts.Type,\n checker: ts.TypeChecker,\n schemaCtx: SchemaCtx,\n): SchemaObject | null {\n const errorShapeType = getRouterErrorType(routerType, checker);\n if (!errorShapeType) {\n return null;\n }\n\n return typeToJsonSchema(errorShapeType, schemaCtx);\n}\n\n// ---------------------------------------------------------------------------\n// OpenAPI document builder\n// ---------------------------------------------------------------------------\n\nfunction wrapInErrorEnvelope(errorSchema: SchemaObject): SchemaObject {\n return {\n type: 'object',\n properties: { error: errorSchema },\n required: ['error'],\n };\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 errorResponseRef: string,\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: errorResponseRef },\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 buildErrorResponse(schema: SchemaObject): ResponseObject {\n return {\n description: 'Error response',\n content: {\n 'application/json': { schema: wrapInErrorEnvelope(schema) },\n },\n };\n}\n\nfunction buildErrorResponses(\n procedures: ProcedureInfo[],\n routerErrorSchema: SchemaObject,\n schemas: Record<string, SchemaObject>,\n): {\n responses: Record<string, ResponseObject>;\n refByProcedurePath: Map<string, string>;\n} {\n const responses: Record<string, ResponseObject> = {\n Error: buildErrorResponse(routerErrorSchema),\n };\n const shapeKey = (schema: SchemaObject) =>\n canonicalize(resolveBareRef(schema, schemas));\n const refByShape = new Map<string, string>([\n [shapeKey(routerErrorSchema), '#/components/responses/Error'],\n ]);\n const refByProcedurePath = new Map<string, string>();\n\n for (const proc of procedures) {\n if (!proc.errorSchema) {\n continue;\n }\n\n const key = shapeKey(proc.errorSchema);\n let ref = refByShape.get(key);\n if (!ref) {\n // A shape that already is a component needs no second name for it.\n const name = `${pascalCasePath(proc.path) || 'Procedure'}Error`;\n const shape = isBareRef(proc.errorSchema)\n ? proc.errorSchema\n : registerSchema(`${name}Shape`, proc.errorSchema, schemas);\n const responseName = ensureUniqueName(name, responses);\n responses[responseName] = buildErrorResponse(shape);\n ref = `#/components/responses/${responseName}`;\n refByShape.set(key, ref);\n }\n refByProcedurePath.set(proc.path, ref);\n }\n\n return { responses, refByProcedurePath };\n}\n\nfunction registerSchema(\n name: string,\n schema: SchemaObject,\n schemas: Record<string, SchemaObject>,\n): SchemaObject {\n const refName = ensureUniqueName(name, schemas);\n schemas[refName] = schema;\n return { $ref: `#/components/schemas/${refName}` };\n}\n\nfunction buildOpenAPIDocument(\n procedures: ProcedureInfo[],\n options: GenerateOptions,\n meta: RouterMeta = { errorSchema: null },\n): Document {\n const paths: PathsObject = {};\n const included = procedures.filter((proc) =>\n shouldIncludeProcedureInOpenAPI(proc.type),\n );\n\n const schemas = meta.schemas ?? {};\n const { responses: errorResponses, refByProcedurePath } = buildErrorResponses(\n included,\n meta.errorSchema ?? DEFAULT_ERROR_SCHEMA,\n schemas,\n );\n\n for (const proc of included) {\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 refByProcedurePath.get(proc.path) ?? '#/components/responses/Error',\n ) as PathItemObject[typeof method];\n }\n\n const hasNamedSchemas = Object.keys(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 ? { schemas } : {}),\n responses: errorResponses,\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 routerErrorType: getRouterErrorType(routerType, checker),\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 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,13 +2,12 @@
|
|
|
2
2
|
"name": "@trpc/openapi",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "11.
|
|
5
|
+
"version": "11.23.0-alpha",
|
|
6
6
|
"description": "OpenAPI document generator for tRPC routers",
|
|
7
7
|
"author": "KATT",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"bin": {
|
|
10
|
-
"trpc-openapi": "./dist/cli.mjs"
|
|
11
|
-
"intent": "./bin/intent.js"
|
|
10
|
+
"trpc-openapi": "./dist/cli.mjs"
|
|
12
11
|
},
|
|
13
12
|
"homepage": "https://trpc.io",
|
|
14
13
|
"repository": {
|
|
@@ -16,18 +15,11 @@
|
|
|
16
15
|
"url": "git+https://github.com/trpc/trpc.git",
|
|
17
16
|
"directory": "packages/openapi"
|
|
18
17
|
},
|
|
19
|
-
"eslintConfig": {
|
|
20
|
-
"rules": {
|
|
21
|
-
"no-restricted-imports": [
|
|
22
|
-
"error",
|
|
23
|
-
"@trpc/openapi"
|
|
24
|
-
]
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
18
|
"scripts": {
|
|
28
19
|
"build": "tsdown",
|
|
20
|
+
"prepack": "node ../../www/build/skills.ts --package .",
|
|
29
21
|
"dev": "tsdown --watch",
|
|
30
|
-
"lint": "
|
|
22
|
+
"lint": "oxlint src",
|
|
31
23
|
"codegen": "tsx test/scripts/codegen.run.ts",
|
|
32
24
|
"typecheck": "tsc --noEmit --preserveWatchOutput --pretty"
|
|
33
25
|
},
|
|
@@ -66,9 +58,7 @@
|
|
|
66
58
|
"!**/__tests__",
|
|
67
59
|
"!test",
|
|
68
60
|
"heyapi",
|
|
69
|
-
"skills"
|
|
70
|
-
"bin",
|
|
71
|
-
"!skills/_artifacts"
|
|
61
|
+
"skills"
|
|
72
62
|
],
|
|
73
63
|
"publishConfig": {
|
|
74
64
|
"access": "public"
|
|
@@ -79,12 +69,13 @@
|
|
|
79
69
|
"devDependencies": {
|
|
80
70
|
"@hey-api/openapi-ts": "^0.99.0",
|
|
81
71
|
"@swagger-api/apidom-ls": "^1.6.0",
|
|
82
|
-
"@tanstack/intent": "
|
|
83
|
-
"@trpc/server": "11.
|
|
72
|
+
"@tanstack/intent": "0.5.6",
|
|
73
|
+
"@trpc/server": "11.23.0",
|
|
84
74
|
"@types/node": "^24.13.4",
|
|
85
75
|
"bson": "^7.2.0",
|
|
86
|
-
"eslint": "^10.10.0",
|
|
87
76
|
"ion-js": "^5.2.1",
|
|
77
|
+
"oxlint": "^1.90.0",
|
|
78
|
+
"oxlint-tsgolint": "^7.0.2005",
|
|
88
79
|
"superjson": "^1.12.4",
|
|
89
80
|
"tsdown": "0.23.0",
|
|
90
81
|
"typescript": "^6.0.3",
|
|
@@ -94,7 +85,7 @@
|
|
|
94
85
|
},
|
|
95
86
|
"peerDependencies": {
|
|
96
87
|
"@hey-api/openapi-ts": ">=0.94.5",
|
|
97
|
-
"@trpc/server": "11.
|
|
88
|
+
"@trpc/server": "11.23.0",
|
|
98
89
|
"typescript": ">=5.8.2 <7",
|
|
99
90
|
"zod": ">=4.0.0"
|
|
100
91
|
},
|
|
@@ -112,5 +103,5 @@
|
|
|
112
103
|
"keywords": [
|
|
113
104
|
"tanstack-intent"
|
|
114
105
|
],
|
|
115
|
-
"gitHead": "
|
|
106
|
+
"gitHead": "c3c5ebb95499dc8e91b639013c22d695be8c3cf8"
|
|
116
107
|
}
|
package/skills/openapi/SKILL.md
CHANGED
|
@@ -1,128 +1,117 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openapi
|
|
3
|
-
description:
|
|
4
|
-
Generate OpenAPI 3.1 spec from a tRPC router with @trpc/openapi CLI or
|
|
5
|
-
programmatic API. Generate typed REST client with @hey-api/openapi-ts and
|
|
6
|
-
configureTRPCHeyApiClient(). Configure transformers (superjson, EJSON) for
|
|
7
|
-
generated clients. Alpha status.
|
|
8
|
-
type: composition
|
|
9
|
-
library: trpc
|
|
10
|
-
library_version: '11.16.0-alpha'
|
|
3
|
+
description: Generate OpenAPI 3.1 spec from a tRPC router with @trpc/openapi CLI (trpc-openapi) or generateOpenAPIDocument(). Generate typed REST client with @hey-api/openapi-ts, createTRPCHeyApiTypeResolvers() and configureTRPCHeyApiClient(), and read results from result.data. Configure transformers (superjson, EJSON) for generated clients. Compare spec versions with oasdiff. Alpha status.
|
|
11
4
|
requires:
|
|
12
5
|
- server-setup
|
|
13
6
|
sources:
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
- www/v11/docs/openapi.md
|
|
8
|
+
metadata:
|
|
9
|
+
type: composition
|
|
10
|
+
library: trpc
|
|
11
|
+
library_version: 11.23.0-alpha
|
|
17
12
|
---
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
<!-- Generated from www/v11/docs/openapi.md by www/build/skills.ts. Edit the docs instead. -->
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
# OpenAPI (alpha)
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
From https://trpc.io/docs/openapi
|
|
24
19
|
|
|
25
|
-
|
|
20
|
+
> [!WARNING] Caution
|
|
21
|
+
> This package is in alpha. APIs may change without notice.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
The `@trpc/openapi` package generates an OpenAPI 3.1 specification from your tRPC router. Use the spec to:
|
|
25
|
+
|
|
26
|
+
- Generate a typed API client in any language
|
|
27
|
+
- Call tRPC endpoints via HTTP tools like Postman or Insomnia
|
|
28
|
+
- Enable AI agent integrations such as MCP servers
|
|
29
|
+
|
|
30
|
+
## Install
|
|
26
31
|
|
|
27
32
|
```bash
|
|
28
33
|
pnpm add @trpc/openapi
|
|
29
34
|
```
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
> [!NOTE]
|
|
37
|
+
> `@trpc/openapi` is currently versioned like 11.x.x-alpha, and should work with any recent tRPC v11 version, but as always we recommend aligning the version numbers
|
|
32
38
|
|
|
33
|
-
```bash
|
|
34
|
-
pnpm add @hey-api/openapi-ts -D
|
|
35
|
-
```
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
## Adapting your tRPC setup
|
|
41
|
+
|
|
42
|
+
The generator works with your existing router — no annotations or decorators required. A few things to be aware of:
|
|
43
|
+
|
|
44
|
+
- **No output types needed** — unlike other OpenAPI tools, `.output()` schemas are optional. The generator infers return types from your implementation automatically.
|
|
45
|
+
- **Transformers** — if your server uses a [data transformer](https://trpc.io/docs/server/data-transformers), your OpenAPI clients must use the same one. See [Transformers](https://trpc.io/docs/openapi#transformers) for setup and cross-language options.
|
|
46
|
+
- **Subscriptions** — currently excluded from the generated spec. SSE support is planned.
|
|
47
|
+
- **Descriptions** — Zod `.describe()` calls and JSDoc comments on types, routers, and procedures, all become `description` fields in the spec.
|
|
38
48
|
|
|
39
|
-
|
|
49
|
+
## Generate the spec
|
|
40
50
|
|
|
41
|
-
|
|
51
|
+
### CLI
|
|
42
52
|
|
|
43
53
|
```bash
|
|
44
|
-
pnpm exec trpc-openapi ./src/server/
|
|
54
|
+
pnpm exec trpc-openapi ./src/server/router.ts
|
|
45
55
|
```
|
|
46
56
|
|
|
47
|
-
| Option | Default | Description
|
|
48
|
-
| --------------------- | -------------- |
|
|
49
|
-
| `-e, --export <name>` | `AppRouter` | Name of the exported router |
|
|
50
|
-
| `-o, --output <file>` | `openapi.json` | Output file path
|
|
51
|
-
| `--title <text>` | `tRPC API` | OpenAPI `info.title`
|
|
52
|
-
| `--version <ver>` | `0.0.0` | OpenAPI `info.version`
|
|
57
|
+
| Option | Default | Description |
|
|
58
|
+
| --------------------- | -------------- | -------------------------------------------------------------------- |
|
|
59
|
+
| `-e, --export <name>` | `AppRouter` | Name of the exported router type |
|
|
60
|
+
| `-o, --output <file>` | `openapi.json` | Output file path |
|
|
61
|
+
| `--title <text>` | `tRPC API` | OpenAPI `info.title` |
|
|
62
|
+
| `--version <ver>` | `0.0.0` | OpenAPI `info.version` |
|
|
63
|
+
| `--server-url <url>` | | Base URL (including any prefix), e.g. `https://api.example.com/trpc` |
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
```bash
|
|
66
|
+
pnpm exec trpc-openapi ./src/server/router.ts -o api.json --title "My API" --version 1.0.0 --server-url https://api.example.com/trpc
|
|
67
|
+
```
|
|
55
68
|
|
|
56
|
-
|
|
69
|
+
### Programmatic
|
|
70
|
+
|
|
71
|
+
```ts title="scripts/generate-openapi.ts"
|
|
57
72
|
import { generateOpenAPIDocument } from '@trpc/openapi';
|
|
58
73
|
|
|
59
|
-
const doc = await generateOpenAPIDocument('./src/server/
|
|
60
|
-
exportName: '
|
|
74
|
+
const doc = await generateOpenAPIDocument('./src/server/router.ts', {
|
|
75
|
+
exportName: 'AppRouter',
|
|
61
76
|
title: 'My API',
|
|
62
77
|
version: '1.0.0',
|
|
78
|
+
servers: [{ url: 'https://api.example.com/trpc' }],
|
|
63
79
|
});
|
|
64
80
|
```
|
|
65
81
|
|
|
66
|
-
|
|
82
|
+
The generator builds the spec by statically analysing your router's TypeScript types. It also tries to import the router file to pick up Zod `.describe()` text, and carries on from the types alone if that import fails. Because of that, point it at a module that only defines the router, not one that starts your server.
|
|
67
83
|
|
|
68
|
-
|
|
69
|
-
// scripts/codegen.ts
|
|
70
|
-
import { rmSync, writeFileSync } from 'node:fs';
|
|
71
|
-
import * as path from 'node:path';
|
|
72
|
-
import { fileURLToPath } from 'node:url';
|
|
73
|
-
import { createClient } from '@hey-api/openapi-ts';
|
|
74
|
-
import { generateOpenAPIDocument } from '@trpc/openapi';
|
|
75
|
-
import { createTRPCHeyApiTypeResolvers } from '@trpc/openapi/heyapi';
|
|
84
|
+
## Generate a client from the spec
|
|
76
85
|
|
|
77
|
-
|
|
78
|
-
const __dirname = path.dirname(__filename);
|
|
79
|
-
|
|
80
|
-
const routerPath = path.resolve(__dirname, '..', 'server', 'index.ts');
|
|
81
|
-
const outputDir = path.resolve(__dirname, '..', 'client', 'generated');
|
|
82
|
-
const specPath = path.resolve(__dirname, '..', '..', 'openapi.json');
|
|
83
|
-
|
|
84
|
-
async function main() {
|
|
85
|
-
const doc = await generateOpenAPIDocument(routerPath, {
|
|
86
|
-
exportName: 'appRouter',
|
|
87
|
-
title: 'Example API',
|
|
88
|
-
version: '1.0.0',
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
writeFileSync(specPath, JSON.stringify(doc, null, 2) + '\n');
|
|
92
|
-
|
|
93
|
-
rmSync(outputDir, { recursive: true, force: true });
|
|
94
|
-
|
|
95
|
-
await createClient({
|
|
96
|
-
input: specPath,
|
|
97
|
-
output: outputDir,
|
|
98
|
-
plugins: [
|
|
99
|
-
{
|
|
100
|
-
name: '@hey-api/typescript',
|
|
101
|
-
'~resolvers': createTRPCHeyApiTypeResolvers(),
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: '@hey-api/sdk',
|
|
105
|
-
operations: { strategy: 'single' },
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
});
|
|
109
|
-
}
|
|
86
|
+
Any OpenAPI client generator should work, but the most tested integration is with [Hey API](https://heyapi.dev/openapi-ts/get-started).
|
|
110
87
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
88
|
+
A generated client will produce typed SDK functions matching your tRPC procedures:
|
|
89
|
+
|
|
90
|
+
- **Queries** → `GET /procedure.path`
|
|
91
|
+
- **Mutations** → `POST /procedure.path`
|
|
92
|
+
- **Subscriptions** are ignored (SSE coming soon)
|
|
93
|
+
|
|
94
|
+
### Hey API (TypeScript)
|
|
95
|
+
|
|
96
|
+
[Hey API Documentation](https://heyapi.dev/)
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pnpm add @trpc/openapi @hey-api/openapi-ts
|
|
115
100
|
```
|
|
116
101
|
|
|
117
|
-
|
|
102
|
+
Out of the box, an OpenAPI-generated client won't know about your transformer setup or how to encode query parameters. The `@trpc/openapi/heyapi` package provides a `configureTRPCHeyApiClient` helper that bridges this gap — it configures request serialisation, response parsing, and error deserialization so the generated SDK works correctly with tRPC endpoints.
|
|
103
|
+
|
|
104
|
+
#### Without a transformer
|
|
105
|
+
|
|
106
|
+
You can generate your client using Hey API's CLI or programmatic API in this case
|
|
118
107
|
|
|
119
108
|
```bash
|
|
120
|
-
pnpm
|
|
109
|
+
pnpm exec openapi-ts -i openapi.json -o ./generated
|
|
121
110
|
```
|
|
122
111
|
|
|
123
|
-
|
|
112
|
+
Next a little configuration is required at runtime:
|
|
124
113
|
|
|
125
|
-
```ts
|
|
114
|
+
```ts title="src/usage.ts"
|
|
126
115
|
import { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';
|
|
127
116
|
import { client } from './generated/client.gen';
|
|
128
117
|
import { Sdk } from './generated/sdk.gen';
|
|
@@ -132,37 +121,32 @@ configureTRPCHeyApiClient(client, {
|
|
|
132
121
|
});
|
|
133
122
|
const sdk = new Sdk({ client });
|
|
134
123
|
|
|
135
|
-
// Queries -> GET, Mutations -> POST
|
|
136
124
|
const result = await sdk.greeting({ query: { input: { name: 'World' } } });
|
|
137
125
|
const user = await sdk.user.create({ body: { name: 'Bob', age: 30 } });
|
|
138
126
|
```
|
|
139
127
|
|
|
140
|
-
|
|
128
|
+
#### With a transformer (superjson, devalue, etc.)
|
|
141
129
|
|
|
142
|
-
|
|
130
|
+
> [!WARNING]
|
|
131
|
+
> If your backend uses a [data transformer](https://trpc.io/docs/server/data-transformers) like `superjson`, you **must** pass it to the client config. Without this, Dates, Maps, Sets, and other non-JSON types may be silently wrong.
|
|
143
132
|
|
|
144
|
-
```bash
|
|
145
|
-
# Default export name "AppRouter", output "openapi.json"
|
|
146
|
-
pnpm exec trpc-openapi ./src/server/router.ts
|
|
147
133
|
|
|
148
|
-
|
|
149
|
-
pnpm exec trpc-openapi ./src/server/router.ts -e appRouter -o api.json --title "My API" --version 1.0.0
|
|
150
|
-
```
|
|
134
|
+
First generate your client code using Hey API's programmatic API, this way you can use `createTRPCHeyApiTypeResolvers` to ensure your emitted types are correct:
|
|
151
135
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
When the server uses a transformer, pass `createTRPCHeyApiTypeResolvers()` to the `@hey-api/typescript` plugin so generated types use `Date` instead of `string` for date-time fields and `bigint` for bigint fields:
|
|
155
|
-
|
|
156
|
-
```ts
|
|
136
|
+
```ts title="src/client.ts"
|
|
157
137
|
import { createClient } from '@hey-api/openapi-ts';
|
|
158
138
|
import { createTRPCHeyApiTypeResolvers } from '@trpc/openapi/heyapi';
|
|
159
139
|
|
|
140
|
+
const openApiJson = './path/to/openapi.json'
|
|
141
|
+
const outputDir = './generated'
|
|
142
|
+
|
|
160
143
|
await createClient({
|
|
161
|
-
input:
|
|
162
|
-
output:
|
|
144
|
+
input: openApiJson,
|
|
145
|
+
output: outputDir,
|
|
163
146
|
plugins: [
|
|
164
147
|
{
|
|
165
148
|
name: '@hey-api/typescript',
|
|
149
|
+
// Important: this ensures that your emitted types like Dates are correct
|
|
166
150
|
'~resolvers': createTRPCHeyApiTypeResolvers(),
|
|
167
151
|
},
|
|
168
152
|
{
|
|
@@ -173,54 +157,113 @@ await createClient({
|
|
|
173
157
|
});
|
|
174
158
|
```
|
|
175
159
|
|
|
176
|
-
|
|
160
|
+
At runtime configure the generated client with your transformer, you can then pass native types directly and get them back deserialised:
|
|
177
161
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
```ts
|
|
181
|
-
// src/shared/transformer.ts
|
|
162
|
+
```ts title="src/usage.ts"
|
|
163
|
+
import { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';
|
|
182
164
|
import superjson from 'superjson';
|
|
165
|
+
import { client } from './generated/client.gen';
|
|
166
|
+
import { Sdk } from './generated/sdk.gen';
|
|
167
|
+
|
|
168
|
+
configureTRPCHeyApiClient(client, {
|
|
169
|
+
baseUrl: 'http://localhost:3000',
|
|
170
|
+
// Important, this transformer must match your tRPC API's transformer:
|
|
171
|
+
transformer: superjson,
|
|
172
|
+
});
|
|
173
|
+
const sdk = new Sdk({ client });
|
|
183
174
|
|
|
184
|
-
|
|
175
|
+
const event = await sdk.getEvent({
|
|
176
|
+
query: { input: { id: 'evt_1', at: new Date('2025-06-15T10:00:00Z') } },
|
|
177
|
+
});
|
|
178
|
+
// event.data.result.data.at is a Date object ✅
|
|
179
|
+
|
|
180
|
+
const created = await sdk.createEvent({
|
|
181
|
+
body: { name: 'Conference', at: new Date('2025-09-01T09:00:00Z') },
|
|
182
|
+
});
|
|
185
183
|
```
|
|
186
184
|
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
#### Reading results and errors
|
|
186
|
+
|
|
187
|
+
The SDK returns tRPC's [response envelope](https://trpc.io/docs/rpc#http-response-specification), so a procedure's return value is under `result.data`. A failed call resolves with `error` set to the tRPC error envelope instead of throwing:
|
|
188
|
+
|
|
189
|
+
```ts title="src/usage.ts"
|
|
190
|
+
import { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';
|
|
191
|
+
import { client } from './generated/client.gen';
|
|
192
|
+
import { Sdk } from './generated/sdk.gen';
|
|
193
|
+
|
|
194
|
+
configureTRPCHeyApiClient(client, { baseUrl: 'http://localhost:3000' });
|
|
195
|
+
const sdk = new Sdk({ client });
|
|
196
|
+
|
|
197
|
+
const { data, error } = await sdk.user.byId({ query: { input: '1' } });
|
|
198
|
+
if (error) {
|
|
199
|
+
console.log(error.error.data.code); // e.g. 'NOT_FOUND'
|
|
200
|
+
} else {
|
|
201
|
+
console.log(data?.result.data); // what the procedure returned
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Using a different generator or language
|
|
206
|
+
|
|
207
|
+
The generated OpenAPI spec works with any OpenAPI-compatible client generator which can:
|
|
208
|
+
|
|
209
|
+
- Emit accurate types for classes like Date
|
|
210
|
+
- Support customising Search Params and request/response body serialization
|
|
211
|
+
|
|
212
|
+
To integrate correctly with tRPC's protocol, you need to set up your generated client to do two things:
|
|
213
|
+
|
|
214
|
+
- **Transformers** — If your tRPC API uses a transformer, the client must serialise inputs and deserialise outputs using the same format
|
|
215
|
+
- **Query Inputs** — GET requests encode input as `?input=<JSON>`, not as individual query parameters
|
|
216
|
+
|
|
217
|
+
See the [Hey API config source](https://github.com/trpc/trpc/blob/f346e9bb97ff3c8a7e874f59110a47730293097a/packages/openapi/src/heyapi/index.ts) for a complete reference implementation.
|
|
218
|
+
|
|
219
|
+
### Transformers
|
|
220
|
+
|
|
221
|
+
tRPC [data transformers](https://trpc.io/docs/server/data-transformers) let you send rich types like `Date`, `Map`, `Set`, and `BigInt` over the wire. When using the OpenAPI client, the same transformer must be configured on both the server and client so that inputs are serialised and outputs are deserialised correctly.
|
|
222
|
+
|
|
223
|
+
Any transformer that implements the tRPC `DataTransformer` interface (`serialize` / `deserialize`) works with `configureTRPCHeyApiClient`. Below are some tested options.
|
|
224
|
+
|
|
225
|
+
#### SuperJSON
|
|
226
|
+
|
|
227
|
+
The most popular transformer for TypeScript-to-TypeScript setups. Handles `Date`, `Map`, `Set`, `BigInt`, `RegExp`, and more.
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
pnpm add superjson
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```ts title="src/server.ts"
|
|
189
234
|
import { initTRPC } from '@trpc/server';
|
|
190
|
-
import
|
|
235
|
+
import superjson from 'superjson';
|
|
191
236
|
|
|
192
|
-
const t = initTRPC.create({ transformer });
|
|
193
|
-
export const router = t.router;
|
|
194
|
-
export const publicProcedure = t.procedure;
|
|
237
|
+
const t = initTRPC.create({ transformer: superjson });
|
|
195
238
|
```
|
|
196
239
|
|
|
197
|
-
```ts
|
|
198
|
-
// src/client/index.ts
|
|
240
|
+
```ts title="src/client.ts"
|
|
199
241
|
import { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';
|
|
200
242
|
import superjson from 'superjson';
|
|
201
243
|
import { client } from './generated/client.gen';
|
|
202
|
-
import { Sdk } from './generated/sdk.gen';
|
|
203
244
|
|
|
204
245
|
configureTRPCHeyApiClient(client, {
|
|
205
246
|
baseUrl: 'http://localhost:3000',
|
|
206
247
|
transformer: superjson,
|
|
207
248
|
});
|
|
208
|
-
const sdk = new Sdk({ client });
|
|
209
|
-
|
|
210
|
-
const event = await sdk.getEvent({
|
|
211
|
-
query: { input: { id: 'evt_1', at: new Date('2025-06-15T10:00:00Z') } },
|
|
212
|
-
});
|
|
213
|
-
// event.data.result.data.at is a Date object
|
|
214
249
|
```
|
|
215
250
|
|
|
216
|
-
|
|
251
|
+
See the [superjson test](https://github.com/trpc/trpc/blob/main/packages/openapi/test/generate.test.ts) for a full end-to-end example.
|
|
217
252
|
|
|
218
|
-
|
|
253
|
+
#### MongoDB Extended JSON v2
|
|
219
254
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
255
|
+
[EJSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/#mongodb-extended-json-v2-usage) is a good choice when you need cross-language support. The `bson` npm package provides `EJSON.serialize` / `EJSON.deserialize` which map directly to a tRPC `DataTransformer`.
|
|
256
|
+
|
|
257
|
+
Available in: C, C#, C++, Go, Java, Node.js, Perl, PHP, Python, Ruby, Scala
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
pnpm add bson
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```ts title="src/transformer.ts"
|
|
223
264
|
import { EJSON } from 'bson';
|
|
265
|
+
import type { Document } from 'bson';
|
|
266
|
+
import type { TRPCDataTransformer } from '@trpc/server';
|
|
224
267
|
|
|
225
268
|
export const ejsonTransformer: TRPCDataTransformer = {
|
|
226
269
|
serialize: (value) => EJSON.serialize(value),
|
|
@@ -228,7 +271,7 @@ export const ejsonTransformer: TRPCDataTransformer = {
|
|
|
228
271
|
};
|
|
229
272
|
```
|
|
230
273
|
|
|
231
|
-
```ts
|
|
274
|
+
```ts title="src/client.ts"
|
|
232
275
|
import { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';
|
|
233
276
|
import { client } from './generated/client.gen';
|
|
234
277
|
import { ejsonTransformer } from './transformer';
|
|
@@ -239,62 +282,84 @@ configureTRPCHeyApiClient(client, {
|
|
|
239
282
|
});
|
|
240
283
|
```
|
|
241
284
|
|
|
242
|
-
|
|
285
|
+
See the [MongoDB EJSON test](https://github.com/trpc/trpc/blob/main/packages/openapi/test/mongoEjson.test.ts) for a full end-to-end example.
|
|
243
286
|
|
|
244
|
-
|
|
287
|
+
#### Amazon Ion
|
|
245
288
|
|
|
246
|
-
|
|
247
|
-
const listResult = await sdk.user.list();
|
|
248
|
-
const users = listResult.data?.result.data; // the actual return value
|
|
289
|
+
[Amazon Ion](https://amazon-ion.github.io/ion-docs/) is a richly-typed data format with broad language support. It doesn't directly support the `TRPCDataTransformer` interface and requires a bit of boilerplate to make work with tRPC in JS/TS, but may be a good choice for your own system.
|
|
249
290
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
291
|
+
Available in: C, C#, D, Go, Java, JavaScript, PHP, Python, Rust
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
pnpm add ion-js
|
|
253
295
|
```
|
|
254
296
|
|
|
255
|
-
|
|
297
|
+
See the [Amazon Ion test](https://github.com/trpc/trpc/blob/main/packages/openapi/test/amazonIon.test.ts) for the transformer implementation, boilerplate, and a full end-to-end example.
|
|
256
298
|
|
|
257
|
-
|
|
299
|
+
#### Writing a custom transformer
|
|
258
300
|
|
|
259
|
-
|
|
301
|
+
Any object with `serialize` and `deserialize` methods works:
|
|
260
302
|
|
|
261
|
-
|
|
303
|
+
```ts
|
|
304
|
+
import type { TRPCDataTransformer } from '@trpc/server';
|
|
262
305
|
|
|
263
|
-
|
|
306
|
+
const myTransformer: TRPCDataTransformer = {
|
|
307
|
+
serialize: (value) => {
|
|
308
|
+
/* encode rich types */
|
|
309
|
+
},
|
|
310
|
+
deserialize: (value) => {
|
|
311
|
+
/* decode them back */
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
```
|
|
264
315
|
|
|
265
|
-
|
|
316
|
+
Pass it to both `initTRPC.create({ transformer })` on the server and `configureTRPCHeyApiClient(client, { transformer })` on the client. See the [data transformers docs](https://trpc.io/docs/server/data-transformers) for more details.
|
|
266
317
|
|
|
267
|
-
|
|
268
|
-
configureTRPCHeyApiClient(client, {
|
|
269
|
-
baseUrl: 'http://localhost:3000',
|
|
270
|
-
// missing transformer -- Dates will be broken
|
|
271
|
-
});
|
|
272
|
-
```
|
|
318
|
+
### Full example
|
|
273
319
|
|
|
274
|
-
|
|
320
|
+
For a complete, runnable project that ties all of these steps together, see the [openapi-codegen example](https://github.com/trpc/trpc/tree/main/examples/openapi-codegen). Its [codegen script](https://github.com/trpc/trpc/blob/main/examples/openapi-codegen/src/scripts/codegen.ts) generates the spec with `generateOpenAPIDocument` and then the SDK with Hey API in one step.
|
|
275
321
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
```
|
|
322
|
+
## API changelog and breaking-change checks with `oasdiff`
|
|
323
|
+
|
|
324
|
+
After generating OpenAPI specs, you can compare two versions with [`oasdiff`](https://github.com/oasdiff/oasdiff).
|
|
325
|
+
|
|
326
|
+
For installation options (Homebrew, Docker, binaries, etc), see the official docs:
|
|
282
327
|
|
|
283
|
-
|
|
328
|
+
- [oasdiff install docs](https://github.com/oasdiff/oasdiff/blob/main/docs/README.md)
|
|
329
|
+
- [oasdiff changelog and breaking checks](https://github.com/oasdiff/oasdiff/blob/main/docs/BREAKING-CHANGES.md)
|
|
284
330
|
|
|
285
|
-
|
|
331
|
+
Using this you can quick generate changelogs or detect inadvertent breaking changes to APIs to help plan and coordinate releases
|
|
286
332
|
|
|
287
|
-
|
|
333
|
+
```sh
|
|
334
|
+
# Get a complete changelog including minor and breaking changes
|
|
335
|
+
$ oasdiff changelog packages/openapi/test/routers/superjsonRouter.openapi.json /tmp/superjsonRouter.openapi.next.json
|
|
288
336
|
|
|
289
|
-
|
|
337
|
+
3 changes: 2 error, 0 warning, 1 info
|
|
338
|
+
error [new-required-request-property] in API POST /createEvent
|
|
339
|
+
added the new required request property 'location'
|
|
340
|
+
error [api-path-removed-without-deprecation] in API GET /getBigInt
|
|
341
|
+
api path removed without deprecation
|
|
342
|
+
info [endpoint-added] in API GET /health
|
|
343
|
+
endpoint added
|
|
344
|
+
|
|
345
|
+
# Get a list of breaking changes if any
|
|
346
|
+
$ oasdiff breaking packages/openapi/test/routers/superjsonRouter.openapi.json /tmp/superjsonRouter.openapi.next.json
|
|
347
|
+
|
|
348
|
+
2 changes: 2 error, 0 warning, 0 info
|
|
349
|
+
error [new-required-request-property] in API POST /createEvent
|
|
350
|
+
added the new required request property 'location'
|
|
351
|
+
error [api-path-removed-without-deprecation] in API GET /getBigInt
|
|
352
|
+
api path removed without deprecation
|
|
353
|
+
```
|
|
290
354
|
|
|
291
|
-
|
|
355
|
+
## Common mistakes
|
|
292
356
|
|
|
293
|
-
|
|
357
|
+
- **Using the wrong export name.** `--export` (`exportName`) defaults to `AppRouter`. If your file exports the router as `appRouter`, pass `-e appRouter`. When the name isn't found, the error lists the file's exports.
|
|
358
|
+
- **Leaving the tRPC prefix out of the base URL.** The spec's paths are relative to where tRPC is mounted (`/user.create`), so if your adapter serves tRPC under `/trpc`, both `--server-url` and the client's `baseUrl` need to end in `/trpc`.
|
|
359
|
+
- **Skipping `createTRPCHeyApiTypeResolvers()` when you use a transformer.** Without it, Hey API types `Date` fields as `string` and `bigint` fields as `number`.
|
|
360
|
+
- **Configuring a transformer on the server only.** `configureTRPCHeyApiClient` needs the same `transformer` as your `initTRPC`, or rich types arrive still encoded.
|
|
361
|
+
- **Expecting subscriptions in the spec.** The generator skips subscription procedures.
|
|
294
362
|
|
|
295
|
-
##
|
|
363
|
+
## Related skills
|
|
296
364
|
|
|
297
|
-
-
|
|
298
|
-
- **superjson** -- Transformer configuration for server and client. OpenAPI clients need matching transformer config.
|
|
299
|
-
- **validators** -- Zod `.describe()` calls propagate into OpenAPI `description` fields.
|
|
300
|
-
- Full working example: `examples/openapi-codegen/`
|
|
365
|
+
- `server-setup` (https://trpc.io/docs/server/overview): `npx @tanstack/intent@latest load @trpc/server#server-setup`
|
package/src/cli.ts
CHANGED
package/src/heyapi/index.ts
CHANGED
|
@@ -5,7 +5,8 @@ import type {
|
|
|
5
5
|
} from '@trpc/server';
|
|
6
6
|
|
|
7
7
|
export type DataTransformerOptions =
|
|
8
|
-
|
|
8
|
+
| TRPCDataTransformer
|
|
9
|
+
| TRPCCombinedDataTransformer;
|
|
9
10
|
export interface TRPCHeyApiClientOptions {
|
|
10
11
|
transformer?: DataTransformerOptions;
|
|
11
12
|
}
|
package/src/types.ts
CHANGED
|
@@ -4,7 +4,13 @@ export type Replace<TTarget, TReplaceWith> = Omit<TTarget, keyof TReplaceWith> &
|
|
|
4
4
|
TReplaceWith;
|
|
5
5
|
|
|
6
6
|
export type SchemaType =
|
|
7
|
-
|
|
7
|
+
| 'array'
|
|
8
|
+
| 'boolean'
|
|
9
|
+
| 'integer'
|
|
10
|
+
| 'null'
|
|
11
|
+
| 'number'
|
|
12
|
+
| 'object'
|
|
13
|
+
| 'string';
|
|
8
14
|
|
|
9
15
|
export type PrimitiveSchemaType = SchemaType;
|
|
10
16
|
|
package/bin/intent.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Auto-generated by @tanstack/intent setup
|
|
3
|
-
// Exposes the intent end-user CLI for consumers of this library.
|
|
4
|
-
// Commit this file, then add to your package.json:
|
|
5
|
-
// "bin": { "intent": "./bin/intent.js" }
|
|
6
|
-
try {
|
|
7
|
-
await import('@tanstack/intent/intent-library');
|
|
8
|
-
} catch (e) {
|
|
9
|
-
if (e?.code === 'ERR_MODULE_NOT_FOUND' || e?.code === 'MODULE_NOT_FOUND') {
|
|
10
|
-
console.error('@tanstack/intent is not installed.');
|
|
11
|
-
console.error('');
|
|
12
|
-
console.error('Install it as a dev dependency:');
|
|
13
|
-
console.error(' npm add -D @tanstack/intent');
|
|
14
|
-
console.error('');
|
|
15
|
-
console.error('Or run directly:');
|
|
16
|
-
console.error(' npx @tanstack/intent@latest list');
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
throw e;
|
|
20
|
-
}
|