@atproto/oauth-provider 0.16.5 → 0.17.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.
Files changed (321) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/access-token/access-token-mode.js +2 -5
  3. package/dist/access-token/access-token-mode.js.map +1 -1
  4. package/dist/account/account-manager.js +25 -33
  5. package/dist/account/account-manager.js.map +1 -1
  6. package/dist/account/account-store.js +11 -32
  7. package/dist/account/account-store.js.map +1 -1
  8. package/dist/account/sign-in-data.js +9 -12
  9. package/dist/account/sign-in-data.js.map +1 -1
  10. package/dist/account/sign-up-input.js +14 -17
  11. package/dist/account/sign-up-input.js.map +1 -1
  12. package/dist/client/client-auth.js +1 -2
  13. package/dist/client/client-data.js +1 -2
  14. package/dist/client/client-id.js +2 -5
  15. package/dist/client/client-id.js.map +1 -1
  16. package/dist/client/client-info.js +1 -2
  17. package/dist/client/client-manager.js +86 -97
  18. package/dist/client/client-manager.js.map +1 -1
  19. package/dist/client/client-store.js +7 -26
  20. package/dist/client/client-store.js.map +1 -1
  21. package/dist/client/client-utils.js +10 -14
  22. package/dist/client/client-utils.js.map +1 -1
  23. package/dist/client/client.js +43 -53
  24. package/dist/client/client.js.map +1 -1
  25. package/dist/constants.js +28 -31
  26. package/dist/constants.js.map +1 -1
  27. package/dist/customization/branding.js +8 -11
  28. package/dist/customization/branding.js.map +1 -1
  29. package/dist/customization/build-customization-css.js +8 -11
  30. package/dist/customization/build-customization-css.js.map +1 -1
  31. package/dist/customization/build-customization-data.js +1 -4
  32. package/dist/customization/build-customization-data.js.map +1 -1
  33. package/dist/customization/colors.js +11 -14
  34. package/dist/customization/colors.js.map +1 -1
  35. package/dist/customization/customization.js +8 -11
  36. package/dist/customization/customization.js.map +1 -1
  37. package/dist/customization/links.js +7 -10
  38. package/dist/customization/links.js.map +1 -1
  39. package/dist/device/device-data.js +7 -10
  40. package/dist/device/device-data.js.map +1 -1
  41. package/dist/device/device-id.js +11 -16
  42. package/dist/device/device-id.js.map +1 -1
  43. package/dist/device/device-manager.js +32 -38
  44. package/dist/device/device-manager.js.map +1 -1
  45. package/dist/device/device-store.js +7 -25
  46. package/dist/device/device-store.js.map +1 -1
  47. package/dist/device/session-id.js +9 -13
  48. package/dist/device/session-id.js.map +1 -1
  49. package/dist/dpop/dpop-manager.d.ts +3 -3
  50. package/dist/dpop/dpop-manager.js +38 -43
  51. package/dist/dpop/dpop-manager.js.map +1 -1
  52. package/dist/dpop/dpop-nonce.d.ts +2 -2
  53. package/dist/dpop/dpop-nonce.d.ts.map +1 -1
  54. package/dist/dpop/dpop-nonce.js +14 -18
  55. package/dist/dpop/dpop-nonce.js.map +1 -1
  56. package/dist/dpop/dpop-proof.js +1 -2
  57. package/dist/errors/access-denied-error.js +2 -6
  58. package/dist/errors/access-denied-error.js.map +1 -1
  59. package/dist/errors/account-selection-required-error.js +2 -6
  60. package/dist/errors/account-selection-required-error.js.map +1 -1
  61. package/dist/errors/authorization-error.js +7 -12
  62. package/dist/errors/authorization-error.js.map +1 -1
  63. package/dist/errors/consent-required-error.js +2 -6
  64. package/dist/errors/consent-required-error.js.map +1 -1
  65. package/dist/errors/error-parser.js +14 -18
  66. package/dist/errors/error-parser.js.map +1 -1
  67. package/dist/errors/handle-unavailable-error.js +2 -7
  68. package/dist/errors/handle-unavailable-error.js.map +1 -1
  69. package/dist/errors/invalid-authorization-details-error.js +2 -6
  70. package/dist/errors/invalid-authorization-details-error.js.map +1 -1
  71. package/dist/errors/invalid-client-error.js +2 -6
  72. package/dist/errors/invalid-client-error.js.map +1 -1
  73. package/dist/errors/invalid-client-id-error.js +2 -6
  74. package/dist/errors/invalid-client-id-error.js.map +1 -1
  75. package/dist/errors/invalid-client-metadata-error.js +7 -11
  76. package/dist/errors/invalid-client-metadata-error.js.map +1 -1
  77. package/dist/errors/invalid-credentials-error.js +2 -7
  78. package/dist/errors/invalid-credentials-error.js.map +1 -1
  79. package/dist/errors/invalid-dpop-key-binding-error.js +2 -6
  80. package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -1
  81. package/dist/errors/invalid-dpop-proof-error.js +2 -6
  82. package/dist/errors/invalid-dpop-proof-error.js.map +1 -1
  83. package/dist/errors/invalid-grant-error.js +2 -6
  84. package/dist/errors/invalid-grant-error.js.map +1 -1
  85. package/dist/errors/invalid-invite-code-error.d.ts +1 -1
  86. package/dist/errors/invalid-invite-code-error.d.ts.map +1 -1
  87. package/dist/errors/invalid-invite-code-error.js +2 -6
  88. package/dist/errors/invalid-invite-code-error.js.map +1 -1
  89. package/dist/errors/invalid-redirect-uri-error.js +2 -6
  90. package/dist/errors/invalid-redirect-uri-error.js.map +1 -1
  91. package/dist/errors/invalid-request-error.js +3 -7
  92. package/dist/errors/invalid-request-error.js.map +1 -1
  93. package/dist/errors/invalid-scope-error.js +2 -6
  94. package/dist/errors/invalid-scope-error.js.map +1 -1
  95. package/dist/errors/invalid-token-error.js +10 -15
  96. package/dist/errors/invalid-token-error.js.map +1 -1
  97. package/dist/errors/login-required-error.js +2 -6
  98. package/dist/errors/login-required-error.js.map +1 -1
  99. package/dist/errors/oauth-error.js +1 -9
  100. package/dist/errors/oauth-error.js.map +1 -1
  101. package/dist/errors/second-authentication-factor-required-error.js +2 -8
  102. package/dist/errors/second-authentication-factor-required-error.js.map +1 -1
  103. package/dist/errors/unauthorized-client-error.js +2 -6
  104. package/dist/errors/unauthorized-client-error.js.map +1 -1
  105. package/dist/errors/use-dpop-nonce-error.js +4 -8
  106. package/dist/errors/use-dpop-nonce-error.js.map +1 -1
  107. package/dist/errors/www-authenticate-error.js +4 -9
  108. package/dist/errors/www-authenticate-error.js.map +1 -1
  109. package/dist/index.js +14 -30
  110. package/dist/index.js.map +1 -1
  111. package/dist/lexicon/lexicon-data.js +1 -2
  112. package/dist/lexicon/lexicon-getter.js +6 -10
  113. package/dist/lexicon/lexicon-getter.js.map +1 -1
  114. package/dist/lexicon/lexicon-manager.js +10 -30
  115. package/dist/lexicon/lexicon-manager.js.map +1 -1
  116. package/dist/lexicon/lexicon-store.js +5 -10
  117. package/dist/lexicon/lexicon-store.js.map +1 -1
  118. package/dist/lib/csp/index.js +3 -8
  119. package/dist/lib/csp/index.js.map +1 -1
  120. package/dist/lib/hcaptcha.js +33 -43
  121. package/dist/lib/hcaptcha.js.map +1 -1
  122. package/dist/lib/html/build-document.js +19 -24
  123. package/dist/lib/html/build-document.js.map +1 -1
  124. package/dist/lib/html/escapers.js +10 -16
  125. package/dist/lib/html/escapers.js.map +1 -1
  126. package/dist/lib/html/html.js +1 -5
  127. package/dist/lib/html/html.js.map +1 -1
  128. package/dist/lib/html/hydration-data.js +6 -10
  129. package/dist/lib/html/hydration-data.js.map +1 -1
  130. package/dist/lib/html/index.js +3 -19
  131. package/dist/lib/html/index.js.map +1 -1
  132. package/dist/lib/html/tags.js +14 -23
  133. package/dist/lib/html/tags.js.map +1 -1
  134. package/dist/lib/html/util.js +1 -4
  135. package/dist/lib/html/util.js.map +1 -1
  136. package/dist/lib/http/accept.d.ts.map +1 -1
  137. package/dist/lib/http/accept.js +8 -8
  138. package/dist/lib/http/accept.js.map +1 -1
  139. package/dist/lib/http/context.js +1 -4
  140. package/dist/lib/http/context.js.map +1 -1
  141. package/dist/lib/http/headers.js +1 -4
  142. package/dist/lib/http/headers.js.map +1 -1
  143. package/dist/lib/http/index.js +10 -26
  144. package/dist/lib/http/index.js.map +1 -1
  145. package/dist/lib/http/method.js +1 -4
  146. package/dist/lib/http/method.js.map +1 -1
  147. package/dist/lib/http/middleware.js +11 -17
  148. package/dist/lib/http/middleware.js.map +1 -1
  149. package/dist/lib/http/parser.js +13 -20
  150. package/dist/lib/http/parser.js.map +1 -1
  151. package/dist/lib/http/path.js +1 -4
  152. package/dist/lib/http/path.js.map +1 -1
  153. package/dist/lib/http/request.d.ts.map +1 -1
  154. package/dist/lib/http/request.js +32 -47
  155. package/dist/lib/http/request.js.map +1 -1
  156. package/dist/lib/http/response.js +14 -27
  157. package/dist/lib/http/response.js.map +1 -1
  158. package/dist/lib/http/route.js +9 -12
  159. package/dist/lib/http/route.js.map +1 -1
  160. package/dist/lib/http/router.js +8 -13
  161. package/dist/lib/http/router.js.map +1 -1
  162. package/dist/lib/http/security-headers.js +10 -15
  163. package/dist/lib/http/security-headers.js.map +1 -1
  164. package/dist/lib/http/stream.js +12 -20
  165. package/dist/lib/http/stream.js.map +1 -1
  166. package/dist/lib/http/types.js +1 -2
  167. package/dist/lib/http/url.js +1 -4
  168. package/dist/lib/http/url.js.map +1 -1
  169. package/dist/lib/nsid.js +4 -8
  170. package/dist/lib/nsid.js.map +1 -1
  171. package/dist/lib/redis.js +4 -7
  172. package/dist/lib/redis.js.map +1 -1
  173. package/dist/lib/util/authorization-header.js +11 -15
  174. package/dist/lib/util/authorization-header.js.map +1 -1
  175. package/dist/lib/util/cast.js +3 -8
  176. package/dist/lib/util/cast.js.map +1 -1
  177. package/dist/lib/util/color.js +23 -32
  178. package/dist/lib/util/color.js.map +1 -1
  179. package/dist/lib/util/crypto.js +5 -10
  180. package/dist/lib/util/crypto.js.map +1 -1
  181. package/dist/lib/util/date.js +2 -6
  182. package/dist/lib/util/date.js.map +1 -1
  183. package/dist/lib/util/error.js +5 -8
  184. package/dist/lib/util/error.js.map +1 -1
  185. package/dist/lib/util/function.js +3 -8
  186. package/dist/lib/util/function.js.map +1 -1
  187. package/dist/lib/util/locale.js +3 -6
  188. package/dist/lib/util/locale.js.map +1 -1
  189. package/dist/lib/util/object.js +1 -4
  190. package/dist/lib/util/object.js.map +1 -1
  191. package/dist/lib/util/redirect-uri.js +3 -6
  192. package/dist/lib/util/redirect-uri.js.map +1 -1
  193. package/dist/lib/util/time.js +5 -9
  194. package/dist/lib/util/time.js.map +1 -1
  195. package/dist/lib/util/type.d.ts.map +1 -1
  196. package/dist/lib/util/type.js +1 -5
  197. package/dist/lib/util/type.js.map +1 -1
  198. package/dist/lib/util/ui8.js +3 -8
  199. package/dist/lib/util/ui8.js.map +1 -1
  200. package/dist/lib/util/well-known.js +1 -4
  201. package/dist/lib/util/well-known.js.map +1 -1
  202. package/dist/lib/util/zod-error.js +4 -8
  203. package/dist/lib/util/zod-error.js.map +1 -1
  204. package/dist/lib/write-form-redirect.js +9 -12
  205. package/dist/lib/write-form-redirect.js.map +1 -1
  206. package/dist/lib/write-html.js +12 -15
  207. package/dist/lib/write-html.js.map +1 -1
  208. package/dist/metadata/build-metadata.js +9 -12
  209. package/dist/metadata/build-metadata.js.map +1 -1
  210. package/dist/oauth-client.js +2 -18
  211. package/dist/oauth-client.js.map +1 -1
  212. package/dist/oauth-dpop.js +2 -18
  213. package/dist/oauth-dpop.js.map +1 -1
  214. package/dist/oauth-errors.js +24 -42
  215. package/dist/oauth-errors.js.map +1 -1
  216. package/dist/oauth-hooks.js +8 -15
  217. package/dist/oauth-hooks.js.map +1 -1
  218. package/dist/oauth-middleware.js +13 -16
  219. package/dist/oauth-middleware.js.map +1 -1
  220. package/dist/oauth-provider.js +108 -125
  221. package/dist/oauth-provider.js.map +1 -1
  222. package/dist/oauth-store.js +7 -23
  223. package/dist/oauth-store.js.map +1 -1
  224. package/dist/oauth-verifier.js +41 -53
  225. package/dist/oauth-verifier.js.map +1 -1
  226. package/dist/oidc/sub.js +2 -5
  227. package/dist/oidc/sub.js.map +1 -1
  228. package/dist/replay/replay-manager.js +6 -11
  229. package/dist/replay/replay-manager.js.map +1 -1
  230. package/dist/replay/replay-store-memory.js +5 -7
  231. package/dist/replay/replay-store-memory.js.map +1 -1
  232. package/dist/replay/replay-store-redis.js +3 -8
  233. package/dist/replay/replay-store-redis.js.map +1 -1
  234. package/dist/replay/replay-store.js +3 -8
  235. package/dist/replay/replay-store.js.map +1 -1
  236. package/dist/request/code.js +10 -15
  237. package/dist/request/code.js.map +1 -1
  238. package/dist/request/request-data.js +1 -5
  239. package/dist/request/request-data.js.map +1 -1
  240. package/dist/request/request-id.js +9 -13
  241. package/dist/request/request-id.js.map +1 -1
  242. package/dist/request/request-manager.js +61 -71
  243. package/dist/request/request-manager.js.map +1 -1
  244. package/dist/request/request-store.js +9 -27
  245. package/dist/request/request-store.js.map +1 -1
  246. package/dist/request/request-uri.js +17 -23
  247. package/dist/request/request-uri.js.map +1 -1
  248. package/dist/result/authorization-redirect-parameters.js +1 -2
  249. package/dist/result/authorization-result-authorize-page.js +1 -2
  250. package/dist/result/authorization-result-redirect.js +1 -2
  251. package/dist/router/assets/assets-manifest.d.ts.map +1 -1
  252. package/dist/router/assets/assets-manifest.js +14 -15
  253. package/dist/router/assets/assets-manifest.js.map +1 -1
  254. package/dist/router/assets/assets.d.ts.map +1 -1
  255. package/dist/router/assets/assets.js +25 -27
  256. package/dist/router/assets/assets.js.map +1 -1
  257. package/dist/router/assets/csrf.js +16 -25
  258. package/dist/router/assets/csrf.js.map +1 -1
  259. package/dist/router/assets/send-account-page.js +3 -6
  260. package/dist/router/assets/send-account-page.js.map +1 -1
  261. package/dist/router/assets/send-authorization-page.js +3 -6
  262. package/dist/router/assets/send-authorization-page.js.map +1 -1
  263. package/dist/router/assets/send-cookie-error-page.js +3 -6
  264. package/dist/router/assets/send-cookie-error-page.js.map +1 -1
  265. package/dist/router/assets/send-error-page.js +6 -9
  266. package/dist/router/assets/send-error-page.js.map +1 -1
  267. package/dist/router/assets/send-redirect.js +12 -20
  268. package/dist/router/assets/send-redirect.js.map +1 -1
  269. package/dist/router/create-account-page-middleware.js +11 -14
  270. package/dist/router/create-account-page-middleware.js.map +1 -1
  271. package/dist/router/create-api-middleware.js +83 -90
  272. package/dist/router/create-api-middleware.js.map +1 -1
  273. package/dist/router/create-authorization-page-middleware.js +43 -46
  274. package/dist/router/create-authorization-page-middleware.js.map +1 -1
  275. package/dist/router/create-oauth-middleware.js +31 -34
  276. package/dist/router/create-oauth-middleware.js.map +1 -1
  277. package/dist/router/error-handler.js +1 -2
  278. package/dist/router/middleware-options.js +1 -2
  279. package/dist/signer/access-token-payload.js +12 -15
  280. package/dist/signer/access-token-payload.js.map +1 -1
  281. package/dist/signer/api-token-payload.js +8 -11
  282. package/dist/signer/api-token-payload.js.map +1 -1
  283. package/dist/signer/signer.js +11 -17
  284. package/dist/signer/signer.js.map +1 -1
  285. package/dist/token/refresh-token.js +10 -15
  286. package/dist/token/refresh-token.js.map +1 -1
  287. package/dist/token/token-claims.js +1 -2
  288. package/dist/token/token-data.js +1 -2
  289. package/dist/token/token-id.js +10 -15
  290. package/dist/token/token-id.js.map +1 -1
  291. package/dist/token/token-manager.js +40 -51
  292. package/dist/token/token-manager.js.map +1 -1
  293. package/dist/token/token-store.js +7 -25
  294. package/dist/token/token-store.js.map +1 -1
  295. package/dist/types/authorization-response-error.js +8 -12
  296. package/dist/types/authorization-response-error.js.map +1 -1
  297. package/dist/types/color-hue.js +2 -5
  298. package/dist/types/color-hue.js.map +1 -1
  299. package/dist/types/email-otp.js +2 -5
  300. package/dist/types/email-otp.js.map +1 -1
  301. package/dist/types/email.js +6 -9
  302. package/dist/types/email.js.map +1 -1
  303. package/dist/types/handle.js +6 -9
  304. package/dist/types/handle.js.map +1 -1
  305. package/dist/types/invite-code.js +2 -5
  306. package/dist/types/invite-code.js.map +1 -1
  307. package/dist/types/par-response-error.js +5 -9
  308. package/dist/types/par-response-error.js.map +1 -1
  309. package/dist/types/password.js +3 -6
  310. package/dist/types/password.js.map +1 -1
  311. package/dist/types/rgb-color.js +7 -10
  312. package/dist/types/rgb-color.js.map +1 -1
  313. package/package.json +20 -22
  314. package/src/dpop/dpop-nonce.ts +1 -1
  315. package/src/errors/invalid-invite-code-error.ts +1 -1
  316. package/src/lib/http/accept.ts +4 -1
  317. package/src/lib/http/request.ts +4 -1
  318. package/src/lib/util/type.ts +0 -1
  319. package/src/router/assets/assets-manifest.ts +3 -1
  320. package/src/router/assets/assets.ts +2 -0
  321. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,31 +1,24 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.parsers = void 0;
7
- exports.parseContentType = parseContentType;
8
- const bourne_1 = require("@hapi/bourne");
9
- const content_1 = require("@hapi/content");
10
- const http_errors_1 = __importDefault(require("http-errors"));
1
+ import { parse as parseJson } from '@hapi/bourne';
2
+ import { type as hapiContentType } from '@hapi/content';
3
+ import createHttpError from 'http-errors';
11
4
  /**
12
5
  * Parse a content-type string into its components.
13
6
  *
14
7
  * @throws {TypeError} If the content-type is invalid.
15
8
  */
16
- function parseContentType(type) {
9
+ export function parseContentType(type) {
17
10
  if (typeof type !== 'string') {
18
- throw (0, http_errors_1.default)(415, `Invalid content-type: ${type == null ? String(type) : typeof type}`);
11
+ throw createHttpError(415, `Invalid content-type: ${type == null ? String(type) : typeof type}`);
19
12
  }
20
13
  try {
21
- return (0, content_1.type)(type);
14
+ return hapiContentType(type);
22
15
  }
23
16
  catch (err) {
24
17
  // De-boomify the error
25
- throw (0, http_errors_1.default)(415, err instanceof Error ? err.message : 'Invalid content-type');
18
+ throw createHttpError(415, err instanceof Error ? err.message : 'Invalid content-type');
26
19
  }
27
20
  }
28
- exports.parsers = [
21
+ export const parsers = [
29
22
  {
30
23
  name: 'json',
31
24
  test: (mime) => {
@@ -33,13 +26,13 @@ exports.parsers = [
33
26
  },
34
27
  parse: (buffer, { charset }) => {
35
28
  if (charset != null && !/^utf-?8$/i.test(charset)) {
36
- throw (0, http_errors_1.default)(415, 'Unsupported charset');
29
+ throw createHttpError(415, 'Unsupported charset');
37
30
  }
38
31
  try {
39
- return (0, bourne_1.parse)(buffer.toString());
32
+ return parseJson(buffer.toString());
40
33
  }
41
34
  catch (err) {
42
- throw (0, http_errors_1.default)(400, 'Invalid JSON', { cause: err });
35
+ throw createHttpError(400, 'Invalid JSON', { cause: err });
43
36
  }
44
37
  },
45
38
  },
@@ -50,7 +43,7 @@ exports.parsers = [
50
43
  },
51
44
  parse: (buffer, { charset }) => {
52
45
  if (charset != null && !/^utf-?8$/i.test(charset)) {
53
- throw (0, http_errors_1.default)(415, 'Unsupported charset');
46
+ throw createHttpError(415, 'Unsupported charset');
54
47
  }
55
48
  try {
56
49
  if (!buffer.length)
@@ -61,7 +54,7 @@ exports.parsers = [
61
54
  return Object.fromEntries(params);
62
55
  }
63
56
  catch (err) {
64
- throw (0, http_errors_1.default)(400, 'Invalid URL-encoded data', { cause: err });
57
+ throw createHttpError(400, 'Invalid URL-encoded data', { cause: err });
65
58
  }
66
59
  },
67
60
  },
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/lib/http/parser.ts"],"names":[],"mappings":";;;;;;AAYA,4CAiBC;AA7BD,yCAAiD;AACjD,2CAAuD;AACvD,8DAAyC;AAKzC;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,IAAa;IAC5C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAA,qBAAe,EACnB,GAAG,EACH,yBAAyB,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CACrE,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAA,cAAe,EAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,uBAAuB;QACvB,MAAM,IAAA,qBAAe,EACnB,GAAG,EACH,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAC5D,CAAA;IACH,CAAC;AACH,CAAC;AAuBY,QAAA,OAAO,GAAG;IACrB;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,CAAC,IAAI,EAA6D,EAAE;YACxE,OAAO,8BAA8B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClD,CAAC;QACD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,EAAQ,EAAE;YACnC,IAAI,OAAO,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClD,MAAM,IAAA,qBAAe,EAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA;YACnD,CAAC;YACD,IAAI,CAAC;gBACH,OAAO,IAAA,cAAS,EAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;YACrC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,IAAA,qBAAe,EAAC,GAAG,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;YAC5D,CAAC;QACH,CAAC;KACF;IACD;QACE,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,CAAC,IAAI,EAA+C,EAAE;YAC1D,OAAO,IAAI,KAAK,mCAAmC,CAAA;QACrD,CAAC;QACD,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,EAA8B,EAAE;YACzD,IAAI,OAAO,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClD,MAAM,IAAA,qBAAe,EAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA;YACnD,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,MAAM;oBAAE,OAAO,EAAE,CAAA;gBAC7B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;gBACrD,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;oBAAE,MAAM,IAAI,SAAS,CAAC,aAAa,CAAC,CAAA;gBAC/D,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;YACnC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,IAAA,qBAAe,EAAC,GAAG,EAAE,0BAA0B,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;YACxE,CAAC;QACH,CAAC;KACF;IACD;QACE,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,CAAC,IAAI,EAAsC,EAAE;YACjD,OAAO,IAAI,KAAK,0BAA0B,CAAA;QAC5C,CAAC;QACD,KAAK,EAAE,CAAC,MAAM,EAAU,EAAE,CAAC,MAAM;KAClC;CAC0B,CAAA","sourcesContent":["import { parse as parseJson } from '@hapi/bourne'\nimport { type as hapiContentType } from '@hapi/content'\nimport createHttpError from 'http-errors'\n\nexport type JsonScalar = string | number | boolean | null\nexport type Json = JsonScalar | Json[] | { [_ in string]?: Json }\n\n/**\n * Parse a content-type string into its components.\n *\n * @throws {TypeError} If the content-type is invalid.\n */\nexport function parseContentType(type: unknown): ContentType {\n if (typeof type !== 'string') {\n throw createHttpError(\n 415,\n `Invalid content-type: ${type == null ? String(type) : typeof type}`,\n )\n }\n\n try {\n return hapiContentType(type)\n } catch (err) {\n // De-boomify the error\n throw createHttpError(\n 415,\n err instanceof Error ? err.message : 'Invalid content-type',\n )\n }\n}\n\nexport type ContentType = {\n mime: string\n charset?: string\n boundary?: string\n}\n\nexport type Parser<T extends string = string, R = unknown> = {\n readonly name: string\n readonly test: (mime: string) => mime is T\n readonly parse: (buffer: Buffer, type: ContentType) => R\n}\n\nexport type ParserName<P extends Parser> = P extends { readonly name: infer N }\n ? N\n : never\nexport type ParserType<P extends Parser> = P extends Parser<infer T> ? T : never\nexport type ParserResult<P extends Parser> = ReturnType<P['parse']>\n\nexport type ParserForType<P extends Parser, T> =\n P extends Parser<infer U> ? (U extends T ? P : never) : never\n\nexport const parsers = [\n {\n name: 'json',\n test: (mime): mime is `application/json` | `application/${string}+json` => {\n return /^application\\/(?:.+\\+)?json$/.test(mime)\n },\n parse: (buffer, { charset }): Json => {\n if (charset != null && !/^utf-?8$/i.test(charset)) {\n throw createHttpError(415, 'Unsupported charset')\n }\n try {\n return parseJson(buffer.toString())\n } catch (err) {\n throw createHttpError(400, 'Invalid JSON', { cause: err })\n }\n },\n },\n {\n name: 'urlencoded',\n test: (mime): mime is 'application/x-www-form-urlencoded' => {\n return mime === 'application/x-www-form-urlencoded'\n },\n parse: (buffer, { charset }): { [_ in string]?: string } => {\n if (charset != null && !/^utf-?8$/i.test(charset)) {\n throw createHttpError(415, 'Unsupported charset')\n }\n try {\n if (!buffer.length) return {}\n const params = new URLSearchParams(buffer.toString())\n if (params.has('__proto__')) throw new TypeError('Invalid key')\n return Object.fromEntries(params)\n } catch (err) {\n throw createHttpError(400, 'Invalid URL-encoded data', { cause: err })\n }\n },\n },\n {\n name: 'bytes',\n test: (mime): mime is 'application/octet-stream' => {\n return mime === 'application/octet-stream'\n },\n parse: (buffer): Buffer => buffer,\n },\n] as const satisfies Parser[]\n\nexport type KnownParser = (typeof parsers)[number]\n\nexport type KnownNames = KnownParser['name']\nexport type KnownTypes = ParserType<KnownParser>\n"]}
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/lib/http/parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { parse as parseJson } from '@hapi/bourne'\nimport { type as hapiContentType } from '@hapi/content'\nimport createHttpError from 'http-errors'\n\nexport type JsonScalar = string | number | boolean | null\nexport type Json = JsonScalar | Json[] | { [_ in string]?: Json }\n\n/**\n * Parse a content-type string into its components.\n *\n * @throws {TypeError} If the content-type is invalid.\n */\nexport function parseContentType(type: unknown): ContentType {\n if (typeof type !== 'string') {\n throw createHttpError(\n 415,\n `Invalid content-type: ${type == null ? String(type) : typeof type}`,\n )\n }\n\n try {\n return hapiContentType(type)\n } catch (err) {\n // De-boomify the error\n throw createHttpError(\n 415,\n err instanceof Error ? err.message : 'Invalid content-type',\n )\n }\n}\n\nexport type ContentType = {\n mime: string\n charset?: string\n boundary?: string\n}\n\nexport type Parser<T extends string = string, R = unknown> = {\n readonly name: string\n readonly test: (mime: string) => mime is T\n readonly parse: (buffer: Buffer, type: ContentType) => R\n}\n\nexport type ParserName<P extends Parser> = P extends { readonly name: infer N }\n ? N\n : never\nexport type ParserType<P extends Parser> = P extends Parser<infer T> ? T : never\nexport type ParserResult<P extends Parser> = ReturnType<P['parse']>\n\nexport type ParserForType<P extends Parser, T> =\n P extends Parser<infer U> ? (U extends T ? P : never) : never\n\nexport const parsers = [\n {\n name: 'json',\n test: (mime): mime is `application/json` | `application/${string}+json` => {\n return /^application\\/(?:.+\\+)?json$/.test(mime)\n },\n parse: (buffer, { charset }): Json => {\n if (charset != null && !/^utf-?8$/i.test(charset)) {\n throw createHttpError(415, 'Unsupported charset')\n }\n try {\n return parseJson(buffer.toString())\n } catch (err) {\n throw createHttpError(400, 'Invalid JSON', { cause: err })\n }\n },\n },\n {\n name: 'urlencoded',\n test: (mime): mime is 'application/x-www-form-urlencoded' => {\n return mime === 'application/x-www-form-urlencoded'\n },\n parse: (buffer, { charset }): { [_ in string]?: string } => {\n if (charset != null && !/^utf-?8$/i.test(charset)) {\n throw createHttpError(415, 'Unsupported charset')\n }\n try {\n if (!buffer.length) return {}\n const params = new URLSearchParams(buffer.toString())\n if (params.has('__proto__')) throw new TypeError('Invalid key')\n return Object.fromEntries(params)\n } catch (err) {\n throw createHttpError(400, 'Invalid URL-encoded data', { cause: err })\n }\n },\n },\n {\n name: 'bytes',\n test: (mime): mime is 'application/octet-stream' => {\n return mime === 'application/octet-stream'\n },\n parse: (buffer): Buffer => buffer,\n },\n] as const satisfies Parser[]\n\nexport type KnownParser = (typeof parsers)[number]\n\nexport type KnownNames = KnownParser['name']\nexport type KnownTypes = ParserType<KnownParser>\n"]}
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createPathMatcher = createPathMatcher;
4
- function createPathMatcher(refPath) {
1
+ export function createPathMatcher(refPath) {
5
2
  if (typeof refPath === 'string') {
6
3
  // Create a path matcher for a path with parameters (like /foo/:fooId/bar/:barId).
7
4
  if (refPath.includes('/:')) {
@@ -1 +1 @@
1
- {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/lib/http/path.ts"],"names":[],"mappings":"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","sourcesContent":["export type PathMatcher<P extends Params> = (pathname: string) => P | undefined\n\ntype StringPath<P extends Params> = string extends keyof P\n ? `/${string}`\n : keyof P extends never\n ? `/${string}` | ``\n : {\n [K in keyof P]: K extends string\n ?\n | `${`/:${K}` | `/${string}/:${K}`}${StringPath<Omit<P, K>>}`\n | `${StringPath<Omit<P, K>>}${`/:${K}` | `/:${K}/${string}`}`\n : never\n }[keyof P]\n\nexport type Path<P extends Params> =\n | string\n | StringPath<P>\n | RegExp\n | PathMatcher<P>\nexport type Params = Record<string, undefined | string>\n\nexport function createPathMatcher<P extends Params = Params>(\n refPath: Path<P>,\n): PathMatcher<P> {\n if (typeof refPath === 'string') {\n // Create a path matcher for a path with parameters (like /foo/:fooId/bar/:barId).\n if (refPath.includes('/:')) {\n const refParts = refPath\n .slice(1)\n .split('/')\n .map((part, i) => [part, i] as const)\n const refPartsLength = refParts.length\n\n const staticParts = refParts.filter(([p]) => !p.startsWith(':'))\n const paramParts = refParts\n // Extract parameters, ignoring those with no name (like /foo/:/bar).\n .filter(([p]) => p.startsWith(':') && p.length > 1)\n .map(([p, i]) => [p.slice(1), i] as const)\n\n return (reqPath: string) => {\n const reqParts = reqPath.slice(1).split('/')\n\n if (reqParts.length !== refPartsLength) return undefined\n\n // Make sure all static parts match.\n for (let i = 0; i < staticParts.length; i++) {\n const value = staticParts[i]![0]\n const idx = staticParts[i]![1]\n\n if (value !== reqParts[idx]) return undefined\n }\n\n // Then extract the parameters.\n const params: Record<string, string> = {}\n for (let i = 0; i < paramParts.length; i++) {\n const name = paramParts[i]![0]\n const idx = paramParts[i]![1]\n\n const value = reqParts[idx]\n\n // Empty parameter values are not allowed.\n if (!value) return undefined\n\n params[name] = value\n }\n\n return params as P\n }\n }\n\n return (reqPath: string) => (reqPath === refPath ? ({} as P) : undefined)\n }\n\n if (refPath instanceof RegExp) {\n return (reqPath: string) => {\n const match = reqPath.match(refPath)\n return match ? ((match.groups || {}) as P) : undefined\n }\n }\n\n return refPath\n}\n"]}
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/lib/http/path.ts"],"names":[],"mappings":"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","sourcesContent":["export type PathMatcher<P extends Params> = (pathname: string) => P | undefined\n\ntype StringPath<P extends Params> = string extends keyof P\n ? `/${string}`\n : keyof P extends never\n ? `/${string}` | ``\n : {\n [K in keyof P]: K extends string\n ?\n | `${`/:${K}` | `/${string}/:${K}`}${StringPath<Omit<P, K>>}`\n | `${StringPath<Omit<P, K>>}${`/:${K}` | `/:${K}/${string}`}`\n : never\n }[keyof P]\n\nexport type Path<P extends Params> =\n | string\n | StringPath<P>\n | RegExp\n | PathMatcher<P>\nexport type Params = Record<string, undefined | string>\n\nexport function createPathMatcher<P extends Params = Params>(\n refPath: Path<P>,\n): PathMatcher<P> {\n if (typeof refPath === 'string') {\n // Create a path matcher for a path with parameters (like /foo/:fooId/bar/:barId).\n if (refPath.includes('/:')) {\n const refParts = refPath\n .slice(1)\n .split('/')\n .map((part, i) => [part, i] as const)\n const refPartsLength = refParts.length\n\n const staticParts = refParts.filter(([p]) => !p.startsWith(':'))\n const paramParts = refParts\n // Extract parameters, ignoring those with no name (like /foo/:/bar).\n .filter(([p]) => p.startsWith(':') && p.length > 1)\n .map(([p, i]) => [p.slice(1), i] as const)\n\n return (reqPath: string) => {\n const reqParts = reqPath.slice(1).split('/')\n\n if (reqParts.length !== refPartsLength) return undefined\n\n // Make sure all static parts match.\n for (let i = 0; i < staticParts.length; i++) {\n const value = staticParts[i]![0]\n const idx = staticParts[i]![1]\n\n if (value !== reqParts[idx]) return undefined\n }\n\n // Then extract the parameters.\n const params: Record<string, string> = {}\n for (let i = 0; i < paramParts.length; i++) {\n const name = paramParts[i]![0]\n const idx = paramParts[i]![1]\n\n const value = reqParts[idx]\n\n // Empty parameter values are not allowed.\n if (!value) return undefined\n\n params[name] = value\n }\n\n return params as P\n }\n }\n\n return (reqPath: string) => (reqPath === refPath ? ({} as P) : undefined)\n }\n\n if (refPath instanceof RegExp) {\n return (reqPath: string) => {\n const match = reqPath.match(refPath)\n return match ? ((match.groups || {}) as P) : undefined\n }\n }\n\n return refPath\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/lib/http/request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/lib/http/request.ts"],"names":[],"mappings":"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"}
@@ -1,80 +1,65 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.validateHeaderValue = validateHeaderValue;
7
- exports.validateFetchMode = validateFetchMode;
8
- exports.validateFetchDest = validateFetchDest;
9
- exports.validateFetchSite = validateFetchSite;
10
- exports.validateReferrer = validateReferrer;
11
- exports.validateOrigin = validateOrigin;
12
- exports.setCookie = setCookie;
13
- exports.getCookie = getCookie;
14
- exports.clearCookie = clearCookie;
15
- exports.parseHttpCookies = parseHttpCookies;
16
- exports.extractRequestMetadata = extractRequestMetadata;
17
- exports.extractLocales = extractLocales;
18
- exports.negotiateResponseContent = negotiateResponseContent;
19
- const accept_1 = require("@hapi/accept");
20
- const cookie_1 = require("cookie");
21
- const forwarded_1 = __importDefault(require("forwarded"));
22
- const http_errors_1 = __importDefault(require("http-errors"));
23
- const headers_js_1 = require("./headers.js");
24
- const url_js_1 = require("./url.js");
25
- function validateHeaderValue(req, name, allowedValues) {
1
+ // eslint-disable-next-line import/default, import/no-named-as-default-member
2
+ import accept from '@hapi/accept';
3
+ // eslint-disable-next-line import/no-named-as-default-member
4
+ const { languages, mediaType } = accept;
5
+ import { parse as parseCookie, serialize as serializeCookie, } from 'cookie';
6
+ import forwarded from 'forwarded';
7
+ import createHttpError from 'http-errors';
8
+ import { appendHeader } from './headers.js';
9
+ import { urlMatch } from './url.js';
10
+ export function validateHeaderValue(req, name, allowedValues) {
26
11
  const value = req.headers[name] ?? null;
27
12
  if (Array.isArray(value)) {
28
- throw (0, http_errors_1.default)(400, `Invalid ${name} header`);
13
+ throw createHttpError(400, `Invalid ${name} header`);
29
14
  }
30
15
  if (!allowedValues.includes(value)) {
31
- throw (0, http_errors_1.default)(400, value
16
+ throw createHttpError(400, value
32
17
  ? `Forbidden ${name} header "${value}" (expected ${allowedValues})`
33
18
  : `Missing ${name} header`);
34
19
  }
35
20
  }
36
- function validateFetchMode(req, expectedMode) {
21
+ export function validateFetchMode(req, expectedMode) {
37
22
  validateHeaderValue(req, 'sec-fetch-mode', expectedMode);
38
23
  }
39
- function validateFetchDest(req, expectedDest) {
24
+ export function validateFetchDest(req, expectedDest) {
40
25
  validateHeaderValue(req, 'sec-fetch-dest', expectedDest);
41
26
  }
42
- function validateFetchSite(req, expectedSite) {
27
+ export function validateFetchSite(req, expectedSite) {
43
28
  validateHeaderValue(req, 'sec-fetch-site', expectedSite);
44
29
  }
45
- function validateReferrer(req, reference, allowNull = false) {
30
+ export function validateReferrer(req, reference, allowNull = false) {
46
31
  // @NOTE The header name "referer" is actually a misspelling of the word
47
32
  // "referrer". https://en.wikipedia.org/wiki/HTTP_referer
48
33
  const referrer = req.headers['referer'];
49
34
  const referrerUrl = referrer ? new URL(referrer) : null;
50
- if (referrerUrl ? !(0, url_js_1.urlMatch)(referrerUrl, reference) : !allowNull) {
51
- throw (0, http_errors_1.default)(400, `Invalid referrer ${referrer}`);
35
+ if (referrerUrl ? !urlMatch(referrerUrl, reference) : !allowNull) {
36
+ throw createHttpError(400, `Invalid referrer ${referrer}`);
52
37
  }
53
38
  return referrerUrl;
54
39
  }
55
- function validateOrigin(req, expectedOrigin, optional = true) {
40
+ export function validateOrigin(req, expectedOrigin, optional = true) {
56
41
  const reqOrigin = req.headers['origin'];
57
42
  if (reqOrigin ? reqOrigin !== expectedOrigin : !optional) {
58
- throw (0, http_errors_1.default)(400, `Invalid origin ${reqOrigin}`);
43
+ throw createHttpError(400, `Invalid origin ${reqOrigin}`);
59
44
  }
60
45
  }
61
- function setCookie(res, cookieName, value, options) {
62
- (0, headers_js_1.appendHeader)(res, 'Set-Cookie', (0, cookie_1.serialize)(cookieName, value, options));
46
+ export function setCookie(res, cookieName, value, options) {
47
+ appendHeader(res, 'Set-Cookie', serializeCookie(cookieName, value, options));
63
48
  }
64
- function getCookie(req, cookieName) {
49
+ export function getCookie(req, cookieName) {
65
50
  const cookies = parseHttpCookies(req);
66
51
  return Object.hasOwn(cookies, cookieName) ? cookies[cookieName] : undefined;
67
52
  }
68
- function clearCookie(res, cookieName, options) {
53
+ export function clearCookie(res, cookieName, options) {
69
54
  setCookie(res, cookieName, '', { ...options, maxAge: 0 });
70
55
  }
71
- function parseHttpCookies(req) {
56
+ export function parseHttpCookies(req) {
72
57
  req.cookies ??= req.headers['cookie']
73
- ? { __proto__: null, ...(0, cookie_1.parse)(req.headers['cookie']) }
58
+ ? { __proto__: null, ...parseCookie(req.headers['cookie']) }
74
59
  : { __proto__: null };
75
60
  return req.cookies;
76
61
  }
77
- function extractRequestMetadata(req, options) {
62
+ export function extractRequestMetadata(req, options) {
78
63
  const ip = extractIp(req, options);
79
64
  return {
80
65
  userAgent: req.headers['user-agent'],
@@ -85,7 +70,7 @@ function extractRequestMetadata(req, options) {
85
70
  function extractIp(req, options) {
86
71
  const trust = options?.trustProxy;
87
72
  if (trust) {
88
- const ips = (0, forwarded_1.default)(req);
73
+ const ips = forwarded(req);
89
74
  for (let i = 0; i < ips.length; i++) {
90
75
  const isTrusted = trust(ips[i], i);
91
76
  if (!isTrusted)
@@ -128,12 +113,12 @@ function extractPort(req, ip) {
128
113
  return port;
129
114
  throw new Error('Could not determine port');
130
115
  }
131
- function extractLocales(req) {
116
+ export function extractLocales(req) {
132
117
  const acceptLanguage = req.headers['accept-language'];
133
- return acceptLanguage ? (0, accept_1.languages)(acceptLanguage) : [];
118
+ return acceptLanguage ? languages(acceptLanguage) : [];
134
119
  }
135
- function negotiateResponseContent(req, types) {
136
- const type = (0, accept_1.mediaType)(req.headers['accept'], types);
120
+ export function negotiateResponseContent(req, types) {
121
+ const type = mediaType(req.headers['accept'], types);
137
122
  if (type)
138
123
  return type;
139
124
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/lib/http/request.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { languages, mediaType } from '@hapi/accept'\nimport {\n CookieSerializeOptions,\n parse as parseCookie,\n serialize as serializeCookie,\n} from 'cookie'\nimport forwarded from 'forwarded'\nimport createHttpError from 'http-errors'\nimport { appendHeader } from './headers.js'\nimport { UrlReference, urlMatch } from './url.js'\n\nexport function validateHeaderValue(\n req: IncomingMessage,\n name: keyof IncomingMessage['headers'],\n allowedValues: readonly (string | null)[],\n) {\n const value = req.headers[name] ?? null\n\n if (Array.isArray(value)) {\n throw createHttpError(400, `Invalid ${name} header`)\n }\n\n if (!allowedValues.includes(value)) {\n throw createHttpError(\n 400,\n value\n ? `Forbidden ${name} header \"${value}\" (expected ${allowedValues})`\n : `Missing ${name} header`,\n )\n }\n}\n\nexport function validateFetchMode(\n req: IncomingMessage,\n expectedMode: readonly (\n | null\n | 'navigate'\n | 'same-origin'\n | 'no-cors'\n | 'cors'\n )[],\n) {\n validateHeaderValue(req, 'sec-fetch-mode', expectedMode)\n}\n\nexport function validateFetchDest(\n req: IncomingMessage,\n expectedDest: readonly (\n | null\n | 'document'\n | 'embed'\n | 'font'\n | 'image'\n | 'manifest'\n | 'media'\n | 'object'\n | 'report'\n | 'script'\n | 'serviceworker'\n | 'sharedworker'\n | 'style'\n | 'worker'\n | 'xslt'\n )[],\n) {\n validateHeaderValue(req, 'sec-fetch-dest', expectedDest)\n}\n\nexport function validateFetchSite(\n req: IncomingMessage,\n expectedSite: readonly (\n | null\n | 'same-origin'\n | 'same-site'\n | 'cross-site'\n | 'none'\n )[],\n) {\n validateHeaderValue(req, 'sec-fetch-site', expectedSite)\n}\n\nexport function validateReferrer(\n req: IncomingMessage,\n reference: UrlReference,\n allowNull: true,\n): URL | null\nexport function validateReferrer(\n req: IncomingMessage,\n reference: UrlReference,\n allowNull?: false,\n): URL\nexport function validateReferrer(\n req: IncomingMessage,\n reference: UrlReference,\n allowNull = false,\n) {\n // @NOTE The header name \"referer\" is actually a misspelling of the word\n // \"referrer\". https://en.wikipedia.org/wiki/HTTP_referer\n const referrer = req.headers['referer']\n const referrerUrl = referrer ? new URL(referrer) : null\n if (referrerUrl ? !urlMatch(referrerUrl, reference) : !allowNull) {\n throw createHttpError(400, `Invalid referrer ${referrer}`)\n }\n return referrerUrl\n}\n\nexport function validateOrigin(\n req: IncomingMessage,\n expectedOrigin: string,\n optional = true,\n) {\n const reqOrigin = req.headers['origin']\n if (reqOrigin ? reqOrigin !== expectedOrigin : !optional) {\n throw createHttpError(400, `Invalid origin ${reqOrigin}`)\n }\n}\n\nexport type { CookieSerializeOptions }\n\nexport function setCookie(\n res: ServerResponse,\n cookieName: string,\n value: string,\n options?: CookieSerializeOptions,\n) {\n appendHeader(res, 'Set-Cookie', serializeCookie(cookieName, value, options))\n}\n\nexport function getCookie(\n req: IncomingMessage,\n cookieName: string,\n): string | undefined {\n const cookies = parseHttpCookies(req)\n return Object.hasOwn(cookies, cookieName) ? cookies[cookieName] : undefined\n}\n\nexport function clearCookie(\n res: ServerResponse,\n cookieName: string,\n options?: Omit<CookieSerializeOptions, 'maxAge' | 'expires'>,\n) {\n setCookie(res, cookieName, '', { ...options, maxAge: 0 })\n}\n\nexport function parseHttpCookies(\n req: IncomingMessage & { cookies?: any },\n): Record<string, undefined | string> {\n req.cookies ??= req.headers['cookie']\n ? { __proto__: null, ...parseCookie(req.headers['cookie']) }\n : { __proto__: null }\n return req.cookies\n}\n\nexport type ExtractRequestMetadataOptions = {\n /**\n * A function that determines whether a given IP address is trusted. The\n * function is called with the IP addresses and its index in the list of\n * forwarded addresses (starting from 0, 0 corresponding to the ip of the\n * incoming HTTP connection, and the last item being the first proxied IP\n * address in the proxy chain, deduced from the `X-Forwarded-For` header). The\n * function should return `true` if the IP address is trusted, and `false`\n * otherwise.\n *\n * @see {@link https://www.npmjs.com/package/proxy-addr} for a utility that\n * allows you to create a trust function.\n */\n trustProxy?: (addr: string, i: number) => boolean\n}\n\nexport type RequestMetadata = {\n userAgent?: string\n ipAddress: string\n port: number\n}\n\nexport function extractRequestMetadata(\n req: IncomingMessage,\n options?: ExtractRequestMetadataOptions,\n): RequestMetadata {\n const ip = extractIp(req, options)\n return {\n userAgent: req.headers['user-agent'],\n ipAddress: ip,\n port: extractPort(req, ip),\n }\n}\n\nfunction extractIp(\n req: IncomingMessage,\n options?: ExtractRequestMetadataOptions,\n): string {\n const trust = options?.trustProxy\n if (trust) {\n const ips = forwarded(req)\n for (let i = 0; i < ips.length; i++) {\n const isTrusted = trust(ips[i], i)\n if (!isTrusted) return ips[i]\n }\n // Let's return the last (\"furthest\") IP address in the chain if all of them\n // are trusted. Note that this may indicate an issue with either the trust\n // function (too permissive), or the proxy configuration (one of them not\n // setting the X-Forwarded-For header).\n const ip = ips[ips.length - 1]\n if (ip) return ip\n }\n\n // Express app compatibility (see \"trust proxy\" setting)\n if ('ip' in req) {\n const ip = req.ip\n if (typeof ip === 'string') return ip\n }\n\n const ip = req.socket.remoteAddress\n if (ip) return ip\n\n throw new Error('Could not determine IP address')\n}\n\nfunction extractPort(req: IncomingMessage, ip: string): number {\n if (ip !== req.socket.remoteAddress) {\n // Trust the X-Forwarded-Port header only if the IP address was a trusted\n // proxied IP.\n const forwardedPort = req.headers['x-forwarded-port']\n if (typeof forwardedPort === 'string') {\n const port = Number(forwardedPort.trim())\n if (!Number.isInteger(port) || port < 0 || port > 65535) {\n throw new Error('Invalid forwarded port')\n }\n return port\n }\n }\n\n const port = req.socket.remotePort\n if (port != null) return port\n\n throw new Error('Could not determine port')\n}\n\nexport function extractLocales(req: IncomingMessage) {\n const acceptLanguage = req.headers['accept-language']\n return acceptLanguage ? languages(acceptLanguage) : []\n}\n\nexport function negotiateResponseContent<T extends string>(\n req: IncomingMessage,\n types: readonly T[],\n): T | undefined {\n const type = mediaType(req.headers['accept'], types)\n if (type) return type as T\n\n return undefined\n}\n"]}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/lib/http/request.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\n// eslint-disable-next-line import/default, import/no-named-as-default-member\nimport accept from '@hapi/accept'\n// eslint-disable-next-line import/no-named-as-default-member\nconst { languages, mediaType } = accept\nimport {\n CookieSerializeOptions,\n parse as parseCookie,\n serialize as serializeCookie,\n} from 'cookie'\nimport forwarded from 'forwarded'\nimport createHttpError from 'http-errors'\nimport { appendHeader } from './headers.js'\nimport { UrlReference, urlMatch } from './url.js'\n\nexport function validateHeaderValue(\n req: IncomingMessage,\n name: keyof IncomingMessage['headers'],\n allowedValues: readonly (string | null)[],\n) {\n const value = req.headers[name] ?? null\n\n if (Array.isArray(value)) {\n throw createHttpError(400, `Invalid ${name} header`)\n }\n\n if (!allowedValues.includes(value)) {\n throw createHttpError(\n 400,\n value\n ? `Forbidden ${name} header \"${value}\" (expected ${allowedValues})`\n : `Missing ${name} header`,\n )\n }\n}\n\nexport function validateFetchMode(\n req: IncomingMessage,\n expectedMode: readonly (\n | null\n | 'navigate'\n | 'same-origin'\n | 'no-cors'\n | 'cors'\n )[],\n) {\n validateHeaderValue(req, 'sec-fetch-mode', expectedMode)\n}\n\nexport function validateFetchDest(\n req: IncomingMessage,\n expectedDest: readonly (\n | null\n | 'document'\n | 'embed'\n | 'font'\n | 'image'\n | 'manifest'\n | 'media'\n | 'object'\n | 'report'\n | 'script'\n | 'serviceworker'\n | 'sharedworker'\n | 'style'\n | 'worker'\n | 'xslt'\n )[],\n) {\n validateHeaderValue(req, 'sec-fetch-dest', expectedDest)\n}\n\nexport function validateFetchSite(\n req: IncomingMessage,\n expectedSite: readonly (\n | null\n | 'same-origin'\n | 'same-site'\n | 'cross-site'\n | 'none'\n )[],\n) {\n validateHeaderValue(req, 'sec-fetch-site', expectedSite)\n}\n\nexport function validateReferrer(\n req: IncomingMessage,\n reference: UrlReference,\n allowNull: true,\n): URL | null\nexport function validateReferrer(\n req: IncomingMessage,\n reference: UrlReference,\n allowNull?: false,\n): URL\nexport function validateReferrer(\n req: IncomingMessage,\n reference: UrlReference,\n allowNull = false,\n) {\n // @NOTE The header name \"referer\" is actually a misspelling of the word\n // \"referrer\". https://en.wikipedia.org/wiki/HTTP_referer\n const referrer = req.headers['referer']\n const referrerUrl = referrer ? new URL(referrer) : null\n if (referrerUrl ? !urlMatch(referrerUrl, reference) : !allowNull) {\n throw createHttpError(400, `Invalid referrer ${referrer}`)\n }\n return referrerUrl\n}\n\nexport function validateOrigin(\n req: IncomingMessage,\n expectedOrigin: string,\n optional = true,\n) {\n const reqOrigin = req.headers['origin']\n if (reqOrigin ? reqOrigin !== expectedOrigin : !optional) {\n throw createHttpError(400, `Invalid origin ${reqOrigin}`)\n }\n}\n\nexport type { CookieSerializeOptions }\n\nexport function setCookie(\n res: ServerResponse,\n cookieName: string,\n value: string,\n options?: CookieSerializeOptions,\n) {\n appendHeader(res, 'Set-Cookie', serializeCookie(cookieName, value, options))\n}\n\nexport function getCookie(\n req: IncomingMessage,\n cookieName: string,\n): string | undefined {\n const cookies = parseHttpCookies(req)\n return Object.hasOwn(cookies, cookieName) ? cookies[cookieName] : undefined\n}\n\nexport function clearCookie(\n res: ServerResponse,\n cookieName: string,\n options?: Omit<CookieSerializeOptions, 'maxAge' | 'expires'>,\n) {\n setCookie(res, cookieName, '', { ...options, maxAge: 0 })\n}\n\nexport function parseHttpCookies(\n req: IncomingMessage & { cookies?: any },\n): Record<string, undefined | string> {\n req.cookies ??= req.headers['cookie']\n ? { __proto__: null, ...parseCookie(req.headers['cookie']) }\n : { __proto__: null }\n return req.cookies\n}\n\nexport type ExtractRequestMetadataOptions = {\n /**\n * A function that determines whether a given IP address is trusted. The\n * function is called with the IP addresses and its index in the list of\n * forwarded addresses (starting from 0, 0 corresponding to the ip of the\n * incoming HTTP connection, and the last item being the first proxied IP\n * address in the proxy chain, deduced from the `X-Forwarded-For` header). The\n * function should return `true` if the IP address is trusted, and `false`\n * otherwise.\n *\n * @see {@link https://www.npmjs.com/package/proxy-addr} for a utility that\n * allows you to create a trust function.\n */\n trustProxy?: (addr: string, i: number) => boolean\n}\n\nexport type RequestMetadata = {\n userAgent?: string\n ipAddress: string\n port: number\n}\n\nexport function extractRequestMetadata(\n req: IncomingMessage,\n options?: ExtractRequestMetadataOptions,\n): RequestMetadata {\n const ip = extractIp(req, options)\n return {\n userAgent: req.headers['user-agent'],\n ipAddress: ip,\n port: extractPort(req, ip),\n }\n}\n\nfunction extractIp(\n req: IncomingMessage,\n options?: ExtractRequestMetadataOptions,\n): string {\n const trust = options?.trustProxy\n if (trust) {\n const ips = forwarded(req)\n for (let i = 0; i < ips.length; i++) {\n const isTrusted = trust(ips[i], i)\n if (!isTrusted) return ips[i]\n }\n // Let's return the last (\"furthest\") IP address in the chain if all of them\n // are trusted. Note that this may indicate an issue with either the trust\n // function (too permissive), or the proxy configuration (one of them not\n // setting the X-Forwarded-For header).\n const ip = ips[ips.length - 1]\n if (ip) return ip\n }\n\n // Express app compatibility (see \"trust proxy\" setting)\n if ('ip' in req) {\n const ip = req.ip\n if (typeof ip === 'string') return ip\n }\n\n const ip = req.socket.remoteAddress\n if (ip) return ip\n\n throw new Error('Could not determine IP address')\n}\n\nfunction extractPort(req: IncomingMessage, ip: string): number {\n if (ip !== req.socket.remoteAddress) {\n // Trust the X-Forwarded-Port header only if the IP address was a trusted\n // proxied IP.\n const forwardedPort = req.headers['x-forwarded-port']\n if (typeof forwardedPort === 'string') {\n const port = Number(forwardedPort.trim())\n if (!Number.isInteger(port) || port < 0 || port > 65535) {\n throw new Error('Invalid forwarded port')\n }\n return port\n }\n }\n\n const port = req.socket.remotePort\n if (port != null) return port\n\n throw new Error('Could not determine port')\n}\n\nexport function extractLocales(req: IncomingMessage) {\n const acceptLanguage = req.headers['accept-language']\n return acceptLanguage ? languages(acceptLanguage) : []\n}\n\nexport function negotiateResponseContent<T extends string>(\n req: IncomingMessage,\n types: readonly T[],\n): T | undefined {\n const type = mediaType(req.headers['accept'], types)\n if (type) return type as T\n\n return undefined\n}\n"]}
@@ -1,23 +1,10 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.writeRedirect = writeRedirect;
7
- exports.writeStream = writeStream;
8
- exports.writeBuffer = writeBuffer;
9
- exports.toJsonBuffer = toJsonBuffer;
10
- exports.writeJson = writeJson;
11
- exports.staticJsonMiddleware = staticJsonMiddleware;
12
- exports.cacheControlMiddleware = cacheControlMiddleware;
13
- exports.jsonHandler = jsonHandler;
14
- const node_stream_1 = require("node:stream");
15
- const http_errors_1 = __importDefault(require("http-errors"));
16
- const request_js_1 = require("./request.js");
17
- function writeRedirect(res, url, status = 302) {
1
+ import { pipeline } from 'node:stream';
2
+ import createHttpError from 'http-errors';
3
+ import { negotiateResponseContent } from './request.js';
4
+ export function writeRedirect(res, url, status = 302) {
18
5
  res.writeHead(status, { Location: url }).end();
19
6
  }
20
- function writeStream(res, stream, { status = 200, contentType = 'application/octet-stream', } = {}) {
7
+ export function writeStream(res, stream, { status = 200, contentType = 'application/octet-stream', } = {}) {
21
8
  res.statusCode = status;
22
9
  res.setHeader('content-type', contentType);
23
10
  if (res.req.method === 'HEAD') {
@@ -25,18 +12,18 @@ function writeStream(res, stream, { status = 200, contentType = 'application/oct
25
12
  stream.destroy();
26
13
  }
27
14
  else {
28
- (0, node_stream_1.pipeline)([stream, res], (_err) => {
15
+ pipeline([stream, res], (_err) => {
29
16
  // The error will be propagated through the streams
30
17
  });
31
18
  }
32
19
  }
33
- function writeBuffer(res, chunk, opts) {
20
+ export function writeBuffer(res, chunk, opts) {
34
21
  if (opts?.status != null)
35
22
  res.statusCode = opts.status;
36
23
  res.setHeader('content-type', opts?.contentType || 'application/octet-stream');
37
24
  res.end(chunk);
38
25
  }
39
- function toJsonBuffer(value) {
26
+ export function toJsonBuffer(value) {
40
27
  try {
41
28
  return Buffer.from(JSON.stringify(value));
42
29
  }
@@ -44,29 +31,29 @@ function toJsonBuffer(value) {
44
31
  throw new Error(`Failed to serialize as JSON`, { cause });
45
32
  }
46
33
  }
47
- function writeJson(res, payload, { contentType = 'application/json', ...options } = {}) {
34
+ export function writeJson(res, payload, { contentType = 'application/json', ...options } = {}) {
48
35
  const buffer = toJsonBuffer(payload);
49
36
  writeBuffer(res, buffer, { ...options, contentType });
50
37
  }
51
- function staticJsonMiddleware(value, { contentType = 'application/json', ...options } = {}) {
38
+ export function staticJsonMiddleware(value, { contentType = 'application/json', ...options } = {}) {
52
39
  const buffer = toJsonBuffer(value);
53
40
  const staticOptions = { ...options, contentType };
54
41
  return function (req, res) {
55
42
  writeBuffer(res, buffer, staticOptions);
56
43
  };
57
44
  }
58
- function cacheControlMiddleware(maxAge) {
45
+ export function cacheControlMiddleware(maxAge) {
59
46
  const header = `max-age=${maxAge}`;
60
47
  return function (req, res, next) {
61
48
  res.setHeader('Cache-Control', header);
62
49
  next();
63
50
  };
64
51
  }
65
- function jsonHandler(buildJson) {
52
+ export function jsonHandler(buildJson) {
66
53
  return function (req, res, next) {
67
54
  // Ensure we can agree on a content encoding & type before starting to
68
55
  // build the JSON response.
69
- if ((0, request_js_1.negotiateResponseContent)(req, ['application/json'])) {
56
+ if (negotiateResponseContent(req, ['application/json'])) {
70
57
  // A middleware should not be async, so we wrap the async operation in a
71
58
  // promise and return it.
72
59
  void (async () => {
@@ -81,7 +68,7 @@ function jsonHandler(buildJson) {
81
68
  })();
82
69
  }
83
70
  else {
84
- next((0, http_errors_1.default)(406, 'Unsupported media type'));
71
+ next(createHttpError(406, 'Unsupported media type'));
85
72
  }
86
73
  };
87
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/lib/http/response.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { type Readable, pipeline } from 'node:stream'\nimport createHttpError from 'http-errors'\nimport { Awaitable } from '../util/type.js'\nimport { negotiateResponseContent } from './request.js'\nimport type { Handler, Middleware } from './types.js'\n\nexport function writeRedirect(\n res: ServerResponse,\n url: string,\n status = 302,\n): void {\n res.writeHead(status, { Location: url }).end()\n}\n\nexport type WriteResponseOptions = {\n status?: number\n contentType?: string\n}\n\nexport function writeStream(\n res: ServerResponse,\n stream: Readable,\n {\n status = 200,\n contentType = 'application/octet-stream',\n }: WriteResponseOptions = {},\n): void {\n res.statusCode = status\n res.setHeader('content-type', contentType)\n\n if (res.req.method === 'HEAD') {\n res.end()\n stream.destroy()\n } else {\n pipeline([stream, res], (_err: Error | null) => {\n // The error will be propagated through the streams\n })\n }\n}\n\nexport function writeBuffer(\n res: ServerResponse,\n chunk: string | Buffer,\n opts: WriteResponseOptions,\n): void {\n if (opts?.status != null) res.statusCode = opts.status\n res.setHeader('content-type', opts?.contentType || 'application/octet-stream')\n res.end(chunk)\n}\n\nexport function toJsonBuffer(value: unknown): Buffer {\n try {\n return Buffer.from(JSON.stringify(value))\n } catch (cause) {\n throw new Error(`Failed to serialize as JSON`, { cause })\n }\n}\n\nexport function writeJson(\n res: ServerResponse,\n payload: unknown,\n { contentType = 'application/json', ...options }: WriteResponseOptions = {},\n): void {\n const buffer = toJsonBuffer(payload)\n writeBuffer(res, buffer, { ...options, contentType })\n}\n\nexport function staticJsonMiddleware(\n value: unknown,\n { contentType = 'application/json', ...options }: WriteResponseOptions = {},\n): Handler<unknown> {\n const buffer = toJsonBuffer(value)\n const staticOptions: WriteResponseOptions = { ...options, contentType }\n return function (req, res) {\n writeBuffer(res, buffer, staticOptions)\n }\n}\n\nexport function cacheControlMiddleware(maxAge: number): Middleware<void> {\n const header = `max-age=${maxAge}`\n return function (req, res, next) {\n res.setHeader('Cache-Control', header)\n next()\n }\n}\n\nexport type JsonResponse<P = unknown> = WriteResponseOptions & {\n json: P\n}\n\nexport function jsonHandler<\n T,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n buildJson: (this: T, req: Req, res: Res) => Awaitable<JsonResponse>,\n): Middleware<T, Req, Res> {\n return function (req, res, next) {\n // Ensure we can agree on a content encoding & type before starting to\n // build the JSON response.\n if (negotiateResponseContent(req, ['application/json'])) {\n // A middleware should not be async, so we wrap the async operation in a\n // promise and return it.\n void (async () => {\n try {\n const jsonResponse = await buildJson.call(this, req, res)\n const { json, status = 200, ...options } = jsonResponse\n writeJson(res, json, { ...options, status })\n } catch (err) {\n next(asError(err, 'Failed to build JSON response'))\n }\n })()\n } else {\n next(createHttpError(406, 'Unsupported media type'))\n }\n }\n}\n\nfunction asError(cause: unknown, message: string): Error {\n return cause instanceof Error ? cause : new Error(message, { cause })\n}\n"]}
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/lib/http/response.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { type Readable, pipeline } from 'node:stream'\nimport createHttpError from 'http-errors'\nimport { Awaitable } from '../util/type.js'\nimport { negotiateResponseContent } from './request.js'\nimport type { Handler, Middleware } from './types.js'\n\nexport function writeRedirect(\n res: ServerResponse,\n url: string,\n status = 302,\n): void {\n res.writeHead(status, { Location: url }).end()\n}\n\nexport type WriteResponseOptions = {\n status?: number\n contentType?: string\n}\n\nexport function writeStream(\n res: ServerResponse,\n stream: Readable,\n {\n status = 200,\n contentType = 'application/octet-stream',\n }: WriteResponseOptions = {},\n): void {\n res.statusCode = status\n res.setHeader('content-type', contentType)\n\n if (res.req.method === 'HEAD') {\n res.end()\n stream.destroy()\n } else {\n pipeline([stream, res], (_err: Error | null) => {\n // The error will be propagated through the streams\n })\n }\n}\n\nexport function writeBuffer(\n res: ServerResponse,\n chunk: string | Buffer,\n opts: WriteResponseOptions,\n): void {\n if (opts?.status != null) res.statusCode = opts.status\n res.setHeader('content-type', opts?.contentType || 'application/octet-stream')\n res.end(chunk)\n}\n\nexport function toJsonBuffer(value: unknown): Buffer {\n try {\n return Buffer.from(JSON.stringify(value))\n } catch (cause) {\n throw new Error(`Failed to serialize as JSON`, { cause })\n }\n}\n\nexport function writeJson(\n res: ServerResponse,\n payload: unknown,\n { contentType = 'application/json', ...options }: WriteResponseOptions = {},\n): void {\n const buffer = toJsonBuffer(payload)\n writeBuffer(res, buffer, { ...options, contentType })\n}\n\nexport function staticJsonMiddleware(\n value: unknown,\n { contentType = 'application/json', ...options }: WriteResponseOptions = {},\n): Handler<unknown> {\n const buffer = toJsonBuffer(value)\n const staticOptions: WriteResponseOptions = { ...options, contentType }\n return function (req, res) {\n writeBuffer(res, buffer, staticOptions)\n }\n}\n\nexport function cacheControlMiddleware(maxAge: number): Middleware<void> {\n const header = `max-age=${maxAge}`\n return function (req, res, next) {\n res.setHeader('Cache-Control', header)\n next()\n }\n}\n\nexport type JsonResponse<P = unknown> = WriteResponseOptions & {\n json: P\n}\n\nexport function jsonHandler<\n T,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n buildJson: (this: T, req: Req, res: Res) => Awaitable<JsonResponse>,\n): Middleware<T, Req, Res> {\n return function (req, res, next) {\n // Ensure we can agree on a content encoding & type before starting to\n // build the JSON response.\n if (negotiateResponseContent(req, ['application/json'])) {\n // A middleware should not be async, so we wrap the async operation in a\n // promise and return it.\n void (async () => {\n try {\n const jsonResponse = await buildJson.call(this, req, res)\n const { json, status = 200, ...options } = jsonResponse\n writeJson(res, json, { ...options, status })\n } catch (err) {\n next(asError(err, 'Failed to build JSON response'))\n }\n })()\n } else {\n next(createHttpError(406, 'Unsupported media type'))\n }\n }\n}\n\nfunction asError(cause: unknown, message: string): Error {\n return cause instanceof Error ? cause : new Error(message, { cause })\n}\n"]}
@@ -1,10 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createRoute = createRoute;
4
- const context_js_1 = require("./context.js");
5
- const method_js_1 = require("./method.js");
6
- const middleware_js_1 = require("./middleware.js");
7
- const path_js_1 = require("./path.js");
1
+ import { subCtx } from './context.js';
2
+ import { createMethodMatcher } from './method.js';
3
+ import { combineMiddlewares } from './middleware.js';
4
+ import { createPathMatcher } from './path.js';
8
5
  /**
9
6
  * @example
10
7
  * ```ts
@@ -19,16 +16,16 @@ const path_js_1 = require("./path.js");
19
16
  * })
20
17
  * ```
21
18
  */
22
- function createRoute(method, path, ...mw) {
23
- const paramsMatcher = (0, path_js_1.createPathMatcher)(path);
24
- const methodMatcher = (0, method_js_1.createMethodMatcher)(method);
25
- const middleware = (0, middleware_js_1.combineMiddlewares)(mw, { skipKeyword: 'route' });
19
+ export function createRoute(method, path, ...mw) {
20
+ const paramsMatcher = createPathMatcher(path);
21
+ const methodMatcher = createMethodMatcher(method);
22
+ const middleware = combineMiddlewares(mw, { skipKeyword: 'route' });
26
23
  return function (req, res, next) {
27
24
  if (methodMatcher(req)) {
28
25
  const pathname = req.url?.split('?')[0] ?? '/';
29
26
  const params = paramsMatcher(pathname);
30
27
  if (params) {
31
- const context = (0, context_js_1.subCtx)(this, { params });
28
+ const context = subCtx(this, { params });
32
29
  return middleware.call(context, req, res, next);
33
30
  }
34
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../src/lib/http/route.ts"],"names":[],"mappings":";;AAgCA,kCA2BC;AA1DD,6CAA6C;AAC7C,2CAAqE;AACrE,mDAAoD;AACpD,uCAA2D;AAc3D;;;;;;;;;;;;;GAaG;AACH,SAAgB,WAAW,CAMzB,MAA0B,EAC1B,IAAa,EACb,GAAG,EAAqC;IAExC,MAAM,aAAa,GAAG,IAAA,2BAAiB,EAAI,IAAI,CAAC,CAAA;IAChD,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,MAAM,CAAC,CAAA;IAEjD,MAAM,UAAU,GAAG,IAAA,kCAAkB,EAAC,EAAE,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAA;IAEnE,OAAO,UAAU,GAAG,EAAE,GAAG,EAAE,IAAI;QAC7B,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;YAC9C,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;YACtC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,OAAO,GAAG,IAAA,mBAAM,EAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;gBACxC,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;YACjD,CAAC;QACH,CAAC;QAED,OAAO,IAAI,EAAE,CAAA;IACf,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { SubCtx, subCtx } from './context.js'\nimport { MethodMatcherInput, createMethodMatcher } from './method.js'\nimport { combineMiddlewares } from './middleware.js'\nimport { Params, Path, createPathMatcher } from './path.js'\nimport { Middleware } from './types.js'\n\nexport type RouteCtx<\n T extends object | void,\n P extends Params = Params,\n> = SubCtx<T, { params: Readonly<P> }>\nexport type RouteMiddleware<\n T extends object | void,\n P extends Params,\n Req = IncomingMessage,\n Res = ServerResponse,\n> = Middleware<RouteCtx<T, P>, Req, Res>\n\n/**\n * @example\n * ```ts\n * createRoute<{ foo: string }>('GET', '/foo/:foo', function (req, res) {\n * console.log(this.params.foo) // OK\n * console.log(this.params.bar) // Error\n * })\n *\n * createRoute<{ foo: string }>(['POST', 'PUT'], '/foo/:foo', function (req, res) {\n * console.log(this.params.foo) // OK\n * console.log(this.params.bar) // Error\n * })\n * ```\n */\nexport function createRoute<\n P extends Params = Params,\n T extends object | void = void,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n method: MethodMatcherInput,\n path: Path<P>,\n ...mw: RouteMiddleware<T, P, Req, Res>[]\n): Middleware<T, Req, Res> {\n const paramsMatcher = createPathMatcher<P>(path)\n const methodMatcher = createMethodMatcher(method)\n\n const middleware = combineMiddlewares(mw, { skipKeyword: 'route' })\n\n return function (req, res, next) {\n if (methodMatcher(req)) {\n const pathname = req.url?.split('?')[0] ?? '/'\n const params = paramsMatcher(pathname)\n if (params) {\n const context = subCtx(this, { params })\n return middleware.call(context, req, res, next)\n }\n }\n\n return next()\n }\n}\n"]}
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../src/lib/http/route.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,MAAM,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAsB,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAgB,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAc3D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAMzB,MAA0B,EAC1B,IAAa,EACb,GAAG,EAAqC;IAExC,MAAM,aAAa,GAAG,iBAAiB,CAAI,IAAI,CAAC,CAAA;IAChD,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAEjD,MAAM,UAAU,GAAG,kBAAkB,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAA;IAEnE,OAAO,UAAU,GAAG,EAAE,GAAG,EAAE,IAAI;QAC7B,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;YAC9C,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;YACtC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;gBACxC,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;YACjD,CAAC;QACH,CAAC;QAED,OAAO,IAAI,EAAE,CAAA;IACf,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { SubCtx, subCtx } from './context.js'\nimport { MethodMatcherInput, createMethodMatcher } from './method.js'\nimport { combineMiddlewares } from './middleware.js'\nimport { Params, Path, createPathMatcher } from './path.js'\nimport { Middleware } from './types.js'\n\nexport type RouteCtx<\n T extends object | void,\n P extends Params = Params,\n> = SubCtx<T, { params: Readonly<P> }>\nexport type RouteMiddleware<\n T extends object | void,\n P extends Params,\n Req = IncomingMessage,\n Res = ServerResponse,\n> = Middleware<RouteCtx<T, P>, Req, Res>\n\n/**\n * @example\n * ```ts\n * createRoute<{ foo: string }>('GET', '/foo/:foo', function (req, res) {\n * console.log(this.params.foo) // OK\n * console.log(this.params.bar) // Error\n * })\n *\n * createRoute<{ foo: string }>(['POST', 'PUT'], '/foo/:foo', function (req, res) {\n * console.log(this.params.foo) // OK\n * console.log(this.params.bar) // Error\n * })\n * ```\n */\nexport function createRoute<\n P extends Params = Params,\n T extends object | void = void,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n method: MethodMatcherInput,\n path: Path<P>,\n ...mw: RouteMiddleware<T, P, Req, Res>[]\n): Middleware<T, Req, Res> {\n const paramsMatcher = createPathMatcher<P>(path)\n const methodMatcher = createMethodMatcher(method)\n\n const middleware = combineMiddlewares(mw, { skipKeyword: 'route' })\n\n return function (req, res, next) {\n if (methodMatcher(req)) {\n const pathname = req.url?.split('?')[0] ?? '/'\n const params = paramsMatcher(pathname)\n if (params) {\n const context = subCtx(this, { params })\n return middleware.call(context, req, res, next)\n }\n }\n\n return next()\n }\n}\n"]}
@@ -1,14 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Router = void 0;
4
- const context_js_1 = require("./context.js");
5
- const middleware_js_1 = require("./middleware.js");
6
- const route_js_1 = require("./route.js");
7
- class Router {
8
- config;
9
- middlewares = [];
1
+ import { subCtx } from './context.js';
2
+ import { combineMiddlewares } from './middleware.js';
3
+ import { createRoute } from './route.js';
4
+ export class Router {
10
5
  constructor(config) {
11
6
  this.config = config;
7
+ this.middlewares = [];
12
8
  }
13
9
  use(...middlewares) {
14
10
  this.middlewares.push(...middlewares);
@@ -27,7 +23,7 @@ class Router {
27
23
  return this.addRoute('OPTIONS', path, ...mw);
28
24
  }
29
25
  addRoute(method, path, ...mw) {
30
- return this.use((0, route_js_1.createRoute)(method, path, ...mw));
26
+ return this.use(createRoute(method, path, ...mw));
31
27
  }
32
28
  /**
33
29
  * @returns router middleware which dispatches a route matching the request.
@@ -36,7 +32,7 @@ class Router {
36
32
  const { config } = this;
37
33
  // Calling next('router') from a middleware will skip all the remaining
38
34
  // middlewares in the stack.
39
- const middleware = (0, middleware_js_1.combineMiddlewares)(this.middlewares, {
35
+ const middleware = combineMiddlewares(this.middlewares, {
40
36
  skipKeyword: 'router',
41
37
  });
42
38
  return function (req, res, next) {
@@ -46,12 +42,11 @@ class Router {
46
42
  return next(url);
47
43
  // Any error thrown here will be uncaught/unhandled (a middleware should
48
44
  // never throw)
49
- const context = (0, context_js_1.subCtx)(this, { url, headers: req.headers });
45
+ const context = subCtx(this, { url, headers: req.headers });
50
46
  middleware.call(context, req, res, next);
51
47
  };
52
48
  }
53
49
  }
54
- exports.Router = Router;
55
50
  function extractUrl(req, config) {
56
51
  try {
57
52
  const protocol = config?.protocol || 'https:';
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/lib/http/router.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from 'node:http'\nimport { SubCtx, subCtx } from './context.js'\nimport { MethodMatcherInput } from './method.js'\nimport { combineMiddlewares } from './middleware.js'\nimport { Params, Path } from './path.js'\nimport { RouteMiddleware, createRoute } from './route.js'\nimport { Middleware } from './types.js'\n\nexport type RouterCtx<T extends object | void = void> = SubCtx<\n T,\n { url: Readonly<URL>; headers: IncomingHttpHeaders }\n>\n\nexport type RouterMiddleware<\n T extends object | void = void,\n Req = IncomingMessage,\n Res = ServerResponse,\n> = Middleware<RouterCtx<T>, Req, Res>\n\nexport type RouterConfig = {\n /** Used to build the origin of the {@link RouterCtx['url']} context property */\n protocol?: string\n /** Used to build the origin of the {@link RouterCtx['url']} context property */\n host?: string\n}\n\nexport class Router<\n T extends object | void = void,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n> {\n private readonly middlewares: RouterMiddleware<T, Req, Res>[] = []\n\n constructor(private readonly config?: RouterConfig) {}\n\n use(...middlewares: RouterMiddleware<T, Req, Res>[]) {\n this.middlewares.push(...middlewares)\n return this\n }\n\n all<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('*', path, ...mw)\n }\n\n get<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('GET', path, ...mw)\n }\n\n post<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('POST', path, ...mw)\n }\n\n options<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('OPTIONS', path, ...mw)\n }\n\n addRoute<P extends Params>(\n method: MethodMatcherInput,\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.use(createRoute(method, path, ...mw))\n }\n\n /**\n * @returns router middleware which dispatches a route matching the request.\n */\n buildMiddleware(): Middleware<T, Req, Res> {\n const { config } = this\n\n // Calling next('router') from a middleware will skip all the remaining\n // middlewares in the stack.\n const middleware = combineMiddlewares(this.middlewares, {\n skipKeyword: 'router',\n })\n\n return function (this, req, res, next) {\n // Parse the URL using node's URL parser.\n const url = extractUrl(req, config)\n if (url instanceof Error) return next(url)\n\n // Any error thrown here will be uncaught/unhandled (a middleware should\n // never throw)\n const context = subCtx(this, { url, headers: req.headers })\n middleware.call(context, req, res, next)\n }\n }\n}\n\nfunction extractUrl(req: IncomingMessage, config?: RouterConfig): URL | Error {\n try {\n const protocol = config?.protocol || 'https:'\n const host = config?.host || req.headers.host || 'localhost'\n const pathname = req.url || '/'\n return new URL(pathname, `${protocol}//${host}`)\n } catch (cause) {\n const error =\n cause instanceof Error ? cause : new Error('Invalid URL', { cause })\n return Object.assign(error, { status: 400, statusCode: 400 })\n }\n}\n"]}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/lib/http/router.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n IncomingHttpHeaders,\n IncomingMessage,\n ServerResponse,\n} from 'node:http'\nimport { SubCtx, subCtx } from './context.js'\nimport { MethodMatcherInput } from './method.js'\nimport { combineMiddlewares } from './middleware.js'\nimport { Params, Path } from './path.js'\nimport { RouteMiddleware, createRoute } from './route.js'\nimport { Middleware } from './types.js'\n\nexport type RouterCtx<T extends object | void = void> = SubCtx<\n T,\n { url: Readonly<URL>; headers: IncomingHttpHeaders }\n>\n\nexport type RouterMiddleware<\n T extends object | void = void,\n Req = IncomingMessage,\n Res = ServerResponse,\n> = Middleware<RouterCtx<T>, Req, Res>\n\nexport type RouterConfig = {\n /** Used to build the origin of the {@link RouterCtx['url']} context property */\n protocol?: string\n /** Used to build the origin of the {@link RouterCtx['url']} context property */\n host?: string\n}\n\nexport class Router<\n T extends object | void = void,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n> {\n private readonly middlewares: RouterMiddleware<T, Req, Res>[] = []\n\n constructor(private readonly config?: RouterConfig) {}\n\n use(...middlewares: RouterMiddleware<T, Req, Res>[]) {\n this.middlewares.push(...middlewares)\n return this\n }\n\n all<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('*', path, ...mw)\n }\n\n get<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('GET', path, ...mw)\n }\n\n post<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('POST', path, ...mw)\n }\n\n options<P extends Params = Params>(\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.addRoute<P>('OPTIONS', path, ...mw)\n }\n\n addRoute<P extends Params>(\n method: MethodMatcherInput,\n path: Path<P>,\n ...mw: RouteMiddleware<RouterCtx<T>, P, Req, Res>[]\n ) {\n return this.use(createRoute(method, path, ...mw))\n }\n\n /**\n * @returns router middleware which dispatches a route matching the request.\n */\n buildMiddleware(): Middleware<T, Req, Res> {\n const { config } = this\n\n // Calling next('router') from a middleware will skip all the remaining\n // middlewares in the stack.\n const middleware = combineMiddlewares(this.middlewares, {\n skipKeyword: 'router',\n })\n\n return function (this, req, res, next) {\n // Parse the URL using node's URL parser.\n const url = extractUrl(req, config)\n if (url instanceof Error) return next(url)\n\n // Any error thrown here will be uncaught/unhandled (a middleware should\n // never throw)\n const context = subCtx(this, { url, headers: req.headers })\n middleware.call(context, req, res, next)\n }\n }\n}\n\nfunction extractUrl(req: IncomingMessage, config?: RouterConfig): URL | Error {\n try {\n const protocol = config?.protocol || 'https:'\n const host = config?.host || req.headers.host || 'localhost'\n const pathname = req.url || '/'\n return new URL(pathname, `${protocol}//${host}`)\n } catch (cause) {\n const error =\n cause instanceof Error ? cause : new Error('Invalid URL', { cause })\n return Object.assign(error, { status: 400, statusCode: 400 })\n }\n}\n"]}