@irvinebroque/http-rfc-utils 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/dist/auth.d.ts +139 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +991 -0
- package/dist/auth.js.map +1 -0
- package/dist/cache-status.d.ts +15 -0
- package/dist/cache-status.d.ts.map +1 -0
- package/dist/cache-status.js +152 -0
- package/dist/cache-status.js.map +1 -0
- package/dist/cache.d.ts +94 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +244 -0
- package/dist/cache.js.map +1 -0
- package/dist/client-hints.d.ts +23 -0
- package/dist/client-hints.d.ts.map +1 -0
- package/dist/client-hints.js +81 -0
- package/dist/client-hints.js.map +1 -0
- package/dist/conditional.d.ts +97 -0
- package/dist/conditional.d.ts.map +1 -0
- package/dist/conditional.js +300 -0
- package/dist/conditional.js.map +1 -0
- package/dist/content-disposition.d.ts +23 -0
- package/dist/content-disposition.d.ts.map +1 -0
- package/dist/content-disposition.js +122 -0
- package/dist/content-disposition.js.map +1 -0
- package/dist/cookie.d.ts +43 -0
- package/dist/cookie.d.ts.map +1 -0
- package/dist/cookie.js +472 -0
- package/dist/cookie.js.map +1 -0
- package/dist/cors.d.ts +53 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +170 -0
- package/dist/cors.js.map +1 -0
- package/dist/datetime.d.ts +53 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.js +205 -0
- package/dist/datetime.js.map +1 -0
- package/dist/digest.d.ts +220 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +355 -0
- package/dist/digest.js.map +1 -0
- package/dist/encoding.d.ts +14 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +86 -0
- package/dist/encoding.js.map +1 -0
- package/dist/etag.d.ts +55 -0
- package/dist/etag.d.ts.map +1 -0
- package/dist/etag.js +182 -0
- package/dist/etag.js.map +1 -0
- package/dist/ext-value.d.ts +40 -0
- package/dist/ext-value.d.ts.map +1 -0
- package/dist/ext-value.js +119 -0
- package/dist/ext-value.js.map +1 -0
- package/dist/forwarded.d.ts +14 -0
- package/dist/forwarded.d.ts.map +1 -0
- package/dist/forwarded.js +93 -0
- package/dist/forwarded.js.map +1 -0
- package/dist/header-utils.d.ts +71 -0
- package/dist/header-utils.d.ts.map +1 -0
- package/dist/header-utils.js +143 -0
- package/dist/header-utils.js.map +1 -0
- package/dist/headers.d.ts +71 -0
- package/dist/headers.d.ts.map +1 -0
- package/dist/headers.js +134 -0
- package/dist/headers.js.map +1 -0
- package/dist/hsts.d.ts +15 -0
- package/dist/hsts.d.ts.map +1 -0
- package/dist/hsts.js +106 -0
- package/dist/hsts.js.map +1 -0
- package/dist/http-signatures.d.ts +202 -0
- package/dist/http-signatures.d.ts.map +1 -0
- package/dist/http-signatures.js +720 -0
- package/dist/http-signatures.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/dist/json-pointer.d.ts +97 -0
- package/dist/json-pointer.d.ts.map +1 -0
- package/dist/json-pointer.js +278 -0
- package/dist/json-pointer.js.map +1 -0
- package/dist/jsonpath.d.ts +98 -0
- package/dist/jsonpath.d.ts.map +1 -0
- package/dist/jsonpath.js +1470 -0
- package/dist/jsonpath.js.map +1 -0
- package/dist/language.d.ts +14 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +95 -0
- package/dist/language.js.map +1 -0
- package/dist/link.d.ts +102 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +437 -0
- package/dist/link.js.map +1 -0
- package/dist/linkset.d.ts +111 -0
- package/dist/linkset.d.ts.map +1 -0
- package/dist/linkset.js +501 -0
- package/dist/linkset.js.map +1 -0
- package/dist/negotiate.d.ts +71 -0
- package/dist/negotiate.d.ts.map +1 -0
- package/dist/negotiate.js +357 -0
- package/dist/negotiate.js.map +1 -0
- package/dist/pagination.d.ts +80 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +188 -0
- package/dist/pagination.js.map +1 -0
- package/dist/prefer.d.ts +18 -0
- package/dist/prefer.d.ts.map +1 -0
- package/dist/prefer.js +93 -0
- package/dist/prefer.js.map +1 -0
- package/dist/problem.d.ts +54 -0
- package/dist/problem.d.ts.map +1 -0
- package/dist/problem.js +104 -0
- package/dist/problem.js.map +1 -0
- package/dist/proxy-status.d.ts +28 -0
- package/dist/proxy-status.d.ts.map +1 -0
- package/dist/proxy-status.js +220 -0
- package/dist/proxy-status.js.map +1 -0
- package/dist/range.d.ts +28 -0
- package/dist/range.d.ts.map +1 -0
- package/dist/range.js +243 -0
- package/dist/range.js.map +1 -0
- package/dist/response.d.ts +101 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +200 -0
- package/dist/response.js.map +1 -0
- package/dist/sorting.d.ts +66 -0
- package/dist/sorting.d.ts.map +1 -0
- package/dist/sorting.js +168 -0
- package/dist/sorting.js.map +1 -0
- package/dist/structured-fields.d.ts +30 -0
- package/dist/structured-fields.d.ts.map +1 -0
- package/dist/structured-fields.js +468 -0
- package/dist/structured-fields.js.map +1 -0
- package/dist/types.d.ts +772 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/uri-template.d.ts +48 -0
- package/dist/uri-template.d.ts.map +1 -0
- package/dist/uri-template.js +483 -0
- package/dist/uri-template.js.map +1 -0
- package/dist/uri.d.ts +80 -0
- package/dist/uri.d.ts.map +1 -0
- package/dist/uri.js +423 -0
- package/dist/uri.js.map +1 -0
- package/package.json +66 -0
package/dist/prefer.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prefer / Preference-Applied utilities per RFC 7240.
|
|
3
|
+
* RFC 7240 §2, §3.
|
|
4
|
+
*/
|
|
5
|
+
import { isEmptyHeader, splitQuotedValue, unquote, quoteIfNeeded } from './header-utils.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse a Prefer header into a map of preference tokens.
|
|
8
|
+
*/
|
|
9
|
+
// RFC 7240 §2: Prefer header parsing.
|
|
10
|
+
export function parsePrefer(header) {
|
|
11
|
+
const map = new Map();
|
|
12
|
+
if (isEmptyHeader(header)) {
|
|
13
|
+
return map;
|
|
14
|
+
}
|
|
15
|
+
const parts = splitQuotedValue(header, ',');
|
|
16
|
+
for (const part of parts) {
|
|
17
|
+
const trimmed = part.trim();
|
|
18
|
+
if (!trimmed)
|
|
19
|
+
continue;
|
|
20
|
+
const segments = splitQuotedValue(trimmed, ';').map(segment => segment.trim()).filter(Boolean);
|
|
21
|
+
if (segments.length === 0) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const [tokenPart, ...paramParts] = segments;
|
|
25
|
+
if (!tokenPart)
|
|
26
|
+
continue;
|
|
27
|
+
const eqIndex = tokenPart.indexOf('=');
|
|
28
|
+
// RFC 7240 §2: Token names are case-insensitive.
|
|
29
|
+
const token = (eqIndex === -1 ? tokenPart : tokenPart.slice(0, eqIndex)).trim().toLowerCase();
|
|
30
|
+
if (!token)
|
|
31
|
+
continue;
|
|
32
|
+
const rawValue = eqIndex === -1 ? undefined : unquote(tokenPart.slice(eqIndex + 1).trim());
|
|
33
|
+
// RFC 7240 §2: Empty values are equivalent to no value.
|
|
34
|
+
const value = rawValue === '' ? undefined : rawValue;
|
|
35
|
+
const params = [];
|
|
36
|
+
for (const paramPart of paramParts) {
|
|
37
|
+
const paramEq = paramPart.indexOf('=');
|
|
38
|
+
if (paramEq === -1) {
|
|
39
|
+
params.push({ key: paramPart.trim().toLowerCase() });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const key = paramPart.slice(0, paramEq).trim().toLowerCase();
|
|
43
|
+
const val = unquote(paramPart.slice(paramEq + 1).trim());
|
|
44
|
+
if (key) {
|
|
45
|
+
// RFC 7240 §2: Empty values are equivalent to no value.
|
|
46
|
+
params.push({ key, value: val === '' ? undefined : val });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!map.has(token)) {
|
|
51
|
+
map.set(token, { token, value, params });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return map;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Format Prefer header from tokens.
|
|
58
|
+
*/
|
|
59
|
+
// RFC 7240 §2: Prefer header formatting.
|
|
60
|
+
export function formatPrefer(preferences) {
|
|
61
|
+
const tokens = Array.isArray(preferences) ? preferences : Array.from(preferences.values());
|
|
62
|
+
return tokens.map(token => {
|
|
63
|
+
const parts = [];
|
|
64
|
+
const base = token.value !== undefined ? `${token.token}=${quoteIfNeeded(token.value)}` : token.token;
|
|
65
|
+
parts.push(base);
|
|
66
|
+
for (const param of token.params ?? []) {
|
|
67
|
+
if (param.value === undefined) {
|
|
68
|
+
parts.push(param.key);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
parts.push(`${param.key}=${quoteIfNeeded(param.value)}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return parts.join('; ');
|
|
75
|
+
}).join(', ');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Format Preference-Applied header.
|
|
79
|
+
*/
|
|
80
|
+
// RFC 7240 §3: Preference-Applied header formatting.
|
|
81
|
+
export function formatPreferenceApplied(preferences) {
|
|
82
|
+
if (Array.isArray(preferences)) {
|
|
83
|
+
return preferences.join(', ');
|
|
84
|
+
}
|
|
85
|
+
const tokens = Array.from(preferences.values());
|
|
86
|
+
return tokens.map(token => {
|
|
87
|
+
if (token.value !== undefined) {
|
|
88
|
+
return `${token.token}=${quoteIfNeeded(token.value)}`;
|
|
89
|
+
}
|
|
90
|
+
return token.token;
|
|
91
|
+
}).join(', ');
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=prefer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer.js","sourceRoot":"","sources":["../src/prefer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Problem Details utilities per RFC 9457.
|
|
3
|
+
* RFC 9457 §3.1, §3.2, §4.1.
|
|
4
|
+
*/
|
|
5
|
+
import type { ProblemDetails, ProblemOptions } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Create a Problem Details object per RFC 9457.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Problem configuration
|
|
10
|
+
* @returns Problem Details object
|
|
11
|
+
*
|
|
12
|
+
* RFC 9457 members:
|
|
13
|
+
* - type: URI reference identifying problem type (default: 'about:blank')
|
|
14
|
+
* - title: Short human-readable summary
|
|
15
|
+
* - status: HTTP status code
|
|
16
|
+
* - detail: Human-readable explanation specific to this occurrence
|
|
17
|
+
* - instance: URI reference identifying specific occurrence (optional)
|
|
18
|
+
*
|
|
19
|
+
* Extension members from options.extensions are spread into the result.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createProblem(options: ProblemOptions): ProblemDetails;
|
|
22
|
+
/**
|
|
23
|
+
* Create a Problem Details Response with proper headers.
|
|
24
|
+
*
|
|
25
|
+
* @param options - Problem configuration
|
|
26
|
+
* @param corsHeaders - Optional CORS headers (defaults to defaultCorsHeaders)
|
|
27
|
+
*/
|
|
28
|
+
export declare function problemResponse(options: ProblemOptions, corsHeaders?: Record<string, string>): Response;
|
|
29
|
+
/**
|
|
30
|
+
* Create a Problem Details Response with proper headers.
|
|
31
|
+
*
|
|
32
|
+
* @param status - HTTP status code
|
|
33
|
+
* @param title - Error title
|
|
34
|
+
* @param detail - Error detail
|
|
35
|
+
* @param instance - Optional instance URI
|
|
36
|
+
*/
|
|
37
|
+
export declare function problemResponse(status: number, title: string, detail: string, instance?: string): Response;
|
|
38
|
+
/**
|
|
39
|
+
* Common HTTP error responses as Problem Details
|
|
40
|
+
*/
|
|
41
|
+
export declare const Problems: {
|
|
42
|
+
readonly badRequest: (detail: string, instance?: string) => Response;
|
|
43
|
+
readonly unauthorized: (detail: string, instance?: string) => Response;
|
|
44
|
+
readonly forbidden: (detail: string, instance?: string) => Response;
|
|
45
|
+
readonly notFound: (detail: string, instance?: string) => Response;
|
|
46
|
+
readonly methodNotAllowed: (detail: string, allowed: string[], instance?: string) => Response;
|
|
47
|
+
readonly conflict: (detail: string, instance?: string) => Response;
|
|
48
|
+
readonly gone: (detail: string, instance?: string) => Response;
|
|
49
|
+
readonly unprocessableEntity: (detail: string, errors?: unknown[], instance?: string) => Response;
|
|
50
|
+
readonly tooManyRequests: (detail: string, retryAfter?: number, instance?: string) => Response;
|
|
51
|
+
readonly internalServerError: (detail: string, instance?: string) => Response;
|
|
52
|
+
readonly serviceUnavailable: (detail: string, retryAfter?: number, instance?: string) => Response;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=problem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"problem.d.ts","sourceRoot":"","sources":["../src/problem.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjE;;;;;;;;;;;;;;GAcG;AAEH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAiBrE;AAED;;;;;GAKG;AAEH,wBAAgB,eAAe,CAAC,OAAO,EAAE,cAAc,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC;AACzG;;;;;;;GAOG;AAEH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;AAkC5G;;GAEG;AAEH,eAAO,MAAM,QAAQ;kCACI,MAAM,aAAa,MAAM;oCAGvB,MAAM,aAAa,MAAM;iCAG5B,MAAM,aAAa,MAAM;gCAG1B,MAAM,aAAa,MAAM;wCAGjB,MAAM,WAAW,MAAM,EAAE,aAAa,MAAM;gCASpD,MAAM,aAAa,MAAM;4BAG7B,MAAM,aAAa,MAAM;2CAGV,MAAM,WAAW,OAAO,EAAE,aAAa,MAAM;uCASjD,MAAM,eAAe,MAAM,aAAa,MAAM;2CAS1C,MAAM,aAAa,MAAM;0CAG1B,MAAM,eAAe,MAAM,aAAa,MAAM;CAQrE,CAAC"}
|
package/dist/problem.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Problem Details utilities per RFC 9457.
|
|
3
|
+
* RFC 9457 §3.1, §3.2, §4.1.
|
|
4
|
+
*/
|
|
5
|
+
import { defaultCorsHeaders } from './cors.js';
|
|
6
|
+
/**
|
|
7
|
+
* Create a Problem Details object per RFC 9457.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Problem configuration
|
|
10
|
+
* @returns Problem Details object
|
|
11
|
+
*
|
|
12
|
+
* RFC 9457 members:
|
|
13
|
+
* - type: URI reference identifying problem type (default: 'about:blank')
|
|
14
|
+
* - title: Short human-readable summary
|
|
15
|
+
* - status: HTTP status code
|
|
16
|
+
* - detail: Human-readable explanation specific to this occurrence
|
|
17
|
+
* - instance: URI reference identifying specific occurrence (optional)
|
|
18
|
+
*
|
|
19
|
+
* Extension members from options.extensions are spread into the result.
|
|
20
|
+
*/
|
|
21
|
+
// RFC 9457 §3.1, §3.2: Problem Details members and extensions.
|
|
22
|
+
export function createProblem(options) {
|
|
23
|
+
const problem = {
|
|
24
|
+
type: options.type ?? 'about:blank',
|
|
25
|
+
title: options.title,
|
|
26
|
+
status: options.status,
|
|
27
|
+
detail: options.detail,
|
|
28
|
+
};
|
|
29
|
+
if (options.instance !== undefined) {
|
|
30
|
+
problem.instance = options.instance;
|
|
31
|
+
}
|
|
32
|
+
if (options.extensions) {
|
|
33
|
+
Object.assign(problem, options.extensions);
|
|
34
|
+
}
|
|
35
|
+
return problem;
|
|
36
|
+
}
|
|
37
|
+
export function problemResponse(optionsOrStatus, titleOrCorsHeaders, detail, instance) {
|
|
38
|
+
let problem;
|
|
39
|
+
let cors;
|
|
40
|
+
if (typeof optionsOrStatus === 'number') {
|
|
41
|
+
// Backward-compatible signature: (status, title, detail, instance?)
|
|
42
|
+
problem = createProblem({
|
|
43
|
+
status: optionsOrStatus,
|
|
44
|
+
title: titleOrCorsHeaders,
|
|
45
|
+
detail: detail,
|
|
46
|
+
instance,
|
|
47
|
+
});
|
|
48
|
+
cors = defaultCorsHeaders;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Full options object: (options, corsHeaders?)
|
|
52
|
+
problem = createProblem(optionsOrStatus);
|
|
53
|
+
cors = titleOrCorsHeaders ?? defaultCorsHeaders;
|
|
54
|
+
}
|
|
55
|
+
return new Response(JSON.stringify(problem), {
|
|
56
|
+
status: problem.status,
|
|
57
|
+
headers: {
|
|
58
|
+
'Content-Type': 'application/problem+json',
|
|
59
|
+
...cors,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Common HTTP error responses as Problem Details
|
|
65
|
+
*/
|
|
66
|
+
// RFC 9457 §3.1: Problem Details members populated by helpers.
|
|
67
|
+
export const Problems = {
|
|
68
|
+
badRequest: (detail, instance) => problemResponse({ status: 400, title: 'Bad Request', detail, instance }),
|
|
69
|
+
unauthorized: (detail, instance) => problemResponse({ status: 401, title: 'Unauthorized', detail, instance }),
|
|
70
|
+
forbidden: (detail, instance) => problemResponse({ status: 403, title: 'Forbidden', detail, instance }),
|
|
71
|
+
notFound: (detail, instance) => problemResponse({ status: 404, title: 'Not Found', detail, instance }),
|
|
72
|
+
methodNotAllowed: (detail, allowed, instance) => problemResponse({
|
|
73
|
+
status: 405,
|
|
74
|
+
title: 'Method Not Allowed',
|
|
75
|
+
detail,
|
|
76
|
+
instance,
|
|
77
|
+
extensions: { allowed },
|
|
78
|
+
}),
|
|
79
|
+
conflict: (detail, instance) => problemResponse({ status: 409, title: 'Conflict', detail, instance }),
|
|
80
|
+
gone: (detail, instance) => problemResponse({ status: 410, title: 'Gone', detail, instance }),
|
|
81
|
+
unprocessableEntity: (detail, errors, instance) => problemResponse({
|
|
82
|
+
status: 422,
|
|
83
|
+
title: 'Unprocessable Entity',
|
|
84
|
+
detail,
|
|
85
|
+
instance,
|
|
86
|
+
extensions: errors ? { errors } : undefined,
|
|
87
|
+
}),
|
|
88
|
+
tooManyRequests: (detail, retryAfter, instance) => problemResponse({
|
|
89
|
+
status: 429,
|
|
90
|
+
title: 'Too Many Requests',
|
|
91
|
+
detail,
|
|
92
|
+
instance,
|
|
93
|
+
extensions: retryAfter !== undefined ? { retryAfter } : undefined,
|
|
94
|
+
}),
|
|
95
|
+
internalServerError: (detail, instance) => problemResponse({ status: 500, title: 'Internal Server Error', detail, instance }),
|
|
96
|
+
serviceUnavailable: (detail, retryAfter, instance) => problemResponse({
|
|
97
|
+
status: 503,
|
|
98
|
+
title: 'Service Unavailable',
|
|
99
|
+
detail,
|
|
100
|
+
instance,
|
|
101
|
+
extensions: retryAfter !== undefined ? { retryAfter } : undefined,
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=problem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"problem.js","sourceRoot":"","sources":["../src/problem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proxy-Status utilities per RFC 9209.
|
|
3
|
+
* RFC 9209 §2-§2.4.
|
|
4
|
+
* @see https://www.rfc-editor.org/rfc/rfc9209.html#section-2
|
|
5
|
+
*/
|
|
6
|
+
import type { ProxyStatusEntry, ProxyErrorType } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* All 32 proxy error types defined in RFC 9209 §2.3.
|
|
9
|
+
*/
|
|
10
|
+
export declare const PROXY_ERROR_TYPES: readonly ProxyErrorType[];
|
|
11
|
+
/**
|
|
12
|
+
* Type guard to check if a value is a known proxy error type.
|
|
13
|
+
* RFC 9209 §2.3.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isProxyErrorType(value: string): value is ProxyErrorType;
|
|
16
|
+
/**
|
|
17
|
+
* Parse Proxy-Status header value into entries.
|
|
18
|
+
* RFC 9209 §2: Proxy-Status is a Structured Field List.
|
|
19
|
+
* Each member MUST be a String or Token (not Inner List).
|
|
20
|
+
* First member = closest to origin; last = closest to user agent.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseProxyStatus(header: string): ProxyStatusEntry[] | null;
|
|
23
|
+
/**
|
|
24
|
+
* Format Proxy-Status header value from entries.
|
|
25
|
+
* RFC 9209 §2: Proxy-Status Structured Field serialization.
|
|
26
|
+
*/
|
|
27
|
+
export declare function formatProxyStatus(entries: ProxyStatusEntry[]): string;
|
|
28
|
+
//# sourceMappingURL=proxy-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-status.d.ts","sourceRoot":"","sources":["../src/proxy-status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAqB,cAAc,EAA8B,MAAM,YAAY,CAAC;AAGlH;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAiC7C,CAAC;AAIX;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAEvE;AAyID;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,EAAE,GAAG,IAAI,CA4B1E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAQrE"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proxy-Status utilities per RFC 9209.
|
|
3
|
+
* RFC 9209 §2-§2.4.
|
|
4
|
+
* @see https://www.rfc-editor.org/rfc/rfc9209.html#section-2
|
|
5
|
+
*/
|
|
6
|
+
import { parseSfList, serializeSfList } from './structured-fields.js';
|
|
7
|
+
/**
|
|
8
|
+
* All 32 proxy error types defined in RFC 9209 §2.3.
|
|
9
|
+
*/
|
|
10
|
+
export const PROXY_ERROR_TYPES = [
|
|
11
|
+
'dns_timeout',
|
|
12
|
+
'dns_error',
|
|
13
|
+
'destination_not_found',
|
|
14
|
+
'destination_unavailable',
|
|
15
|
+
'destination_ip_prohibited',
|
|
16
|
+
'destination_ip_unroutable',
|
|
17
|
+
'connection_refused',
|
|
18
|
+
'connection_terminated',
|
|
19
|
+
'connection_timeout',
|
|
20
|
+
'connection_read_timeout',
|
|
21
|
+
'connection_write_timeout',
|
|
22
|
+
'connection_limit_reached',
|
|
23
|
+
'tls_protocol_error',
|
|
24
|
+
'tls_certificate_error',
|
|
25
|
+
'tls_alert_received',
|
|
26
|
+
'http_request_error',
|
|
27
|
+
'http_request_denied',
|
|
28
|
+
'http_response_incomplete',
|
|
29
|
+
'http_response_header_section_size',
|
|
30
|
+
'http_response_header_size',
|
|
31
|
+
'http_response_body_size',
|
|
32
|
+
'http_response_trailer_section_size',
|
|
33
|
+
'http_response_trailer_size',
|
|
34
|
+
'http_response_transfer_coding',
|
|
35
|
+
'http_response_content_coding',
|
|
36
|
+
'http_response_timeout',
|
|
37
|
+
'http_upgrade_failed',
|
|
38
|
+
'http_protocol_error',
|
|
39
|
+
'proxy_internal_response',
|
|
40
|
+
'proxy_internal_error',
|
|
41
|
+
'proxy_configuration_error',
|
|
42
|
+
'proxy_loop_detected',
|
|
43
|
+
];
|
|
44
|
+
const PROXY_ERROR_TYPE_SET = new Set(PROXY_ERROR_TYPES);
|
|
45
|
+
/**
|
|
46
|
+
* Type guard to check if a value is a known proxy error type.
|
|
47
|
+
* RFC 9209 §2.3.
|
|
48
|
+
*/
|
|
49
|
+
export function isProxyErrorType(value) {
|
|
50
|
+
return PROXY_ERROR_TYPE_SET.has(value);
|
|
51
|
+
}
|
|
52
|
+
function isInteger(value) {
|
|
53
|
+
return Number.isInteger(value) && Number.isFinite(value);
|
|
54
|
+
}
|
|
55
|
+
// RFC 9209 §2.1: Parse parameters from SF item params.
|
|
56
|
+
function parseProxyStatusParams(params) {
|
|
57
|
+
const result = {};
|
|
58
|
+
if (!params) {
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
const extensions = {};
|
|
62
|
+
for (const [key, value] of Object.entries(params)) {
|
|
63
|
+
switch (key) {
|
|
64
|
+
// RFC 9209 §2.1.1: error parameter is a Token.
|
|
65
|
+
case 'error':
|
|
66
|
+
if (typeof value === 'string') {
|
|
67
|
+
result.error = value;
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
// RFC 9209 §2.1.2: next-hop is a String or Token.
|
|
71
|
+
case 'next-hop':
|
|
72
|
+
if (typeof value === 'string') {
|
|
73
|
+
result.nextHop = value;
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
// RFC 9209 §2.1.3: next-protocol is a Token or Byte Sequence.
|
|
77
|
+
case 'next-protocol':
|
|
78
|
+
if (typeof value === 'string') {
|
|
79
|
+
result.nextProtocol = value;
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
// RFC 9209 §2.1.4: received-status is an Integer.
|
|
83
|
+
case 'received-status':
|
|
84
|
+
if (typeof value === 'number' && isInteger(value)) {
|
|
85
|
+
result.receivedStatus = value;
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
// RFC 9209 §2.1.5: details is a String.
|
|
89
|
+
case 'details':
|
|
90
|
+
if (typeof value === 'string') {
|
|
91
|
+
result.details = value;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
// RFC 9209 §2.3.2: rcode extra parameter for dns_error.
|
|
95
|
+
case 'rcode':
|
|
96
|
+
if (typeof value === 'string') {
|
|
97
|
+
result.rcode = value;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
// RFC 9209 §2.3.2: info-code extra parameter for dns_error.
|
|
101
|
+
case 'info-code':
|
|
102
|
+
if (typeof value === 'number' && isInteger(value)) {
|
|
103
|
+
result.infoCode = value;
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
// RFC 9209 §2.3.15: alert-id extra parameter for tls_alert_received.
|
|
107
|
+
case 'alert-id':
|
|
108
|
+
if (typeof value === 'number' && isInteger(value)) {
|
|
109
|
+
result.alertId = value;
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
// RFC 9209 §2.3.15: alert-message extra parameter for tls_alert_received.
|
|
113
|
+
case 'alert-message':
|
|
114
|
+
if (typeof value === 'string') {
|
|
115
|
+
result.alertMessage = value;
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
// RFC 9209 §2.1: Unrecognized parameters MUST be ignored, but preserve for extensibility.
|
|
120
|
+
extensions[key] = value;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (Object.keys(extensions).length > 0) {
|
|
125
|
+
result.extensions = extensions;
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
// RFC 9209 §2: Build SF item params from typed interface.
|
|
130
|
+
function buildProxyStatusParams(params) {
|
|
131
|
+
const result = {};
|
|
132
|
+
if (params.error !== undefined) {
|
|
133
|
+
result.error = params.error;
|
|
134
|
+
}
|
|
135
|
+
if (params.nextHop !== undefined) {
|
|
136
|
+
result['next-hop'] = params.nextHop;
|
|
137
|
+
}
|
|
138
|
+
if (params.nextProtocol !== undefined) {
|
|
139
|
+
result['next-protocol'] = params.nextProtocol;
|
|
140
|
+
}
|
|
141
|
+
if (params.receivedStatus !== undefined) {
|
|
142
|
+
if (!isInteger(params.receivedStatus)) {
|
|
143
|
+
throw new Error('Invalid Proxy-Status received-status value');
|
|
144
|
+
}
|
|
145
|
+
result['received-status'] = params.receivedStatus;
|
|
146
|
+
}
|
|
147
|
+
if (params.details !== undefined) {
|
|
148
|
+
result.details = params.details;
|
|
149
|
+
}
|
|
150
|
+
if (params.rcode !== undefined) {
|
|
151
|
+
result.rcode = params.rcode;
|
|
152
|
+
}
|
|
153
|
+
if (params.infoCode !== undefined) {
|
|
154
|
+
if (!isInteger(params.infoCode)) {
|
|
155
|
+
throw new Error('Invalid Proxy-Status info-code value');
|
|
156
|
+
}
|
|
157
|
+
result['info-code'] = params.infoCode;
|
|
158
|
+
}
|
|
159
|
+
if (params.alertId !== undefined) {
|
|
160
|
+
if (!isInteger(params.alertId)) {
|
|
161
|
+
throw new Error('Invalid Proxy-Status alert-id value');
|
|
162
|
+
}
|
|
163
|
+
result['alert-id'] = params.alertId;
|
|
164
|
+
}
|
|
165
|
+
if (params.alertMessage !== undefined) {
|
|
166
|
+
result['alert-message'] = params.alertMessage;
|
|
167
|
+
}
|
|
168
|
+
if (params.extensions) {
|
|
169
|
+
for (const [key, value] of Object.entries(params.extensions)) {
|
|
170
|
+
if (!(key in result)) {
|
|
171
|
+
result[key] = value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Parse Proxy-Status header value into entries.
|
|
179
|
+
* RFC 9209 §2: Proxy-Status is a Structured Field List.
|
|
180
|
+
* Each member MUST be a String or Token (not Inner List).
|
|
181
|
+
* First member = closest to origin; last = closest to user agent.
|
|
182
|
+
*/
|
|
183
|
+
export function parseProxyStatus(header) {
|
|
184
|
+
if (!header || !header.trim()) {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
const list = parseSfList(header);
|
|
188
|
+
if (!list) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const entries = [];
|
|
192
|
+
for (const member of list) {
|
|
193
|
+
// RFC 9209 §2: Each member MUST have a type of either String or Token.
|
|
194
|
+
// Inner lists are not allowed.
|
|
195
|
+
if ('items' in member) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
if (typeof member.value !== 'string') {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
entries.push({
|
|
202
|
+
proxy: member.value,
|
|
203
|
+
params: parseProxyStatusParams(member.params),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return entries;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Format Proxy-Status header value from entries.
|
|
210
|
+
* RFC 9209 §2: Proxy-Status Structured Field serialization.
|
|
211
|
+
*/
|
|
212
|
+
export function formatProxyStatus(entries) {
|
|
213
|
+
const list = entries.map((entry) => {
|
|
214
|
+
const params = buildProxyStatusParams(entry.params ?? {});
|
|
215
|
+
const item = params ? { value: entry.proxy, params } : { value: entry.proxy };
|
|
216
|
+
return item;
|
|
217
|
+
});
|
|
218
|
+
return serializeSfList(list);
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=proxy-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-status.js","sourceRoot":"","sources":["../src/proxy-status.ts"],"names":[],"mappings":"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"}
|
package/dist/range.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Range request utilities per RFC 9110 (13.2.1, 14.2).
|
|
3
|
+
*/
|
|
4
|
+
import type { ByteRange, RangeSpec, ContentRange, RangeDecision } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Parse a Range header into raw byte ranges.
|
|
7
|
+
*
|
|
8
|
+
* NOTE: Open-ended ranges use end = Infinity.
|
|
9
|
+
* Suffix ranges use start = -N and end = -1.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseRange(header: string): RangeSpec | null;
|
|
12
|
+
/**
|
|
13
|
+
* Parse a Content-Range header.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseContentRange(header: string): ContentRange | null;
|
|
16
|
+
/**
|
|
17
|
+
* Format a Content-Range header value.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatContentRange(range: ByteRange, size: number | '*'): string;
|
|
20
|
+
/**
|
|
21
|
+
* Build Accept-Ranges header value.
|
|
22
|
+
*/
|
|
23
|
+
export declare function acceptRanges(value?: 'bytes' | 'none'): string;
|
|
24
|
+
/**
|
|
25
|
+
* Evaluate a Range request and determine partial content handling.
|
|
26
|
+
*/
|
|
27
|
+
export declare function evaluateRange(request: Request, size: number, etag?: string, lastModified?: Date): RangeDecision;
|
|
28
|
+
//# sourceMappingURL=range.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"range.d.ts","sourceRoot":"","sources":["../src/range.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMpF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAmE3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAoDrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,MAAM,CAG/E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,GAAE,OAAO,GAAG,MAAgB,GAAG,MAAM,CAEtE;AA6ED;;GAEG;AACH,wBAAgB,aAAa,CACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,IAAI,GACpB,aAAa,CA0Df"}
|