@apifuse/provider-sdk 2.2.0-beta.57 → 2.2.0-beta.59
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 +9 -0
- package/CHANGELOG.md +8 -0
- package/README.md +22 -5
- package/SUBMISSION.md +2 -1
- package/bin/apifuse-pack-types.ts +49 -0
- package/bin/apifuse-record.ts +6 -0
- package/dist/cli/templates/provider/README.md.tpl +19 -5
- package/dist/config/loader.d.ts +7 -0
- package/dist/config/loader.js +30 -6
- package/dist/declaration-validation.d.ts +2 -1
- package/dist/declaration-validation.js +39 -0
- package/dist/define.d.ts +5 -4
- package/dist/define.js +25 -1
- package/dist/engine.d.ts +16 -0
- package/dist/engine.js +58 -1
- package/dist/error-resolution.js +13 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -2
- package/dist/lint.js +3 -3
- package/dist/provider.d.ts +3 -3
- package/dist/provider.js +2 -2
- package/dist/runtime/bounded-expiring-map.d.ts +21 -0
- package/dist/runtime/bounded-expiring-map.js +64 -0
- package/dist/runtime/cache.d.ts +2 -0
- package/dist/runtime/cache.js +8 -1
- package/dist/runtime/egress-lease.d.ts +63 -0
- package/dist/runtime/egress-lease.js +233 -0
- package/dist/runtime/http.js +1 -0
- package/dist/runtime/proxy-retry-policy.d.ts +4 -1
- package/dist/runtime/proxy-retry-policy.js +11 -2
- package/dist/runtime/request-telemetry.d.ts +7 -9
- package/dist/runtime/resolver-config.d.ts +7 -0
- package/dist/runtime/resolver-config.js +8 -0
- package/dist/runtime/resolver-public.d.ts +3 -1
- package/dist/runtime/resolver-public.js +1 -1
- package/dist/runtime/resolver-shared.d.ts +9 -0
- package/dist/runtime/resolver-shared.js +57 -0
- package/dist/runtime/resolver-telemetry.d.ts +134 -0
- package/dist/runtime/resolver-telemetry.js +204 -0
- package/dist/runtime/resolver-usage.d.ts +24 -0
- package/dist/runtime/resolver-usage.js +60 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +5 -0
- package/dist/runtime/resolver-vendors/bindings.js +5 -0
- package/dist/runtime/resolver-vendors/capsolver.d.ts +2 -2
- package/dist/runtime/resolver-vendors/capsolver.js +21 -9
- package/dist/runtime/resolver-vendors/hypersolutions.d.ts +27 -0
- package/dist/runtime/resolver-vendors/hypersolutions.js +369 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +2 -2
- package/dist/runtime/resolver-vendors/twocaptcha.js +26 -10
- package/dist/runtime/resolver-vendors/types.d.ts +35 -5
- package/dist/runtime/resolver-vendors/types.js +20 -10
- package/dist/runtime/resolver.d.ts +5 -1
- package/dist/runtime/resolver.js +397 -109
- package/dist/runtime/stealth-akamai-sbsd.d.ts +54 -0
- package/dist/runtime/stealth-akamai-sbsd.js +142 -0
- package/dist/runtime/stealth.js +547 -53
- package/dist/schema.d.ts +9 -0
- package/dist/schema.js +16 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +1 -0
- package/dist/server/self-test.d.ts +4 -0
- package/dist/server/self-test.js +10 -1
- package/dist/server/serve-implementation.d.ts +7 -1
- package/dist/server/serve-implementation.js +181 -53
- package/dist/server/types.d.ts +6 -0
- package/dist/server/types.js +14 -0
- package/dist/stealth/profiles.d.ts +7 -1
- package/dist/stealth/profiles.js +9 -0
- package/dist/testing/run.js +6 -0
- package/dist/types.d.ts +115 -12
- package/package.json +1 -1
- package/src/cli/templates/provider/README.md.tpl +19 -5
- package/src/config/loader.ts +34 -6
- package/src/declaration-validation.ts +47 -1
- package/src/define.ts +46 -3
- package/src/engine.ts +76 -1
- package/src/error-resolution.ts +13 -0
- package/src/index.ts +32 -1
- package/src/lint.ts +3 -3
- package/src/provider.ts +9 -0
- package/src/runtime/bounded-expiring-map.ts +67 -0
- package/src/runtime/cache.ts +10 -1
- package/src/runtime/egress-lease.ts +336 -0
- package/src/runtime/http.ts +1 -0
- package/src/runtime/proxy-retry-policy.ts +12 -1
- package/src/runtime/request-telemetry.ts +5 -7
- package/src/runtime/resolver-config.ts +12 -0
- package/src/runtime/resolver-public.ts +21 -0
- package/src/runtime/resolver-shared.ts +75 -0
- package/src/runtime/resolver-telemetry.ts +362 -0
- package/src/runtime/resolver-usage.ts +96 -0
- package/src/runtime/resolver-vendors/bindings.ts +5 -0
- package/src/runtime/resolver-vendors/capsolver.ts +22 -3
- package/src/runtime/resolver-vendors/hypersolutions.ts +480 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +26 -12
- package/src/runtime/resolver-vendors/types.ts +60 -12
- package/src/runtime/resolver.ts +465 -124
- package/src/runtime/stealth-akamai-sbsd.ts +207 -0
- package/src/runtime/stealth.ts +727 -95
- package/src/schema.ts +17 -0
- package/src/server/index.ts +21 -0
- package/src/server/self-test.ts +13 -0
- package/src/server/serve-implementation.ts +268 -48
- package/src/server/types.ts +14 -0
- package/src/stealth/profiles.ts +10 -0
- package/src/testing/run.ts +6 -0
- package/src/types.ts +130 -22
package/src/engine.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { ProviderError } from "./errors.js";
|
|
2
|
+
import {
|
|
3
|
+
APIFUSE__RESOLVER__2CAPTCHA__API_KEY,
|
|
4
|
+
APIFUSE__RESOLVER__CAPMONSTER__API_KEY,
|
|
5
|
+
APIFUSE__RESOLVER__CAPSOLVER__API_KEY,
|
|
6
|
+
APIFUSE__RESOLVER__HYPERSOLUTIONS__API_KEY,
|
|
7
|
+
} from "./runtime/resolver-config.js";
|
|
2
8
|
import {
|
|
3
9
|
OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
4
10
|
OTEL_EXPORTER_OTLP_HEADERS,
|
|
@@ -55,6 +61,36 @@ export function isEngineOwnedProxyCredentialName(name: string): boolean {
|
|
|
55
61
|
return ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAME_SET.has(canonicalEnvName(name));
|
|
56
62
|
}
|
|
57
63
|
|
|
64
|
+
/** Hosted resolver credentials owned by the engine and never projected to providers. */
|
|
65
|
+
export const ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES = [
|
|
66
|
+
APIFUSE__RESOLVER__2CAPTCHA__API_KEY,
|
|
67
|
+
APIFUSE__RESOLVER__CAPSOLVER__API_KEY,
|
|
68
|
+
APIFUSE__RESOLVER__CAPMONSTER__API_KEY,
|
|
69
|
+
APIFUSE__RESOLVER__HYPERSOLUTIONS__API_KEY,
|
|
70
|
+
] as const;
|
|
71
|
+
|
|
72
|
+
const ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAME_SET = new Set<string>(
|
|
73
|
+
ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Engine variable a provider-declared secret name resolves to, or `undefined` when the
|
|
78
|
+
* name is not an engine-owned resolver credential. Provider-scoped Hyper aliases
|
|
79
|
+
* (`APIFUSE__PROVIDER__<ID>__HYPER_API_KEY`, measured on zozotown) map to the shared key.
|
|
80
|
+
*/
|
|
81
|
+
export function engineOwnedResolverCredentialTarget(name: string): string | undefined {
|
|
82
|
+
const canonical = canonicalEnvName(name);
|
|
83
|
+
if (ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAME_SET.has(canonical)) return canonical;
|
|
84
|
+
if (/^APIFUSE__PROVIDER__.+__HYPER_API_KEY$/u.test(canonical)) {
|
|
85
|
+
return APIFUSE__RESOLVER__HYPERSOLUTIONS__API_KEY;
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function isEngineOwnedResolverCredentialName(name: string): boolean {
|
|
91
|
+
return engineOwnedResolverCredentialTarget(name) !== undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
58
94
|
/**
|
|
59
95
|
* Trace-export configuration owned by the engine and forbidden in provider
|
|
60
96
|
* declarations. The header variables carry collector credentials; the rest are
|
|
@@ -75,9 +111,47 @@ export function isEngineOwnedTelemetryEnvName(name: string): boolean {
|
|
|
75
111
|
return ENGINE_OWNED_TELEMETRY_ENV_NAME_SET.has(canonicalEnvName(name));
|
|
76
112
|
}
|
|
77
113
|
|
|
114
|
+
/** Engine control-plane configuration is never declarable or visible to provider code. */
|
|
115
|
+
function isEngineOwnedEngineEnvName(name: string): boolean {
|
|
116
|
+
return canonicalEnvName(name).startsWith("APIFUSE__ENGINE__");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Hosted runtime settings the engine reads for OCR, STT, cache keying, choice
|
|
121
|
+
* tokens, and the CDP pool. Providers never own them: declarations are rejected
|
|
122
|
+
* and projections drop them, like the vendor credentials above.
|
|
123
|
+
*/
|
|
124
|
+
export const ENGINE_OWNED_RUNTIME_ENV_NAMES = [
|
|
125
|
+
"APIFUSE__STT__CLOUDFLARE_API_TOKEN",
|
|
126
|
+
"APIFUSE__OCR__CLOUDFLARE_API_TOKEN",
|
|
127
|
+
"APIFUSE__OCR__API_KEY",
|
|
128
|
+
"APIFUSE__CLOUDFLARE__ACCOUNT_ID",
|
|
129
|
+
"APIFUSE__CACHE__KEY_PEPPER",
|
|
130
|
+
"APIFUSE__PROVIDER_RUNTIME__CHOICE_TOKEN_MASTER_SECRET",
|
|
131
|
+
] as const;
|
|
132
|
+
|
|
133
|
+
const ENGINE_OWNED_RUNTIME_ENV_NAME_SET = new Set<string>(ENGINE_OWNED_RUNTIME_ENV_NAMES);
|
|
134
|
+
|
|
135
|
+
/** CDP pool settings form a prefix family (`APIFUSE__CDP_POOL__URL` today); the whole prefix is engine-owned. */
|
|
136
|
+
const ENGINE_OWNED_CDP_POOL_ENV_PREFIX = "APIFUSE__CDP_POOL__";
|
|
137
|
+
|
|
138
|
+
export function isEngineOwnedRuntimeEnvName(name: string): boolean {
|
|
139
|
+
const canonical = canonicalEnvName(name);
|
|
140
|
+
return (
|
|
141
|
+
ENGINE_OWNED_RUNTIME_ENV_NAME_SET.has(canonical) ||
|
|
142
|
+
canonical.startsWith(ENGINE_OWNED_CDP_POOL_ENV_PREFIX)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
78
146
|
/** Every environment name the engine owns: rejected in declarations and filtered from provider projections. */
|
|
79
147
|
export function isEngineOwnedEnvName(name: string): boolean {
|
|
80
|
-
return
|
|
148
|
+
return (
|
|
149
|
+
isEngineOwnedEngineEnvName(name) ||
|
|
150
|
+
isEngineOwnedProxyCredentialName(name) ||
|
|
151
|
+
isEngineOwnedResolverCredentialName(name) ||
|
|
152
|
+
isEngineOwnedRuntimeEnvName(name) ||
|
|
153
|
+
isEngineOwnedTelemetryEnvName(name)
|
|
154
|
+
);
|
|
81
155
|
}
|
|
82
156
|
|
|
83
157
|
/** Capture credentials in the engine host before constructing provider bindings. */
|
|
@@ -199,6 +273,7 @@ function declaresCapability(
|
|
|
199
273
|
provider: ProviderDefinition,
|
|
200
274
|
capability: ProviderCapabilityKey,
|
|
201
275
|
): boolean {
|
|
276
|
+
if (capability === "credential" && provider.auth?.mode === "platform-managed") return true;
|
|
202
277
|
return Object.hasOwn(provider, capability) && provider[capability] !== undefined;
|
|
203
278
|
}
|
|
204
279
|
|
package/src/error-resolution.ts
CHANGED
|
@@ -10,6 +10,7 @@ export const SDK_OWNED_PROVIDER_ERROR_CODES = new Set([
|
|
|
10
10
|
"BROWSER_CDP_POOL_REQUIRED",
|
|
11
11
|
"BROWSER_RUNTIME_UNSUPPORTED",
|
|
12
12
|
"STEALTH_RUNTIME_UNSUPPORTED",
|
|
13
|
+
"STEALTH_HEADER_OVERRIDE_UNSUPPORTED",
|
|
13
14
|
"SSE_EVENT_UNDECLARED",
|
|
14
15
|
"STREAM_EVENT_TOO_LARGE",
|
|
15
16
|
"STREAM_CHUNK_TOO_LARGE",
|
|
@@ -51,6 +52,13 @@ export const SDK_OWNED_PROVIDER_ERROR_CODES = new Set([
|
|
|
51
52
|
"http_redirect_missing_location",
|
|
52
53
|
"http_redirect_loop",
|
|
53
54
|
"transport_invalid_url",
|
|
55
|
+
"EGRESS_LEASE_INVALID",
|
|
56
|
+
"EGRESS_LEASE_BINDING_INVALID",
|
|
57
|
+
"EGRESS_LEASE_KEY_MISSING",
|
|
58
|
+
"EGRESS_LEASE_KEY_WEAK",
|
|
59
|
+
"STEALTH_BODY_UNSUPPORTED",
|
|
60
|
+
"REPLAY_SESSION_MISMATCH",
|
|
61
|
+
"REPLAY_ALREADY_ATTEMPTED",
|
|
54
62
|
"retry_exhausted",
|
|
55
63
|
"auth_abort_unsafe_data",
|
|
56
64
|
"credentials_auth_missing_credential_keys",
|
|
@@ -117,6 +125,11 @@ export const SDK_STATUS_MAPPED_PROVIDER_ERROR_CODES: ReadonlyMap<string, Provide
|
|
|
117
125
|
// contract): the upstream evaluated the request and said no under its
|
|
118
126
|
// own rules — a conflict with upstream state, never a 5xx.
|
|
119
127
|
["UPSTREAM_REJECTED", 409],
|
|
128
|
+
// Only an unverifiable or foreign handle is the caller's: key and binding
|
|
129
|
+
// faults stay unmapped (500) because the engine host, not the caller, owns them.
|
|
130
|
+
["EGRESS_LEASE_INVALID", 409],
|
|
131
|
+
["REPLAY_SESSION_MISMATCH", 409],
|
|
132
|
+
["REPLAY_ALREADY_ATTEMPTED", 409],
|
|
120
133
|
["UPSTREAM_ERROR", 502],
|
|
121
134
|
["BLOCKED", 502],
|
|
122
135
|
["OCR_UNAVAILABLE", 503],
|
package/src/index.ts
CHANGED
|
@@ -198,17 +198,43 @@ export {
|
|
|
198
198
|
type TelemetryKey,
|
|
199
199
|
type TenantNeutral,
|
|
200
200
|
} from "./runtime/request-telemetry.js";
|
|
201
|
+
export { APIFUSE__ENGINE__CEREMONY_LEASE_KEY } from "./runtime/egress-lease.js";
|
|
202
|
+
export {
|
|
203
|
+
ResolverTelemetryCollector,
|
|
204
|
+
type ResolverCacheReadTelemetryEvent,
|
|
205
|
+
type ResolverCacheWriteTelemetryEvent,
|
|
206
|
+
type ResolverFailoverTelemetryEvent,
|
|
207
|
+
type ResolverIdentityTelemetryEvent,
|
|
208
|
+
type ResolverOutcomeTelemetryEvent,
|
|
209
|
+
type ResolverTelemetryAttemptOutcome,
|
|
210
|
+
type ResolverAttemptSample,
|
|
211
|
+
type ResolverTelemetryCacheStatus,
|
|
212
|
+
type ResolverTelemetryCacheWriteReason,
|
|
213
|
+
type ResolverTelemetryErrorClass,
|
|
214
|
+
type ResolverTelemetryHeaderPayload,
|
|
215
|
+
type ResolverTelemetryIdentitySource,
|
|
216
|
+
type ResolverTelemetryLogPayload,
|
|
217
|
+
type ResolverTelemetryOutcome,
|
|
218
|
+
type ResolverTelemetryPhase,
|
|
219
|
+
type ResolverTelemetrySink,
|
|
220
|
+
type ResolverVendorAttemptTelemetryEvent,
|
|
221
|
+
} from "./runtime/resolver-telemetry.js";
|
|
201
222
|
export {
|
|
202
223
|
APIFUSE__CDP_POOL__URL,
|
|
203
224
|
APIFUSE__RESOLVER__2CAPTCHA__API_KEY,
|
|
204
225
|
APIFUSE__RESOLVER__CAPMONSTER__API_KEY,
|
|
205
226
|
APIFUSE__RESOLVER__CAPSOLVER__API_KEY,
|
|
227
|
+
APIFUSE__RESOLVER__HYPERSOLUTIONS__API_KEY,
|
|
206
228
|
APIFUSE__RESOLVER__TIMEOUT_MS,
|
|
207
229
|
DEFAULT_RESOLVER_TIMEOUT_MS,
|
|
208
230
|
} from "./runtime/resolver-config.js";
|
|
209
231
|
export { createUnsupportedResolverClient } from "./runtime/resolver-shared.js";
|
|
210
232
|
export type { ResolverRuntimeOptions } from "./runtime/resolver.js";
|
|
211
|
-
export type {
|
|
233
|
+
export type {
|
|
234
|
+
ResolverPaidUsageContext,
|
|
235
|
+
ResolverVendorTransport,
|
|
236
|
+
ResolverVendorUnavailableReason,
|
|
237
|
+
} from "./runtime/resolver-vendors/types.js";
|
|
212
238
|
export {
|
|
213
239
|
assertRequiredSecretsPresent,
|
|
214
240
|
listMissingRequiredSecrets,
|
|
@@ -250,6 +276,8 @@ export {
|
|
|
250
276
|
type TraceContext,
|
|
251
277
|
} from "./runtime/trace.js";
|
|
252
278
|
export {
|
|
279
|
+
APIFUSE_CONTENT_PROVENANCE_META_KEY,
|
|
280
|
+
APIFUSE_CONTENT_TRUST_META_KEY,
|
|
253
281
|
APIFUSE_DESCRIPTION_KEY_META_KEY,
|
|
254
282
|
APIFUSE_REDACTION_MARKER,
|
|
255
283
|
APIFUSE_SENSITIVE_KIND_META_KEY,
|
|
@@ -264,6 +292,7 @@ export {
|
|
|
264
292
|
type SensitiveFieldOptions,
|
|
265
293
|
type SensitivePath,
|
|
266
294
|
sensitive,
|
|
295
|
+
untrustedContent,
|
|
267
296
|
z,
|
|
268
297
|
} from "./schema.js";
|
|
269
298
|
export {
|
|
@@ -432,6 +461,7 @@ export type {
|
|
|
432
461
|
ProviderRuntimeTarget,
|
|
433
462
|
ProviderRuntimeState,
|
|
434
463
|
ProviderSecretDeclaration,
|
|
464
|
+
ProviderStealthConfig,
|
|
435
465
|
ProviderStateDurationString,
|
|
436
466
|
ProviderStateNamespace,
|
|
437
467
|
ProviderStreamEvent,
|
|
@@ -455,6 +485,7 @@ export type {
|
|
|
455
485
|
StateWriteOptions,
|
|
456
486
|
StealthClient,
|
|
457
487
|
StealthBrowser,
|
|
488
|
+
StealthChallengeClassification,
|
|
458
489
|
StealthCookieStore,
|
|
459
490
|
StealthCookieStoreV1,
|
|
460
491
|
StealthFetchOptions,
|
package/src/lint.ts
CHANGED
|
@@ -398,7 +398,7 @@ function lintAuthModel(provider: {
|
|
|
398
398
|
rule: "platform-managed-no-credential-keys",
|
|
399
399
|
level: "error",
|
|
400
400
|
field: "credential.keys",
|
|
401
|
-
message: `${providerLabel} must not declare credential.keys
|
|
401
|
+
message: `${providerLabel} must not declare credential.keys because platform-managed auth mode already implies the unfiltered credential capability.`,
|
|
402
402
|
});
|
|
403
403
|
}
|
|
404
404
|
|
|
@@ -1032,9 +1032,9 @@ function browserVersionLiteralMessage(finding: BrowserVersionLiteralFinding): st
|
|
|
1032
1032
|
case "profile":
|
|
1033
1033
|
return `Hardcoded stealth profile "${finding.literal}" pins a browser version and will rot. Select the browser and OS structurally, for example stealth: { browser: "chrome", os: "macos" }.`;
|
|
1034
1034
|
case "user-agent":
|
|
1035
|
-
return `Hardcoded User-Agent browser version "${finding.literal}" can disagree with the stealth TLS fingerprint. Remove the literal and
|
|
1035
|
+
return `Hardcoded User-Agent browser version "${finding.literal}" can disagree with the stealth TLS fingerprint. Remove the literal. ctx.stealth owns User-Agent and rejects a caller value with STEALTH_HEADER_OVERRIDE_UNSUPPORTED, so omit the header there and select the profile with stealth: { browser: "chrome", os: "macos" }. For ctx.http only, derive it from getStealthProfile({ browser: "chrome", os: "macos" }).userAgent.`;
|
|
1036
1036
|
case "sec-ch-ua":
|
|
1037
|
-
return 'Hardcoded sec-ch-ua versions can disagree with the stealth TLS fingerprint. Remove the literal and let ctx.stealth generate client hints from stealth: { browser: "chrome", os: "macos" }
|
|
1037
|
+
return 'Hardcoded sec-ch-ua versions can disagree with the stealth TLS fingerprint. Remove the literal and let ctx.stealth generate client hints from stealth: { browser: "chrome", os: "macos" }. ctx.stealth also owns User-Agent, so omit that header there as well; for ctx.http only, derive it from getStealthProfile({ browser: "chrome", os: "macos" }).userAgent.';
|
|
1038
1038
|
}
|
|
1039
1039
|
}
|
|
1040
1040
|
|
package/src/provider.ts
CHANGED
|
@@ -133,9 +133,13 @@ export {
|
|
|
133
133
|
createProviderEnvironment,
|
|
134
134
|
createInProcessProviderEngine,
|
|
135
135
|
ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES,
|
|
136
|
+
ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES,
|
|
137
|
+
ENGINE_OWNED_RUNTIME_ENV_NAMES,
|
|
136
138
|
ENGINE_OWNED_TELEMETRY_ENV_NAMES,
|
|
137
139
|
isEngineOwnedEnvName,
|
|
138
140
|
isEngineOwnedProxyCredentialName,
|
|
141
|
+
isEngineOwnedResolverCredentialName,
|
|
142
|
+
isEngineOwnedRuntimeEnvName,
|
|
139
143
|
isEngineOwnedTelemetryEnvName,
|
|
140
144
|
PROVIDER_CAPABILITY_KEYS,
|
|
141
145
|
PROVIDER_ENGINE_PROTOCOL_VERSION,
|
|
@@ -164,6 +168,8 @@ export {
|
|
|
164
168
|
PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
|
|
165
169
|
} from "./runtime/choice.js";
|
|
166
170
|
export {
|
|
171
|
+
APIFUSE_CONTENT_PROVENANCE_META_KEY,
|
|
172
|
+
APIFUSE_CONTENT_TRUST_META_KEY,
|
|
167
173
|
APIFUSE_DESCRIPTION_KEY_META_KEY,
|
|
168
174
|
APIFUSE_REDACTION_MARKER,
|
|
169
175
|
APIFUSE_SENSITIVE_KIND_META_KEY,
|
|
@@ -178,6 +184,7 @@ export {
|
|
|
178
184
|
type SensitiveFieldOptions,
|
|
179
185
|
type SensitivePath,
|
|
180
186
|
sensitive,
|
|
187
|
+
untrustedContent,
|
|
181
188
|
z,
|
|
182
189
|
} from "./schema.js";
|
|
183
190
|
export type {
|
|
@@ -261,6 +268,7 @@ export type {
|
|
|
261
268
|
ProviderResolvedFile,
|
|
262
269
|
ProviderRuntimeTarget,
|
|
263
270
|
ProviderRuntimeState,
|
|
271
|
+
ProviderStealthConfig,
|
|
264
272
|
ProviderStateDurationString,
|
|
265
273
|
ProviderStateNamespace,
|
|
266
274
|
ProviderSupportLevel,
|
|
@@ -273,6 +281,7 @@ export type {
|
|
|
273
281
|
StateNamespaceScope,
|
|
274
282
|
StateValue,
|
|
275
283
|
StateWriteOptions,
|
|
284
|
+
StealthChallengeClassification,
|
|
276
285
|
} from "./types.js";
|
|
277
286
|
export {
|
|
278
287
|
NativeEgressGrantExpiredError,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map whose entries carry an expiry and whose size is capped.
|
|
3
|
+
*
|
|
4
|
+
* Expired entries are dropped when read and swept on every insert, so a
|
|
5
|
+
* process that keeps minting new keys does not retain dead values. When the
|
|
6
|
+
* cap is still exceeded after the sweep, the least recently used entry is
|
|
7
|
+
* evicted and counted in `capacityEvictions` so callers can tell the two
|
|
8
|
+
* kinds of removal apart. Callers pass `now` explicitly so a single timestamp
|
|
9
|
+
* is used across a lookup-then-store sequence.
|
|
10
|
+
*/
|
|
11
|
+
export class BoundedExpiringMap<K, V> {
|
|
12
|
+
readonly #entries = new Map<K, V>();
|
|
13
|
+
readonly #maxEntries: number;
|
|
14
|
+
readonly #expiresAt: (value: V) => number;
|
|
15
|
+
#capacityEvictions = 0;
|
|
16
|
+
|
|
17
|
+
constructor(maxEntries: number, expiresAt: (value: V) => number) {
|
|
18
|
+
if (!Number.isInteger(maxEntries) || maxEntries <= 0) {
|
|
19
|
+
throw new RangeError("maxEntries must be a positive integer");
|
|
20
|
+
}
|
|
21
|
+
this.#maxEntries = maxEntries;
|
|
22
|
+
this.#expiresAt = expiresAt;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get size(): number {
|
|
26
|
+
return this.#entries.size;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Entries removed to satisfy `maxEntries`; expiry removals are not counted. */
|
|
30
|
+
get capacityEvictions(): number {
|
|
31
|
+
return this.#capacityEvictions;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get(key: K, now: number): V | undefined {
|
|
35
|
+
if (!this.#entries.has(key)) return undefined;
|
|
36
|
+
const value = this.#entries.get(key) as V;
|
|
37
|
+
this.#entries.delete(key);
|
|
38
|
+
if (this.#expiresAt(value) <= now) return undefined;
|
|
39
|
+
// Re-insert so Map iteration order doubles as the LRU order.
|
|
40
|
+
this.#entries.set(key, value);
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
set(key: K, value: V, now: number): void {
|
|
45
|
+
for (const [existingKey, existing] of this.#entries) {
|
|
46
|
+
if (this.#expiresAt(existing) <= now) this.#entries.delete(existingKey);
|
|
47
|
+
}
|
|
48
|
+
this.#entries.delete(key);
|
|
49
|
+
if (this.#expiresAt(value) <= now) return;
|
|
50
|
+
this.#entries.set(key, value);
|
|
51
|
+
if (this.#entries.size > this.#maxEntries) {
|
|
52
|
+
const oldest = this.#entries.keys().next();
|
|
53
|
+
if (!oldest.done) {
|
|
54
|
+
this.#entries.delete(oldest.value);
|
|
55
|
+
this.#capacityEvictions += 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
delete(key: K): boolean {
|
|
61
|
+
return this.#entries.delete(key);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
clear(): void {
|
|
65
|
+
this.#entries.clear();
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/runtime/cache.ts
CHANGED
|
@@ -589,6 +589,13 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
|
|
|
589
589
|
};
|
|
590
590
|
}
|
|
591
591
|
|
|
592
|
+
const bypassCaches = new WeakSet<ProviderCache>();
|
|
593
|
+
|
|
594
|
+
/** Internal cache capability, separate from hit/miss metadata. */
|
|
595
|
+
export function isProviderCacheBypassed(cache: ProviderCache): boolean {
|
|
596
|
+
return bypassCaches.has(cache);
|
|
597
|
+
}
|
|
598
|
+
|
|
592
599
|
export function createBypassProviderCache(
|
|
593
600
|
options: Pick<ProviderCacheOptions, "providerId">,
|
|
594
601
|
): ProviderCache {
|
|
@@ -597,7 +604,7 @@ export function createBypassProviderCache(
|
|
|
597
604
|
const events: ProviderCacheLookupMeta[] = [];
|
|
598
605
|
const secretScopedKeys = new Set<string>();
|
|
599
606
|
|
|
600
|
-
|
|
607
|
+
const cache: ProviderCache = {
|
|
601
608
|
key(namespace, parts, keyOptions?: ProviderCacheKeyOptions) {
|
|
602
609
|
const extra = new Set((keyOptions?.redactFields ?? []).map((field) => field.toLowerCase()));
|
|
603
610
|
const normalized = normalizeKeyPart(parts, extra, pepper);
|
|
@@ -643,6 +650,8 @@ export function createBypassProviderCache(
|
|
|
643
650
|
};
|
|
644
651
|
},
|
|
645
652
|
};
|
|
653
|
+
bypassCaches.add(cache);
|
|
654
|
+
return cache;
|
|
646
655
|
}
|
|
647
656
|
|
|
648
657
|
export function resetProviderCacheForTests(): void {
|