@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.4
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 +14 -0
- package/CHANGELOG.md +4 -0
- package/bin/apifuse-check.ts +18 -58
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +27 -52
- package/bin/apifuse-pack-smoke.ts +22 -81
- package/bin/apifuse-pack-types.ts +266 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +23 -61
- package/bin/apifuse-submit-check.ts +26 -21
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-xml.ts +1 -1
- package/dist/auth-turn/index.d.ts +1 -1
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +9 -18
- package/dist/ceremonies/index.d.ts +1 -1
- package/dist/ceremonies/index.js +8 -18
- package/dist/config/loader.d.ts +2 -2
- package/dist/config/loader.js +19 -42
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +3 -6
- package/dist/contract-types.d.ts +2 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +4 -6
- package/dist/define.d.ts +8 -1
- package/dist/define.js +57 -115
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -3
- package/dist/i18n/catalog.d.ts +2 -2
- package/dist/i18n/catalog.js +4 -10
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/keys.d.ts +2 -2
- package/dist/index.d.ts +43 -42
- package/dist/index.js +38 -37
- package/dist/lint.js +8 -15
- package/dist/provider.d.ts +11 -11
- package/dist/provider.js +9 -9
- package/dist/public-schema-field-lint.d.ts +1 -1
- package/dist/recipes/gov-api.js +1 -1
- package/dist/runtime/auth-flow.d.ts +1 -1
- package/dist/runtime/auth-flow.js +3 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +15 -29
- package/dist/runtime/cache.d.ts +1 -1
- package/dist/runtime/cache.js +4 -8
- package/dist/runtime/choice.d.ts +1 -1
- package/dist/runtime/choice.js +12 -34
- package/dist/runtime/credential.d.ts +1 -1
- package/dist/runtime/credential.js +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/runtime/executor.d.ts +1 -1
- package/dist/runtime/executor.js +2 -2
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +5 -5
- package/dist/runtime/insights.d.ts +1 -1
- package/dist/runtime/insights.js +6 -13
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +5 -15
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/otlp.d.ts +1 -1
- package/dist/runtime/perf.d.ts +1 -1
- package/dist/runtime/provider.d.ts +1 -1
- package/dist/runtime/provider.js +1 -2
- package/dist/runtime/proxy-errors.d.ts +1 -1
- package/dist/runtime/proxy-errors.js +3 -5
- package/dist/runtime/proxy-retry-policy.d.ts +2 -2
- package/dist/runtime/proxy-retry-policy.js +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +1 -1
- package/dist/runtime/proxy-telemetry.js +16 -48
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +2 -4
- package/dist/runtime/request-options.d.ts +1 -1
- package/dist/runtime/state.d.ts +2 -2
- package/dist/runtime/state.js +3 -3
- package/dist/runtime/stealth.d.ts +2 -2
- package/dist/runtime/stealth.js +6 -6
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +11 -15
- package/dist/runtime/trace.d.ts +2 -2
- package/dist/runtime/trace.js +2 -4
- package/dist/runtime/waterfall.d.ts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +7 -15
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +6 -6
- package/dist/server/self-test-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +3 -3
- package/dist/server/self-test.js +3 -3
- package/dist/server/serve.d.ts +3 -3
- package/dist/server/serve.js +36 -49
- package/dist/server/types.js +2 -7
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +5 -14
- package/dist/stream.d.ts +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/testing/run.d.ts +1 -1
- package/dist/testing/run.js +7 -14
- package/dist/types.d.ts +57 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +6 -4
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +28 -86
- package/src/ceremonies/index.ts +24 -78
- package/src/config/loader.ts +58 -176
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +12 -28
- package/src/define.ts +174 -495
- package/src/dev.ts +4 -9
- package/src/errors.ts +4 -11
- package/src/i18n/catalog.ts +10 -32
- package/src/i18n/index.ts +2 -2
- package/src/i18n/keys.ts +5 -11
- package/src/index.ts +44 -42
- package/src/lint.ts +89 -159
- package/src/provider.ts +12 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +5 -7
- package/src/runtime/browser.ts +64 -187
- package/src/runtime/cache.ts +20 -67
- package/src/runtime/choice.ts +55 -129
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +9 -19
- package/src/runtime/http.ts +7 -7
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +19 -58
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/otlp.ts +12 -23
- package/src/runtime/perf.ts +1 -1
- package/src/runtime/provider.ts +4 -9
- package/src/runtime/proxy-errors.ts +17 -38
- package/src/runtime/proxy-retry-policy.ts +3 -3
- package/src/runtime/proxy-telemetry.ts +23 -72
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +4 -13
- package/src/runtime/state.ts +30 -109
- package/src/runtime/stealth.ts +8 -8
- package/src/runtime/stt.ts +38 -94
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +1 -1
- package/src/server/index.ts +7 -7
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +5 -5
- package/src/server/serve.ts +87 -242
- package/src/server/types.ts +6 -19
- package/src/stealth/profiles.ts +10 -26
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +2 -2
- package/src/testing/run.ts +19 -67
- package/src/types.ts +58 -0
- package/src/user-input.ts +118 -0
|
@@ -4,7 +4,7 @@ import type {
|
|
|
4
4
|
ProxyResolutionTelemetryEvent,
|
|
5
5
|
ProxyTelemetrySink,
|
|
6
6
|
SmartproxyAllocatorBodyClass,
|
|
7
|
-
} from "../config/loader";
|
|
7
|
+
} from "../config/loader.js";
|
|
8
8
|
|
|
9
9
|
export const PROVIDER_TELEMETRY_HEADER = "X-ApiFuse-Provider-Telemetry";
|
|
10
10
|
|
|
@@ -55,31 +55,18 @@ const CACHE_STATUS_SEVERITY: Record<ProxyCacheStatus, number> = {
|
|
|
55
55
|
allocator: 7,
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
function sumOptional(
|
|
59
|
-
left: number | undefined,
|
|
60
|
-
right: number | undefined,
|
|
61
|
-
): number | undefined {
|
|
58
|
+
function sumOptional(left: number | undefined, right: number | undefined): number | undefined {
|
|
62
59
|
const total = (left ?? 0) + (right ?? 0);
|
|
63
60
|
return total > 0 ? total : undefined;
|
|
64
61
|
}
|
|
65
62
|
|
|
66
|
-
function maxOptional(
|
|
67
|
-
left: number
|
|
68
|
-
right: number | undefined,
|
|
69
|
-
): number | undefined {
|
|
70
|
-
const values = [left, right].filter(
|
|
71
|
-
(value): value is number => typeof value === "number",
|
|
72
|
-
);
|
|
63
|
+
function maxOptional(left: number | undefined, right: number | undefined): number | undefined {
|
|
64
|
+
const values = [left, right].filter((value): value is number => typeof value === "number");
|
|
73
65
|
return values.length > 0 ? Math.max(...values) : undefined;
|
|
74
66
|
}
|
|
75
67
|
|
|
76
|
-
function worseStatus(
|
|
77
|
-
left:
|
|
78
|
-
right: ProxyCacheStatus,
|
|
79
|
-
): ProxyCacheStatus {
|
|
80
|
-
return CACHE_STATUS_SEVERITY[right] > CACHE_STATUS_SEVERITY[left]
|
|
81
|
-
? right
|
|
82
|
-
: left;
|
|
68
|
+
function worseStatus(left: ProxyCacheStatus, right: ProxyCacheStatus): ProxyCacheStatus {
|
|
69
|
+
return CACHE_STATUS_SEVERITY[right] > CACHE_STATUS_SEVERITY[left] ? right : left;
|
|
83
70
|
}
|
|
84
71
|
|
|
85
72
|
function encodeBase64Url(value: string): string {
|
|
@@ -97,9 +84,7 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
|
|
|
97
84
|
cacheHit: event.cacheHit,
|
|
98
85
|
resolutionMs: Math.max(0, Math.floor(event.resolutionMs)),
|
|
99
86
|
allocatorMs:
|
|
100
|
-
event.allocatorMs === undefined
|
|
101
|
-
? undefined
|
|
102
|
-
: Math.max(0, Math.floor(event.allocatorMs)),
|
|
87
|
+
event.allocatorMs === undefined ? undefined : Math.max(0, Math.floor(event.allocatorMs)),
|
|
103
88
|
allocatorStatus:
|
|
104
89
|
event.allocatorStatus === undefined
|
|
105
90
|
? undefined
|
|
@@ -110,30 +95,20 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
|
|
|
110
95
|
? undefined
|
|
111
96
|
: Math.max(1, Math.floor(event.allocatorAttempts)),
|
|
112
97
|
lockWaitMs:
|
|
113
|
-
event.lockWaitMs === undefined
|
|
114
|
-
? undefined
|
|
115
|
-
: Math.max(0, Math.floor(event.lockWaitMs)),
|
|
98
|
+
event.lockWaitMs === undefined ? undefined : Math.max(0, Math.floor(event.lockWaitMs)),
|
|
116
99
|
redisReadMs:
|
|
117
|
-
event.redisReadMs === undefined
|
|
118
|
-
? undefined
|
|
119
|
-
: Math.max(0, Math.floor(event.redisReadMs)),
|
|
100
|
+
event.redisReadMs === undefined ? undefined : Math.max(0, Math.floor(event.redisReadMs)),
|
|
120
101
|
redisWriteMs:
|
|
121
|
-
event.redisWriteMs === undefined
|
|
122
|
-
? undefined
|
|
123
|
-
: Math.max(0, Math.floor(event.redisWriteMs)),
|
|
102
|
+
event.redisWriteMs === undefined ? undefined : Math.max(0, Math.floor(event.redisWriteMs)),
|
|
124
103
|
poolAgeMs:
|
|
125
|
-
event.poolAgeMs === undefined
|
|
126
|
-
? undefined
|
|
127
|
-
: Math.max(0, Math.floor(event.poolAgeMs)),
|
|
104
|
+
event.poolAgeMs === undefined ? undefined : Math.max(0, Math.floor(event.poolAgeMs)),
|
|
128
105
|
poolExpiresInMs:
|
|
129
106
|
event.poolExpiresInMs === undefined
|
|
130
107
|
? undefined
|
|
131
108
|
: Math.max(0, Math.floor(event.poolExpiresInMs)),
|
|
132
109
|
attempts: Math.max(1, Math.floor(event.attempts || 1)),
|
|
133
110
|
refreshes:
|
|
134
|
-
event.refreshes === undefined
|
|
135
|
-
? undefined
|
|
136
|
-
: Math.max(0, Math.floor(event.refreshes)),
|
|
111
|
+
event.refreshes === undefined ? undefined : Math.max(0, Math.floor(event.refreshes)),
|
|
137
112
|
});
|
|
138
113
|
}
|
|
139
114
|
|
|
@@ -148,9 +123,7 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
|
|
|
148
123
|
...(event.proxyHash ? { proxyHash: event.proxyHash.slice(0, 16) } : {}),
|
|
149
124
|
outcome: event.outcome === "ok" ? "ok" : "error",
|
|
150
125
|
...(event.errorCode ? { errorCode: event.errorCode.slice(0, 80) } : {}),
|
|
151
|
-
...(event.status === undefined
|
|
152
|
-
? {}
|
|
153
|
-
: { status: Math.max(0, Math.floor(event.status)) }),
|
|
126
|
+
...(event.status === undefined ? {} : { status: Math.max(0, Math.floor(event.status)) }),
|
|
154
127
|
...(event.durationMs === undefined
|
|
155
128
|
? {}
|
|
156
129
|
: { durationMs: Math.max(0, Math.floor(event.durationMs)) }),
|
|
@@ -170,18 +143,12 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
|
|
|
170
143
|
allocatorMs: sumOptional(acc.allocatorMs, event.allocatorMs),
|
|
171
144
|
allocatorStatus: event.allocatorStatus ?? acc.allocatorStatus,
|
|
172
145
|
allocatorBodyClass: event.allocatorBodyClass ?? acc.allocatorBodyClass,
|
|
173
|
-
allocatorAttempts: sumOptional(
|
|
174
|
-
acc.allocatorAttempts,
|
|
175
|
-
event.allocatorAttempts,
|
|
176
|
-
),
|
|
146
|
+
allocatorAttempts: sumOptional(acc.allocatorAttempts, event.allocatorAttempts),
|
|
177
147
|
lockWaitMs: sumOptional(acc.lockWaitMs, event.lockWaitMs),
|
|
178
148
|
redisReadMs: sumOptional(acc.redisReadMs, event.redisReadMs),
|
|
179
149
|
redisWriteMs: sumOptional(acc.redisWriteMs, event.redisWriteMs),
|
|
180
150
|
poolAgeMs: maxOptional(acc.poolAgeMs, event.poolAgeMs),
|
|
181
|
-
poolExpiresInMs: maxOptional(
|
|
182
|
-
acc.poolExpiresInMs,
|
|
183
|
-
event.poolExpiresInMs,
|
|
184
|
-
),
|
|
151
|
+
poolExpiresInMs: maxOptional(acc.poolExpiresInMs, event.poolExpiresInMs),
|
|
185
152
|
attempts: acc.attempts + event.attempts,
|
|
186
153
|
refreshes: sumOptional(acc.refreshes, event.refreshes),
|
|
187
154
|
}),
|
|
@@ -194,9 +161,7 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
|
|
|
194
161
|
cacheStatus: aggregate.cacheStatus,
|
|
195
162
|
cacheHit: aggregate.cacheHit,
|
|
196
163
|
resolutionMs: aggregate.resolutionMs,
|
|
197
|
-
...(aggregate.allocatorMs !== undefined
|
|
198
|
-
? { allocatorMs: aggregate.allocatorMs }
|
|
199
|
-
: {}),
|
|
164
|
+
...(aggregate.allocatorMs !== undefined ? { allocatorMs: aggregate.allocatorMs } : {}),
|
|
200
165
|
...(aggregate.allocatorStatus !== undefined
|
|
201
166
|
? { allocatorStatus: aggregate.allocatorStatus }
|
|
202
167
|
: {}),
|
|
@@ -206,40 +171,26 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
|
|
|
206
171
|
...(aggregate.allocatorAttempts !== undefined
|
|
207
172
|
? { allocatorAttempts: aggregate.allocatorAttempts }
|
|
208
173
|
: {}),
|
|
209
|
-
...(aggregate.lockWaitMs !== undefined
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
...(aggregate.
|
|
213
|
-
? { redisReadMs: aggregate.redisReadMs }
|
|
214
|
-
: {}),
|
|
215
|
-
...(aggregate.redisWriteMs !== undefined
|
|
216
|
-
? { redisWriteMs: aggregate.redisWriteMs }
|
|
217
|
-
: {}),
|
|
218
|
-
...(aggregate.poolAgeMs !== undefined
|
|
219
|
-
? { poolAgeMs: aggregate.poolAgeMs }
|
|
220
|
-
: {}),
|
|
174
|
+
...(aggregate.lockWaitMs !== undefined ? { lockWaitMs: aggregate.lockWaitMs } : {}),
|
|
175
|
+
...(aggregate.redisReadMs !== undefined ? { redisReadMs: aggregate.redisReadMs } : {}),
|
|
176
|
+
...(aggregate.redisWriteMs !== undefined ? { redisWriteMs: aggregate.redisWriteMs } : {}),
|
|
177
|
+
...(aggregate.poolAgeMs !== undefined ? { poolAgeMs: aggregate.poolAgeMs } : {}),
|
|
221
178
|
...(aggregate.poolExpiresInMs !== undefined
|
|
222
179
|
? { poolExpiresInMs: aggregate.poolExpiresInMs }
|
|
223
180
|
: {}),
|
|
224
181
|
attempts: aggregate.attempts,
|
|
225
|
-
...(aggregate.refreshes !== undefined
|
|
226
|
-
? { refreshes: aggregate.refreshes }
|
|
227
|
-
: {}),
|
|
182
|
+
...(aggregate.refreshes !== undefined ? { refreshes: aggregate.refreshes } : {}),
|
|
228
183
|
...(this.#attempts.length > 0
|
|
229
184
|
? {
|
|
230
185
|
attemptSamples: this.#attempts.map((attempt, index) => ({
|
|
231
186
|
n: index + 1,
|
|
232
187
|
a: attempt.attempt,
|
|
233
|
-
...(attempt.poolIndex === undefined
|
|
234
|
-
? {}
|
|
235
|
-
: { i: attempt.poolIndex }),
|
|
188
|
+
...(attempt.poolIndex === undefined ? {} : { i: attempt.poolIndex }),
|
|
236
189
|
...(attempt.proxyHash ? { h: attempt.proxyHash } : {}),
|
|
237
190
|
o: attempt.outcome,
|
|
238
191
|
...(attempt.errorCode ? { c: attempt.errorCode } : {}),
|
|
239
192
|
...(attempt.status === undefined ? {} : { s: attempt.status }),
|
|
240
|
-
...(attempt.durationMs === undefined
|
|
241
|
-
? {}
|
|
242
|
-
: { d: attempt.durationMs }),
|
|
193
|
+
...(attempt.durationMs === undefined ? {} : { d: attempt.durationMs }),
|
|
243
194
|
})),
|
|
244
195
|
}
|
|
245
196
|
: {}),
|
package/src/runtime/redis.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Redis from "ioredis";
|
|
1
|
+
import { Redis } from "ioredis";
|
|
2
2
|
|
|
3
3
|
export type ProviderRedisClient = Redis;
|
|
4
4
|
|
|
@@ -43,9 +43,7 @@ export async function withRedisTimeout<T>(
|
|
|
43
43
|
}
|
|
44
44
|
}, options.timeoutMs);
|
|
45
45
|
});
|
|
46
|
-
const operationResult = options.onError
|
|
47
|
-
? operation().catch(options.onError)
|
|
48
|
-
: operation();
|
|
46
|
+
const operationResult = options.onError ? operation().catch(options.onError) : operation();
|
|
49
47
|
return await Promise.race([operationResult, timeout]);
|
|
50
48
|
} finally {
|
|
51
49
|
if (timeoutId) clearTimeout(timeoutId);
|
|
@@ -56,10 +54,7 @@ export function redisStatus(redis: ProviderRedisClient): string {
|
|
|
56
54
|
return redis.status;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
async function waitForRedisReady(
|
|
60
|
-
redis: ProviderRedisClient,
|
|
61
|
-
timeoutMs: number,
|
|
62
|
-
): Promise<boolean> {
|
|
57
|
+
async function waitForRedisReady(redis: ProviderRedisClient, timeoutMs: number): Promise<boolean> {
|
|
63
58
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
64
59
|
let settled = false;
|
|
65
60
|
|
|
@@ -80,10 +75,7 @@ async function waitForRedisReady(
|
|
|
80
75
|
const onReady = () => finish(true);
|
|
81
76
|
const onUnavailable = () => finish(false);
|
|
82
77
|
|
|
83
|
-
timeoutId = setTimeout(
|
|
84
|
-
() => finish(redisStatus(redis) === "ready"),
|
|
85
|
-
timeoutMs,
|
|
86
|
-
);
|
|
78
|
+
timeoutId = setTimeout(() => finish(redisStatus(redis) === "ready"), timeoutMs);
|
|
87
79
|
redis.once("ready", onReady);
|
|
88
80
|
redis.once("close", onUnavailable);
|
|
89
81
|
redis.once("end", onUnavailable);
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
RequestParamPrimitive,
|
|
3
|
-
RequestParams,
|
|
4
|
-
RequestParamValue,
|
|
5
|
-
} from "../types";
|
|
1
|
+
import type { RequestParamPrimitive, RequestParams, RequestParamValue } from "../types.js";
|
|
6
2
|
|
|
7
|
-
function isParamArray(
|
|
8
|
-
value: RequestParamValue,
|
|
9
|
-
): value is readonly RequestParamPrimitive[] {
|
|
3
|
+
function isParamArray(value: RequestParamValue): value is readonly RequestParamPrimitive[] {
|
|
10
4
|
return Array.isArray(value);
|
|
11
5
|
}
|
|
12
6
|
|
|
@@ -29,8 +23,7 @@ export function appendQueryParams(url: string, params?: RequestParams): string {
|
|
|
29
23
|
const parsed = new URL(url);
|
|
30
24
|
for (const [key, value] of Object.entries(params)) {
|
|
31
25
|
if (isParamArray(value)) {
|
|
32
|
-
for (const item of value)
|
|
33
|
-
appendQueryValue(parsed.searchParams, key, item);
|
|
26
|
+
for (const item of value) appendQueryValue(parsed.searchParams, key, item);
|
|
34
27
|
continue;
|
|
35
28
|
}
|
|
36
29
|
appendQueryValue(parsed.searchParams, key, value);
|
|
@@ -39,9 +32,7 @@ export function appendQueryParams(url: string, params?: RequestParams): string {
|
|
|
39
32
|
return parsed.toString();
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
export function normalizeHttpRequestBody(
|
|
43
|
-
body: unknown,
|
|
44
|
-
): string | Buffer | undefined {
|
|
35
|
+
export function normalizeHttpRequestBody(body: unknown): string | Buffer | undefined {
|
|
45
36
|
if (body === undefined) {
|
|
46
37
|
return undefined;
|
|
47
38
|
}
|
package/src/runtime/state.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { providerStateRedisUrlFromEnv } from "../config/loader";
|
|
2
|
-
import { ProviderError } from "../errors";
|
|
1
|
+
import { providerStateRedisUrlFromEnv } from "../config/loader.js";
|
|
2
|
+
import { ProviderError } from "../errors.js";
|
|
3
3
|
import type {
|
|
4
4
|
ProviderRuntimeState,
|
|
5
5
|
ProviderStateNamespace,
|
|
@@ -7,13 +7,13 @@ import type {
|
|
|
7
7
|
StateNamespaceOptions,
|
|
8
8
|
StateValue,
|
|
9
9
|
StateWriteOptions,
|
|
10
|
-
} from "../types";
|
|
10
|
+
} from "../types.js";
|
|
11
11
|
import {
|
|
12
12
|
createProviderRedisClient,
|
|
13
13
|
ensureRedisReady,
|
|
14
14
|
type ProviderRedisClient,
|
|
15
15
|
withRedisTimeout,
|
|
16
|
-
} from "./redis";
|
|
16
|
+
} from "./redis.js";
|
|
17
17
|
|
|
18
18
|
const DEFAULT_REDIS_TIMEOUT_MS = 250;
|
|
19
19
|
const REDIS_STATE_PREFIX = "apifuse:provider-state:v1";
|
|
@@ -57,37 +57,24 @@ async function withRequiredRedis<T>(operation: () => Promise<T>): Promise<T> {
|
|
|
57
57
|
return await withRedisTimeout(operation, {
|
|
58
58
|
timeoutMs: DEFAULT_REDIS_TIMEOUT_MS,
|
|
59
59
|
onTimeout: () => {
|
|
60
|
-
throw new UnsupportedProviderStateError(
|
|
61
|
-
"Provider runtime state Redis timed out",
|
|
62
|
-
);
|
|
60
|
+
throw new UnsupportedProviderStateError("Provider runtime state Redis timed out");
|
|
63
61
|
},
|
|
64
62
|
onError: () => {
|
|
65
|
-
throw new UnsupportedProviderStateError(
|
|
66
|
-
"Provider runtime state Redis is unavailable",
|
|
67
|
-
);
|
|
63
|
+
throw new UnsupportedProviderStateError("Provider runtime state Redis is unavailable");
|
|
68
64
|
},
|
|
69
65
|
});
|
|
70
66
|
}
|
|
71
67
|
|
|
72
68
|
async function requireRedisReady(redis: ProviderRedisClient): Promise<void> {
|
|
73
69
|
if (await ensureRedisReady(redis, DEFAULT_REDIS_TIMEOUT_MS)) return;
|
|
74
|
-
throw new UnsupportedProviderStateError(
|
|
75
|
-
"Provider runtime state Redis is unavailable",
|
|
76
|
-
);
|
|
70
|
+
throw new UnsupportedProviderStateError("Provider runtime state Redis is unavailable");
|
|
77
71
|
}
|
|
78
72
|
|
|
79
|
-
function providerStatePrefix(
|
|
80
|
-
providerId: string | undefined,
|
|
81
|
-
namespace: string,
|
|
82
|
-
): string {
|
|
73
|
+
function providerStatePrefix(providerId: string | undefined, namespace: string): string {
|
|
83
74
|
return `${REDIS_STATE_PREFIX}:${providerId ?? "default"}:${namespace}`;
|
|
84
75
|
}
|
|
85
76
|
|
|
86
|
-
function providerStateKey(
|
|
87
|
-
providerId: string | undefined,
|
|
88
|
-
namespace: string,
|
|
89
|
-
key: string,
|
|
90
|
-
): string {
|
|
77
|
+
function providerStateKey(providerId: string | undefined, namespace: string, key: string): string {
|
|
91
78
|
return `${providerStatePrefix(providerId, namespace)}:${key}`;
|
|
92
79
|
}
|
|
93
80
|
|
|
@@ -132,9 +119,7 @@ function envelopeFromJson(
|
|
|
132
119
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
133
120
|
return null;
|
|
134
121
|
}
|
|
135
|
-
const record: Record<string, unknown> = Object.fromEntries(
|
|
136
|
-
Object.entries(parsed),
|
|
137
|
-
);
|
|
122
|
+
const record: Record<string, unknown> = Object.fromEntries(Object.entries(parsed));
|
|
138
123
|
if (
|
|
139
124
|
typeof record.version !== "number" ||
|
|
140
125
|
typeof record.expiresAt !== "string" ||
|
|
@@ -182,9 +167,7 @@ class RedisProviderStateNamespace implements ProviderStateNamespace {
|
|
|
182
167
|
|
|
183
168
|
private async activeKeys(): Promise<string[]> {
|
|
184
169
|
await requireRedisReady(this.backend.redis);
|
|
185
|
-
return await withRequiredRedis(() =>
|
|
186
|
-
this.backend.redis.keys(`${this.prefix()}*`),
|
|
187
|
-
);
|
|
170
|
+
return await withRequiredRedis(() => this.backend.redis.keys(`${this.prefix()}*`));
|
|
188
171
|
}
|
|
189
172
|
|
|
190
173
|
private enforceValueSize(value: unknown): void {
|
|
@@ -207,47 +190,29 @@ class RedisProviderStateNamespace implements ProviderStateNamespace {
|
|
|
207
190
|
}
|
|
208
191
|
}
|
|
209
192
|
|
|
210
|
-
async list<T>(options?: {
|
|
211
|
-
limit?: number;
|
|
212
|
-
prefix?: string;
|
|
213
|
-
}): Promise<StateValue<T>[]> {
|
|
193
|
+
async list<T>(options?: { limit?: number; prefix?: string }): Promise<StateValue<T>[]> {
|
|
214
194
|
const keys = (await this.activeKeys()).filter((key) => {
|
|
215
|
-
const publicKey = publicStateKey(
|
|
216
|
-
this.providerId,
|
|
217
|
-
this.namespaceName,
|
|
218
|
-
key,
|
|
219
|
-
);
|
|
195
|
+
const publicKey = publicStateKey(this.providerId, this.namespaceName, key);
|
|
220
196
|
return options?.prefix ? publicKey.startsWith(options.prefix) : true;
|
|
221
197
|
});
|
|
222
198
|
const limited = keys.slice(0, Math.max(0, options?.limit ?? keys.length));
|
|
223
199
|
if (limited.length === 0) return [];
|
|
224
|
-
const values = await withRequiredRedis(() =>
|
|
225
|
-
this.backend.redis.mget(limited),
|
|
226
|
-
);
|
|
200
|
+
const values = await withRequiredRedis(() => this.backend.redis.mget(limited));
|
|
227
201
|
return values.flatMap((raw, index) => {
|
|
228
202
|
const key = limited[index];
|
|
229
203
|
if (!key) return [];
|
|
230
|
-
const value = envelopeFromJson(
|
|
231
|
-
publicStateKey(this.providerId, this.namespaceName, key),
|
|
232
|
-
raw,
|
|
233
|
-
);
|
|
204
|
+
const value = envelopeFromJson(publicStateKey(this.providerId, this.namespaceName, key), raw);
|
|
234
205
|
return value ? [value] : [];
|
|
235
206
|
});
|
|
236
207
|
}
|
|
237
208
|
|
|
238
209
|
async get<T>(key: string): Promise<StateValue<T> | null> {
|
|
239
210
|
await requireRedisReady(this.backend.redis);
|
|
240
|
-
const raw = await withRequiredRedis(() =>
|
|
241
|
-
this.backend.redis.get(this.redisKey(key)),
|
|
242
|
-
);
|
|
211
|
+
const raw = await withRequiredRedis(() => this.backend.redis.get(this.redisKey(key)));
|
|
243
212
|
return envelopeFromJson(key, raw);
|
|
244
213
|
}
|
|
245
214
|
|
|
246
|
-
async set<T>(
|
|
247
|
-
key: string,
|
|
248
|
-
value: T,
|
|
249
|
-
options?: StateWriteOptions,
|
|
250
|
-
): Promise<StateValue<T>> {
|
|
215
|
+
async set<T>(key: string, value: T, options?: StateWriteOptions): Promise<StateValue<T>> {
|
|
251
216
|
this.enforceValueSize(value);
|
|
252
217
|
await this.enforceMaxEntries(key);
|
|
253
218
|
const current = await this.get<T>(key);
|
|
@@ -258,12 +223,7 @@ class RedisProviderStateNamespace implements ProviderStateNamespace {
|
|
|
258
223
|
const expiresAt = resolveExpiresAt(ttl);
|
|
259
224
|
const envelope = redisEnvelope(value, version, createdAt, expiresAt);
|
|
260
225
|
await withRequiredRedis(() =>
|
|
261
|
-
this.backend.redis.set(
|
|
262
|
-
this.redisKey(key),
|
|
263
|
-
JSON.stringify(envelope),
|
|
264
|
-
"PX",
|
|
265
|
-
ttlMs,
|
|
266
|
-
),
|
|
226
|
+
this.backend.redis.set(this.redisKey(key), JSON.stringify(envelope), "PX", ttlMs),
|
|
267
227
|
);
|
|
268
228
|
return {
|
|
269
229
|
key,
|
|
@@ -313,11 +273,7 @@ class RedisProviderStateNamespace implements ProviderStateNamespace {
|
|
|
313
273
|
): Promise<StateValue<Record<string, unknown>>> {
|
|
314
274
|
const current = (await this.get<Record<string, unknown>>(key))?.value ?? {};
|
|
315
275
|
const previous = typeof current[field] === "number" ? current[field] : 0;
|
|
316
|
-
return await this.set(
|
|
317
|
-
key,
|
|
318
|
-
{ ...current, [field]: previous + delta },
|
|
319
|
-
options,
|
|
320
|
-
);
|
|
276
|
+
return await this.set(key, { ...current, [field]: previous + delta }, options);
|
|
321
277
|
}
|
|
322
278
|
}
|
|
323
279
|
|
|
@@ -330,43 +286,26 @@ class RedisProviderRuntimeState implements ProviderRuntimeState {
|
|
|
330
286
|
this.providerId = options.providerId;
|
|
331
287
|
}
|
|
332
288
|
|
|
333
|
-
namespace(
|
|
334
|
-
name
|
|
335
|
-
options: StateNamespaceOptions,
|
|
336
|
-
): ProviderStateNamespace {
|
|
337
|
-
return new RedisProviderStateNamespace(
|
|
338
|
-
this.backend,
|
|
339
|
-
this.providerId,
|
|
340
|
-
name,
|
|
341
|
-
options,
|
|
342
|
-
);
|
|
289
|
+
namespace(name: string, options: StateNamespaceOptions): ProviderStateNamespace {
|
|
290
|
+
return new RedisProviderStateNamespace(this.backend, this.providerId, name, options);
|
|
343
291
|
}
|
|
344
292
|
}
|
|
345
293
|
|
|
346
294
|
export class UnsupportedProviderStateError extends ProviderError {
|
|
347
|
-
constructor(
|
|
348
|
-
message = "Provider runtime state is not available in this runtime",
|
|
349
|
-
) {
|
|
295
|
+
constructor(message = "Provider runtime state is not available in this runtime") {
|
|
350
296
|
super(message, { code: "PROVIDER_STATE_UNSUPPORTED" });
|
|
351
297
|
this.name = "UnsupportedProviderStateError";
|
|
352
298
|
}
|
|
353
299
|
}
|
|
354
300
|
|
|
355
301
|
class UnsupportedProviderStateNamespace implements ProviderStateNamespace {
|
|
356
|
-
async list<T>(_options?: {
|
|
357
|
-
limit?: number;
|
|
358
|
-
prefix?: string;
|
|
359
|
-
}): Promise<StateValue<T>[]> {
|
|
302
|
+
async list<T>(_options?: { limit?: number; prefix?: string }): Promise<StateValue<T>[]> {
|
|
360
303
|
throw new UnsupportedProviderStateError();
|
|
361
304
|
}
|
|
362
305
|
async get<T>(_key: string): Promise<StateValue<T> | null> {
|
|
363
306
|
throw new UnsupportedProviderStateError();
|
|
364
307
|
}
|
|
365
|
-
async set<T>(
|
|
366
|
-
_key: string,
|
|
367
|
-
_value: T,
|
|
368
|
-
_options?: StateWriteOptions,
|
|
369
|
-
): Promise<StateValue<T>> {
|
|
308
|
+
async set<T>(_key: string, _value: T, _options?: StateWriteOptions): Promise<StateValue<T>> {
|
|
370
309
|
throw new UnsupportedProviderStateError();
|
|
371
310
|
}
|
|
372
311
|
async patch<T extends Record<string, unknown>>(
|
|
@@ -398,10 +337,7 @@ class UnsupportedProviderStateNamespace implements ProviderStateNamespace {
|
|
|
398
337
|
}
|
|
399
338
|
|
|
400
339
|
class UnsupportedProviderRuntimeState implements ProviderRuntimeState {
|
|
401
|
-
namespace(
|
|
402
|
-
_name: string,
|
|
403
|
-
_options: StateNamespaceOptions,
|
|
404
|
-
): ProviderStateNamespace {
|
|
340
|
+
namespace(_name: string, _options: StateNamespaceOptions): ProviderStateNamespace {
|
|
405
341
|
return new UnsupportedProviderStateNamespace();
|
|
406
342
|
}
|
|
407
343
|
}
|
|
@@ -420,10 +356,7 @@ class MemoryProviderStateNamespace implements ProviderStateNamespace {
|
|
|
420
356
|
}
|
|
421
357
|
}
|
|
422
358
|
|
|
423
|
-
async list<T>(_options?: {
|
|
424
|
-
limit?: number;
|
|
425
|
-
prefix?: string;
|
|
426
|
-
}): Promise<StateValue<T>[]> {
|
|
359
|
+
async list<T>(_options?: { limit?: number; prefix?: string }): Promise<StateValue<T>[]> {
|
|
427
360
|
this.pruneExpired();
|
|
428
361
|
const rows = Array.from(this.values.values()).filter((value) =>
|
|
429
362
|
_options?.prefix ? value.key.startsWith(_options.prefix) : true,
|
|
@@ -436,17 +369,11 @@ class MemoryProviderStateNamespace implements ProviderStateNamespace {
|
|
|
436
369
|
return this.values.get(key) ?? null;
|
|
437
370
|
}
|
|
438
371
|
|
|
439
|
-
async set<T>(
|
|
440
|
-
key: string,
|
|
441
|
-
value: T,
|
|
442
|
-
options?: StateWriteOptions,
|
|
443
|
-
): Promise<StateValue<T>> {
|
|
372
|
+
async set<T>(key: string, value: T, options?: StateWriteOptions): Promise<StateValue<T>> {
|
|
444
373
|
this.pruneExpired();
|
|
445
374
|
const now = new Date().toISOString();
|
|
446
375
|
const current = this.values.get(key);
|
|
447
|
-
const expiresAt = resolveMemoryStateExpiresAt(
|
|
448
|
-
options?.ttl ?? this.options.defaultTtl,
|
|
449
|
-
);
|
|
376
|
+
const expiresAt = resolveMemoryStateExpiresAt(options?.ttl ?? this.options.defaultTtl);
|
|
450
377
|
const row = {
|
|
451
378
|
key,
|
|
452
379
|
value,
|
|
@@ -499,10 +426,7 @@ class MemoryProviderStateNamespace implements ProviderStateNamespace {
|
|
|
499
426
|
class MemoryProviderRuntimeState implements ProviderRuntimeState {
|
|
500
427
|
readonly namespaces = new Map<string, MemoryProviderStateNamespace>();
|
|
501
428
|
|
|
502
|
-
namespace(
|
|
503
|
-
name: string,
|
|
504
|
-
_options: StateNamespaceOptions,
|
|
505
|
-
): ProviderStateNamespace {
|
|
429
|
+
namespace(name: string, _options: StateNamespaceOptions): ProviderStateNamespace {
|
|
506
430
|
const existing = this.namespaces.get(name);
|
|
507
431
|
if (existing) return existing;
|
|
508
432
|
const created = new MemoryProviderStateNamespace(_options);
|
|
@@ -536,10 +460,7 @@ export function createRedisProviderRuntimeState(
|
|
|
536
460
|
}
|
|
537
461
|
|
|
538
462
|
export function createProviderRuntimeStateFromEnv(
|
|
539
|
-
options: {
|
|
540
|
-
readonly providerId?: string;
|
|
541
|
-
readonly allowMemoryFallback?: boolean;
|
|
542
|
-
} = {},
|
|
463
|
+
options: { readonly providerId?: string; readonly allowMemoryFallback?: boolean } = {},
|
|
543
464
|
): ProviderRuntimeState {
|
|
544
465
|
const redisUrl = providerStateRedisUrlFromEnv();
|
|
545
466
|
if (redisUrl) {
|
package/src/runtime/stealth.ts
CHANGED
|
@@ -2,16 +2,16 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import type { Browser, ImpitOptions, ImpitResponse, RequestInit } from "impit";
|
|
3
3
|
import { Impit } from "impit";
|
|
4
4
|
|
|
5
|
-
import type { ProxyResolutionOptions } from "../config/loader";
|
|
5
|
+
import type { ProxyResolutionOptions } from "../config/loader.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_SMARTPROXY_POOL_SIZE,
|
|
8
8
|
invalidateProxyResolutionCacheAsync,
|
|
9
9
|
ProxyResolutionError,
|
|
10
10
|
resolveProxyConfigAsync,
|
|
11
11
|
SMARTPROXY_MAX_POOL_SIZE,
|
|
12
|
-
} from "../config/loader";
|
|
13
|
-
import { SDKError, TransportError } from "../errors";
|
|
14
|
-
import { getStealthProfile } from "../stealth/profiles";
|
|
12
|
+
} from "../config/loader.js";
|
|
13
|
+
import { SDKError, TransportError } from "../errors.js";
|
|
14
|
+
import { getStealthProfile } from "../stealth/profiles.js";
|
|
15
15
|
import type {
|
|
16
16
|
CookieJar,
|
|
17
17
|
HttpMethod,
|
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
StealthRedirectHop,
|
|
21
21
|
StealthResponse,
|
|
22
22
|
StealthSession,
|
|
23
|
-
} from "../types";
|
|
23
|
+
} from "../types.js";
|
|
24
24
|
import {
|
|
25
25
|
createProxyAuthIpDeniedError,
|
|
26
26
|
createProxyEdgeAuthRejectedError,
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
isProxyPoolStaleStatus,
|
|
36
36
|
PROXY_EDGE_AUTH_REJECTED_CODE,
|
|
37
37
|
PROXY_POOL_STALE_CODE,
|
|
38
|
-
} from "./proxy-errors";
|
|
38
|
+
} from "./proxy-errors.js";
|
|
39
39
|
import {
|
|
40
40
|
computeProxyAttemptIndex,
|
|
41
41
|
computeProxyTransportRetryDelayMs,
|
|
@@ -43,8 +43,8 @@ import {
|
|
|
43
43
|
normalizeProxyTransportRetryOptions,
|
|
44
44
|
shouldRetryProxyTransportAttempt,
|
|
45
45
|
validateUnsafeProxyTransportRetryMethods,
|
|
46
|
-
} from "./proxy-retry-policy";
|
|
47
|
-
import { appendQueryParams } from "./request-options";
|
|
46
|
+
} from "./proxy-retry-policy.js";
|
|
47
|
+
import { appendQueryParams } from "./request-options.js";
|
|
48
48
|
|
|
49
49
|
const DEFAULT_PROFILE = "chrome-146";
|
|
50
50
|
|