{"version":3,"sources":["../src/handlers/proxyRequests.ts","../src/util/responseHelpers.ts","../src/index.ts"],"sourcesContent":["import { URL } from 'node:url';\nimport type { RequestMethod, REST, RouteLike } from '@discordjs/rest';\nimport { populateSuccessfulResponse, populateErrorResponse } from '../util/responseHelpers.js';\nimport type { RequestHandler } from '../util/util.js';\n\n/**\n * Creates an HTTP handler used to forward requests to Discord\n *\n * @param rest - REST instance to use for the requests\n */\nexport function proxyRequests(rest: REST): RequestHandler {\n\treturn async (req, res) => {\n\t\tconst { method, url } = req;\n\n\t\tif (!method || !url) {\n\t\t\tthrow new TypeError(\n\t\t\t\t'Invalid request. Missing method and/or url, implying that this is not a Server IncomingMessage',\n\t\t\t);\n\t\t}\n\n\t\t// The 2nd parameter is here so the URL constructor doesn't complain about an \"invalid url\" when the origin is missing\n\t\t// we don't actually care about the origin and the value passed is irrelevant\n\t\tconst parsedUrl = new URL(url, 'http://noop');\n\t\t// eslint-disable-next-line prefer-named-capture-group\n\t\tconst fullRoute = parsedUrl.pathname.replace(/^\\/api(\\/v\\d+)?/, '') as RouteLike;\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t'Content-Type': req.headers['content-type']!,\n\t\t};\n\n\t\tif (req.headers.authorization) {\n\t\t\theaders.authorization = req.headers.authorization;\n\t\t}\n\n\t\tif (req.headers['x-audit-log-reason']) {\n\t\t\theaders['x-audit-log-reason'] = req.headers['x-audit-log-reason'] as string;\n\t\t}\n\n\t\ttry {\n\t\t\tconst discordResponse = await rest.queueRequest({\n\t\t\t\tbody: req,\n\t\t\t\tfullRoute,\n\t\t\t\t// This type cast is technically incorrect, but we want Discord to throw Method Not Allowed for us\n\t\t\t\tmethod: method as RequestMethod,\n\t\t\t\t// We forward the auth header anyway\n\t\t\t\tauth: false,\n\t\t\t\tpassThroughBody: true,\n\t\t\t\tquery: parsedUrl.searchParams,\n\t\t\t\theaders,\n\t\t\t});\n\n\t\t\tawait populateSuccessfulResponse(res, discordResponse);\n\t\t} catch (error) {\n\t\t\tconst knownError = populateErrorResponse(res, error);\n\t\t\tif (!knownError) {\n\t\t\t\t// Unclear if there's better course of action here for unknown errors.\n\t\t\t\t// Any web framework allows to pass in an error handler for something like this\n\t\t\t\t// at which point the user could dictate what to do with the error - otherwise we could just 500\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t} finally {\n\t\t\tres.end();\n\t\t}\n\t};\n}\n","import type { ServerResponse } from 'node:http';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { DiscordAPIError, HTTPError, RateLimitError, type ResponseLike } from '@discordjs/rest';\n\n/**\n * Populates a server response with the data from a Discord 2xx REST response\n *\n * @param res - The server response to populate\n * @param data - The data to populate the response with\n */\nexport async function populateSuccessfulResponse(res: ServerResponse, data: ResponseLike): Promise<void> {\n\tres.statusCode = data.status;\n\n\tfor (const [header, value] of data.headers) {\n\t\t// Strip ratelimit headers\n\t\tif (/^x-ratelimit/i.test(header)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tres.setHeader(header, value);\n\t}\n\n\tif (data.body) {\n\t\tawait pipeline(data.body instanceof Readable ? data.body : Readable.fromWeb(data.body), res);\n\t}\n}\n\n/**\n * Populates a server response with the data from a Discord non-2xx REST response that is NOT a 429\n *\n * @param res - The server response to populate\n * @param error - The error to populate the response with\n */\nexport function populateGeneralErrorResponse(res: ServerResponse, error: DiscordAPIError | HTTPError): void {\n\tres.statusCode = error.status;\n\n\tif ('rawError' in error) {\n\t\tres.setHeader('Content-Type', 'application/json');\n\t\tres.write(JSON.stringify(error.rawError));\n\t}\n}\n\n/**\n * Populates a server response with the data from a Discord 429 REST response\n *\n * @param res - The server response to populate\n * @param error - The error to populate the response with\n */\nexport function populateRatelimitErrorResponse(res: ServerResponse, error: RateLimitError): void {\n\tres.statusCode = 429;\n\tres.setHeader('Retry-After', error.timeToReset / 1_000);\n}\n\n/**\n * Populates a server response with data relevant for a timeout\n *\n * @param res - The sever response to populate\n */\nexport function populateAbortErrorResponse(res: ServerResponse): void {\n\tres.statusCode = 504;\n\tres.statusMessage = 'Upstream timed out';\n}\n\n/**\n * Tries to populate a server response from an error object\n *\n * @param res - The server response to populate\n * @param error - The error to check and use\n * @returns `true` if the error is known and the response object was populated, otherwise `false`\n */\nexport function populateErrorResponse(res: ServerResponse, error: unknown): boolean {\n\tif (error instanceof DiscordAPIError || error instanceof HTTPError) {\n\t\tpopulateGeneralErrorResponse(res, error);\n\t} else if (error instanceof RateLimitError) {\n\t\tpopulateRatelimitErrorResponse(res, error);\n\t} else if (error instanceof Error && error.name === 'AbortError') {\n\t\tpopulateAbortErrorResponse(res);\n\t} else {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n","export * from './handlers/proxyRequests.js';\nexport * from './util/responseHelpers.js';\nexport type { RequestHandler } from './util/util.js';\n\n/**\n * The {@link https://github.com/discordjs/discord.js/blob/main/packages/proxy#readme | @discordjs/proxy} version\n * that you are currently using.\n *\n * @privateRemarks This needs to explicitly be `string` so it is not typed as a \"const string\" that gets injected by esbuild.\n */\nexport const version = '2.1.1' as string;\n"],"mappings":";;;;AAAA,SAAS,WAAW;;;ACCpB,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB,WAAW,sBAAyC;AAQ9E,eAAsB,2BAA2B,KAAqB,MAAmC;AACxG,MAAI,aAAa,KAAK;AAEtB,aAAW,CAAC,QAAQ,KAAK,KAAK,KAAK,SAAS;AAE3C,QAAI,gBAAgB,KAAK,MAAM,GAAG;AACjC;AAAA,IACD;AAEA,QAAI,UAAU,QAAQ,KAAK;AAAA,EAC5B;AAEA,MAAI,KAAK,MAAM;AACd,UAAM,SAAS,KAAK,gBAAgB,WAAW,KAAK,OAAO,SAAS,QAAQ,KAAK,IAAI,GAAG,GAAG;AAAA,EAC5F;AACD;AAfsB;AAuBf,SAAS,6BAA6B,KAAqB,OAA0C;AAC3G,MAAI,aAAa,MAAM;AAEvB,MAAI,cAAc,OAAO;AACxB,QAAI,UAAU,gBAAgB,kBAAkB;AAChD,QAAI,MAAM,KAAK,UAAU,MAAM,QAAQ,CAAC;AAAA,EACzC;AACD;AAPgB;AAeT,SAAS,+BAA+B,KAAqB,OAA6B;AAChG,MAAI,aAAa;AACjB,MAAI,UAAU,eAAe,MAAM,cAAc,GAAK;AACvD;AAHgB;AAUT,SAAS,2BAA2B,KAA2B;AACrE,MAAI,aAAa;AACjB,MAAI,gBAAgB;AACrB;AAHgB;AAYT,SAAS,sBAAsB,KAAqB,OAAyB;AACnF,MAAI,iBAAiB,mBAAmB,iBAAiB,WAAW;AACnE,iCAA6B,KAAK,KAAK;AAAA,EACxC,WAAW,iBAAiB,gBAAgB;AAC3C,mCAA+B,KAAK,KAAK;AAAA,EAC1C,WAAW,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACjE,+BAA2B,GAAG;AAAA,EAC/B,OAAO;AACN,WAAO;AAAA,EACR;AAEA,SAAO;AACR;AAZgB;;;AD7DT,SAAS,cAAc,MAA4B;AACzD,SAAO,OAAO,KAAK,QAAQ;AAC1B,UAAM,EAAE,QAAQ,IAAI,IAAI;AAExB,QAAI,CAAC,UAAU,CAAC,KAAK;AACpB,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAIA,UAAM,YAAY,IAAI,IAAI,KAAK,aAAa;AAE5C,UAAM,YAAY,UAAU,SAAS,QAAQ,mBAAmB,EAAE;AAElE,UAAM,UAAkC;AAAA,MACvC,gBAAgB,IAAI,QAAQ,cAAc;AAAA,IAC3C;AAEA,QAAI,IAAI,QAAQ,eAAe;AAC9B,cAAQ,gBAAgB,IAAI,QAAQ;AAAA,IACrC;AAEA,QAAI,IAAI,QAAQ,oBAAoB,GAAG;AACtC,cAAQ,oBAAoB,IAAI,IAAI,QAAQ,oBAAoB;AAAA,IACjE;AAEA,QAAI;AACH,YAAM,kBAAkB,MAAM,KAAK,aAAa;AAAA,QAC/C,MAAM;AAAA,QACN;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA,MAAM;AAAA,QACN,iBAAiB;AAAA,QACjB,OAAO,UAAU;AAAA,QACjB;AAAA,MACD,CAAC;AAED,YAAM,2BAA2B,KAAK,eAAe;AAAA,IACtD,SAAS,OAAO;AACf,YAAM,aAAa,sBAAsB,KAAK,KAAK;AACnD,UAAI,CAAC,YAAY;AAIhB,cAAM;AAAA,MACP;AAAA,IACD,UAAE;AACD,UAAI,IAAI;AAAA,IACT;AAAA,EACD;AACD;AAtDgB;;;AEAT,IAAM,UAAU;","names":[]}