@johntalton/http-util 6.0.0 → 7.0.1

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 (56) hide show
  1. package/README.md +1 -1
  2. package/package.json +17 -2
  3. package/src/defs.js +34 -1
  4. package/src/headers/accept-encoding.js +9 -12
  5. package/src/headers/accept-language.js +10 -4
  6. package/src/headers/accept.js +0 -28
  7. package/src/headers/cache-control.js +0 -6
  8. package/src/headers/clear-site-data.js +4 -10
  9. package/src/headers/client-hints.js +9 -2
  10. package/src/headers/conditional.js +170 -106
  11. package/src/headers/content-disposition.js +0 -14
  12. package/src/headers/content-range.js +0 -17
  13. package/src/headers/content-type.js +1 -1
  14. package/src/headers/forwarded.js +2 -33
  15. package/src/headers/link.js +11 -12
  16. package/src/headers/multipart.js +19 -18
  17. package/src/headers/preference.js +0 -43
  18. package/src/headers/range.js +5 -31
  19. package/src/headers/rate-limit.js +7 -2
  20. package/src/headers/server-timing.js +1 -14
  21. package/src/headers/strict-transport-security.js +1 -0
  22. package/src/headers/util/mime.js +3 -3
  23. package/src/headers/util/whitespace.js +3 -1
  24. package/src/headers/www-authenticate.js +0 -1
  25. package/src/response/2xx/bytes.js +19 -13
  26. package/src/response/2xx/created.js +16 -8
  27. package/src/response/2xx/json.js +29 -10
  28. package/src/response/2xx/no-content.js +12 -6
  29. package/src/response/2xx/partial-content.js +17 -14
  30. package/src/response/2xx/preflight.js +22 -10
  31. package/src/response/3xx/found.js +25 -0
  32. package/src/response/3xx/moved-permanently.js +7 -5
  33. package/src/response/3xx/not-modified.js +13 -8
  34. package/src/response/3xx/permanent-redirect.js +4 -2
  35. package/src/response/3xx/see-other.js +7 -5
  36. package/src/response/3xx/temporary-redirect.js +4 -2
  37. package/src/response/4xx/bad-request.js +19 -0
  38. package/src/response/4xx/content-too-large.js +1 -1
  39. package/src/response/4xx/gone.js +1 -1
  40. package/src/response/4xx/im-a-teapot.js +1 -1
  41. package/src/response/4xx/not-acceptable.js +6 -4
  42. package/src/response/4xx/not-allowed.js +6 -4
  43. package/src/response/4xx/payment-required.js +17 -0
  44. package/src/response/4xx/precondition-failed.js +18 -3
  45. package/src/response/4xx/range-not-satisfiable.js +5 -3
  46. package/src/response/4xx/too-many-requests.js +8 -5
  47. package/src/response/4xx/unauthorized.js +1 -1
  48. package/src/response/4xx/unsupported-media.js +9 -5
  49. package/src/response/5xx/error.js +2 -3
  50. package/src/response/5xx/insufficient-storage.js +2 -2
  51. package/src/response/5xx/not-implemented.js +2 -3
  52. package/src/response/5xx/unavailable.js +7 -12
  53. package/src/response/header-util.js +1 -1
  54. package/src/response/index.js +4 -0
  55. package/src/response/response.js +8 -2
  56. package/src/response/send-util.js +46 -14
@@ -1,15 +1,18 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
3
  import {
4
+ HTTP_HEADER_ACCEPT_PATCH,
5
+ HTTP_HEADER_ACCEPT_POST,
4
6
  HTTP_HEADER_ACCEPT_QUERY,
5
7
  HTTP_METHOD_QUERY,
6
8
  HTTP2_HEADER_ACCESS_CONTROL_MAX_AGE,
7
9
  PREFLIGHT_AGE_SECONDS
10
+
8
11
  } from '../../defs.js'
9
12
  import { send } from '../send-util.js'
10
13
 
11
14
  /** @import { ServerHttp2Stream } from 'node:http2' */
12
- /** @import { Metadata } from '../../defs.js' */
15
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
13
16
 
14
17
  const {
15
18
  HTTP2_HEADER_CONTENT_TYPE,
@@ -27,29 +30,38 @@ const { HTTP_STATUS_OK } = http2.constants
27
30
 
28
31
  /**
29
32
  * @param {ServerHttp2Stream} stream
30
- * @param {Array<string>} methods
31
- * @param {Array<string>|undefined} supportedQueryTypes
32
- * @param {'byte'|'none'|undefined} acceptRanges
33
+ * @param {Pick<SendInfo, 'supportedMethods' | 'supportedQueryTypes' | 'acceptRanges'>} info
33
34
  * @param {Metadata} meta
34
35
  */
35
- export function sendPreflight(stream, methods, supportedQueryTypes, acceptRanges, meta) {
36
- const supportsQuery = methods.includes(HTTP_METHOD_QUERY) && supportedQueryTypes !== undefined && supportedQueryTypes.length > 0
36
+ export function sendPreflight(stream, info, meta) {
37
+ const {
38
+ supportedMethods,
39
+ supportedQueryTypes,
40
+ acceptRanges
41
+ } = info
42
+
43
+ const supportsQuery = supportedMethods.includes(HTTP_METHOD_QUERY) && supportedQueryTypes !== undefined && supportedQueryTypes.length > 0
37
44
  const exposedHeadersAcceptQuery = supportsQuery ? [ HTTP_HEADER_ACCEPT_QUERY ] : []
38
45
  const exposedHeaders = acceptRanges === undefined ? exposedHeadersAcceptQuery : [ HTTP2_HEADER_ACCEPT_RANGES, ...exposedHeadersAcceptQuery ]
39
46
 
47
+ // todo: if supportedMethods includes POST | PATCH
48
+ // include accept-post / accept-patch headers
49
+
40
50
  send(stream, HTTP_STATUS_OK, {
41
- [HTTP2_HEADER_ACCESS_CONTROL_ALLOW_METHODS]: methods.join(','),
51
+ [HTTP2_HEADER_ACCESS_CONTROL_ALLOW_METHODS]: supportedMethods.join(','),
42
52
  [HTTP2_HEADER_ACCESS_CONTROL_ALLOW_HEADERS]: [
43
53
  HTTP2_HEADER_IF_MATCH,
44
54
  HTTP2_HEADER_IF_NONE_MATCH,
45
55
  HTTP2_HEADER_AUTHORIZATION,
46
- HTTP2_HEADER_CONTENT_TYPE,
47
- HTTP2_HEADER_RANGE,
56
+ HTTP2_HEADER_CONTENT_TYPE, // overrides cors safe restriction (for json)
57
+ HTTP2_HEADER_RANGE, // todo cors safe override not needed
48
58
  HTTP2_HEADER_IF_RANGE
49
59
  ].join(','),
50
60
  [HTTP2_HEADER_ACCESS_CONTROL_MAX_AGE]: PREFLIGHT_AGE_SECONDS,
61
+ // [HTTP_HEADER_ACCEPT_POST]: ,
62
+ // [HTTP_HEADER_ACCEPT_PATCH]: ,
51
63
  [HTTP2_HEADER_ACCEPT_RANGES]: acceptRanges,
52
- [HTTP_HEADER_ACCEPT_QUERY]: supportedQueryTypes?.join(',')
64
+ [HTTP_HEADER_ACCEPT_QUERY]: supportedQueryTypes?.join(',') // todo should empty array return undef
53
65
  // Access-Control-Allow-Credentials
54
66
  }, exposedHeaders, undefined, undefined, meta)
55
67
  }
@@ -0,0 +1,25 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { send } from '../send-util.js'
4
+
5
+ /** @import { ServerHttp2Stream } from 'node:http2' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
+
8
+ const {
9
+ HTTP2_HEADER_LOCATION
10
+ } = http2.constants
11
+
12
+ const { HTTP_STATUS_FOUND } = http2.constants
13
+
14
+ /**
15
+ * @param {ServerHttp2Stream} stream
16
+ * @param {URL|string} location
17
+ * @param {Metadata} meta
18
+ */
19
+ export function sendFound(stream, location, meta) {
20
+ const loc = (location instanceof URL) ? location.href : location
21
+
22
+ send(stream, HTTP_STATUS_FOUND, {
23
+ [HTTP2_HEADER_LOCATION]: loc
24
+ }, [ HTTP2_HEADER_LOCATION ], undefined, undefined, meta)
25
+ }
@@ -6,18 +6,20 @@ import { send } from '../send-util.js'
6
6
  /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const {
9
- HTTP2_HEADER_LOCATION
9
+ HTTP2_HEADER_LOCATION
10
10
  } = http2.constants
11
11
 
12
12
  const { HTTP_STATUS_MOVED_PERMANENTLY } = http2.constants
13
13
 
14
14
  /**
15
15
  * @param {ServerHttp2Stream} stream
16
- * @param {URL} location
16
+ * @param {URL|string} location
17
17
  * @param {Metadata} meta
18
18
  */
19
19
  export function sendMovedPermanently(stream, location, meta) {
20
- send(stream, HTTP_STATUS_MOVED_PERMANENTLY, {
21
- [HTTP2_HEADER_LOCATION]: location.href
22
- }, [ HTTP2_HEADER_LOCATION ], undefined, undefined, meta)
20
+ const loc = (location instanceof URL) ? location.href : location
21
+
22
+ send(stream, HTTP_STATUS_MOVED_PERMANENTLY, {
23
+ [HTTP2_HEADER_LOCATION]: loc
24
+ }, [HTTP2_HEADER_LOCATION], undefined, undefined, meta)
23
25
  }
@@ -5,13 +5,12 @@ import { Conditional } from '../../headers/conditional.js'
5
5
  import { send } from '../send-util.js'
6
6
 
7
7
  /** @import { ServerHttp2Stream } from 'node:http2' */
8
- /** @import { Metadata } from '../../defs.js' */
9
- /** @import { EtagItem } from '../../headers/conditional.js' */
10
- /** @import { CacheControlOptions } from '../../headers/cache-control.js' */
8
+ /** @import { SendContent, Metadata } from '../../defs.js' */
11
9
 
12
10
  const {
13
11
  HTTP2_HEADER_AGE,
14
12
  HTTP2_HEADER_ETAG,
13
+ HTTP2_HEADER_LAST_MODIFIED,
15
14
  HTTP2_HEADER_VARY,
16
15
  HTTP2_HEADER_CACHE_CONTROL
17
16
  } = http2.constants
@@ -20,16 +19,22 @@ const { HTTP_STATUS_NOT_MODIFIED } = http2.constants
20
19
 
21
20
  /**
22
21
  * @param {ServerHttp2Stream} stream
23
- * @param {EtagItem|undefined} etag
24
- * @param {number|undefined} age
25
- * @param {CacheControlOptions} cacheControl
22
+ * @param {Pick<SendContent, 'etag' | 'lastModified' | 'age' | 'cacheControl'>} content
26
23
  * @param {Metadata} meta
27
24
  */
28
- export function sendNotModified(stream, etag, age, cacheControl, meta) {
25
+ export function sendNotModified(stream, content, meta) {
26
+ const {
27
+ etag,
28
+ lastModified,
29
+ age,
30
+ cacheControl
31
+ } = content
32
+
29
33
  send(stream, HTTP_STATUS_NOT_MODIFIED, {
30
34
  [HTTP2_HEADER_VARY]: 'Accept, Accept-Encoding',
31
35
  [HTTP2_HEADER_CACHE_CONTROL]: CacheControl.encode(cacheControl),
32
36
  [HTTP2_HEADER_ETAG]: Conditional.encodeEtag(etag),
33
- [HTTP2_HEADER_AGE]: age === undefined ? undefined : `${age}`
37
+ [HTTP2_HEADER_LAST_MODIFIED]: Conditional.encodeFixDate(lastModified),
38
+ [HTTP2_HEADER_AGE]: Number.isInteger(age) ? `${age}` : undefined
34
39
  }, [ HTTP2_HEADER_AGE ], undefined, undefined, meta)
35
40
  }
@@ -13,11 +13,13 @@ const { HTTP_STATUS_PERMANENT_REDIRECT } = http2.constants
13
13
 
14
14
  /**
15
15
  * @param {ServerHttp2Stream} stream
16
- * @param {URL} location
16
+ * @param {URL|string} location
17
17
  * @param {Metadata} meta
18
18
  */
19
19
  export function sendPermanentRedirect(stream, location, meta) {
20
+ const loc = (location instanceof URL) ? location.href : location
21
+
20
22
  send(stream, HTTP_STATUS_PERMANENT_REDIRECT, {
21
- [HTTP2_HEADER_LOCATION]: location.href
23
+ [HTTP2_HEADER_LOCATION]: loc
22
24
  }, [ HTTP2_HEADER_LOCATION ], undefined, undefined, meta)
23
25
  }
@@ -6,18 +6,20 @@ import { send } from '../send-util.js'
6
6
  /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const {
9
- HTTP2_HEADER_LOCATION
9
+ HTTP2_HEADER_LOCATION
10
10
  } = http2.constants
11
11
 
12
12
  const { HTTP_STATUS_SEE_OTHER } = http2.constants
13
13
 
14
14
  /**
15
15
  * @param {ServerHttp2Stream} stream
16
- * @param {URL} location
16
+ * @param {URL|string} location
17
17
  * @param {Metadata} meta
18
18
  */
19
19
  export function sendSeeOther(stream, location, meta) {
20
- send(stream, HTTP_STATUS_SEE_OTHER, {
21
- [HTTP2_HEADER_LOCATION]: location.href
22
- }, [ HTTP2_HEADER_LOCATION ], undefined, undefined, meta)
20
+ const loc = (location instanceof URL) ? location.href : location
21
+
22
+ send(stream, HTTP_STATUS_SEE_OTHER, {
23
+ [HTTP2_HEADER_LOCATION]: loc
24
+ }, [HTTP2_HEADER_LOCATION], undefined, undefined, meta)
23
25
  }
@@ -13,11 +13,13 @@ const { HTTP_STATUS_TEMPORARY_REDIRECT } = http2.constants
13
13
 
14
14
  /**
15
15
  * @param {ServerHttp2Stream} stream
16
- * @param {URL} location
16
+ * @param {URL|string} location
17
17
  * @param {Metadata} meta
18
18
  */
19
19
  export function sendTemporaryRedirect(stream, location, meta) {
20
+ const loc = (location instanceof URL) ? location.href : location
21
+
20
22
  send(stream, HTTP_STATUS_TEMPORARY_REDIRECT, {
21
- [HTTP2_HEADER_LOCATION]: location.href
23
+ [HTTP2_HEADER_LOCATION]: loc
22
24
  }, [ HTTP2_HEADER_LOCATION ], undefined, undefined, meta)
23
25
  }
@@ -0,0 +1,19 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { CONTENT_TYPE_TEXT } from '../../headers/content-type.js'
4
+ import { send } from '../send-util.js'
5
+
6
+ /** @import { ServerHttp2Stream } from 'node:http2' */
7
+ /** @import { Metadata } from '../../defs.js' */
8
+
9
+ const { HTTP_STATUS_BAD_REQUEST } = http2.constants
10
+
11
+ /**
12
+ * @param {ServerHttp2Stream} stream
13
+ * @param {string} message
14
+ * @param {Metadata} meta
15
+ */
16
+ export function sendBadRequest(stream, message, meta) {
17
+ send(stream, HTTP_STATUS_BAD_REQUEST, {
18
+ }, [], CONTENT_TYPE_TEXT, message, meta)
19
+ }
@@ -12,5 +12,5 @@ const { HTTP_STATUS_PAYLOAD_TOO_LARGE } = http2.constants
12
12
  * @param {Metadata} meta
13
13
  */
14
14
  export function sendContentTooLarge(stream, meta) {
15
- send(stream, HTTP_STATUS_PAYLOAD_TOO_LARGE, {}, [], undefined, undefined, meta)
15
+ send(stream, HTTP_STATUS_PAYLOAD_TOO_LARGE, {}, [], undefined, undefined, meta)
16
16
  }
@@ -12,5 +12,5 @@ const { HTTP_STATUS_GONE } = http2.constants
12
12
  * @param {Metadata} meta
13
13
  */
14
14
  export function sendGone(stream, meta) {
15
- send(stream, HTTP_STATUS_GONE, {}, [], undefined, undefined, meta)
15
+ send(stream, HTTP_STATUS_GONE, {}, [], undefined, undefined, meta)
16
16
  }
@@ -12,5 +12,5 @@ const { HTTP_STATUS_TEAPOT } = http2.constants
12
12
  * @param {Metadata} meta
13
13
  */
14
14
  export function sendImATeapot(stream, meta) {
15
- send(stream, HTTP_STATUS_TEAPOT, {}, [], undefined, undefined, meta)
15
+ send(stream, HTTP_STATUS_TEAPOT, {}, [], undefined, undefined, meta)
16
16
  }
@@ -4,16 +4,18 @@ import { CONTENT_TYPE_JSON } from '../../headers/content-type.js'
4
4
  import { send } from '../send-util.js'
5
5
 
6
6
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
- /** @import { Metadata } from '../../defs.js' */
7
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
8
8
 
9
9
  const { HTTP_STATUS_NOT_ACCEPTABLE } = http2.constants
10
10
 
11
11
  /**
12
12
  * @param {ServerHttp2Stream} stream
13
- * @param {Array<string>|string} supportedTypes
13
+ * @param {Pick<SendInfo, 'supportedTypes'>} info
14
14
  * @param {Metadata} meta
15
15
  */
16
- export function sendNotAcceptable(stream, supportedTypes, meta) {
16
+ export function sendNotAcceptable(stream, info, meta) {
17
+ const { supportedTypes } = info
18
+
17
19
  const supportedTypesList = Array.isArray(supportedTypes) ? supportedTypes : [ supportedTypes ]
18
20
  const has = supportedTypesList.length > 0
19
21
 
@@ -22,6 +24,6 @@ export function sendNotAcceptable(stream, supportedTypes, meta) {
22
24
  {},
23
25
  [],
24
26
  has ? CONTENT_TYPE_JSON : undefined,
25
- has ? JSON.stringify(supportedTypes) : undefined,
27
+ has ? JSON.stringify({ supportedTypes: supportedTypesList }) : undefined,
26
28
  meta)
27
29
  }
@@ -3,7 +3,7 @@ import http2 from 'node:http2'
3
3
  import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from '../../defs.js' */
6
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
7
7
 
8
8
  const {
9
9
  HTTP_STATUS_METHOD_NOT_ALLOWED
@@ -13,11 +13,13 @@ const { HTTP2_HEADER_ALLOW } = http2.constants
13
13
 
14
14
  /**
15
15
  * @param {ServerHttp2Stream} stream
16
- * @param {Array<string>} methods
16
+ * @param {Pick<SendInfo, 'supportedMethods'>} info
17
17
  * @param {Metadata} meta
18
18
  */
19
- export function sendNotAllowed(stream, methods, meta) {
19
+ export function sendNotAllowed(stream, info, meta) {
20
+ const { supportedMethods } = info
21
+
20
22
  send(stream, HTTP_STATUS_METHOD_NOT_ALLOWED, {
21
- [HTTP2_HEADER_ALLOW]: methods.join(',')
23
+ [HTTP2_HEADER_ALLOW]: supportedMethods.join(',')
22
24
  }, [ HTTP2_HEADER_ALLOW ], undefined, undefined, meta)
23
25
  }
@@ -0,0 +1,17 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { send } from '../send-util.js'
4
+
5
+ /** @import { ServerHttp2Stream } from 'node:http2' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
+
8
+ const { HTTP_STATUS_PAYMENT_REQUIRED } = http2.constants
9
+
10
+ /**
11
+ * @param {ServerHttp2Stream} stream
12
+ * @param {Metadata} meta
13
+ */
14
+ export function sendPaymentRequired(stream, meta) {
15
+ send(stream, HTTP_STATUS_PAYMENT_REQUIRED, {
16
+ }, [ ], undefined, undefined, meta)
17
+ }
@@ -1,16 +1,31 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
+ import { Conditional } from '../../headers/conditional.js'
3
4
  import { send } from '../send-util.js'
4
5
 
5
6
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from '../../defs.js' */
7
+ /** @import { SendContent, Metadata } from '../../defs.js' */
8
+
9
+ const {
10
+ HTTP2_HEADER_ETAG,
11
+ HTTP2_HEADER_LAST_MODIFIED
12
+ } = http2.constants
7
13
 
8
14
  const { HTTP_STATUS_PRECONDITION_FAILED } = http2.constants
9
15
 
10
16
  /**
11
17
  * @param {ServerHttp2Stream} stream
18
+ * @param {Pick<SendContent, 'etag' | 'lastModified'>} content
12
19
  * @param {Metadata} meta
13
20
  */
14
- export function sendPreconditionFailed(stream, meta) {
15
- send(stream, HTTP_STATUS_PRECONDITION_FAILED, {}, [], undefined, undefined, meta)
21
+ export function sendPreconditionFailed(stream, content, meta) {
22
+ const {
23
+ etag,
24
+ lastModified
25
+ } = content
26
+
27
+ send(stream, HTTP_STATUS_PRECONDITION_FAILED, {
28
+ [HTTP2_HEADER_ETAG]: Conditional.encodeEtag(etag),
29
+ [HTTP2_HEADER_LAST_MODIFIED]: Conditional.encodeFixDate(lastModified)
30
+ }, [], undefined, undefined, meta)
16
31
  }
@@ -4,7 +4,7 @@ import { CONTENT_RANGE_UNKNOWN, ContentRange } from '../../headers/content-range
4
4
  import { send } from '../send-util.js'
5
5
 
6
6
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
- /** @import { Metadata } from '../../defs.js' */
7
+ /** @import { SendContent, Metadata } from '../../defs.js' */
8
8
  /** @import { ContentRangeDirective} from '../../headers/content-range.js' */
9
9
 
10
10
  const {
@@ -15,10 +15,12 @@ const { HTTP_STATUS_RANGE_NOT_SATISFIABLE } = http2.constants
15
15
 
16
16
  /**
17
17
  * @param {ServerHttp2Stream} stream
18
- * @param {ContentRangeDirective} rangeDirective
18
+ * @param {Pick<SendContent, 'rangeDirective'>} content
19
19
  * @param {Metadata} meta
20
20
  */
21
- export function sendRangeNotSatisfiable(stream, rangeDirective, meta) {
21
+ export function sendRangeNotSatisfiable(stream, content, meta) {
22
+ const { rangeDirective } = content
23
+
22
24
  /** @type {ContentRangeDirective} */
23
25
  const invalidRange = { size: rangeDirective.size, range: CONTENT_RANGE_UNKNOWN }
24
26
 
@@ -10,8 +10,7 @@ import {
10
10
  import { send } from '../send-util.js'
11
11
 
12
12
  /** @import { ServerHttp2Stream } from 'node:http2' */
13
- /** @import { Metadata } from '../../defs.js' */
14
- /** @import { RateLimitInfo, RateLimitPolicyInfo } from '../../headers/rate-limit.js' */
13
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
15
14
 
16
15
  const {
17
16
  HTTP2_HEADER_RETRY_AFTER
@@ -21,11 +20,15 @@ const { HTTP_STATUS_TOO_MANY_REQUESTS } = http2.constants
21
20
 
22
21
  /**
23
22
  * @param {ServerHttp2Stream} stream
24
- * @param {RateLimitInfo} limitInfo
25
- * @param {Array<RateLimitPolicyInfo>} policies
23
+ * @param {Pick<SendInfo, 'limitInfo' | 'policies'>} info
26
24
  * @param {Metadata} meta
27
25
  */
28
- export function sendTooManyRequests(stream, limitInfo, policies, meta) {
26
+ export function sendTooManyRequests(stream, info, meta) {
27
+ const {
28
+ limitInfo,
29
+ policies
30
+ } = info
31
+
29
32
  send(stream, HTTP_STATUS_TOO_MANY_REQUESTS, {
30
33
  [HTTP2_HEADER_RETRY_AFTER]: `${limitInfo.resetSeconds}`,
31
34
  [HTTP_HEADER_RATE_LIMIT]: RateLimit.from(limitInfo),
@@ -20,6 +20,6 @@ const { HTTP_STATUS_UNAUTHORIZED } = http2.constants
20
20
  */
21
21
  export function sendUnauthorized(stream, challenge, meta) {
22
22
  send(stream, HTTP_STATUS_UNAUTHORIZED, {
23
- [HTTP2_HEADER_WWW_AUTHENTICATE]: challenge?.map(Challenge.encode),
23
+ [HTTP2_HEADER_WWW_AUTHENTICATE]: challenge?.map(Challenge.encode), // todo stringify ?
24
24
  }, [ HTTP2_HEADER_WWW_AUTHENTICATE ], undefined, undefined, meta)
25
25
  }
@@ -4,7 +4,7 @@ import { HTTP_HEADER_ACCEPT_PATCH, HTTP_HEADER_ACCEPT_POST, HTTP_HEADER_ACCEPT_Q
4
4
  import { send } from '../send-util.js'
5
5
 
6
6
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
- /** @import { Metadata } from '../../defs.js' */
7
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
8
8
 
9
9
  const { HTTP2_METHOD_POST, HTTP2_METHOD_PATCH } = http2.constants
10
10
 
@@ -12,16 +12,20 @@ const { HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE } = http2.constants
12
12
 
13
13
  /**
14
14
  * @param {ServerHttp2Stream} stream
15
- * @param {Array<string>|string} acceptableMediaType
16
- * @param {Array<string>|undefined} supportedQueryTypes
15
+ * @param {Pick<SendInfo, 'acceptableMediaType' | 'supportedQueryTypes'>} info
17
16
  * @param {Metadata} meta
18
17
  */
19
- export function sendUnsupportedMediaType(stream, acceptableMediaType, supportedQueryTypes, meta) {
18
+ export function sendUnsupportedMediaType(stream, info, meta) {
19
+ const {
20
+ supportedQueryTypes,
21
+ acceptableMediaType
22
+ } = info
23
+
20
24
  const supportsQuery = supportedQueryTypes !== undefined && supportedQueryTypes.length > 0
21
25
  const exposedHeaders = supportsQuery ? [ HTTP_HEADER_ACCEPT_QUERY, HTTP_HEADER_ACCEPT_POST ] : [ HTTP_HEADER_ACCEPT_POST ]
22
26
 
23
27
  const method = HTTP2_METHOD_POST // todo pass in as parameter or split acceptable to post and patch types
24
- const acceptable = Array.isArray(acceptableMediaType) ? acceptableMediaType : [ acceptableMediaType ]
28
+ const acceptable = Array.isArray(acceptableMediaType) ? acceptableMediaType : [ acceptableMediaType ] // todo undefined creates array of one item
25
29
  const acceptHeader = (method === HTTP2_METHOD_POST) ? HTTP_HEADER_ACCEPT_POST : HTTP_HEADER_ACCEPT_PATCH
26
30
  const acceptValue = ((method === HTTP2_METHOD_POST) || (method === HTTP2_METHOD_PATCH)) ? acceptable.join(',') : undefined
27
31
 
@@ -1,7 +1,6 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { CONTENT_TYPE_TEXT } from '../../headers/content-type.js'
4
- import { send } from '../send-util.js'
3
+ import { send_error } from '../send-util.js'
5
4
 
6
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
6
  /** @import { Metadata } from '../../defs.js' */
@@ -14,5 +13,5 @@ const { HTTP_STATUS_INTERNAL_SERVER_ERROR } = http2.constants
14
13
  * @param {Metadata} meta
15
14
  */
16
15
  export function sendError(stream, message, meta) {
17
- send(stream, HTTP_STATUS_INTERNAL_SERVER_ERROR, {}, [], CONTENT_TYPE_TEXT, message, meta)
16
+ send_error(stream, HTTP_STATUS_INTERNAL_SERVER_ERROR, message, undefined, meta)
18
17
  }
@@ -1,6 +1,6 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from '../send-util.js'
3
+ import { send_error } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
6
  /** @import { Metadata } from '../../defs.js' */
@@ -12,5 +12,5 @@ const { HTTP_STATUS_INSUFFICIENT_STORAGE } = http2.constants
12
12
  * @param {Metadata} meta
13
13
  */
14
14
  export function sendInsufficientStorage(stream, meta) {
15
- send(stream, HTTP_STATUS_INSUFFICIENT_STORAGE, {}, [], undefined, undefined, meta)
15
+ send_error(stream, HTTP_STATUS_INSUFFICIENT_STORAGE, 'Insufficient Storage', undefined, meta)
16
16
  }
@@ -1,7 +1,6 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { CONTENT_TYPE_TEXT } from '../../headers/content-type.js'
4
- import { send } from '../send-util.js'
3
+ import { send_error } from '../send-util.js'
5
4
 
6
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
6
  /** @import { Metadata } from '../../defs.js' */
@@ -14,5 +13,5 @@ const { HTTP_STATUS_NOT_IMPLEMENTED } = http2.constants
14
13
  * @param {Metadata} meta
15
14
  */
16
15
  export function sendNotImplemented(stream, message, meta) {
17
- send(stream, HTTP_STATUS_NOT_IMPLEMENTED, {}, [], CONTENT_TYPE_TEXT, message, meta)
16
+ send_error(stream, HTTP_STATUS_NOT_IMPLEMENTED, message, undefined, meta)
18
17
  }
@@ -1,25 +1,20 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { CONTENT_TYPE_TEXT } from '../../headers/content-type.js'
4
- import { send } from '../send-util.js'
3
+ import { send_error } from '../send-util.js'
5
4
 
6
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
- /** @import { Metadata } from '../../defs.js' */
8
-
9
- const {
10
- HTTP2_HEADER_RETRY_AFTER
11
- } = http2.constants
6
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
12
7
 
13
8
  const { HTTP_STATUS_SERVICE_UNAVAILABLE } = http2.constants
14
9
 
15
10
  /**
16
11
  * @param {ServerHttp2Stream} stream
17
12
  * @param {string|undefined} message
18
- * @param {number|undefined} retryAfter
13
+ * @param {Pick<SendInfo, 'retryAfter'>} info
19
14
  * @param {Metadata} meta
20
15
  */
21
- export function sendUnavailable(stream, message, retryAfter, meta) {
22
- send(stream, HTTP_STATUS_SERVICE_UNAVAILABLE, {
23
- [HTTP2_HEADER_RETRY_AFTER]: Number.isInteger(retryAfter) ? `${retryAfter}` : undefined
24
- }, [ HTTP2_HEADER_RETRY_AFTER ], CONTENT_TYPE_TEXT, message, meta)
16
+ export function sendUnavailable(stream, message, info, meta) {
17
+ const { retryAfter } = info
18
+
19
+ send_error(stream, HTTP_STATUS_SERVICE_UNAVAILABLE, message, retryAfter, meta)
25
20
  }
@@ -27,7 +27,7 @@ const {
27
27
  * @returns {OutgoingHttpHeaders}
28
28
  */
29
29
  export function coreHeaders(status, contentType, exposedHeaders, meta) {
30
- const exposed = [ HTTP2_HEADER_ETAG, HTTP2_HEADER_SERVER, ...exposedHeaders ]
30
+ const exposed = [ HTTP2_HEADER_ETAG, HTTP2_HEADER_SERVER, ...exposedHeaders ] // todo include lastModified
31
31
 
32
32
  return {
33
33
  [HTTP2_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN]: meta.origin,
@@ -1,6 +1,7 @@
1
1
  /** biome-ignore-all lint/performance/noBarrelFile: entry point */
2
2
  /** biome-ignore-all lint/performance/noReExportAll: entry point */
3
3
  export * from '../defs.js'
4
+ export * from './header-util.js'
4
5
  export * from './send-util.js'
5
6
  // end common headers
6
7
 
@@ -13,12 +14,14 @@ export * from './2xx/partial-content.js'
13
14
  export * from './2xx/preflight.js'
14
15
  export * from './2xx/sse.js'
15
16
  export * from './2xx/trace.js'
17
+ export * from './3xx/found.js'
16
18
  export * from './3xx/moved-permanently.js'
17
19
  export * from './3xx/multiple-choices.js'
18
20
  export * from './3xx/not-modified.js'
19
21
  export * from './3xx/permanent-redirect.js'
20
22
  export * from './3xx/see-other.js'
21
23
  export * from './3xx/temporary-redirect.js'
24
+ export * from './4xx/bad-request.js'
22
25
  export * from './4xx/conflict.js'
23
26
  export * from './4xx/content-too-large.js'
24
27
  export * from './4xx/forbidden.js'
@@ -27,6 +30,7 @@ export * from './4xx/im-a-teapot.js'
27
30
  export * from './4xx/not-acceptable.js'
28
31
  export * from './4xx/not-allowed.js'
29
32
  export * from './4xx/not-found.js'
33
+ export * from './4xx/payment-required.js'
30
34
  export * from './4xx/precondition-failed.js'
31
35
  export * from './4xx/range-not-satisfiable.js'
32
36
  export * from './4xx/timeout.js'