@aglyn/shared-util-http 1.0.0-beta.143
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 +201 -0
- package/README.md +3 -0
- package/jest.config.d.ts +30 -0
- package/package.json +38 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +18 -0
- package/src/index.js.map +1 -0
- package/src/lib/authorized-token.d.ts +109 -0
- package/src/lib/authorized-token.js +189 -0
- package/src/lib/authorized-token.js.map +1 -0
- package/src/lib/cookie-get-user-id-token.d.ts +19 -0
- package/src/lib/cookie-get-user-id-token.js +23 -0
- package/src/lib/cookie-get-user-id-token.js.map +1 -0
- package/src/lib/cookie-set-user-id-token.d.ts +20 -0
- package/src/lib/cookie-set-user-id-token.js +25 -0
- package/src/lib/cookie-set-user-id-token.js.map +1 -0
- package/src/lib/cors-build-response-handler.d.ts +7 -0
- package/src/lib/cors-build-response-handler.js +25 -0
- package/src/lib/cors-build-response-handler.js.map +1 -0
- package/src/lib/cors-handle-response.d.ts +22 -0
- package/src/lib/cors-handle-response.js +94 -0
- package/src/lib/cors-handle-response.js.map +1 -0
- package/src/lib/get-absolute-url.d.ts +34 -0
- package/src/lib/get-absolute-url.js +48 -0
- package/src/lib/get-absolute-url.js.map +1 -0
- package/src/lib/get-allowed-headers.d.ts +26 -0
- package/src/lib/get-allowed-headers.js +39 -0
- package/src/lib/get-allowed-headers.js.map +1 -0
- package/src/lib/get-origin-headers-from-request.d.ts +20 -0
- package/src/lib/get-origin-headers-from-request.js +26 -0
- package/src/lib/get-origin-headers-from-request.js.map +1 -0
- package/src/lib/get-origin-headers.d.ts +3 -0
- package/src/lib/get-origin-headers.js +37 -0
- package/src/lib/get-origin-headers.js.map +1 -0
- package/src/lib/get-request-header.d.ts +20 -0
- package/src/lib/get-request-header.js +21 -0
- package/src/lib/get-request-header.js.map +1 -0
- package/src/lib/http.d.ts +27 -0
- package/src/lib/http.js +28 -0
- package/src/lib/http.js.map +1 -0
- package/src/lib/is-origin-allowed.d.ts +19 -0
- package/src/lib/is-origin-allowed.js +21 -0
- package/src/lib/is-origin-allowed.js.map +1 -0
- package/src/lib/safe-redirect.d.ts +41 -0
- package/src/lib/safe-redirect.js +101 -0
- package/src/lib/safe-redirect.js.map +1 -0
- package/src/lib/safe-url-scheme.d.ts +42 -0
- package/src/lib/safe-url-scheme.js +124 -0
- package/src/lib/safe-url-scheme.js.map +1 -0
- package/src/lib/types.d.ts +30 -0
- package/src/lib/types.js +18 -0
- package/src/lib/types.js.map +1 -0
package/src/lib/http.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ export * from "./types.js";
|
|
17
|
+
export * from "./cookie-get-user-id-token.js";
|
|
18
|
+
export * from "./cookie-set-user-id-token.js";
|
|
19
|
+
export * from "./cors-build-response-handler.js";
|
|
20
|
+
export * from "./cors-handle-response.js";
|
|
21
|
+
export * from "./get-absolute-url.js";
|
|
22
|
+
export * from "./get-allowed-headers.js";
|
|
23
|
+
export * from "./get-origin-headers.js";
|
|
24
|
+
export * from "./get-origin-headers-from-request.js";
|
|
25
|
+
export * from "./get-request-header.js";
|
|
26
|
+
export * from "./is-origin-allowed.js";
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/http/src/lib/http.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport * from './types'\n\nexport * from './cookie-get-user-id-token'\nexport * from './cookie-set-user-id-token'\nexport * from './cors-build-response-handler'\nexport * from './cors-handle-response'\nexport * from './get-absolute-url'\nexport * from './get-allowed-headers'\nexport * from './get-origin-headers'\nexport * from './get-origin-headers-from-request'\nexport * from './get-request-header'\nexport * from './is-origin-allowed'\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,cAAc,aAAS;AAEvB,cAAc,gCAA4B;AAC1C,cAAc,gCAA4B;AAC1C,cAAc,mCAA+B;AAC7C,cAAc,4BAAwB;AACtC,cAAc,wBAAoB;AAClC,cAAc,2BAAuB;AACrC,cAAc,0BAAsB;AACpC,cAAc,uCAAmC;AACjD,cAAc,0BAAsB;AACpC,cAAc,yBAAqB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { StaticOrigin } from './types';
|
|
18
|
+
export declare function isOriginAllowed(origin: string, allowed: StaticOrigin): boolean;
|
|
19
|
+
export default isOriginAllowed;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ export function isOriginAllowed(origin, allowed) {
|
|
17
|
+
return Array.isArray(allowed) ? allowed.some((o)=>isOriginAllowed(origin, o)) : typeof allowed === 'string' ? origin === allowed : allowed instanceof RegExp ? allowed.test(origin) : !!allowed;
|
|
18
|
+
}
|
|
19
|
+
export default isOriginAllowed;
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=is-origin-allowed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/http/src/lib/is-origin-allowed.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {StaticOrigin} from './types'\n\n\nexport function isOriginAllowed(origin: string, allowed: StaticOrigin): boolean {\n return Array.isArray(allowed)\n ? allowed.some((o) => isOriginAllowed(origin, o))\n : typeof allowed === 'string'\n ? origin === allowed\n : allowed instanceof RegExp\n ? allowed.test(origin)\n : !!allowed\n}\n\nexport default isOriginAllowed\n"],"names":["isOriginAllowed","origin","allowed","Array","isArray","some","o","RegExp","test"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAKD,OAAO,SAASA,gBAAgBC,MAAc,EAAEC,OAAqB;IACnE,OAAOC,MAAMC,OAAO,CAACF,WACjBA,QAAQG,IAAI,CAAC,CAACC,IAAMN,gBAAgBC,QAAQK,MAC5C,OAAOJ,YAAY,WACjBD,WAAWC,UACXA,mBAAmBK,SACjBL,QAAQM,IAAI,CAACP,UACb,CAAC,CAACC;AACZ;AAEA,eAAeF,gBAAe"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* True when `candidate` is a relative path that resolves onto its own origin.
|
|
19
|
+
*
|
|
20
|
+
* Answers `false` for absent, non-string and unparseable input rather than
|
|
21
|
+
* throwing: `strictNullChecks` is off repo-wide, so an absent query parameter
|
|
22
|
+
* reaches this as an empty string or `null` at runtime however the types read,
|
|
23
|
+
* and a `TypeError` escaping into a sign-in render is a worse outage than the
|
|
24
|
+
* redirect bug this guards.
|
|
25
|
+
*
|
|
26
|
+
* Absolute URLs are refused here even when they name our own host. A caller
|
|
27
|
+
* that must accept a same-site absolute (the workspace-domain return in
|
|
28
|
+
* `use-continue-url`) checks that separately, against the parsed hostname —
|
|
29
|
+
* for an absolute input the parser's verdict is already ground truth, so that
|
|
30
|
+
* branch never had this bug.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isSameOriginPath(candidate: string | null | undefined): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The trimmed path when it stays on this origin, otherwise `fallback`.
|
|
35
|
+
*
|
|
36
|
+
* The trimmed value is returned, not the raw one, so what was validated is
|
|
37
|
+
* what the caller navigates to. Handing back the original would reintroduce
|
|
38
|
+
* the whole bug class: a guard is only worth anything if the string it
|
|
39
|
+
* approved is the string that gets used.
|
|
40
|
+
*/
|
|
41
|
+
export declare function safeSameOriginPath(candidate: string | null | undefined, fallback?: string): string;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* The one predicate for "this string is a path on MY origin" (AGL-1881).
|
|
18
|
+
*
|
|
19
|
+
* ## Why this exists rather than a sixth hand-rolled shape test
|
|
20
|
+
*
|
|
21
|
+
* Six call sites independently implemented the same guard, and every one of
|
|
22
|
+
* them was written as a list of tricks to reject:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* value.startsWith('/') && !value.startsWith('//') // and later, sometimes:
|
|
26
|
+
* !value.includes('\\')
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* AGL-2486 discovered the backslash and added it to four of the six lists. The
|
|
30
|
+
* list was still incomplete, because the list can never be complete: the
|
|
31
|
+
* WHATWG URL parser **removes every ASCII tab, LF and CR from the input before
|
|
32
|
+
* it parses anything**, so a tab sitting between the two slashes hides the
|
|
33
|
+
* protocol-relative form from any test that reads the raw characters.
|
|
34
|
+
* Measured in node 20 and in the browser alike:
|
|
35
|
+
*
|
|
36
|
+
* new URL('/\t/evil.example', 'https://console.acme.com').href
|
|
37
|
+
* // → 'https://evil.example/'
|
|
38
|
+
*
|
|
39
|
+
* and `window.location.assign` — which is what these call sites go on to do —
|
|
40
|
+
* resolves it exactly the same way. `\n` and `\r` do it too. So does the
|
|
41
|
+
* combination `'/\t\\evil.example'`, which slips past even the
|
|
42
|
+
* backslash-aware version because the character it checks for is no longer in
|
|
43
|
+
* the authority position when the parser is done.
|
|
44
|
+
*
|
|
45
|
+
* ## The shape of the fix
|
|
46
|
+
*
|
|
47
|
+
* Stop enumerating. **Ask the same parser the browser will ask**, and accept
|
|
48
|
+
* only when it agrees the result stayed on the origin we started from. A trick
|
|
49
|
+
* that the parser does not honor cannot hurt us, and a trick it does honor is
|
|
50
|
+
* caught by construction — including the ones nobody has thought of yet.
|
|
51
|
+
*
|
|
52
|
+
* That is the difference between a check that happens to pass today and a
|
|
53
|
+
* check that cannot silently stop working, which is the property a redirect
|
|
54
|
+
* guard needs: these values land the user somewhere immediately after signing
|
|
55
|
+
* them in, and one that has survived a round trip through an external identity
|
|
56
|
+
* provider is fully attacker-chosen.
|
|
57
|
+
*
|
|
58
|
+
* `.invalid` is reserved by RFC 2606 and can never resolve, so the probe
|
|
59
|
+
* origin cannot collide with a real host and the comparison means only what it
|
|
60
|
+
* says.
|
|
61
|
+
*/ const PROBE_ORIGIN = 'https://redirect-probe.aglyn.invalid';
|
|
62
|
+
/**
|
|
63
|
+
* True when `candidate` is a relative path that resolves onto its own origin.
|
|
64
|
+
*
|
|
65
|
+
* Answers `false` for absent, non-string and unparseable input rather than
|
|
66
|
+
* throwing: `strictNullChecks` is off repo-wide, so an absent query parameter
|
|
67
|
+
* reaches this as an empty string or `null` at runtime however the types read,
|
|
68
|
+
* and a `TypeError` escaping into a sign-in render is a worse outage than the
|
|
69
|
+
* redirect bug this guards.
|
|
70
|
+
*
|
|
71
|
+
* Absolute URLs are refused here even when they name our own host. A caller
|
|
72
|
+
* that must accept a same-site absolute (the workspace-domain return in
|
|
73
|
+
* `use-continue-url`) checks that separately, against the parsed hostname —
|
|
74
|
+
* for an absolute input the parser's verdict is already ground truth, so that
|
|
75
|
+
* branch never had this bug.
|
|
76
|
+
*/ export function isSameOriginPath(candidate) {
|
|
77
|
+
if (typeof candidate !== 'string') return false;
|
|
78
|
+
const value = candidate.trim();
|
|
79
|
+
if (!value.startsWith('/')) return false;
|
|
80
|
+
try {
|
|
81
|
+
// Resolve-and-compare. `origin` is what a navigation would actually reach,
|
|
82
|
+
// so any input the parser rewrites into a different authority — `//host`,
|
|
83
|
+
// `/\host`, `/<TAB>/host`, and whatever comes next — fails right here.
|
|
84
|
+
return new URL(value, PROBE_ORIGIN).origin === PROBE_ORIGIN;
|
|
85
|
+
} catch (unused) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The trimmed path when it stays on this origin, otherwise `fallback`.
|
|
91
|
+
*
|
|
92
|
+
* The trimmed value is returned, not the raw one, so what was validated is
|
|
93
|
+
* what the caller navigates to. Handing back the original would reintroduce
|
|
94
|
+
* the whole bug class: a guard is only worth anything if the string it
|
|
95
|
+
* approved is the string that gets used.
|
|
96
|
+
*/ export function safeSameOriginPath(candidate, fallback = '/') {
|
|
97
|
+
if (!isSameOriginPath(candidate)) return fallback;
|
|
98
|
+
return candidate.trim();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=safe-redirect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/http/src/lib/safe-redirect.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The one predicate for \"this string is a path on MY origin\" (AGL-1881).\n *\n * ## Why this exists rather than a sixth hand-rolled shape test\n *\n * Six call sites independently implemented the same guard, and every one of\n * them was written as a list of tricks to reject:\n *\n * ```ts\n * value.startsWith('/') && !value.startsWith('//') // and later, sometimes:\n * !value.includes('\\\\')\n * ```\n *\n * AGL-2486 discovered the backslash and added it to four of the six lists. The\n * list was still incomplete, because the list can never be complete: the\n * WHATWG URL parser **removes every ASCII tab, LF and CR from the input before\n * it parses anything**, so a tab sitting between the two slashes hides the\n * protocol-relative form from any test that reads the raw characters.\n * Measured in node 20 and in the browser alike:\n *\n * new URL('/\\t/evil.example', 'https://console.acme.com').href\n * // → 'https://evil.example/'\n *\n * and `window.location.assign` — which is what these call sites go on to do —\n * resolves it exactly the same way. `\\n` and `\\r` do it too. So does the\n * combination `'/\\t\\\\evil.example'`, which slips past even the\n * backslash-aware version because the character it checks for is no longer in\n * the authority position when the parser is done.\n *\n * ## The shape of the fix\n *\n * Stop enumerating. **Ask the same parser the browser will ask**, and accept\n * only when it agrees the result stayed on the origin we started from. A trick\n * that the parser does not honor cannot hurt us, and a trick it does honor is\n * caught by construction — including the ones nobody has thought of yet.\n *\n * That is the difference between a check that happens to pass today and a\n * check that cannot silently stop working, which is the property a redirect\n * guard needs: these values land the user somewhere immediately after signing\n * them in, and one that has survived a round trip through an external identity\n * provider is fully attacker-chosen.\n *\n * `.invalid` is reserved by RFC 2606 and can never resolve, so the probe\n * origin cannot collide with a real host and the comparison means only what it\n * says.\n */\nconst PROBE_ORIGIN = 'https://redirect-probe.aglyn.invalid'\n\n/**\n * True when `candidate` is a relative path that resolves onto its own origin.\n *\n * Answers `false` for absent, non-string and unparseable input rather than\n * throwing: `strictNullChecks` is off repo-wide, so an absent query parameter\n * reaches this as an empty string or `null` at runtime however the types read,\n * and a `TypeError` escaping into a sign-in render is a worse outage than the\n * redirect bug this guards.\n *\n * Absolute URLs are refused here even when they name our own host. A caller\n * that must accept a same-site absolute (the workspace-domain return in\n * `use-continue-url`) checks that separately, against the parsed hostname —\n * for an absolute input the parser's verdict is already ground truth, so that\n * branch never had this bug.\n */\nexport function isSameOriginPath(\n candidate: string | null | undefined,\n): boolean {\n if (typeof candidate !== 'string') return false\n const value = candidate.trim()\n if (!value.startsWith('/')) return false\n try {\n // Resolve-and-compare. `origin` is what a navigation would actually reach,\n // so any input the parser rewrites into a different authority — `//host`,\n // `/\\host`, `/<TAB>/host`, and whatever comes next — fails right here.\n return new URL(value, PROBE_ORIGIN).origin === PROBE_ORIGIN\n } catch {\n return false\n }\n}\n\n/**\n * The trimmed path when it stays on this origin, otherwise `fallback`.\n *\n * The trimmed value is returned, not the raw one, so what was validated is\n * what the caller navigates to. Handing back the original would reintroduce\n * the whole bug class: a guard is only worth anything if the string it\n * approved is the string that gets used.\n */\nexport function safeSameOriginPath(\n candidate: string | null | undefined,\n fallback = '/',\n): string {\n if (!isSameOriginPath(candidate)) return fallback\n return (candidate as string).trim()\n}\n"],"names":["PROBE_ORIGIN","isSameOriginPath","candidate","value","trim","startsWith","URL","origin","safeSameOriginPath","fallback"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6CC,GACD,MAAMA,eAAe;AAErB;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,iBACdC,SAAoC;IAEpC,IAAI,OAAOA,cAAc,UAAU,OAAO;IAC1C,MAAMC,QAAQD,UAAUE,IAAI;IAC5B,IAAI,CAACD,MAAME,UAAU,CAAC,MAAM,OAAO;IACnC,IAAI;QACF,2EAA2E;QAC3E,0EAA0E;QAC1E,uEAAuE;QACvE,OAAO,IAAIC,IAAIH,OAAOH,cAAcO,MAAM,KAAKP;IACjD,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,SAASQ,mBACdN,SAAoC,EACpCO,WAAW,GAAG;IAEd,IAAI,CAACR,iBAAiBC,YAAY,OAAOO;IACzC,OAAO,AAACP,UAAqBE,IAAI;AACnC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* True when `value` may be emitted as a link target.
|
|
19
|
+
*
|
|
20
|
+
* A value naming no scheme is allowed: a relative path, a `?query` or a
|
|
21
|
+
* `#fragment` resolves against whatever base the document has and can name
|
|
22
|
+
* no protocol at all.
|
|
23
|
+
*
|
|
24
|
+
* ### This runs BEFORE the value is escaped, and that order matters
|
|
25
|
+
*
|
|
26
|
+
* A caller must escape the approved value into the attribute afterwards, and
|
|
27
|
+
* the two steps together are what closes the entity-encoded forms. This
|
|
28
|
+
* function reads raw characters, so `javascript:alert(1)` reads to it as
|
|
29
|
+
* a value with no scheme and is approved — and then the escape turns its `&`
|
|
30
|
+
* into `&`, so the parser sees the literal text `javascript:` in the
|
|
31
|
+
* attribute rather than a character reference, and it names no scheme there
|
|
32
|
+
* either. Drop the escape and that input becomes live; decode entities here
|
|
33
|
+
* instead and the escape double-encodes every legitimate `&` in a query
|
|
34
|
+
* string. Keep both, in this order.
|
|
35
|
+
*/
|
|
36
|
+
export declare function hasSafeLinkScheme(value: string | null | undefined): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* True when `value` may be emitted as a media source — an `img`, a logo, a
|
|
39
|
+
* poster. Same contract as {@link hasSafeLinkScheme}, against the narrower
|
|
40
|
+
* {@link MEDIA_SCHEMES}.
|
|
41
|
+
*/
|
|
42
|
+
export declare function hasSafeMediaScheme(value: string | null | undefined): boolean;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* Scheme allowlists for a URL this codebase writes into markup, in the one
|
|
18
|
+
* shared-scope home a `scope:shared` lib can reach.
|
|
19
|
+
*
|
|
20
|
+
* ## Why here rather than reusing one of the three that already exist
|
|
21
|
+
*
|
|
22
|
+
* The repo has a protocol allowlist in `markdown-lite`'s `safeLinkUrl` /
|
|
23
|
+
* `safeImageUrl`, another in `author-html`'s `isAllowedUrl`, and a third on
|
|
24
|
+
* the published marketplace node. All three live in `libs/aglyn` or in a
|
|
25
|
+
* plugin, and the nx boundary rule `scope:shared → only scope:shared` puts
|
|
26
|
+
* every one of them out of reach of a `scope:shared` consumer — the same wall
|
|
27
|
+
* `host-email-tokens.ts` documents for the host-token registry. So a shared
|
|
28
|
+
* consumer had the choice of a fourth private copy or a shared home; this is
|
|
29
|
+
* the shared home, next to `safe-redirect.ts`, which already answers the
|
|
30
|
+
* neighboring question of whether a path stays on our own origin.
|
|
31
|
+
*
|
|
32
|
+
* ## What these do and, more importantly, what they do not
|
|
33
|
+
*
|
|
34
|
+
* They answer ONE question: does this string name a scheme we are willing to
|
|
35
|
+
* emit? They say nothing about the host, the path, or whether the target
|
|
36
|
+
* exists, and they are not a substitute for escaping the value into the
|
|
37
|
+
* attribute afterwards — see {@link hasSafeLinkScheme} for why the ordering
|
|
38
|
+
* of those two steps is load-bearing.
|
|
39
|
+
*/ /**
|
|
40
|
+
* The scheme grammar a browser accepts: an ASCII letter followed by letters,
|
|
41
|
+
* digits, `+`, `-` or `.`, up to the first colon.
|
|
42
|
+
*/ const SCHEME_PATTERN = /^([a-z][a-z0-9+.-]*):/;
|
|
43
|
+
/**
|
|
44
|
+
* Schemes allowed on a link the reader chooses to follow.
|
|
45
|
+
*
|
|
46
|
+
* `data:` is deliberately absent. A `data:` href is a document the reader
|
|
47
|
+
* navigates INTO, carrying whatever markup and script the author put in it,
|
|
48
|
+
* which is the whole vector rather than a corner of it; and no authoring
|
|
49
|
+
* surface in this product has a reason to mint one, because a link that
|
|
50
|
+
* cannot be visited, shared, or resolved by a mail client is not a link.
|
|
51
|
+
*
|
|
52
|
+
* `javascript:` and `vbscript:` are absent for the obvious reason and are
|
|
53
|
+
* refused by construction rather than by name — anything not on this list is
|
|
54
|
+
* refused, so a scheme nobody has thought of yet is refused too.
|
|
55
|
+
*/ const LINK_SCHEMES = new Set([
|
|
56
|
+
'http',
|
|
57
|
+
'https',
|
|
58
|
+
'mailto',
|
|
59
|
+
'tel',
|
|
60
|
+
'sms'
|
|
61
|
+
]);
|
|
62
|
+
/**
|
|
63
|
+
* Schemes allowed on a source the client fetches on its own, with no reader
|
|
64
|
+
* action: an image, a logo, a thumbnail.
|
|
65
|
+
*
|
|
66
|
+
* Narrower than {@link LINK_SCHEMES} because the trust is different. A link
|
|
67
|
+
* is followed deliberately; a media source is fetched the moment the document
|
|
68
|
+
* renders, so it must name something ordinary over the network and nothing
|
|
69
|
+
* else. `mailto:`/`tel:`/`sms:` are meaningless in the position, and `data:`
|
|
70
|
+
* is excluded for the reason above plus a practical one: a media reference is
|
|
71
|
+
* resolved against an origin precisely so it comes out as something fetchable.
|
|
72
|
+
*/ const MEDIA_SCHEMES = new Set([
|
|
73
|
+
'http',
|
|
74
|
+
'https'
|
|
75
|
+
]);
|
|
76
|
+
/**
|
|
77
|
+
* The scheme a browser would read out of `value`, or `null` when the value
|
|
78
|
+
* names none — a relative path, a query, a fragment, or an empty string.
|
|
79
|
+
*
|
|
80
|
+
* Compared on a copy with every C0 control and space removed and folded to
|
|
81
|
+
* lower case, because that is what browsers strip while resolving a scheme:
|
|
82
|
+
* `"java\tscript:alert(1)"` navigates, and a check that reads the raw
|
|
83
|
+
* characters does not see it. This mirrors `author-html`'s `isAllowedUrl`,
|
|
84
|
+
* which learned the same lesson on the tenant render path.
|
|
85
|
+
*/ function schemeOf(value) {
|
|
86
|
+
// eslint-disable-next-line no-control-regex
|
|
87
|
+
const stripped = value.replace(/[\u0000-\u0020\u007f]/g, '').toLowerCase();
|
|
88
|
+
const match = SCHEME_PATTERN.exec(stripped);
|
|
89
|
+
return match ? match[1] : null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* True when `value` may be emitted as a link target.
|
|
93
|
+
*
|
|
94
|
+
* A value naming no scheme is allowed: a relative path, a `?query` or a
|
|
95
|
+
* `#fragment` resolves against whatever base the document has and can name
|
|
96
|
+
* no protocol at all.
|
|
97
|
+
*
|
|
98
|
+
* ### This runs BEFORE the value is escaped, and that order matters
|
|
99
|
+
*
|
|
100
|
+
* A caller must escape the approved value into the attribute afterwards, and
|
|
101
|
+
* the two steps together are what closes the entity-encoded forms. This
|
|
102
|
+
* function reads raw characters, so `javascript:alert(1)` reads to it as
|
|
103
|
+
* a value with no scheme and is approved — and then the escape turns its `&`
|
|
104
|
+
* into `&`, so the parser sees the literal text `javascript:` in the
|
|
105
|
+
* attribute rather than a character reference, and it names no scheme there
|
|
106
|
+
* either. Drop the escape and that input becomes live; decode entities here
|
|
107
|
+
* instead and the escape double-encodes every legitimate `&` in a query
|
|
108
|
+
* string. Keep both, in this order.
|
|
109
|
+
*/ export function hasSafeLinkScheme(value) {
|
|
110
|
+
if (typeof value !== 'string') return false;
|
|
111
|
+
const scheme = schemeOf(value);
|
|
112
|
+
return scheme === null || LINK_SCHEMES.has(scheme);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* True when `value` may be emitted as a media source — an `img`, a logo, a
|
|
116
|
+
* poster. Same contract as {@link hasSafeLinkScheme}, against the narrower
|
|
117
|
+
* {@link MEDIA_SCHEMES}.
|
|
118
|
+
*/ export function hasSafeMediaScheme(value) {
|
|
119
|
+
if (typeof value !== 'string') return false;
|
|
120
|
+
const scheme = schemeOf(value);
|
|
121
|
+
return scheme === null || MEDIA_SCHEMES.has(scheme);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=safe-url-scheme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/http/src/lib/safe-url-scheme.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Scheme allowlists for a URL this codebase writes into markup, in the one\n * shared-scope home a `scope:shared` lib can reach.\n *\n * ## Why here rather than reusing one of the three that already exist\n *\n * The repo has a protocol allowlist in `markdown-lite`'s `safeLinkUrl` /\n * `safeImageUrl`, another in `author-html`'s `isAllowedUrl`, and a third on\n * the published marketplace node. All three live in `libs/aglyn` or in a\n * plugin, and the nx boundary rule `scope:shared → only scope:shared` puts\n * every one of them out of reach of a `scope:shared` consumer — the same wall\n * `host-email-tokens.ts` documents for the host-token registry. So a shared\n * consumer had the choice of a fourth private copy or a shared home; this is\n * the shared home, next to `safe-redirect.ts`, which already answers the\n * neighboring question of whether a path stays on our own origin.\n *\n * ## What these do and, more importantly, what they do not\n *\n * They answer ONE question: does this string name a scheme we are willing to\n * emit? They say nothing about the host, the path, or whether the target\n * exists, and they are not a substitute for escaping the value into the\n * attribute afterwards — see {@link hasSafeLinkScheme} for why the ordering\n * of those two steps is load-bearing.\n */\n\n/**\n * The scheme grammar a browser accepts: an ASCII letter followed by letters,\n * digits, `+`, `-` or `.`, up to the first colon.\n */\nconst SCHEME_PATTERN = /^([a-z][a-z0-9+.-]*):/\n\n/**\n * Schemes allowed on a link the reader chooses to follow.\n *\n * `data:` is deliberately absent. A `data:` href is a document the reader\n * navigates INTO, carrying whatever markup and script the author put in it,\n * which is the whole vector rather than a corner of it; and no authoring\n * surface in this product has a reason to mint one, because a link that\n * cannot be visited, shared, or resolved by a mail client is not a link.\n *\n * `javascript:` and `vbscript:` are absent for the obvious reason and are\n * refused by construction rather than by name — anything not on this list is\n * refused, so a scheme nobody has thought of yet is refused too.\n */\nconst LINK_SCHEMES: ReadonlySet<string> = new Set([\n 'http',\n 'https',\n 'mailto',\n 'tel',\n 'sms',\n])\n\n/**\n * Schemes allowed on a source the client fetches on its own, with no reader\n * action: an image, a logo, a thumbnail.\n *\n * Narrower than {@link LINK_SCHEMES} because the trust is different. A link\n * is followed deliberately; a media source is fetched the moment the document\n * renders, so it must name something ordinary over the network and nothing\n * else. `mailto:`/`tel:`/`sms:` are meaningless in the position, and `data:`\n * is excluded for the reason above plus a practical one: a media reference is\n * resolved against an origin precisely so it comes out as something fetchable.\n */\nconst MEDIA_SCHEMES: ReadonlySet<string> = new Set(['http', 'https'])\n\n/**\n * The scheme a browser would read out of `value`, or `null` when the value\n * names none — a relative path, a query, a fragment, or an empty string.\n *\n * Compared on a copy with every C0 control and space removed and folded to\n * lower case, because that is what browsers strip while resolving a scheme:\n * `\"java\\tscript:alert(1)\"` navigates, and a check that reads the raw\n * characters does not see it. This mirrors `author-html`'s `isAllowedUrl`,\n * which learned the same lesson on the tenant render path.\n */\nfunction schemeOf(value: string): string | null {\n // eslint-disable-next-line no-control-regex\n const stripped = value.replace(/[\\u0000-\\u0020\\u007f]/g, '').toLowerCase()\n const match = SCHEME_PATTERN.exec(stripped)\n return match ? match[1] : null\n}\n\n/**\n * True when `value` may be emitted as a link target.\n *\n * A value naming no scheme is allowed: a relative path, a `?query` or a\n * `#fragment` resolves against whatever base the document has and can name\n * no protocol at all.\n *\n * ### This runs BEFORE the value is escaped, and that order matters\n *\n * A caller must escape the approved value into the attribute afterwards, and\n * the two steps together are what closes the entity-encoded forms. This\n * function reads raw characters, so `javascript:alert(1)` reads to it as\n * a value with no scheme and is approved — and then the escape turns its `&`\n * into `&`, so the parser sees the literal text `javascript:` in the\n * attribute rather than a character reference, and it names no scheme there\n * either. Drop the escape and that input becomes live; decode entities here\n * instead and the escape double-encodes every legitimate `&` in a query\n * string. Keep both, in this order.\n */\nexport function hasSafeLinkScheme(value: string | null | undefined): boolean {\n if (typeof value !== 'string') return false\n const scheme = schemeOf(value)\n return scheme === null || LINK_SCHEMES.has(scheme)\n}\n\n/**\n * True when `value` may be emitted as a media source — an `img`, a logo, a\n * poster. Same contract as {@link hasSafeLinkScheme}, against the narrower\n * {@link MEDIA_SCHEMES}.\n */\nexport function hasSafeMediaScheme(value: string | null | undefined): boolean {\n if (typeof value !== 'string') return false\n const scheme = schemeOf(value)\n return scheme === null || MEDIA_SCHEMES.has(scheme)\n}\n"],"names":["SCHEME_PATTERN","LINK_SCHEMES","Set","MEDIA_SCHEMES","schemeOf","value","stripped","replace","toLowerCase","match","exec","hasSafeLinkScheme","scheme","has","hasSafeMediaScheme"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GAED;;;CAGC,GACD,MAAMA,iBAAiB;AAEvB;;;;;;;;;;;;CAYC,GACD,MAAMC,eAAoC,IAAIC,IAAI;IAChD;IACA;IACA;IACA;IACA;CACD;AAED;;;;;;;;;;CAUC,GACD,MAAMC,gBAAqC,IAAID,IAAI;IAAC;IAAQ;CAAQ;AAEpE;;;;;;;;;CASC,GACD,SAASE,SAASC,KAAa;IAC7B,4CAA4C;IAC5C,MAAMC,WAAWD,MAAME,OAAO,CAAC,0BAA0B,IAAIC,WAAW;IACxE,MAAMC,QAAQT,eAAeU,IAAI,CAACJ;IAClC,OAAOG,QAAQA,KAAK,CAAC,EAAE,GAAG;AAC5B;AAEA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASE,kBAAkBN,KAAgC;IAChE,IAAI,OAAOA,UAAU,UAAU,OAAO;IACtC,MAAMO,SAASR,SAASC;IACxB,OAAOO,WAAW,QAAQX,aAAaY,GAAG,CAACD;AAC7C;AAEA;;;;CAIC,GACD,OAAO,SAASE,mBAAmBT,KAAgC;IACjE,IAAI,OAAOA,UAAU,UAAU,OAAO;IACtC,MAAMO,SAASR,SAASC;IACxB,OAAOO,WAAW,QAAQT,cAAcU,GAAG,CAACD;AAC9C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { HttpStatusCode } from '@aglyn/shared-data-enums';
|
|
18
|
+
import type { NextApiRequest } from 'next';
|
|
19
|
+
export type StaticOrigin = boolean | string | RegExp | (boolean | string | RegExp)[];
|
|
20
|
+
export type OriginFn = (origin: string[] | string | undefined, request: Request | NextApiRequest) => StaticOrigin | Promise<StaticOrigin>;
|
|
21
|
+
export interface CorsOptions {
|
|
22
|
+
origin?: StaticOrigin | OriginFn;
|
|
23
|
+
methods?: string | string[];
|
|
24
|
+
allowedHeaders?: string | string[];
|
|
25
|
+
exposedHeaders?: string | string[];
|
|
26
|
+
credentials?: boolean;
|
|
27
|
+
maxAge?: number;
|
|
28
|
+
preflightContinue?: boolean;
|
|
29
|
+
optionsSuccessStatus?: HttpStatusCode;
|
|
30
|
+
}
|
package/src/lib/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ export { };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/http/src/lib/types.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type {HttpStatusCode} from '@aglyn/shared-data-enums'\nimport type {NextApiRequest} from 'next'\n\n\nexport type StaticOrigin = boolean | string | RegExp | (boolean | string | RegExp)[]\n\nexport type OriginFn = (\n origin: string[] | string | undefined,\n request: Request | NextApiRequest,\n) => StaticOrigin | Promise<StaticOrigin>\n\nexport interface CorsOptions {\n origin?: StaticOrigin | OriginFn\n methods?: string | string[]\n allowedHeaders?: string | string[]\n exposedHeaders?: string | string[]\n credentials?: boolean\n maxAge?: number\n preflightContinue?: boolean\n optionsSuccessStatus?: HttpStatusCode\n}\n"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAYD,WASC"}
|