@centralping/ergo 0.1.0-beta.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 (155) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +21 -0
  3. package/README.md +139 -0
  4. package/http/accepts.js +69 -0
  5. package/http/authorization.js +65 -0
  6. package/http/body.js +311 -0
  7. package/http/cache-control.js +123 -0
  8. package/http/compress.js +157 -0
  9. package/http/cookie.js +39 -0
  10. package/http/cors.js +79 -0
  11. package/http/csrf.js +76 -0
  12. package/http/handler.js +74 -0
  13. package/http/index.js +13 -0
  14. package/http/json-api-query.js +53 -0
  15. package/http/logger.js +167 -0
  16. package/http/main.js +140 -0
  17. package/http/precondition.js +53 -0
  18. package/http/prefer.js +36 -0
  19. package/http/rate-limit.js +66 -0
  20. package/http/security-headers.js +62 -0
  21. package/http/send.js +399 -0
  22. package/http/timeout.js +47 -0
  23. package/http/url.js +47 -0
  24. package/http/validate.js +84 -0
  25. package/lib/accepts.js +49 -0
  26. package/lib/attach-instance.js +23 -0
  27. package/lib/authorization.js +187 -0
  28. package/lib/body/multiparse.js +173 -0
  29. package/lib/body/multipart/headers.js +69 -0
  30. package/lib/body/writer.js +73 -0
  31. package/lib/cookie/cookie.js +192 -0
  32. package/lib/cookie/index.js +14 -0
  33. package/lib/cookie/jar.js +106 -0
  34. package/lib/cookie/parse.js +101 -0
  35. package/lib/cors.js +191 -0
  36. package/lib/csrf.js +96 -0
  37. package/lib/from-connect.js +69 -0
  38. package/lib/json-api-query/index.js +25 -0
  39. package/lib/json-api-query/schema.json +105 -0
  40. package/lib/json-api-query/validate.js +56 -0
  41. package/lib/link.js +96 -0
  42. package/lib/prefer.js +52 -0
  43. package/lib/query.js +113 -0
  44. package/lib/rate-limit.js +115 -0
  45. package/lib/sanitize-quoted-string.js +28 -0
  46. package/lib/security-headers.js +125 -0
  47. package/lib/validate.js +80 -0
  48. package/lib/vary.js +40 -0
  49. package/package.json +158 -0
  50. package/types/http/accepts.d.ts +8 -0
  51. package/types/http/authorization.d.ts +8 -0
  52. package/types/http/body.d.ts +20 -0
  53. package/types/http/cache-control.d.ts +16 -0
  54. package/types/http/compress.d.ts +5 -0
  55. package/types/http/cookie.d.ts +2 -0
  56. package/types/http/cors.d.ts +9 -0
  57. package/types/http/csrf.d.ts +9 -0
  58. package/types/http/handler.d.ts +2 -0
  59. package/types/http/index.d.ts +1 -0
  60. package/types/http/json-api-query.d.ts +2 -0
  61. package/types/http/logger.d.ts +9 -0
  62. package/types/http/main.d.ts +142 -0
  63. package/types/http/precondition.d.ts +44 -0
  64. package/types/http/prefer.d.ts +2 -0
  65. package/types/http/rate-limit.d.ts +17 -0
  66. package/types/http/security-headers.d.ts +10 -0
  67. package/types/http/send.d.ts +8 -0
  68. package/types/http/timeout.d.ts +5 -0
  69. package/types/http/url.d.ts +2 -0
  70. package/types/http/validate.d.ts +6 -0
  71. package/types/lib/accepts.d.ts +7 -0
  72. package/types/lib/attach-instance.d.ts +19 -0
  73. package/types/lib/authorization.d.ts +6 -0
  74. package/types/lib/body/multiparse.d.ts +9 -0
  75. package/types/lib/body/multipart/headers.d.ts +2 -0
  76. package/types/lib/body/writer.d.ts +2 -0
  77. package/types/lib/cookie/cookie.d.ts +32 -0
  78. package/types/lib/cookie/index.d.ts +2 -0
  79. package/types/lib/cookie/jar.d.ts +8 -0
  80. package/types/lib/cookie/parse.d.ts +19 -0
  81. package/types/lib/cors.d.ts +9 -0
  82. package/types/lib/csrf.d.ts +32 -0
  83. package/types/lib/from-connect.d.ts +47 -0
  84. package/types/lib/json-api-query/index.d.ts +123 -0
  85. package/types/lib/json-api-query/validate.d.ts +5 -0
  86. package/types/lib/link.d.ts +37 -0
  87. package/types/lib/prefer.d.ts +36 -0
  88. package/types/lib/query.d.ts +6 -0
  89. package/types/lib/rate-limit.d.ts +76 -0
  90. package/types/lib/sanitize-quoted-string.d.ts +19 -0
  91. package/types/lib/security-headers.d.ts +24 -0
  92. package/types/lib/validate.d.ts +16 -0
  93. package/types/lib/vary.d.ts +17 -0
  94. package/types/utils/attempt.d.ts +2 -0
  95. package/types/utils/buffers/index.d.ts +2 -0
  96. package/types/utils/buffers/match.d.ts +10 -0
  97. package/types/utils/buffers/split.d.ts +10 -0
  98. package/types/utils/compose-with.d.ts +40 -0
  99. package/types/utils/compose.d.ts +83 -0
  100. package/types/utils/flat-array.d.ts +2 -0
  101. package/types/utils/get.d.ts +5 -0
  102. package/types/utils/http-errors.d.ts +22 -0
  103. package/types/utils/iterables/buffer-split.d.ts +2 -0
  104. package/types/utils/iterables/chain.d.ts +2 -0
  105. package/types/utils/iterables/exec-all.d.ts +2 -0
  106. package/types/utils/iterables/filter.d.ts +2 -0
  107. package/types/utils/iterables/for-each.d.ts +2 -0
  108. package/types/utils/iterables/from-stream.d.ts +2 -0
  109. package/types/utils/iterables/index.d.ts +10 -0
  110. package/types/utils/iterables/map.d.ts +2 -0
  111. package/types/utils/iterables/range.d.ts +24 -0
  112. package/types/utils/iterables/reduce.d.ts +2 -0
  113. package/types/utils/iterables/take.d.ts +2 -0
  114. package/types/utils/observables/buffer-split.d.ts +2 -0
  115. package/types/utils/observables/chain.d.ts +2 -0
  116. package/types/utils/observables/index.d.ts +4 -0
  117. package/types/utils/observables/map.d.ts +2 -0
  118. package/types/utils/observables/take.d.ts +2 -0
  119. package/types/utils/pick.d.ts +2 -0
  120. package/types/utils/set.d.ts +2 -0
  121. package/types/utils/streams/index.d.ts +2 -0
  122. package/types/utils/streams/meter.d.ts +5 -0
  123. package/types/utils/streams/tee.d.ts +2 -0
  124. package/types/utils/type.d.ts +2 -0
  125. package/utils/attempt.js +37 -0
  126. package/utils/buffers/index.js +13 -0
  127. package/utils/buffers/match.js +96 -0
  128. package/utils/buffers/split.js +55 -0
  129. package/utils/compose-with.js +232 -0
  130. package/utils/compose.js +165 -0
  131. package/utils/flat-array.js +24 -0
  132. package/utils/get.js +39 -0
  133. package/utils/http-errors.js +113 -0
  134. package/utils/iterables/buffer-split.js +117 -0
  135. package/utils/iterables/chain.js +32 -0
  136. package/utils/iterables/exec-all.js +42 -0
  137. package/utils/iterables/filter.js +35 -0
  138. package/utils/iterables/for-each.js +33 -0
  139. package/utils/iterables/from-stream.js +29 -0
  140. package/utils/iterables/index.js +21 -0
  141. package/utils/iterables/map.js +47 -0
  142. package/utils/iterables/range.js +34 -0
  143. package/utils/iterables/reduce.js +43 -0
  144. package/utils/iterables/take.js +36 -0
  145. package/utils/observables/buffer-split.js +109 -0
  146. package/utils/observables/chain.js +33 -0
  147. package/utils/observables/index.js +19 -0
  148. package/utils/observables/map.js +34 -0
  149. package/utils/observables/take.js +40 -0
  150. package/utils/pick.js +41 -0
  151. package/utils/set.js +38 -0
  152. package/utils/streams/index.js +11 -0
  153. package/utils/streams/meter.js +98 -0
  154. package/utils/streams/tee.js +84 -0
  155. package/utils/type.js +47 -0
@@ -0,0 +1,6 @@
1
+ declare function _default(strategies?: Array<{
2
+ type: string;
3
+ attributes?: object;
4
+ authorizer: Function;
5
+ }>): Function;
6
+ export default _default;
@@ -0,0 +1,9 @@
1
+ declare function _default(rawbody: any, boundary: any, { maxParts }?: {
2
+ maxParts?: number | undefined;
3
+ }): {
4
+ headers: object;
5
+ name: any;
6
+ filename: any;
7
+ body: any;
8
+ }[];
9
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare function _default(buffers?: Array<any | string>, headers?: object): object;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare function _default(): any;
2
+ export default _default;
@@ -0,0 +1,32 @@
1
+ export default bake;
2
+ /**
3
+ * A cookie factory function.
4
+ * @param {string} name - The name of the cookie.
5
+ * @param {string} [value] - The value of the cookie. If undefined
6
+ * as well as expires and maxAge are undefined, then the cookie will be set to expire.
7
+ * @param {object} [directives] - See {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies|Cookies} for more information about directives.
8
+ * @param {string} [directives.domain] - The domain of the cookie. Defaults to
9
+ * the host portion of the current document location. If a domain is specified,
10
+ * subdomains are always included.
11
+ * @param {string} [directives.path='/'] - The absolute path of the cookie. Defaults
12
+ * to the current path of the current document location.
13
+ * @param {boolean} [directives.secure=true] - Indicates whether the cookie is
14
+ * transmitted over secure protocols such as HTTPS.
15
+ * @param {boolean} [directives.httpOnly=true] - Indicates whether the cookie is
16
+ * accessible via client JavaScript (e.g. document.cookie, Request, XMLHttpRequest, etc.).
17
+ * @param {'lax'|'strict'|'none'} [directives.sameSite] - Indicates if a cookie shouldn't be sent
18
+ * with cross-site requests. See {@link https://www.owasp.org/index.php/SameSite|SameSite} for more information.
19
+ * @param {number} [directives.maxAge] - The maximum age of a cookie in seconds.
20
+ * @param {(Date|string|number)} [directives.expires] - The GMT timestamp of the cookie
21
+ * expiration.
22
+ * @returns {object} - A cookie object with name, value, directives, and toHeader().
23
+ */
24
+ declare function bake(name: string, value?: string, { domain, path, maxAge, expires, sameSite, secure, httpOnly }?: {
25
+ domain?: string | undefined;
26
+ path?: string | undefined;
27
+ secure?: boolean | undefined;
28
+ httpOnly?: boolean | undefined;
29
+ sameSite?: "lax" | "none" | "strict" | undefined;
30
+ maxAge?: number | undefined;
31
+ expires?: string | number | Date | undefined;
32
+ }): object;
@@ -0,0 +1,2 @@
1
+ export { default as parse } from "./parse.js";
2
+ export { default as jar } from "./jar.js";
@@ -0,0 +1,8 @@
1
+ export default jar;
2
+ /**
3
+ * Creates a cookie jar pre-populated from a parsed cookie object.
4
+ *
5
+ * @param {object} [cookies={}] - Initial cookie values (from `parse()`)
6
+ * @returns {object} - Cookie jar with `get`, `set`, `clear`, `toHeader`, `size` members
7
+ */
8
+ declare function jar(cookies?: object): object;
@@ -0,0 +1,19 @@
1
+ export default parse;
2
+ /**
3
+ * Parses a `Cookie` header string into a key-value map.
4
+ *
5
+ * @param {string} [cookie=''] - Raw value of the `Cookie` HTTP header
6
+ * @param {object} [options] - Parser configuration
7
+ * @param {function} [options.decoder=v=>v] - Transform applied to each `[name, value]` pair
8
+ * @param {boolean} [options.loose=false] - Use RFC 2109 (lenient) instead of RFC 6265 (strict) parsing
9
+ * @param {boolean} [options.collection=true] - Aggregate duplicate names into arrays
10
+ * @param {number} [options.max=50] - Maximum number of cookies; throws on excess
11
+ * @returns {object} - Plain object of cookie name → value (or string[])
12
+ * @throws {Error} If `max` is exceeded
13
+ */
14
+ declare function parse(cookie?: string, { decoder, loose, collection, max }?: {
15
+ decoder?: Function | undefined;
16
+ loose?: boolean | undefined;
17
+ collection?: boolean | undefined;
18
+ max?: number | undefined;
19
+ }): object;
@@ -0,0 +1,9 @@
1
+ declare function _default({ origins, allowMethods, allowCredentials, allowHeaders, exposeHeaders, maxAge }?: {
2
+ origins?: string | Function | RegExp | any[] | undefined;
3
+ allowMethods?: string[] | undefined;
4
+ allowCredentials?: boolean | undefined;
5
+ allowHeaders?: string | Function | RegExp | any[] | undefined;
6
+ exposeHeaders?: string | string[] | undefined;
7
+ maxAge?: number | undefined;
8
+ }): Function;
9
+ export default _default;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Issues a new CSRF token/UUID pair signed with HMAC-SHA256.
3
+ *
4
+ * @param {string} secret - Shared HMAC secret; throws `TypeError` if missing
5
+ * @param {string} [uuid=randomUUID()] - Pre-existing UUID to bind the token to
6
+ * @param {string} [encoding='base64'] - Node.js digest encoding for the token
7
+ * @returns {{token: string, uuid: string}} - The signed token and its associated UUID
8
+ * @throws {TypeError} If `secret` is not provided
9
+ */
10
+ export function issue(secret?: string, uuid?: string, encoding?: string): {
11
+ token: string;
12
+ uuid: string;
13
+ };
14
+ /**
15
+ * Verifies a CSRF token against the expected value for the given secret and UUID.
16
+ *
17
+ * Uses `crypto.timingSafeEqual()` to prevent timing attacks. Returns `false` (not throws)
18
+ * for any mismatch, length difference, or type error.
19
+ *
20
+ * @param {string} token - The token from the request header
21
+ * @param {object} key - Key components used to re-derive the expected token
22
+ * @param {string} key.secret - Shared HMAC secret; throws `TypeError` if missing
23
+ * @param {string} key.uuid - UUID from the CSRF cookie; throws `TypeError` if missing
24
+ * @param {string} [key.encoding='base64'] - Encoding used when the token was issued
25
+ * @returns {boolean} - `true` if the token is valid, `false` otherwise
26
+ * @throws {TypeError} If `secret` or `uuid` are not provided
27
+ */
28
+ export function verify(token: string, { secret, uuid, encoding }?: {
29
+ secret: string;
30
+ uuid: string;
31
+ encoding?: string | undefined;
32
+ }): boolean;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @fileoverview Adapter for Connect/Express-style middleware.
3
+ *
4
+ * Wraps a Connect-style `(req, res, next)` middleware into ergo's
5
+ * `(req, res) => Promise<undefined>` signature so it can be used inside
6
+ * ergo's `compose()` pipeline.
7
+ *
8
+ * The adapter handles two completion signals:
9
+ * - `next()` called — the standard path; promise resolves and the pipeline continues.
10
+ * - `res` `finish` event — fallback for middleware that ends the response directly
11
+ * (e.g., CORS preflight, rate limiter sending 429) without calling `next()`.
12
+ *
13
+ * A `settled` guard prevents double-resolution from buggy middleware that calls
14
+ * `next()` multiple times or calls `next()` after ending the response.
15
+ *
16
+ * Returns `undefined` so neither the domain nor response accumulator is affected.
17
+ * Connect middleware communicates via side effects on `res` headers.
18
+ *
19
+ * Limitations:
20
+ * - Express error-handling middleware `(err, req, res, next)` is not supported.
21
+ * Ergo handles errors via `handler()` / `attempt()` try/catch.
22
+ * - Connect middleware may mutate `req` (e.g., `req.user`). This violates ergo's
23
+ * no-mutation convention but is accepted at the interop boundary.
24
+ *
25
+ * @module lib/from-connect
26
+ * @version 0.1.0
27
+ * @since 0.1.0
28
+ *
29
+ * @example
30
+ * import {compose, handler} from 'ergo';
31
+ * import fromConnect from 'ergo/lib/from-connect';
32
+ * import helmet from 'helmet';
33
+ *
34
+ * const pipeline = compose(
35
+ * fromConnect(helmet()),
36
+ * () => ({response: {body: {ok: true}}})
37
+ * );
38
+ *
39
+ * export default handler(pipeline);
40
+ */
41
+ /**
42
+ * Wrap a Connect/Express-style middleware for use in an ergo pipeline.
43
+ *
44
+ * @param {function} middleware - Connect middleware `(req, res, next) => void`
45
+ * @returns {function} - Ergo-compatible middleware `(req, res) => Promise<undefined>`
46
+ */
47
+ export default function fromConnect(middleware: Function): Function;
@@ -0,0 +1,123 @@
1
+ export { default as validate } from "./validate.js";
2
+ /**
3
+ * A deep copy of the default JSON API query schema, computed once at module load.
4
+ * Callers should clone again if mutation is needed.
5
+ *
6
+ * @member {object} schema JSON Schema 2020-12
7
+ */
8
+ export const schema: {
9
+ $schema: string;
10
+ $id: string;
11
+ title: string;
12
+ description: string;
13
+ type: string;
14
+ properties: {
15
+ fields: {
16
+ description: string;
17
+ type: string;
18
+ additionalProperties: {
19
+ type: string;
20
+ items: {
21
+ type: string;
22
+ };
23
+ uniqueItems: boolean;
24
+ minItems: number;
25
+ };
26
+ minProperties: number;
27
+ };
28
+ filter: {
29
+ description: string;
30
+ type: string;
31
+ minProperties: number;
32
+ };
33
+ include: {
34
+ description: string;
35
+ type: string;
36
+ items: {
37
+ type: string;
38
+ };
39
+ uniqueItems: boolean;
40
+ minItems: number;
41
+ };
42
+ page: {
43
+ description: string;
44
+ type: string;
45
+ properties: {
46
+ cursor: {
47
+ type: string;
48
+ minLength: number;
49
+ };
50
+ size: {
51
+ type: string;
52
+ minimum: number;
53
+ };
54
+ number: {
55
+ type: string;
56
+ minimum: number;
57
+ };
58
+ limit: {
59
+ type: string;
60
+ minimum: number;
61
+ };
62
+ offset: {
63
+ type: string;
64
+ minimum: number;
65
+ };
66
+ };
67
+ dependentRequired: {
68
+ offset: string[];
69
+ number: string[];
70
+ };
71
+ additionalProperties: boolean;
72
+ minProperties: number;
73
+ if: {
74
+ required: string[];
75
+ };
76
+ then: {
77
+ maxProperties: number;
78
+ };
79
+ else: {
80
+ maxProperties: number;
81
+ if: {
82
+ required: string[];
83
+ };
84
+ then: {
85
+ not: {
86
+ required: string[];
87
+ };
88
+ };
89
+ };
90
+ };
91
+ sort: {
92
+ description: string;
93
+ type: string;
94
+ items: {
95
+ type: string;
96
+ };
97
+ uniqueItems: boolean;
98
+ minItems: number;
99
+ };
100
+ };
101
+ patternProperties: {
102
+ "[^a-z]": {
103
+ description: string;
104
+ type: string[];
105
+ };
106
+ };
107
+ additionalProperties: boolean;
108
+ if: {
109
+ required: string[];
110
+ properties: {
111
+ page: {
112
+ required: string[];
113
+ };
114
+ };
115
+ };
116
+ then: {
117
+ not: {
118
+ anyOf: {
119
+ required: string[];
120
+ }[];
121
+ };
122
+ };
123
+ };
@@ -0,0 +1,5 @@
1
+ declare function _default({ coerceTypes, ownProperties, ...ajvOptions }?: {
2
+ coerceTypes?: string | boolean | undefined;
3
+ ownProperties?: boolean | undefined;
4
+ }, schema?: object): Function;
5
+ export default _default;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Formats an array of link objects into an RFC 8288 `Link` header value.
3
+ *
4
+ * @param {Array<{href: string, rel: string}>} links - Link descriptors. Each object
5
+ * must have `href` and `rel`; additional properties become link parameters.
6
+ * @returns {string} - Formatted header value (e.g. `<url>; rel="next", <url>; rel="prev"`)
7
+ * @throws {TypeError} If `href` contains `>` or a parameter key is not a valid token
8
+ */
9
+ export function formatLinkHeader(links: Array<{
10
+ href: string;
11
+ rel: string;
12
+ }>): string;
13
+ /**
14
+ * Generates pagination link objects for first, prev, next, and last pages.
15
+ *
16
+ * Only includes `prev` when `page > 1` and `next` when `page < lastPage`.
17
+ * `first` and `last` are always included.
18
+ *
19
+ * @param {object} options - Pagination parameters
20
+ * @param {string} options.baseUrl - Base URL path (e.g. '/articles')
21
+ * @param {number} options.page - Current page number (1-based)
22
+ * @param {number} options.perPage - Items per page
23
+ * @param {number} options.total - Total item count
24
+ * @param {string} [options.searchParams=''] - Additional query parameters to preserve
25
+ * (e.g. 'sort=date&filter=active'). Appended before pagination params.
26
+ * @returns {Array<{href: string, rel: string}>} - Array of link objects
27
+ */
28
+ export function paginationLinks({ baseUrl, page, perPage, total, searchParams }: {
29
+ baseUrl: string;
30
+ page: number;
31
+ perPage: number;
32
+ total: number;
33
+ searchParams?: string | undefined;
34
+ }): Array<{
35
+ href: string;
36
+ rel: string;
37
+ }>;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @fileoverview Pure Prefer header parser (RFC 7240).
3
+ *
4
+ * Parses the HTTP `Prefer` request header into a plain object of preference
5
+ * name-value pairs. Supports:
6
+ * - Simple tokens (`respond-async` -> `{'respond-async': true}`)
7
+ * - Token=value pairs (`return=minimal` -> `{return: 'minimal'}`)
8
+ * - Quoted values (`foo="bar baz"` -> `{foo: 'bar baz'}`)
9
+ * - Multiple comma-separated preferences
10
+ * - Per-preference parameters after semicolons (stripped; only the main token is kept)
11
+ *
12
+ * Used by:
13
+ * - `http/prefer.js` (ergo pipeline middleware)
14
+ *
15
+ * @module lib/prefer
16
+ * @version 0.1.0
17
+ * @since 0.1.0
18
+ *
19
+ * @example
20
+ * import parsePrefer from 'ergo/lib/prefer';
21
+ *
22
+ * parsePrefer('return=minimal');
23
+ * // {return: 'minimal'}
24
+ *
25
+ * parsePrefer('respond-async, wait=100');
26
+ * // {'respond-async': true, wait: '100'}
27
+ *
28
+ * @see {@link https://www.rfc-editor.org/rfc/rfc7240 RFC 7240 - Prefer Header for HTTP}
29
+ */
30
+ /**
31
+ * Parse a Prefer header value into a preferences object.
32
+ *
33
+ * @param {string} [header] - Raw Prefer header value
34
+ * @returns {object} - Map of preference name to value (string) or `true` for bare tokens
35
+ */
36
+ export default function parsePrefer(header?: string): object;
@@ -0,0 +1,6 @@
1
+ declare function _default(query: string, { split, maxPairs, maxLength }?: {
2
+ split?: boolean | undefined;
3
+ maxPairs?: number | undefined;
4
+ maxLength?: number | undefined;
5
+ }): object;
6
+ export default _default;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Compute rate limit state from a store hit.
3
+ *
4
+ * @param {object} store - Store implementing `hit(key, windowMs) => {count, resetMs}`
5
+ * @param {string} key - Client identifier
6
+ * @param {number} max - Maximum requests allowed per window
7
+ * @param {number} windowMs - Window size in milliseconds
8
+ * @returns {{count: number, remaining: number, reset: number, limited: boolean, retryAfter: number|undefined}}
9
+ * - `count`: total hits in the current window
10
+ * - `remaining`: requests remaining before limit
11
+ * - `reset`: Unix timestamp (seconds) when the window resets
12
+ * - `limited`: true when count exceeds max
13
+ * - `retryAfter`: seconds until retry is allowed (only when limited)
14
+ */
15
+ export function checkRateLimit(store: object, key: string, max: number, windowMs: number): {
16
+ count: number;
17
+ remaining: number;
18
+ reset: number;
19
+ limited: boolean;
20
+ retryAfter: number | undefined;
21
+ };
22
+ /**
23
+ * Default key generator: uses the remote IP address.
24
+ * @param {object} req - HTTP request
25
+ * @returns {string} - Client identifier
26
+ */
27
+ export function defaultKeyGenerator(req: object): string;
28
+ /**
29
+ * @fileoverview Rate limiting shared primitives.
30
+ *
31
+ * Provides the core building blocks for both pipeline-level and transport-level
32
+ * rate limiting. The `MemoryStore` implements a sliding-window counter using
33
+ * per-key timestamp arrays. `checkRateLimit` computes the current state
34
+ * (remaining quota, reset time, whether the client is limited) from any store
35
+ * that implements the `hit(key, windowMs)` interface.
36
+ *
37
+ * Used by:
38
+ * - `http/rate-limit.js` (ergo pipeline middleware)
39
+ * - `ergo-router/lib/transport/rate-limit.js` (transport-level rate limiting)
40
+ *
41
+ * @module lib/rate-limit
42
+ * @version 0.1.0
43
+ * @since 0.1.0
44
+ *
45
+ * @example
46
+ * import {MemoryStore, checkRateLimit, defaultKeyGenerator} from 'ergo/lib/rate-limit';
47
+ *
48
+ * const store = new MemoryStore();
49
+ * const key = defaultKeyGenerator(req);
50
+ * const result = checkRateLimit(store, key, 100, 60000);
51
+ * // result.limited === true when over quota
52
+ *
53
+ * @see {@link https://www.rfc-editor.org/rfc/rfc6585#section-4 RFC 6585 Section 4 - 429 Too Many Requests}
54
+ */
55
+ /**
56
+ * In-memory sliding-window rate limit store.
57
+ * Each key maps to an array of request timestamps. Expired entries are pruned
58
+ * on every `hit()` call.
59
+ */
60
+ export class MemoryStore {
61
+ constructor({ maxKeys }?: {
62
+ maxKeys?: number | undefined;
63
+ });
64
+ _hits: Map<any, any>;
65
+ _maxKeys: number;
66
+ /**
67
+ * Record a hit and return the current count within the window.
68
+ * @param {string} key - Client identifier
69
+ * @param {number} windowMs - Window size in milliseconds
70
+ * @returns {{count: number, resetMs: number}} - Current count and ms until the oldest entry expires
71
+ */
72
+ hit(key: string, windowMs: number): {
73
+ count: number;
74
+ resetMs: number;
75
+ };
76
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Shared quoted-string sanitizer per RFC 7230 section 3.2.6.
3
+ *
4
+ * Escapes backslashes and double-quotes and strips control characters (all CTL chars
5
+ * except HTAB, which is valid in `qdtext` per RFC 7230 §3.2.6) so the result is safe
6
+ * for inclusion between double-quote delimiters in HTTP headers such as
7
+ * `WWW-Authenticate`, `Link`, and `Set-Cookie`.
8
+ *
9
+ * @module lib/sanitize-quoted-string
10
+ * @version 0.1.0
11
+ * @since 0.1.0
12
+ */
13
+ /**
14
+ * Escape a value for use inside a quoted-string per RFC 7230 section 3.2.6.
15
+ *
16
+ * @param {string} str - Raw value
17
+ * @returns {string} - Value safe for inclusion between double-quote delimiters
18
+ */
19
+ export default function sanitizeQuotedString(str: string): string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Build an array of security header tuples from a configuration object.
3
+ *
4
+ * @param {object} [options] - Security header configuration
5
+ * @param {string|false} [options.contentSecurityPolicy="default-src 'none'"] - Content-Security-Policy
6
+ * @param {string|object|false} [options.strictTransportSecurity=false] - HSTS directive string or
7
+ * `{maxAge, includeSubDomains, preload}` object. Defaults to `false`.
8
+ * @param {string|boolean|false} [options.xContentTypeOptions='nosniff'] - X-Content-Type-Options.
9
+ * `true` is treated as `'nosniff'`.
10
+ * @param {string|false} [options.xFrameOptions='DENY'] - X-Frame-Options
11
+ * @param {string|false} [options.referrerPolicy='no-referrer'] - Referrer-Policy
12
+ * @param {string|false} [options.xXssProtection='0'] - X-XSS-Protection
13
+ * @param {string} [options.permissionsPolicy] - Permissions-Policy (omitted by default)
14
+ * @returns {Array<[string, string]>} - Header tuples suitable for `res.setHeader()` or accumulator storage
15
+ */
16
+ export default function buildSecurityHeaderTuples({ contentSecurityPolicy, strictTransportSecurity, xContentTypeOptions, xFrameOptions, referrerPolicy, xXssProtection, permissionsPolicy }?: {
17
+ contentSecurityPolicy?: string | false | undefined;
18
+ strictTransportSecurity?: string | false | object | undefined;
19
+ xContentTypeOptions?: string | boolean | undefined;
20
+ xFrameOptions?: string | false | undefined;
21
+ referrerPolicy?: string | false | undefined;
22
+ xXssProtection?: string | false | undefined;
23
+ permissionsPolicy?: string | undefined;
24
+ }): Array<[string, string]>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Compiles a JSON Schema and returns a validating function.
3
+ *
4
+ * @param {object} schema - JSON Schema 2020-12 or draft-07 object
5
+ * @param {object} [options] - Validator options
6
+ * @param {boolean} [options.allErrors=true] - Report all errors instead of stopping at the first
7
+ * @param {boolean} [options.coerceTypes=false] - Coerce input values to match schema types
8
+ * @param {object} [options.ajv] - Additional AJV constructor options
9
+ * @returns {function} - `validateData(data)` — returns `data` on success, throws 422 on failure
10
+ * @throws {Error} 422 with `details` array if schema validation fails
11
+ */
12
+ export default function createValidator(schema: object, options?: {
13
+ allErrors?: boolean | undefined;
14
+ coerceTypes?: boolean | undefined;
15
+ ajv?: object | undefined;
16
+ }): Function;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @fileoverview Shared Vary header utility.
3
+ *
4
+ * Appends tokens to the `Vary` response header without duplicating existing tokens.
5
+ * Uses Set-based deduplication with case-insensitive comparison.
6
+ *
7
+ * @module lib/vary
8
+ * @version 0.1.0
9
+ * @since 0.1.0
10
+ */
11
+ /**
12
+ * Append a Vary token (or comma-separated tokens) to the response, avoiding duplicates.
13
+ *
14
+ * @param {import('node:http').ServerResponse} res - HTTP response object
15
+ * @param {string} value - Token(s) to append (e.g. "Accept-Encoding" or "Accept, Accept-Encoding")
16
+ */
17
+ export default function appendVary(res: any, value: string): void;
@@ -0,0 +1,2 @@
1
+ declare function _default(fn: Function, fail: Function): Function;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ export { default as match } from "./match.js";
2
+ export { default as split } from "./split.js";
@@ -0,0 +1,10 @@
1
+ declare function _default(buffer?: any, searchBuffer?: any, { limit, partial, lookup }?: {
2
+ limit?: number | undefined;
3
+ partial?: number | undefined;
4
+ lookup?: number[] | undefined;
5
+ }): {
6
+ matches: number[];
7
+ partial: number;
8
+ lookup: number[];
9
+ };
10
+ export default _default;
@@ -0,0 +1,10 @@
1
+ declare function _default(buffer?: any | string, separator?: any, { limit, ...options }?: {
2
+ limit?: number | undefined;
3
+ partial?: number | undefined;
4
+ lookup?: number[] | undefined;
5
+ }): {
6
+ buffers: any[];
7
+ partial: number;
8
+ lookup: number[];
9
+ };
10
+ export default _default;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Creates a null-prototype response accumulator.
3
+ *
4
+ * The returned object has a non-enumerable `isResponseAcc` flag used by the pipeline
5
+ * to distinguish it from the domain accumulator in the argument list.
6
+ *
7
+ * @returns {object} - Null-prototype object with `isResponseAcc: true`
8
+ */
9
+ export function createResponseAcc(): object;
10
+ /**
11
+ * Merges a response patch into the response accumulator.
12
+ *
13
+ * - `headers` arrays are **appended** (additive across middleware)
14
+ * - All other properties are **assigned** (last writer wins)
15
+ *
16
+ * @param {object} responseAcc - Mutable response accumulator
17
+ * @param {object} patch - Response contribution from middleware
18
+ */
19
+ export function mergeResponse(responseAcc: object, patch: object): void;
20
+ export default composeWith;
21
+ /**
22
+ * Composes middleware with path-based result storage and two-accumulator support.
23
+ *
24
+ * The composed function pops the domain accumulator (last arg with `isAccumulator`)
25
+ * and response accumulator (last arg with `isResponseAcc`) from its arguments.
26
+ * If either is absent, a fresh one is created.
27
+ *
28
+ * @param {...(function|Array)} ops - Operation specs; each is a function or `[fn, setPath]`
29
+ * @returns {function} - Async composed pipeline
30
+ */
31
+ declare function composeWith(...ops: (Function | any[])[]): Function;
32
+ declare namespace composeWith {
33
+ /**
34
+ * Concurrent variant of composeWith.
35
+ *
36
+ * @param {...(function|Array)} ops - Operation specs
37
+ * @returns {function} - Async composed pipeline
38
+ */
39
+ function all(...ops: (Function | any[])[]): Function;
40
+ }