@apifuse/provider-sdk 2.2.0-beta.17 → 2.2.0-beta.18

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.
@@ -1,98 +0,0 @@
1
- import { domainToASCII } from "node:url";
2
- const STRICT_IPV4_PATTERN = /^(0|[1-9]\d{0,2})\.(0|[1-9]\d{0,2})\.(0|[1-9]\d{0,2})\.(0|[1-9]\d{0,2})$/;
3
- const DECIMAL_COMPONENT_PATTERN = /^\d+$/;
4
- const HEX_COMPONENT_PATTERN = /^0[xX][\da-fA-F]+$/;
5
- const FORMAT_CONTROL_PATTERN = /\p{Cf}/u;
6
- const RESERVED_EGRESS_HOST_DELIMITERS = ["/", "\\", "?", "#", "@", "[", "]", " ", "%"];
7
- export function parseStrictIpv4(value) {
8
- const match = STRICT_IPV4_PATTERN.exec(value);
9
- if (!match || match[0] !== value)
10
- return undefined;
11
- const [, first, second, third, fourth] = match;
12
- if (first === undefined || second === undefined || third === undefined || fourth === undefined)
13
- return undefined;
14
- const octets = [Number(first), Number(second), Number(third), Number(fourth)];
15
- if (octets.some((octet) => octet > 255))
16
- return undefined;
17
- const [a, b, c, d] = octets;
18
- if (a === undefined || b === undefined || c === undefined || d === undefined)
19
- return undefined;
20
- return (a * 0x1000000 + b * 0x10000 + c * 0x100 + d) >>> 0;
21
- }
22
- export function classifyEgressTargetHost(host) {
23
- if (parseStrictIpv4(host) !== undefined)
24
- return "ipv4";
25
- if (host.includes(":"))
26
- return "numeric-ambiguous";
27
- const labels = host.split(".");
28
- if (labels.every((label) => DECIMAL_COMPONENT_PATTERN.exec(label)?.[0] === label ||
29
- HEX_COMPONENT_PATTERN.exec(label)?.[0] === label))
30
- return "numeric-ambiguous";
31
- return "dns";
32
- }
33
- export function hasReservedEgressHostDelimiter(value) {
34
- return RESERVED_EGRESS_HOST_DELIMITERS.some((delimiter) => value.includes(delimiter));
35
- }
36
- export function hasEgressHostControlCharacter(value) {
37
- for (let index = 0; index < value.length; index += 1) {
38
- const code = value.charCodeAt(index);
39
- if (code <= 31 || code === 127)
40
- return true;
41
- }
42
- return FORMAT_CONTROL_PATTERN.test(value);
43
- }
44
- export function canonicalizeEgressHost(value) {
45
- if (typeof value !== "string")
46
- return { ok: false, reason: "not-string" };
47
- if (hasReservedEgressHostDelimiter(value))
48
- return { ok: false, reason: "reserved-delimiter" };
49
- if (hasEgressHostControlCharacter(value))
50
- return { ok: false, reason: "control-character" };
51
- if (/\s/u.test(value))
52
- return { ok: false, reason: "whitespace" };
53
- const raw = value.trim();
54
- if (!raw)
55
- return { ok: false, reason: "canonicalization-empty" };
56
- // Classify the spelling with one optional root-label dot removed before IDNA.
57
- // This keeps resolver-numeric ASCII forms from being widened into canonical IPv4.
58
- const numericCandidate = raw.endsWith(".") ? raw.slice(0, -1) : raw;
59
- const normalizedNumericCandidate = numericCandidate.toLowerCase();
60
- if (classifyEgressTargetHost(normalizedNumericCandidate) === "numeric-ambiguous")
61
- return { ok: true, host: normalizedNumericCandidate };
62
- let ascii;
63
- try {
64
- ascii = domainToASCII(raw).toLowerCase().replace(/\.$/, "");
65
- }
66
- catch {
67
- return { ok: false, reason: "canonicalization-empty" };
68
- }
69
- if (!ascii || /^\.+$/.test(ascii))
70
- return { ok: false, reason: "canonicalization-empty" };
71
- return { ok: true, host: ascii };
72
- }
73
- export function parseIpv4Cidr(value) {
74
- const separator = value.indexOf("/");
75
- if (separator <= 0 || separator !== value.lastIndexOf("/"))
76
- return { ok: false, reason: "malformed" };
77
- const address = parseStrictIpv4(value.slice(0, separator));
78
- const prefixText = value.slice(separator + 1);
79
- const prefix = Number(prefixText);
80
- if (address === undefined ||
81
- !Number.isInteger(prefix) ||
82
- prefix < 0 ||
83
- prefix > 32 ||
84
- String(prefix) !== prefixText)
85
- return { ok: false, reason: "malformed" };
86
- const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
87
- const network = (address & mask) >>> 0;
88
- if (address !== network)
89
- return { ok: false, reason: "non-canonical-network" };
90
- return { ok: true, network, prefix };
91
- }
92
- export function ipv4InCidr(address, cidr) {
93
- const parsed = parseIpv4Cidr(cidr);
94
- if (!parsed.ok)
95
- return false;
96
- return (parsed.prefix === 0 ||
97
- address >>> (32 - parsed.prefix) === parsed.network >>> (32 - parsed.prefix));
98
- }
@@ -1,118 +0,0 @@
1
- import { domainToASCII } from "node:url";
2
-
3
- const STRICT_IPV4_PATTERN =
4
- /^(0|[1-9]\d{0,2})\.(0|[1-9]\d{0,2})\.(0|[1-9]\d{0,2})\.(0|[1-9]\d{0,2})$/;
5
- const DECIMAL_COMPONENT_PATTERN = /^\d+$/;
6
- const HEX_COMPONENT_PATTERN = /^0[xX][\da-fA-F]+$/;
7
- const FORMAT_CONTROL_PATTERN = /\p{Cf}/u;
8
- const RESERVED_EGRESS_HOST_DELIMITERS = ["/", "\\", "?", "#", "@", "[", "]", " ", "%"];
9
-
10
- export type EgressHostCanonicalizationFailure =
11
- | "not-string"
12
- | "reserved-delimiter"
13
- | "control-character"
14
- | "whitespace"
15
- | "canonicalization-empty";
16
-
17
- export type EgressHostCanonicalizationResult =
18
- | { readonly ok: true; readonly host: string }
19
- | { readonly ok: false; readonly reason: EgressHostCanonicalizationFailure };
20
-
21
- export function parseStrictIpv4(value: string): number | undefined {
22
- const match = STRICT_IPV4_PATTERN.exec(value);
23
- if (!match || match[0] !== value) return undefined;
24
- const [, first, second, third, fourth] = match;
25
- if (first === undefined || second === undefined || third === undefined || fourth === undefined)
26
- return undefined;
27
- const octets = [Number(first), Number(second), Number(third), Number(fourth)];
28
- if (octets.some((octet) => octet > 255)) return undefined;
29
- const [a, b, c, d] = octets;
30
- if (a === undefined || b === undefined || c === undefined || d === undefined) return undefined;
31
- return (a * 0x1000000 + b * 0x10000 + c * 0x100 + d) >>> 0;
32
- }
33
-
34
- export function classifyEgressTargetHost(host: string): "ipv4" | "numeric-ambiguous" | "dns" {
35
- if (parseStrictIpv4(host) !== undefined) return "ipv4";
36
- if (host.includes(":")) return "numeric-ambiguous";
37
- const labels = host.split(".");
38
- if (
39
- labels.every(
40
- (label) =>
41
- DECIMAL_COMPONENT_PATTERN.exec(label)?.[0] === label ||
42
- HEX_COMPONENT_PATTERN.exec(label)?.[0] === label,
43
- )
44
- )
45
- return "numeric-ambiguous";
46
- return "dns";
47
- }
48
-
49
- export function hasReservedEgressHostDelimiter(value: string): boolean {
50
- return RESERVED_EGRESS_HOST_DELIMITERS.some((delimiter) => value.includes(delimiter));
51
- }
52
-
53
- export function hasEgressHostControlCharacter(value: string): boolean {
54
- for (let index = 0; index < value.length; index += 1) {
55
- const code = value.charCodeAt(index);
56
- if (code <= 31 || code === 127) return true;
57
- }
58
- return FORMAT_CONTROL_PATTERN.test(value);
59
- }
60
-
61
- export function canonicalizeEgressHost(value: unknown): EgressHostCanonicalizationResult {
62
- if (typeof value !== "string") return { ok: false, reason: "not-string" };
63
- if (hasReservedEgressHostDelimiter(value)) return { ok: false, reason: "reserved-delimiter" };
64
- if (hasEgressHostControlCharacter(value)) return { ok: false, reason: "control-character" };
65
- if (/\s/u.test(value)) return { ok: false, reason: "whitespace" };
66
- const raw = value.trim();
67
- if (!raw) return { ok: false, reason: "canonicalization-empty" };
68
-
69
- // Classify the spelling with one optional root-label dot removed before IDNA.
70
- // This keeps resolver-numeric ASCII forms from being widened into canonical IPv4.
71
- const numericCandidate = raw.endsWith(".") ? raw.slice(0, -1) : raw;
72
- const normalizedNumericCandidate = numericCandidate.toLowerCase();
73
- if (classifyEgressTargetHost(normalizedNumericCandidate) === "numeric-ambiguous")
74
- return { ok: true, host: normalizedNumericCandidate };
75
-
76
- let ascii: string;
77
- try {
78
- ascii = domainToASCII(raw).toLowerCase().replace(/\.$/, "");
79
- } catch {
80
- return { ok: false, reason: "canonicalization-empty" };
81
- }
82
- if (!ascii || /^\.+$/.test(ascii)) return { ok: false, reason: "canonicalization-empty" };
83
- return { ok: true, host: ascii };
84
- }
85
-
86
- export function parseIpv4Cidr(
87
- value: string,
88
- ):
89
- | { readonly ok: true; readonly network: number; readonly prefix: number }
90
- | { readonly ok: false; readonly reason: "malformed" | "non-canonical-network" } {
91
- const separator = value.indexOf("/");
92
- if (separator <= 0 || separator !== value.lastIndexOf("/"))
93
- return { ok: false, reason: "malformed" };
94
- const address = parseStrictIpv4(value.slice(0, separator));
95
- const prefixText = value.slice(separator + 1);
96
- const prefix = Number(prefixText);
97
- if (
98
- address === undefined ||
99
- !Number.isInteger(prefix) ||
100
- prefix < 0 ||
101
- prefix > 32 ||
102
- String(prefix) !== prefixText
103
- )
104
- return { ok: false, reason: "malformed" };
105
- const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
106
- const network = (address & mask) >>> 0;
107
- if (address !== network) return { ok: false, reason: "non-canonical-network" };
108
- return { ok: true, network, prefix };
109
- }
110
-
111
- export function ipv4InCidr(address: number, cidr: string): boolean {
112
- const parsed = parseIpv4Cidr(cidr);
113
- if (!parsed.ok) return false;
114
- return (
115
- parsed.prefix === 0 ||
116
- address >>> (32 - parsed.prefix) === parsed.network >>> (32 - parsed.prefix)
117
- );
118
- }