{"version":3,"file":"node-http-BUlb5EdB.mjs","names":[],"sources":["../src/adapters/node-http/incomingMessageToRequest.ts","../src/adapters/node-http/writeResponse.ts","../src/adapters/node-http/nodeHTTPRequestHandler.ts"],"sourcesContent":["import type * as http from 'http';\nimport { IncomingMessage } from 'node:http';\nimport { TRPCError } from '../../@trpc/server';\nimport type { NodeHTTPRequest, NodeHTTPResponse } from './types';\n\nfunction createBody(\n  req: NodeHTTPRequest,\n  opts: {\n    /**\n     * Max body size in bytes. If the body is larger than this, the request will be aborted\n     */\n    maxBodySize: number | null;\n  },\n): RequestInit['body'] {\n  // Some adapters will pre-parse the body and add it to the request object\n  if ('body' in req) {\n    if (req.body === undefined) {\n      // If body property exists but is undefined, return undefined\n      return undefined;\n    }\n    // If the body is already a string, return it directly\n    if (typeof req.body === 'string') {\n      return req.body;\n    }\n    // formData use\n    if (req.body instanceof IncomingMessage) {\n      return req.body as any;\n    }\n    // If body exists but isn't a string, stringify it as JSON\n    return JSON.stringify(req.body);\n  }\n  let size = 0;\n  let hasClosed = false;\n\n  return new ReadableStream({\n    start(controller) {\n      const onData = (chunk: Buffer) => {\n        size += chunk.length;\n        if (!opts.maxBodySize || size <= opts.maxBodySize) {\n          controller.enqueue(\n            new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength),\n          );\n          return;\n        }\n        controller.error(\n          new TRPCError({\n            code: 'PAYLOAD_TOO_LARGE',\n          }),\n        );\n        hasClosed = true;\n        req.off('data', onData);\n        req.off('end', onEnd);\n      };\n\n      const onEnd = () => {\n        if (hasClosed) {\n          return;\n        }\n        hasClosed = true;\n        req.off('data', onData);\n        req.off('end', onEnd);\n        controller.close();\n      };\n\n      req.on('data', onData);\n      req.on('end', onEnd);\n    },\n    cancel() {\n      req.destroy();\n    },\n  });\n}\nexport function createURL(req: NodeHTTPRequest): URL {\n  try {\n    const protocol =\n      // http2\n      (req.headers[':scheme'] && req.headers[':scheme'] === 'https') ||\n      // http1\n      (req.socket && 'encrypted' in req.socket && req.socket.encrypted)\n        ? 'https:'\n        : 'http:';\n\n    const host = req.headers.host ?? req.headers[':authority'] ?? 'localhost';\n\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    return new URL(req.url!, `${protocol}//${host}`);\n  } catch (cause) {\n    throw new TRPCError({\n      code: 'BAD_REQUEST',\n      message: 'Invalid URL',\n      cause,\n    });\n  }\n}\n\nfunction createHeaders(incoming: http.IncomingHttpHeaders): Headers {\n  const headers = new Headers();\n\n  for (const key in incoming) {\n    const value = incoming[key];\n    if (typeof key === 'string' && key.startsWith(':')) {\n      // Skip HTTP/2 pseudo-headers\n      continue;\n    }\n\n    if (Array.isArray(value)) {\n      for (const item of value) {\n        headers.append(key, item);\n      }\n    } else if (value != null) {\n      headers.append(key, value);\n    }\n  }\n\n  return headers;\n}\n\n/**\n * Convert an [`IncomingMessage`](https://nodejs.org/api/http.html#class-httpincomingmessage) to a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)\n */\nexport function incomingMessageToRequest(\n  req: NodeHTTPRequest,\n  res: NodeHTTPResponse,\n  opts: {\n    /**\n     * Max body size in bytes. If the body is larger than this, the request will be aborted\n     */\n    maxBodySize: number | null;\n  },\n): Request {\n  const ac = new AbortController();\n\n  const onAbort = () => {\n    res.off('close', onAbort);\n    req.off('aborted', onAbort);\n\n    // abort the request\n    ac.abort();\n  };\n\n  res.once('close', onAbort);\n  req.once('aborted', onAbort);\n\n  // Get host from either regular header or HTTP/2 pseudo-header\n  const url = createURL(req);\n\n  const init: RequestInit = {\n    headers: createHeaders(req.headers),\n    method: req.method,\n    signal: ac.signal,\n  };\n\n  if (req.method !== 'GET' && req.method !== 'HEAD') {\n    init.body = createBody(req, opts);\n\n    // init.duplex = 'half' must be set when body is a ReadableStream, and Node follows the spec.\n    // However, this property is not defined in the TypeScript types for RequestInit, so we have\n    // to cast it here in order to set it without a type error.\n    // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex\n    // @ts-expect-error this is fine\n    init.duplex = 'half';\n  }\n\n  const request = new Request(url, init);\n\n  return request;\n}\n","// eslint-disable-next-line no-restricted-imports\nimport { isAbortError } from '../../unstable-core-do-not-import';\nimport type { NodeHTTPResponse } from './types';\n\nasync function writeResponseBodyChunk(\n  res: NodeHTTPResponse,\n  chunk: Uint8Array,\n) {\n  // useful for debugging 🙃\n  // console.debug('writing', new TextDecoder().decode(chunk));\n\n  if (res.write(chunk) === false) {\n    await new Promise<void>((resolve, reject) => {\n      const onError = (err: unknown) => {\n        reject(err);\n        cleanup();\n      };\n      const onDrain = () => {\n        resolve();\n        cleanup();\n      };\n      const cleanup = () => {\n        res.off('error', onError);\n        res.off('drain', onDrain);\n      };\n      res.once('error', onError);\n      res.once('drain', onDrain);\n    });\n  }\n}\n/**\n * @internal\n */\n\nexport async function writeResponseBody(opts: {\n  res: NodeHTTPResponse;\n  signal: AbortSignal;\n  body: NonNullable<Response['body']>;\n}) {\n  const { res } = opts;\n\n  try {\n    const writableStream = new WritableStream({\n      async write(chunk) {\n        await writeResponseBodyChunk(res, chunk);\n        res.flush?.();\n      },\n    });\n\n    await opts.body.pipeTo(writableStream, {\n      signal: opts.signal,\n    });\n  } catch (err) {\n    if (isAbortError(err)) {\n      return;\n    }\n    throw err;\n  }\n}\n/**\n * @internal\n */\n\nexport async function writeResponse(opts: {\n  request: Request;\n  response: Response;\n  rawResponse: NodeHTTPResponse;\n}) {\n  const { response, rawResponse } = opts;\n\n  // Only override status code if it hasn't been explicitly set in a procedure etc\n  if (rawResponse.statusCode === 200) {\n    rawResponse.statusCode = response.status;\n  }\n  for (const [key, value] of response.headers) {\n    if (key.toLowerCase() === 'set-cookie') continue;\n    rawResponse.setHeader(key, value);\n  }\n  const cookies = response.headers.getSetCookie();\n  if (cookies.length > 0) {\n    rawResponse.setHeader('set-cookie', cookies);\n  }\n  try {\n    if (response.body) {\n      await writeResponseBody({\n        res: rawResponse,\n        signal: opts.request.signal,\n        body: response.body,\n      });\n    }\n  } catch (err) {\n    if (!rawResponse.headersSent) {\n      rawResponse.statusCode = 500;\n    }\n    throw err;\n  } finally {\n    rawResponse.end();\n  }\n}\n","/**\n * If you're making an adapter for tRPC and looking at this file for reference, you should import types and functions from `@trpc/server` and `@trpc/server/http`\n *\n * @example\n * ```ts\n * import type { AnyTRPCRouter } from '@trpc/server'\n * import type { HTTPBaseHandlerOptions } from '@trpc/server/http'\n * ```\n */\n\n// @trpc/server\n\nimport {\n  getTRPCErrorFromUnknown,\n  transformTRPCResponse,\n  type AnyRouter,\n} from '../../@trpc/server';\nimport type { ResolveHTTPRequestOptionsContextFn } from '../../@trpc/server/http';\nimport { resolveResponse } from '../../@trpc/server/http';\n// eslint-disable-next-line no-restricted-imports\nimport { getErrorShape, run } from '../../unstable-core-do-not-import';\nimport { incomingMessageToRequest } from './incomingMessageToRequest';\nimport type {\n  NodeHTTPRequest,\n  NodeHTTPRequestHandlerOptions,\n  NodeHTTPResponse,\n} from './types';\nimport { writeResponse } from './writeResponse';\n\n/**\n * @internal\n */\nexport function internal_exceptionHandler<\n  TRouter extends AnyRouter,\n  TRequest extends NodeHTTPRequest,\n  TResponse extends NodeHTTPResponse,\n>(opts: NodeHTTPRequestHandlerOptions<TRouter, TRequest, TResponse>) {\n  return (cause: unknown) => {\n    const { res, req } = opts;\n    const error = getTRPCErrorFromUnknown(cause);\n\n    const shape = getErrorShape({\n      config: opts.router._def._config,\n      error,\n      type: 'unknown',\n      path: undefined,\n      input: undefined,\n      ctx: undefined,\n    });\n\n    opts.onError?.({\n      req,\n      error,\n      type: 'unknown',\n      path: undefined,\n      input: undefined,\n      ctx: undefined,\n    });\n\n    const transformed = transformTRPCResponse(opts.router._def._config, {\n      error: shape,\n    });\n\n    res.statusCode = shape.data.httpStatus;\n    res.end(JSON.stringify(transformed));\n  };\n}\n\n/**\n * @remark the promise never rejects\n */\nexport async function nodeHTTPRequestHandler<\n  TRouter extends AnyRouter,\n  TRequest extends NodeHTTPRequest,\n  TResponse extends NodeHTTPResponse,\n>(opts: NodeHTTPRequestHandlerOptions<TRouter, TRequest, TResponse>) {\n  return new Promise<void>((resolve) => {\n    const handleViaMiddleware =\n      opts.middleware ?? ((_req, _res, next) => next());\n\n    opts.res.once('finish', () => {\n      resolve();\n    });\n    return handleViaMiddleware(opts.req, opts.res, (err: unknown) => {\n      run(async () => {\n        const request = incomingMessageToRequest(opts.req, opts.res, {\n          maxBodySize: opts.maxBodySize ?? null,\n        });\n\n        // Build tRPC dependencies\n        const createContext: ResolveHTTPRequestOptionsContextFn<\n          TRouter\n        > = async (innerOpts) => {\n          return await opts.createContext?.({\n            ...opts,\n            ...innerOpts,\n          });\n        };\n\n        const response = await resolveResponse({\n          ...opts,\n          req: request,\n          error: err ? getTRPCErrorFromUnknown(err) : null,\n          createContext,\n          onError(o) {\n            opts?.onError?.({\n              ...o,\n              req: opts.req,\n            });\n          },\n        });\n\n        await writeResponse({\n          request,\n          response,\n          rawResponse: opts.res,\n        });\n      }).catch(internal_exceptionHandler(opts));\n    });\n  });\n}\n"],"mappings":"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"}