UNPKG

@trpc/openapi

Version:

OpenAPI document generator for tRPC routers

1 lines • 6.32 kB
{"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 | 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":";;;;;;;;;;;;;;;;;;;;;;;;AA6JU,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"}