@discordjs/proxy 1.3.0-dev.1677499475-ffdb197.0 → 1.3.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ # [@discordjs/proxy@1.3.0](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.2.1...@discordjs/proxy@1.3.0) - (2023-03-12)
6
+
7
+ ## Documentation
8
+
9
+ - Fix typos (#9127) ([1ba1f23](https://github.com/discordjs/discord.js/commit/1ba1f238f04221ec890fc921678909b5b7d92c26))
10
+
11
+ ## Features
12
+
13
+ - **website:** Add support for source file links (#9048) ([f6506e9](https://github.com/discordjs/discord.js/commit/f6506e99c496683ee0ab67db0726b105b929af38))
14
+
5
15
  # [@discordjs/proxy@1.2.1](https://github.com/discordjs/discord.js/compare/@discordjs/proxy@1.2.0...@discordjs/proxy@1.2.1) - (2022-11-25)
6
16
 
7
17
  ## Bug Fixes
package/dist/index.js CHANGED
@@ -70,9 +70,7 @@ function proxyRequests(rest) {
70
70
  return async (req, res) => {
71
71
  const { method, url } = req;
72
72
  if (!method || !url) {
73
- throw new TypeError(
74
- "Invalid request. Missing method and/or url, implying that this is not a Server IncomingMessage"
75
- );
73
+ throw new TypeError("Invalid request. Missing method and/or url, implying that this is not a Server IncomingMessage");
76
74
  }
77
75
  const parsedUrl = new import_node_url.URL(url, "http://noop");
78
76
  const fullRoute = parsedUrl.pathname.replace(/^\/api(\/v\d+)?/, "");
@@ -80,6 +78,7 @@ function proxyRequests(rest) {
80
78
  const discordResponse = await rest.raw({
81
79
  body: req,
82
80
  fullRoute,
81
+ // This type cast is technically incorrect, but we want Discord to throw Method Not Allowed for us
83
82
  method,
84
83
  passThroughBody: true,
85
84
  query: parsedUrl.searchParams,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/handlers/proxyRequests.ts","../src/util/responseHelpers.ts"],"sourcesContent":["export * from './handlers/proxyRequests.js';\nexport * from './util/responseHelpers.js';\nexport type { RequestHandler } from './util/util.js';\n","import { URL } from 'node:url';\nimport {\n\tDiscordAPIError,\n\tHTTPError,\n\tRateLimitError,\n\ttype RequestMethod,\n\ttype REST,\n\ttype RouteLike,\n} from '@discordjs/rest';\nimport {\n\tpopulateAbortErrorResponse,\n\tpopulateGeneralErrorResponse,\n\tpopulateSuccessfulResponse,\n\tpopulateRatelimitErrorResponse,\n} from '../util/responseHelpers.js';\nimport type { RequestHandler } from '../util/util';\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 unicorn/no-unsafe-regex, prefer-named-capture-group\n\t\tconst fullRoute = parsedUrl.pathname.replace(/^\\/api(\\/v\\d+)?/, '') as RouteLike;\n\n\t\ttry {\n\t\t\tconst discordResponse = await rest.raw({\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\tpassThroughBody: true,\n\t\t\t\tquery: parsedUrl.searchParams,\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': req.headers['content-type']!,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tawait populateSuccessfulResponse(res, discordResponse);\n\t\t} catch (error) {\n\t\t\tif (error instanceof DiscordAPIError || error instanceof HTTPError) {\n\t\t\t\tpopulateGeneralErrorResponse(res, error);\n\t\t\t} else if (error instanceof RateLimitError) {\n\t\t\t\tpopulateRatelimitErrorResponse(res, error);\n\t\t\t} else if (error instanceof Error && error.name === 'AbortError') {\n\t\t\t\tpopulateAbortErrorResponse(res);\n\t\t\t} else {\n\t\t\t\t// Unclear if there's better course of action here for unknown errors. 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 { pipeline } from 'node:stream/promises';\nimport type { DiscordAPIError, HTTPError, RateLimitError } from '@discordjs/rest';\nimport type { Dispatcher } from 'undici';\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: Dispatcher.ResponseData): Promise<void> {\n\tres.statusCode = data.statusCode;\n\n\tfor (const header of Object.keys(data.headers)) {\n\t\t// Strip ratelimit headers\n\t\tif (header.startsWith('x-ratelimit')) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tres.setHeader(header, data.headers[header]!);\n\t}\n\n\tawait pipeline(data.body, res);\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,sBAAoB;AACpB,kBAOO;;;ACPP,sBAAyB;AAUzB,eAAsB,2BAA2B,KAAqB,MAA8C;AACnH,MAAI,aAAa,KAAK;AAEtB,aAAW,UAAU,OAAO,KAAK,KAAK,OAAO,GAAG;AAE/C,QAAI,OAAO,WAAW,aAAa,GAAG;AACrC;AAAA,IACD;AAEA,QAAI,UAAU,QAAQ,KAAK,QAAQ,OAAQ;AAAA,EAC5C;AAEA,YAAM,0BAAS,KAAK,MAAM,GAAG;AAC9B;AAbsB;AAqBf,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;;;ADnCT,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,oBAAI,KAAK,aAAa;AAE5C,UAAM,YAAY,UAAU,SAAS,QAAQ,mBAAmB,EAAE;AAElE,QAAI;AACH,YAAM,kBAAkB,MAAM,KAAK,IAAI;AAAA,QACtC,MAAM;AAAA,QACN;AAAA,QAEA;AAAA,QACA,iBAAiB;AAAA,QACjB,OAAO,UAAU;AAAA,QACjB,SAAS;AAAA,UACR,gBAAgB,IAAI,QAAQ;AAAA,QAC7B;AAAA,MACD,CAAC;AAED,YAAM,2BAA2B,KAAK,eAAe;AAAA,IACtD,SAAS,OAAP;AACD,UAAI,iBAAiB,+BAAmB,iBAAiB,uBAAW;AACnE,qCAA6B,KAAK,KAAK;AAAA,MACxC,WAAW,iBAAiB,4BAAgB;AAC3C,uCAA+B,KAAK,KAAK;AAAA,MAC1C,WAAW,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACjE,mCAA2B,GAAG;AAAA,MAC/B,OAAO;AAGN,cAAM;AAAA,MACP;AAAA,IACD,UAAE;AACD,UAAI,IAAI;AAAA,IACT;AAAA,EACD;AACD;AA9CgB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/handlers/proxyRequests.ts","../src/util/responseHelpers.ts"],"sourcesContent":["export * from './handlers/proxyRequests.js';\nexport * from './util/responseHelpers.js';\nexport type { RequestHandler } from './util/util.js';\n","import { URL } from 'node:url';\nimport {\n\tDiscordAPIError,\n\tHTTPError,\n\tRateLimitError,\n\ttype RequestMethod,\n\ttype REST,\n\ttype RouteLike,\n} from '@discordjs/rest';\nimport {\n\tpopulateAbortErrorResponse,\n\tpopulateGeneralErrorResponse,\n\tpopulateSuccessfulResponse,\n\tpopulateRatelimitErrorResponse,\n} from '../util/responseHelpers.js';\nimport type { RequestHandler } from '../util/util';\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 unicorn/no-unsafe-regex, prefer-named-capture-group\n\t\tconst fullRoute = parsedUrl.pathname.replace(/^\\/api(\\/v\\d+)?/, '') as RouteLike;\n\n\t\ttry {\n\t\t\tconst discordResponse = await rest.raw({\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\tpassThroughBody: true,\n\t\t\t\tquery: parsedUrl.searchParams,\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': req.headers['content-type']!,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tawait populateSuccessfulResponse(res, discordResponse);\n\t\t} catch (error) {\n\t\t\tif (error instanceof DiscordAPIError || error instanceof HTTPError) {\n\t\t\t\tpopulateGeneralErrorResponse(res, error);\n\t\t\t} else if (error instanceof RateLimitError) {\n\t\t\t\tpopulateRatelimitErrorResponse(res, error);\n\t\t\t} else if (error instanceof Error && error.name === 'AbortError') {\n\t\t\t\tpopulateAbortErrorResponse(res);\n\t\t\t} else {\n\t\t\t\t// Unclear if there's better course of action here for unknown errors. 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 { pipeline } from 'node:stream/promises';\nimport type { DiscordAPIError, HTTPError, RateLimitError } from '@discordjs/rest';\nimport type { Dispatcher } from 'undici';\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: Dispatcher.ResponseData): Promise<void> {\n\tres.statusCode = data.statusCode;\n\n\tfor (const header of Object.keys(data.headers)) {\n\t\t// Strip ratelimit headers\n\t\tif (header.startsWith('x-ratelimit')) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tres.setHeader(header, data.headers[header]!);\n\t}\n\n\tawait pipeline(data.body, res);\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;ACAA,sBAAoB;AACpB,kBAOO;;;ACPP,sBAAyB;AAUzB,eAAsBA,2BAA2BC,KAAqBC,MAA8C;AACnHD,MAAIE,aAAaD,KAAKC;AAEtB,aAAWC,UAAUC,OAAOC,KAAKJ,KAAKK,OAAO,GAAG;AAE/C,QAAIH,OAAOI,WAAW,aAAA,GAAgB;AACrC;IACD;AAEAP,QAAIQ,UAAUL,QAAQF,KAAKK,QAAQH,MAAAA,CAAO;EAC3C;AAEA,YAAMM,0BAASR,KAAKS,MAAMV,GAAAA;AAC3B;AAbsBD;AAqBf,SAASY,6BAA6BX,KAAqBY,OAA0C;AAC3GZ,MAAIE,aAAaU,MAAMC;AAEvB,MAAI,cAAcD,OAAO;AACxBZ,QAAIQ,UAAU,gBAAgB,kBAAA;AAC9BR,QAAIc,MAAMC,KAAKC,UAAUJ,MAAMK,QAAQ,CAAA;EACxC;AACD;AAPgBN;AAeT,SAASO,+BAA+BlB,KAAqBY,OAA6B;AAChGZ,MAAIE,aAAa;AACjBF,MAAIQ,UAAU,eAAeI,MAAMO,cAAc,GAAA;AAClD;AAHgBD;AAUT,SAASE,2BAA2BpB,KAA2B;AACrEA,MAAIE,aAAa;AACjBF,MAAIqB,gBAAgB;AACrB;AAHgBD;;;ADnCT,SAASE,cAAcC,MAA4B;AACzD,SAAO,OAAOC,KAAKC,QAAQ;AAC1B,UAAM,EAAEC,QAAQC,IAAG,IAAKH;AAExB,QAAI,CAACE,UAAU,CAACC,KAAK;AACpB,YAAM,IAAIC,UACT,gGAAA;IAEF;AAIA,UAAMC,YAAY,IAAIC,oBAAIH,KAAK,aAAA;AAE/B,UAAMI,YAAYF,UAAUG,SAASC,QAAQ,mBAAmB,EAAA;AAEhE,QAAI;AACH,YAAMC,kBAAkB,MAAMX,KAAKY,IAAI;QACtCC,MAAMZ;QACNO;;QAEAL;QACAW,iBAAiB;QACjBC,OAAOT,UAAUU;QACjBC,SAAS;UACR,gBAAgBhB,IAAIgB,QAAQ,cAAA;QAC7B;MACD,CAAA;AAEA,YAAMC,2BAA2BhB,KAAKS,eAAAA;IACvC,SAASQ,OAAP;AACD,UAAIA,iBAAiBC,+BAAmBD,iBAAiBE,uBAAW;AACnEC,qCAA6BpB,KAAKiB,KAAAA;MACnC,WAAWA,iBAAiBI,4BAAgB;AAC3CC,uCAA+BtB,KAAKiB,KAAAA;MACrC,WAAWA,iBAAiBM,SAASN,MAAMO,SAAS,cAAc;AACjEC,mCAA2BzB,GAAAA;MAC5B,OAAO;AAGN,cAAMiB;MACP;IACD,UAAA;AACCjB,UAAI0B,IAAG;IACR;EACD;AACD;AA9CgB7B;","names":["populateSuccessfulResponse","res","data","statusCode","header","Object","keys","headers","startsWith","setHeader","pipeline","body","populateGeneralErrorResponse","error","status","write","JSON","stringify","rawError","populateRatelimitErrorResponse","timeToReset","populateAbortErrorResponse","statusMessage","proxyRequests","rest","req","res","method","url","TypeError","parsedUrl","URL","fullRoute","pathname","replace","discordResponse","raw","body","passThroughBody","query","searchParams","headers","populateSuccessfulResponse","error","DiscordAPIError","HTTPError","populateGeneralErrorResponse","RateLimitError","populateRatelimitErrorResponse","Error","name","populateAbortErrorResponse","end"]}
package/dist/index.mjs CHANGED
@@ -3,11 +3,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
 
4
4
  // src/handlers/proxyRequests.ts
5
5
  import { URL } from "node:url";
6
- import {
7
- DiscordAPIError,
8
- HTTPError,
9
- RateLimitError
10
- } from "@discordjs/rest";
6
+ import { DiscordAPIError, HTTPError, RateLimitError } from "@discordjs/rest";
11
7
 
12
8
  // src/util/responseHelpers.ts
13
9
  import { pipeline } from "node:stream/promises";
@@ -46,9 +42,7 @@ function proxyRequests(rest) {
46
42
  return async (req, res) => {
47
43
  const { method, url } = req;
48
44
  if (!method || !url) {
49
- throw new TypeError(
50
- "Invalid request. Missing method and/or url, implying that this is not a Server IncomingMessage"
51
- );
45
+ throw new TypeError("Invalid request. Missing method and/or url, implying that this is not a Server IncomingMessage");
52
46
  }
53
47
  const parsedUrl = new URL(url, "http://noop");
54
48
  const fullRoute = parsedUrl.pathname.replace(/^\/api(\/v\d+)?/, "");
@@ -56,6 +50,7 @@ function proxyRequests(rest) {
56
50
  const discordResponse = await rest.raw({
57
51
  body: req,
58
52
  fullRoute,
53
+ // This type cast is technically incorrect, but we want Discord to throw Method Not Allowed for us
59
54
  method,
60
55
  passThroughBody: true,
61
56
  query: parsedUrl.searchParams,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/handlers/proxyRequests.ts","../src/util/responseHelpers.ts"],"sourcesContent":["import { URL } from 'node:url';\nimport {\n\tDiscordAPIError,\n\tHTTPError,\n\tRateLimitError,\n\ttype RequestMethod,\n\ttype REST,\n\ttype RouteLike,\n} from '@discordjs/rest';\nimport {\n\tpopulateAbortErrorResponse,\n\tpopulateGeneralErrorResponse,\n\tpopulateSuccessfulResponse,\n\tpopulateRatelimitErrorResponse,\n} from '../util/responseHelpers.js';\nimport type { RequestHandler } from '../util/util';\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 unicorn/no-unsafe-regex, prefer-named-capture-group\n\t\tconst fullRoute = parsedUrl.pathname.replace(/^\\/api(\\/v\\d+)?/, '') as RouteLike;\n\n\t\ttry {\n\t\t\tconst discordResponse = await rest.raw({\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\tpassThroughBody: true,\n\t\t\t\tquery: parsedUrl.searchParams,\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': req.headers['content-type']!,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tawait populateSuccessfulResponse(res, discordResponse);\n\t\t} catch (error) {\n\t\t\tif (error instanceof DiscordAPIError || error instanceof HTTPError) {\n\t\t\t\tpopulateGeneralErrorResponse(res, error);\n\t\t\t} else if (error instanceof RateLimitError) {\n\t\t\t\tpopulateRatelimitErrorResponse(res, error);\n\t\t\t} else if (error instanceof Error && error.name === 'AbortError') {\n\t\t\t\tpopulateAbortErrorResponse(res);\n\t\t\t} else {\n\t\t\t\t// Unclear if there's better course of action here for unknown errors. 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 { pipeline } from 'node:stream/promises';\nimport type { DiscordAPIError, HTTPError, RateLimitError } from '@discordjs/rest';\nimport type { Dispatcher } from 'undici';\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: Dispatcher.ResponseData): Promise<void> {\n\tres.statusCode = data.statusCode;\n\n\tfor (const header of Object.keys(data.headers)) {\n\t\t// Strip ratelimit headers\n\t\tif (header.startsWith('x-ratelimit')) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tres.setHeader(header, data.headers[header]!);\n\t}\n\n\tawait pipeline(data.body, res);\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"],"mappings":";;;;AAAA,SAAS,WAAW;AACpB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,OAIM;;;ACPP,SAAS,gBAAgB;AAUzB,eAAsB,2BAA2B,KAAqB,MAA8C;AACnH,MAAI,aAAa,KAAK;AAEtB,aAAW,UAAU,OAAO,KAAK,KAAK,OAAO,GAAG;AAE/C,QAAI,OAAO,WAAW,aAAa,GAAG;AACrC;AAAA,IACD;AAEA,QAAI,UAAU,QAAQ,KAAK,QAAQ,OAAQ;AAAA,EAC5C;AAEA,QAAM,SAAS,KAAK,MAAM,GAAG;AAC9B;AAbsB;AAqBf,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;;;ADnCT,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,QAAI;AACH,YAAM,kBAAkB,MAAM,KAAK,IAAI;AAAA,QACtC,MAAM;AAAA,QACN;AAAA,QAEA;AAAA,QACA,iBAAiB;AAAA,QACjB,OAAO,UAAU;AAAA,QACjB,SAAS;AAAA,UACR,gBAAgB,IAAI,QAAQ;AAAA,QAC7B;AAAA,MACD,CAAC;AAED,YAAM,2BAA2B,KAAK,eAAe;AAAA,IACtD,SAAS,OAAP;AACD,UAAI,iBAAiB,mBAAmB,iBAAiB,WAAW;AACnE,qCAA6B,KAAK,KAAK;AAAA,MACxC,WAAW,iBAAiB,gBAAgB;AAC3C,uCAA+B,KAAK,KAAK;AAAA,MAC1C,WAAW,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACjE,mCAA2B,GAAG;AAAA,MAC/B,OAAO;AAGN,cAAM;AAAA,MACP;AAAA,IACD,UAAE;AACD,UAAI,IAAI;AAAA,IACT;AAAA,EACD;AACD;AA9CgB;","names":[]}
1
+ {"version":3,"sources":["../src/handlers/proxyRequests.ts","../src/util/responseHelpers.ts"],"sourcesContent":["import { URL } from 'node:url';\nimport {\n\tDiscordAPIError,\n\tHTTPError,\n\tRateLimitError,\n\ttype RequestMethod,\n\ttype REST,\n\ttype RouteLike,\n} from '@discordjs/rest';\nimport {\n\tpopulateAbortErrorResponse,\n\tpopulateGeneralErrorResponse,\n\tpopulateSuccessfulResponse,\n\tpopulateRatelimitErrorResponse,\n} from '../util/responseHelpers.js';\nimport type { RequestHandler } from '../util/util';\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 unicorn/no-unsafe-regex, prefer-named-capture-group\n\t\tconst fullRoute = parsedUrl.pathname.replace(/^\\/api(\\/v\\d+)?/, '') as RouteLike;\n\n\t\ttry {\n\t\t\tconst discordResponse = await rest.raw({\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\tpassThroughBody: true,\n\t\t\t\tquery: parsedUrl.searchParams,\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': req.headers['content-type']!,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tawait populateSuccessfulResponse(res, discordResponse);\n\t\t} catch (error) {\n\t\t\tif (error instanceof DiscordAPIError || error instanceof HTTPError) {\n\t\t\t\tpopulateGeneralErrorResponse(res, error);\n\t\t\t} else if (error instanceof RateLimitError) {\n\t\t\t\tpopulateRatelimitErrorResponse(res, error);\n\t\t\t} else if (error instanceof Error && error.name === 'AbortError') {\n\t\t\t\tpopulateAbortErrorResponse(res);\n\t\t\t} else {\n\t\t\t\t// Unclear if there's better course of action here for unknown errors. 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 { pipeline } from 'node:stream/promises';\nimport type { DiscordAPIError, HTTPError, RateLimitError } from '@discordjs/rest';\nimport type { Dispatcher } from 'undici';\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: Dispatcher.ResponseData): Promise<void> {\n\tres.statusCode = data.statusCode;\n\n\tfor (const header of Object.keys(data.headers)) {\n\t\t// Strip ratelimit headers\n\t\tif (header.startsWith('x-ratelimit')) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tres.setHeader(header, data.headers[header]!);\n\t}\n\n\tawait pipeline(data.body, res);\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"],"mappings":";;;;AAAA,SAASA,WAAW;AACpB,SACCC,iBACAC,WACAC,sBAIM;;;ACPP,SAASC,gBAAgB;AAUzB,eAAsBC,2BAA2BC,KAAqBC,MAA8C;AACnHD,MAAIE,aAAaD,KAAKC;AAEtB,aAAWC,UAAUC,OAAOC,KAAKJ,KAAKK,OAAO,GAAG;AAE/C,QAAIH,OAAOI,WAAW,aAAA,GAAgB;AACrC;IACD;AAEAP,QAAIQ,UAAUL,QAAQF,KAAKK,QAAQH,MAAAA,CAAO;EAC3C;AAEA,QAAMM,SAASR,KAAKS,MAAMV,GAAAA;AAC3B;AAbsBD;AAqBf,SAASY,6BAA6BX,KAAqBY,OAA0C;AAC3GZ,MAAIE,aAAaU,MAAMC;AAEvB,MAAI,cAAcD,OAAO;AACxBZ,QAAIQ,UAAU,gBAAgB,kBAAA;AAC9BR,QAAIc,MAAMC,KAAKC,UAAUJ,MAAMK,QAAQ,CAAA;EACxC;AACD;AAPgBN;AAeT,SAASO,+BAA+BlB,KAAqBY,OAA6B;AAChGZ,MAAIE,aAAa;AACjBF,MAAIQ,UAAU,eAAeI,MAAMO,cAAc,GAAA;AAClD;AAHgBD;AAUT,SAASE,2BAA2BpB,KAA2B;AACrEA,MAAIE,aAAa;AACjBF,MAAIqB,gBAAgB;AACrB;AAHgBD;;;ADnCT,SAASE,cAAcC,MAA4B;AACzD,SAAO,OAAOC,KAAKC,QAAQ;AAC1B,UAAM,EAAEC,QAAQC,IAAG,IAAKH;AAExB,QAAI,CAACE,UAAU,CAACC,KAAK;AACpB,YAAM,IAAIC,UACT,gGAAA;IAEF;AAIA,UAAMC,YAAY,IAAIC,IAAIH,KAAK,aAAA;AAE/B,UAAMI,YAAYF,UAAUG,SAASC,QAAQ,mBAAmB,EAAA;AAEhE,QAAI;AACH,YAAMC,kBAAkB,MAAMX,KAAKY,IAAI;QACtCC,MAAMZ;QACNO;;QAEAL;QACAW,iBAAiB;QACjBC,OAAOT,UAAUU;QACjBC,SAAS;UACR,gBAAgBhB,IAAIgB,QAAQ,cAAA;QAC7B;MACD,CAAA;AAEA,YAAMC,2BAA2BhB,KAAKS,eAAAA;IACvC,SAASQ,OAAP;AACD,UAAIA,iBAAiBC,mBAAmBD,iBAAiBE,WAAW;AACnEC,qCAA6BpB,KAAKiB,KAAAA;MACnC,WAAWA,iBAAiBI,gBAAgB;AAC3CC,uCAA+BtB,KAAKiB,KAAAA;MACrC,WAAWA,iBAAiBM,SAASN,MAAMO,SAAS,cAAc;AACjEC,mCAA2BzB,GAAAA;MAC5B,OAAO;AAGN,cAAMiB;MACP;IACD,UAAA;AACCjB,UAAI0B,IAAG;IACR;EACD;AACD;AA9CgB7B;","names":["URL","DiscordAPIError","HTTPError","RateLimitError","pipeline","populateSuccessfulResponse","res","data","statusCode","header","Object","keys","headers","startsWith","setHeader","pipeline","body","populateGeneralErrorResponse","error","status","write","JSON","stringify","rawError","populateRatelimitErrorResponse","timeToReset","populateAbortErrorResponse","statusMessage","proxyRequests","rest","req","res","method","url","TypeError","parsedUrl","URL","fullRoute","pathname","replace","discordResponse","raw","body","passThroughBody","query","searchParams","headers","populateSuccessfulResponse","error","DiscordAPIError","HTTPError","populateGeneralErrorResponse","RateLimitError","populateRatelimitErrorResponse","Error","name","populateAbortErrorResponse","end"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@discordjs/proxy",
3
- "version": "1.3.0-dev.1677499475-ffdb197.0",
3
+ "version": "1.3.0",
4
4
  "description": "Tools for running an HTTP proxy for Discord's API",
5
5
  "scripts": {
6
6
  "test": "vitest run",
@@ -55,26 +55,26 @@
55
55
  },
56
56
  "homepage": "https://discord.js.org",
57
57
  "dependencies": {
58
- "@discordjs/rest": "^1.5.0",
59
- "@discordjs/util": "^0.1.0",
60
- "tslib": "^2.4.1",
61
- "undici": "^5.19.1"
58
+ "@discordjs/rest": "^1.6.0",
59
+ "@discordjs/util": "^0.2.0",
60
+ "tslib": "^2.5.0",
61
+ "undici": "^5.20.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@favware/cliff-jumper": "^1.10.0",
65
- "@microsoft/api-extractor": "^7.33.7",
66
- "@types/node": "16.18.11",
65
+ "@microsoft/api-extractor": "^7.34.4",
66
+ "@types/node": "16.18.13",
67
67
  "@types/supertest": "^2.0.12",
68
- "@vitest/coverage-c8": "^0.27.1",
68
+ "@vitest/coverage-c8": "^0.29.1",
69
69
  "cross-env": "^7.0.3",
70
- "eslint": "^8.31.0",
70
+ "eslint": "^8.35.0",
71
71
  "eslint-config-neon": "^0.1.40",
72
72
  "eslint-formatter-pretty": "^4.1.0",
73
- "prettier": "^2.8.2",
73
+ "prettier": "^2.8.4",
74
74
  "supertest": "^6.3.3",
75
- "tsup": "^6.5.0",
76
- "typescript": "^4.9.4",
77
- "vitest": "^0.27.1"
75
+ "tsup": "^6.6.3",
76
+ "typescript": "^4.9.5",
77
+ "vitest": "^0.29.1"
78
78
  },
79
79
  "engines": {
80
80
  "node": ">=16.9.0"