@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.
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/http/accepts.js +69 -0
- package/http/authorization.js +65 -0
- package/http/body.js +311 -0
- package/http/cache-control.js +123 -0
- package/http/compress.js +157 -0
- package/http/cookie.js +39 -0
- package/http/cors.js +79 -0
- package/http/csrf.js +76 -0
- package/http/handler.js +74 -0
- package/http/index.js +13 -0
- package/http/json-api-query.js +53 -0
- package/http/logger.js +167 -0
- package/http/main.js +140 -0
- package/http/precondition.js +53 -0
- package/http/prefer.js +36 -0
- package/http/rate-limit.js +66 -0
- package/http/security-headers.js +62 -0
- package/http/send.js +399 -0
- package/http/timeout.js +47 -0
- package/http/url.js +47 -0
- package/http/validate.js +84 -0
- package/lib/accepts.js +49 -0
- package/lib/attach-instance.js +23 -0
- package/lib/authorization.js +187 -0
- package/lib/body/multiparse.js +173 -0
- package/lib/body/multipart/headers.js +69 -0
- package/lib/body/writer.js +73 -0
- package/lib/cookie/cookie.js +192 -0
- package/lib/cookie/index.js +14 -0
- package/lib/cookie/jar.js +106 -0
- package/lib/cookie/parse.js +101 -0
- package/lib/cors.js +191 -0
- package/lib/csrf.js +96 -0
- package/lib/from-connect.js +69 -0
- package/lib/json-api-query/index.js +25 -0
- package/lib/json-api-query/schema.json +105 -0
- package/lib/json-api-query/validate.js +56 -0
- package/lib/link.js +96 -0
- package/lib/prefer.js +52 -0
- package/lib/query.js +113 -0
- package/lib/rate-limit.js +115 -0
- package/lib/sanitize-quoted-string.js +28 -0
- package/lib/security-headers.js +125 -0
- package/lib/validate.js +80 -0
- package/lib/vary.js +40 -0
- package/package.json +158 -0
- package/types/http/accepts.d.ts +8 -0
- package/types/http/authorization.d.ts +8 -0
- package/types/http/body.d.ts +20 -0
- package/types/http/cache-control.d.ts +16 -0
- package/types/http/compress.d.ts +5 -0
- package/types/http/cookie.d.ts +2 -0
- package/types/http/cors.d.ts +9 -0
- package/types/http/csrf.d.ts +9 -0
- package/types/http/handler.d.ts +2 -0
- package/types/http/index.d.ts +1 -0
- package/types/http/json-api-query.d.ts +2 -0
- package/types/http/logger.d.ts +9 -0
- package/types/http/main.d.ts +142 -0
- package/types/http/precondition.d.ts +44 -0
- package/types/http/prefer.d.ts +2 -0
- package/types/http/rate-limit.d.ts +17 -0
- package/types/http/security-headers.d.ts +10 -0
- package/types/http/send.d.ts +8 -0
- package/types/http/timeout.d.ts +5 -0
- package/types/http/url.d.ts +2 -0
- package/types/http/validate.d.ts +6 -0
- package/types/lib/accepts.d.ts +7 -0
- package/types/lib/attach-instance.d.ts +19 -0
- package/types/lib/authorization.d.ts +6 -0
- package/types/lib/body/multiparse.d.ts +9 -0
- package/types/lib/body/multipart/headers.d.ts +2 -0
- package/types/lib/body/writer.d.ts +2 -0
- package/types/lib/cookie/cookie.d.ts +32 -0
- package/types/lib/cookie/index.d.ts +2 -0
- package/types/lib/cookie/jar.d.ts +8 -0
- package/types/lib/cookie/parse.d.ts +19 -0
- package/types/lib/cors.d.ts +9 -0
- package/types/lib/csrf.d.ts +32 -0
- package/types/lib/from-connect.d.ts +47 -0
- package/types/lib/json-api-query/index.d.ts +123 -0
- package/types/lib/json-api-query/validate.d.ts +5 -0
- package/types/lib/link.d.ts +37 -0
- package/types/lib/prefer.d.ts +36 -0
- package/types/lib/query.d.ts +6 -0
- package/types/lib/rate-limit.d.ts +76 -0
- package/types/lib/sanitize-quoted-string.d.ts +19 -0
- package/types/lib/security-headers.d.ts +24 -0
- package/types/lib/validate.d.ts +16 -0
- package/types/lib/vary.d.ts +17 -0
- package/types/utils/attempt.d.ts +2 -0
- package/types/utils/buffers/index.d.ts +2 -0
- package/types/utils/buffers/match.d.ts +10 -0
- package/types/utils/buffers/split.d.ts +10 -0
- package/types/utils/compose-with.d.ts +40 -0
- package/types/utils/compose.d.ts +83 -0
- package/types/utils/flat-array.d.ts +2 -0
- package/types/utils/get.d.ts +5 -0
- package/types/utils/http-errors.d.ts +22 -0
- package/types/utils/iterables/buffer-split.d.ts +2 -0
- package/types/utils/iterables/chain.d.ts +2 -0
- package/types/utils/iterables/exec-all.d.ts +2 -0
- package/types/utils/iterables/filter.d.ts +2 -0
- package/types/utils/iterables/for-each.d.ts +2 -0
- package/types/utils/iterables/from-stream.d.ts +2 -0
- package/types/utils/iterables/index.d.ts +10 -0
- package/types/utils/iterables/map.d.ts +2 -0
- package/types/utils/iterables/range.d.ts +24 -0
- package/types/utils/iterables/reduce.d.ts +2 -0
- package/types/utils/iterables/take.d.ts +2 -0
- package/types/utils/observables/buffer-split.d.ts +2 -0
- package/types/utils/observables/chain.d.ts +2 -0
- package/types/utils/observables/index.d.ts +4 -0
- package/types/utils/observables/map.d.ts +2 -0
- package/types/utils/observables/take.d.ts +2 -0
- package/types/utils/pick.d.ts +2 -0
- package/types/utils/set.d.ts +2 -0
- package/types/utils/streams/index.d.ts +2 -0
- package/types/utils/streams/meter.d.ts +5 -0
- package/types/utils/streams/tee.d.ts +2 -0
- package/types/utils/type.d.ts +2 -0
- package/utils/attempt.js +37 -0
- package/utils/buffers/index.js +13 -0
- package/utils/buffers/match.js +96 -0
- package/utils/buffers/split.js +55 -0
- package/utils/compose-with.js +232 -0
- package/utils/compose.js +165 -0
- package/utils/flat-array.js +24 -0
- package/utils/get.js +39 -0
- package/utils/http-errors.js +113 -0
- package/utils/iterables/buffer-split.js +117 -0
- package/utils/iterables/chain.js +32 -0
- package/utils/iterables/exec-all.js +42 -0
- package/utils/iterables/filter.js +35 -0
- package/utils/iterables/for-each.js +33 -0
- package/utils/iterables/from-stream.js +29 -0
- package/utils/iterables/index.js +21 -0
- package/utils/iterables/map.js +47 -0
- package/utils/iterables/range.js +34 -0
- package/utils/iterables/reduce.js +43 -0
- package/utils/iterables/take.js +36 -0
- package/utils/observables/buffer-split.js +109 -0
- package/utils/observables/chain.js +33 -0
- package/utils/observables/index.js +19 -0
- package/utils/observables/map.js +34 -0
- package/utils/observables/take.js +40 -0
- package/utils/pick.js +41 -0
- package/utils/set.js +38 -0
- package/utils/streams/index.js +11 -0
- package/utils/streams/meter.js +98 -0
- package/utils/streams/tee.js +84 -0
- package/utils/type.js +47 -0
|
@@ -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,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,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,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,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
|
+
}
|