@apifuse/provider-sdk 2.2.0-beta.16 → 2.2.0-beta.17
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/AUTHORING.md +40 -0
- package/CHANGELOG.md +5 -0
- package/dist/config/loader.d.ts +19 -0
- package/dist/config/loader.js +59 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/native-egress-policy.d.ts +1 -0
- package/dist/native-egress-policy.js +34 -21
- package/dist/native-ipv4.d.ts +22 -0
- package/dist/native-ipv4.js +98 -0
- package/dist/provider.d.ts +1 -1
- package/dist/provider.js +1 -1
- package/dist/runtime/native-network.d.ts +43 -7
- package/dist/runtime/native-network.js +567 -110
- package/dist/runtime/proxy-nodemaven.d.ts +7 -0
- package/dist/runtime/proxy-nodemaven.js +5 -5
- package/dist/server/serve.js +3 -1
- package/dist/types.d.ts +6 -1
- package/package.json +1 -1
- package/src/config/loader.ts +110 -18
- package/src/index.ts +5 -0
- package/src/native-egress-policy.ts +39 -33
- package/src/native-ipv4.ts +118 -0
- package/src/provider.ts +5 -0
- package/src/runtime/native-network.ts +734 -131
- package/src/runtime/proxy-nodemaven.ts +13 -5
- package/src/server/serve.ts +8 -1
- package/src/types.ts +6 -1
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
}
|
package/src/provider.ts
CHANGED
|
@@ -166,6 +166,7 @@ export type {
|
|
|
166
166
|
} from "./types.js";
|
|
167
167
|
export {
|
|
168
168
|
createNativeNetworkClient,
|
|
169
|
+
createEnvVendorCredentialResolver,
|
|
169
170
|
deriveNativeCredentialAffinityKey,
|
|
170
171
|
NativeEgressGrantExpiredError,
|
|
171
172
|
NativeEgressNotDeclaredError,
|
|
@@ -175,10 +176,14 @@ export {
|
|
|
175
176
|
resolveNativeGatewayProxy,
|
|
176
177
|
type NativeGatewayProxy,
|
|
177
178
|
type NativeGatewayProxyResolutionInput,
|
|
179
|
+
type NativeGatewayProxySkipReason,
|
|
178
180
|
type NativeGatewayProxySynthesizer,
|
|
181
|
+
type NativeGatewayProxySynthesisResult,
|
|
179
182
|
type NativeGatewayProxySynthesisInput,
|
|
180
183
|
type NativeNetworkClientOptions,
|
|
181
184
|
type NativeNetworkErrorCode,
|
|
185
|
+
type VendorCredentialLookup,
|
|
186
|
+
type VendorCredentialResolver,
|
|
182
187
|
} from "./runtime/native-network.js";
|
|
183
188
|
export {
|
|
184
189
|
HttpRetryAfterPolicy,
|