@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/dist/schema.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export declare function safeParseSchemaSync<TSchema extends SchemaLike>(schema:
|
|
|
13
13
|
export declare const APIFUSE_SENSITIVE_META_KEY = "x-apifuse-sensitive";
|
|
14
14
|
export declare const APIFUSE_SENSITIVE_KIND_META_KEY = "x-apifuse-sensitive-kind";
|
|
15
15
|
export declare const APIFUSE_DESCRIPTION_KEY_META_KEY = "x-apifuse-description-key";
|
|
16
|
+
export declare const APIFUSE_CONTENT_TRUST_META_KEY = "x-apifuse-content-trust";
|
|
17
|
+
export declare const APIFUSE_CONTENT_PROVENANCE_META_KEY = "x-apifuse-content-provenance";
|
|
16
18
|
export declare const APIFUSE_REDACTION_MARKER = "<redacted>";
|
|
17
19
|
export type SensitivePathSegment = string | "*";
|
|
18
20
|
export type SensitivePath = readonly SensitivePathSegment[];
|
|
@@ -32,6 +34,13 @@ export interface SensitiveFieldOptions {
|
|
|
32
34
|
description?: string;
|
|
33
35
|
}
|
|
34
36
|
export declare function describeKey<TSchema extends ZodType>(schema: TSchema, key: ProviderLocaleKey | string): TSchema;
|
|
37
|
+
/**
|
|
38
|
+
* Mark an output field as externally authored text (listing bodies, reviews,
|
|
39
|
+
* posts) that the provider relays verbatim. Sets both content-trust JSON Schema
|
|
40
|
+
* meta keys on the field node so the platform can enforce the boundary when it
|
|
41
|
+
* assembles tool output; validation and the parsed value are unchanged.
|
|
42
|
+
*/
|
|
43
|
+
export declare function untrustedContent<TSchema extends ZodType>(schema: TSchema): TSchema;
|
|
35
44
|
declare module "zod" {
|
|
36
45
|
interface ZodType {
|
|
37
46
|
describeKey(key: ProviderLocaleKey | string): this;
|
package/dist/schema.js
CHANGED
|
@@ -41,6 +41,8 @@ export function safeParseSchemaSync(schema, value, fieldPath) {
|
|
|
41
41
|
export const APIFUSE_SENSITIVE_META_KEY = "x-apifuse-sensitive";
|
|
42
42
|
export const APIFUSE_SENSITIVE_KIND_META_KEY = "x-apifuse-sensitive-kind";
|
|
43
43
|
export const APIFUSE_DESCRIPTION_KEY_META_KEY = "x-apifuse-description-key";
|
|
44
|
+
export const APIFUSE_CONTENT_TRUST_META_KEY = "x-apifuse-content-trust";
|
|
45
|
+
export const APIFUSE_CONTENT_PROVENANCE_META_KEY = "x-apifuse-content-provenance";
|
|
44
46
|
export const APIFUSE_REDACTION_MARKER = "<redacted>";
|
|
45
47
|
export function describeKey(schema, key) {
|
|
46
48
|
const descriptionKey = providerLocaleKey(key);
|
|
@@ -50,6 +52,20 @@ export function describeKey(schema, key) {
|
|
|
50
52
|
[APIFUSE_DESCRIPTION_KEY_META_KEY]: descriptionKey,
|
|
51
53
|
});
|
|
52
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Mark an output field as externally authored text (listing bodies, reviews,
|
|
57
|
+
* posts) that the provider relays verbatim. Sets both content-trust JSON Schema
|
|
58
|
+
* meta keys on the field node so the platform can enforce the boundary when it
|
|
59
|
+
* assembles tool output; validation and the parsed value are unchanged.
|
|
60
|
+
*/
|
|
61
|
+
export function untrustedContent(schema) {
|
|
62
|
+
const metadata = schema.meta() ?? {};
|
|
63
|
+
return schema.meta({
|
|
64
|
+
...metadata,
|
|
65
|
+
[APIFUSE_CONTENT_TRUST_META_KEY]: "untrusted",
|
|
66
|
+
[APIFUSE_CONTENT_PROVENANCE_META_KEY]: "external",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
53
69
|
const describeKeyMethod = function (key) {
|
|
54
70
|
return describeKey(this, key);
|
|
55
71
|
};
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export type { ProxyCacheStatus, ProxyProtocol, ProxyUserAgentSource, ProxyVendorName, SmartproxyAllocatorBodyClass, } from "../config/loader.js";
|
|
2
2
|
export type { ProxyTelemetryHeaderPayload, ProxyHash, ProxyTelemetryLogPayload, ProxyTelemetryResolvedPayload, ProxyTelemetryUnresolvedPayload, } from "../runtime/proxy-telemetry.js";
|
|
3
3
|
export { RequestTelemetry, closedEnum, type ClosedEnum, type GatewayIngestible, type RequestTelemetryLogPayload, type SpanIndex, type TelemetryContributor, type TelemetryKey, type TenantNeutral, } from "../runtime/request-telemetry.js";
|
|
4
|
+
export { ResolverTelemetryCollector, type ResolverAttemptSample, type ResolverCacheReadTelemetryEvent, type ResolverCacheWriteTelemetryEvent, type ResolverFailoverTelemetryEvent, type ResolverIdentityTelemetryEvent, type ResolverOutcomeTelemetryEvent, type ResolverTelemetryAttemptOutcome, type ResolverTelemetryCacheStatus, type ResolverTelemetryCacheWriteReason, type ResolverTelemetryErrorClass, type ResolverTelemetryHeaderPayload, type ResolverTelemetryIdentitySource, type ResolverTelemetryLogPayload, type ResolverTelemetryOutcome, type ResolverTelemetryPhase, type ResolverTelemetrySink, type ResolverVendorAttemptTelemetryEvent, } from "../runtime/resolver-telemetry.js";
|
|
5
|
+
export type { ResolverVendorUnavailableReason } from "../runtime/resolver-vendors/types.js";
|
|
4
6
|
export type { Span, TraceContext } from "../runtime/trace.js";
|
|
5
7
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, type ErrorObservabilityDetails, type ProviderServerCloseOptions, type ProviderServerHandle, type ProviderErrorCauseFrame, type ProviderServerLogEvent, type ProviderServerLogger, type ProviderServerOperationExecutor, type ProviderServerOperationExecutorInput, type ProviderServerOptions, type ProviderServerStatefulForwardEnvelope, type ServeOptions, serve, } from "./serve.js";
|
|
6
8
|
export type { ProviderErrorObservability } from "../errors.js";
|
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { RequestTelemetry, closedEnum, } from "../runtime/request-telemetry.js";
|
|
2
|
+
export { ResolverTelemetryCollector, } from "../runtime/resolver-telemetry.js";
|
|
2
3
|
export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, serve, } from "./serve.js";
|
|
3
4
|
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test.js";
|
|
4
5
|
export { resolveHealthCheckInputDateTokens, } from "./self-test-input-tokens.js";
|
|
@@ -88,6 +88,10 @@ export type SelfTestAuthFlowInvoke = (args: {
|
|
|
88
88
|
externalRef?: string;
|
|
89
89
|
input?: Record<string, unknown>;
|
|
90
90
|
context?: Record<string, unknown>;
|
|
91
|
+
/** Opaque engine state from the previous turn (`engine` in the auth response), sent verbatim. */
|
|
92
|
+
engine?: {
|
|
93
|
+
egressLease: string;
|
|
94
|
+
};
|
|
91
95
|
signal?: AbortSignal;
|
|
92
96
|
}) => Promise<{
|
|
93
97
|
status: number;
|
package/dist/server/self-test.js
CHANGED
|
@@ -187,17 +187,21 @@ function logSelfTestCancellation(provider, options, requestId, selected, signal,
|
|
|
187
187
|
}
|
|
188
188
|
/** Binds the self-test auth-flow driver to a tenant app's /auth pipeline in-process. */
|
|
189
189
|
export function createSelfTestAuthFlowInvoke(app) {
|
|
190
|
-
return async ({ route, requestId, flowId, connectionId, externalRef, input, context, signal, }) => {
|
|
190
|
+
return async ({ route, requestId, flowId, connectionId, externalRef, input, context, engine, signal, }) => {
|
|
191
191
|
const response = await app.request(`/auth/${route}`, {
|
|
192
192
|
method: "POST",
|
|
193
193
|
headers: { "content-type": "application/json" },
|
|
194
194
|
body: JSON.stringify({
|
|
195
195
|
requestId,
|
|
196
196
|
flowId,
|
|
197
|
+
// Engine ceremony leases are scoped to a tenant; the self-test has no
|
|
198
|
+
// customer tenant, so it presents a fixed one that never collides.
|
|
199
|
+
tenantId: "self-test",
|
|
197
200
|
...(connectionId ? { connectionId } : {}),
|
|
198
201
|
...(externalRef ? { externalRef } : {}),
|
|
199
202
|
...(input ? { input } : {}),
|
|
200
203
|
...(context ? { context } : {}),
|
|
204
|
+
...(engine ? { engine } : {}),
|
|
201
205
|
}),
|
|
202
206
|
...(signal ? { signal } : {}),
|
|
203
207
|
});
|
|
@@ -329,6 +333,7 @@ function parseAuthFlowResponse(result) {
|
|
|
329
333
|
};
|
|
330
334
|
}
|
|
331
335
|
const contextPatch = objectProperty(result.body, "contextPatch");
|
|
336
|
+
const egressLease = objectProperty(objectProperty(result.body, "engine"), "egressLease");
|
|
332
337
|
return {
|
|
333
338
|
ok: true,
|
|
334
339
|
turn: {
|
|
@@ -339,6 +344,7 @@ function parseAuthFlowResponse(result) {
|
|
|
339
344
|
...(contextPatch && typeof contextPatch === "object" && !Array.isArray(contextPatch)
|
|
340
345
|
? { contextPatch: contextPatch }
|
|
341
346
|
: {}),
|
|
347
|
+
...(typeof egressLease === "string" && egressLease ? { engine: { egressLease } } : {}),
|
|
342
348
|
};
|
|
343
349
|
}
|
|
344
350
|
function applyAuthFlowContextPatch(base, patch) {
|
|
@@ -499,6 +505,9 @@ async function materializeFlowCredential(execution, inputs, options = {}) {
|
|
|
499
505
|
...(options.externalRef ? { externalRef: options.externalRef } : {}),
|
|
500
506
|
input: submitInputs,
|
|
501
507
|
...(Object.keys(flowContext).length > 0 ? { context: flowContext } : {}),
|
|
508
|
+
// The ceremony egress lease is engine state, not flow context: carry it the
|
|
509
|
+
// way the gateway does so the continue turn stays on the start turn's egress.
|
|
510
|
+
...(started.engine ? { engine: started.engine } : {}),
|
|
502
511
|
...(options.signal ? { signal: options.signal } : {}),
|
|
503
512
|
}));
|
|
504
513
|
if (!continued.ok) {
|
|
@@ -4,6 +4,7 @@ import { type ProviderEngine } from "../engine.js";
|
|
|
4
4
|
import { type ProviderErrorObservability } from "../errors.js";
|
|
5
5
|
import { type ProviderErrorCategory } from "../observability.js";
|
|
6
6
|
import { type ProxyTelemetryLogPayload } from "../runtime/proxy-telemetry.js";
|
|
7
|
+
import { type ResolverTelemetryLogPayload } from "../runtime/resolver-telemetry.js";
|
|
7
8
|
import type { OcrContext, ProviderContext, ProviderDefinition, ProviderFilesContext, ProviderRuntimeState, ResolverContext, SttContext } from "../types.js";
|
|
8
9
|
import type { SelfTestCancellationLogEvent } from "./self-test.js";
|
|
9
10
|
import { type AuthFlowRequest, type OperationRequest } from "./types.js";
|
|
@@ -85,6 +86,7 @@ type ProviderServerLogEventBase = ProviderRequestCost & {
|
|
|
85
86
|
requestedProviderId?: string;
|
|
86
87
|
status: number;
|
|
87
88
|
proxy?: ProxyTelemetryLogPayload;
|
|
89
|
+
resolver?: ResolverTelemetryLogPayload;
|
|
88
90
|
};
|
|
89
91
|
export type ProviderServerLogEvent = (ProviderServerLogEventBase & {
|
|
90
92
|
level: "info";
|
|
@@ -164,7 +166,11 @@ export type ProviderServerOptions<TContext extends Partial<ProviderContext> = Pr
|
|
|
164
166
|
stt?: SttContext;
|
|
165
167
|
/** Optional OCR override for tests or custom hosts; local/prod normally resolves from env. */
|
|
166
168
|
ocr?: OcrContext;
|
|
167
|
-
/**
|
|
169
|
+
/**
|
|
170
|
+
* Optional resolver override for tests or custom hosts; local/prod normally resolves from env.
|
|
171
|
+
* SDK chains are reconstructed with each request's telemetry sink. An opaque host
|
|
172
|
+
* resolver is reported as one custom invocation; its internal vendor work is not exposed.
|
|
173
|
+
*/
|
|
168
174
|
resolver?: ResolverContext;
|
|
169
175
|
/** Optional runtime state override for tests or custom hosts. Production resolves Redis from env and fails closed when unavailable. */
|
|
170
176
|
state?: ProviderRuntimeState;
|
|
@@ -10,7 +10,7 @@ import { validateFailClosedDeclaration } from "../declaration-validation.js";
|
|
|
10
10
|
import { safeProviderErrorObservability } from "../error-observability.js";
|
|
11
11
|
import { createInProcessProviderEngine, ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, isEngineOwnedEnvName, readEngineProxyCredentials, } from "../engine.js";
|
|
12
12
|
import { SDK_OWNED_PROVIDER_ERROR_CODES, SDK_RUNTIME_OWNED_ERROR_CODES, SDK_STATUS_MAPPED_PROVIDER_ERROR_CODES, } from "../error-resolution.js";
|
|
13
|
-
import { AuthError, isProviderError, isSessionExpiredError, isTransportError, isValidationError, ProviderError, } from "../errors.js";
|
|
13
|
+
import { AuthError, isProviderError, isSessionExpiredError, isTransportError, isValidationError, ProviderError, SDKError, } from "../errors.js";
|
|
14
14
|
import { sanitizeDiagnosticText } from "../fixture-sanitization.js";
|
|
15
15
|
import { loadProviderLocaleCatalogs, localizeAuthTurn, } from "../i18n/catalog.js";
|
|
16
16
|
import { categoryForStatus, sourceForCategory, isRetryableCategory, PROVIDER_OBSERVABILITY_TAXONOMY_VERSION, } from "../observability.js";
|
|
@@ -18,6 +18,7 @@ import { createScratchpad } from "../runtime/auth-flow.js";
|
|
|
18
18
|
import { createProviderCache } from "../runtime/cache.js";
|
|
19
19
|
import { createProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "../runtime/choice.js";
|
|
20
20
|
import { createCredentialContext } from "../runtime/credential.js";
|
|
21
|
+
import { createCeremonyEgressLeaseRuntime, ENGINE_CEREMONY_EGRESS_LEASE, } from "../runtime/egress-lease.js";
|
|
21
22
|
import { createEnvContext } from "../runtime/env.js";
|
|
22
23
|
import { executeOperation } from "../runtime/executor.js";
|
|
23
24
|
import { createHttpClient } from "../runtime/http.js";
|
|
@@ -27,12 +28,13 @@ import { createOcrClientFromEnv } from "../runtime/ocr.js";
|
|
|
27
28
|
import { PROXY_AUTH_IP_DENIED_CODE, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_EXHAUSTED_CODE, } from "../runtime/proxy-errors.js";
|
|
28
29
|
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector, } from "../runtime/proxy-telemetry.js";
|
|
29
30
|
import { closedEnum, RequestTelemetry, tenantOpaqueKeys, } from "../runtime/request-telemetry.js";
|
|
30
|
-
import {
|
|
31
|
+
import { ResolverTelemetryCollector, } from "../runtime/resolver-telemetry.js";
|
|
32
|
+
import { createUnsupportedResolverClient, bindResolverTelemetry, inheritResolverTelemetryBinding, } from "../runtime/resolver-shared.js";
|
|
31
33
|
import { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "../runtime/secrets.js";
|
|
32
34
|
import { createProviderRuntimeStateFromEnv, createUnsupportedProviderRuntimeState, } from "../runtime/state.js";
|
|
33
35
|
import { StealthCookieJar } from "../runtime/stealth-cookies.js";
|
|
34
36
|
import { createSttClientFromEnv } from "../runtime/stt.js";
|
|
35
|
-
import { createTraceContext, updateTraceContextExportMetadata, } from "../runtime/trace.js";
|
|
37
|
+
import { createTraceContext, getTraceRecorder, updateTraceContextExportMetadata, } from "../runtime/trace.js";
|
|
36
38
|
import { resolveTraceConfigFromEnv } from "../runtime/trace-config.js";
|
|
37
39
|
import { parseSchema } from "../schema.js";
|
|
38
40
|
import { STATEFUL_NONCE_HEADER as STATEFUL_FORWARDING_NONCE_HEADER, STATEFUL_SIGNATURE_HEADER as STATEFUL_FORWARDING_SIGNATURE_HEADER, STATEFUL_TIMESTAMP_HEADER as STATEFUL_FORWARDING_TIMESTAMP_HEADER, verifyStatefulRequestSignature, } from "../stateful-signing.js";
|
|
@@ -268,6 +270,9 @@ function createLazyStealthClient(onCleanupError, ...createArgs) {
|
|
|
268
270
|
async fetch(...args) {
|
|
269
271
|
return (await getSession()).fetch(...args);
|
|
270
272
|
},
|
|
273
|
+
async replayChallenged(...args) {
|
|
274
|
+
return (await getSession()).replayChallenged(...args);
|
|
275
|
+
},
|
|
271
276
|
redirects: {
|
|
272
277
|
async run(...args) {
|
|
273
278
|
return (await getSession()).redirects.run(...args);
|
|
@@ -304,13 +309,15 @@ function createLazyStealthClient(onCleanupError, ...createArgs) {
|
|
|
304
309
|
function bindResolverSignalWithoutRuntime(resolver, defaultSignal) {
|
|
305
310
|
if (!defaultSignal)
|
|
306
311
|
return resolver;
|
|
307
|
-
|
|
312
|
+
const boundResolver = {
|
|
308
313
|
solve(challenge, signal = defaultSignal, traceRecorder) {
|
|
309
314
|
// Forward the instrumentation trace recorder so resolver.vendor.* spans
|
|
310
315
|
// survive this wrapper. See ResolverSolveWithRecorder in resolver-shared.ts.
|
|
311
316
|
return resolver.solve(challenge, signal, traceRecorder);
|
|
312
317
|
},
|
|
313
318
|
};
|
|
319
|
+
inheritResolverTelemetryBinding(resolver, boundResolver);
|
|
320
|
+
return boundResolver;
|
|
314
321
|
}
|
|
315
322
|
function getProviderStealthBaseUrl(provider) {
|
|
316
323
|
const baseUrl = getProviderBaseUrl(provider);
|
|
@@ -323,6 +330,73 @@ function getProviderStealthBaseUrl(provider) {
|
|
|
323
330
|
function getProviderStealthProfile(provider) {
|
|
324
331
|
return provider.stealth ? getStealthProfile(provider.stealth) : undefined;
|
|
325
332
|
}
|
|
333
|
+
/** One option set for ctx.resolver and the automatic SBSD solve, so both share identity scope, cache, proxy intent, and telemetry. */
|
|
334
|
+
function createResolverRuntimeOptions(provider, cache, identityScope, proxyPolicy, proxyClientOptions, stealthProfile, telemetry) {
|
|
335
|
+
return {
|
|
336
|
+
allowedHosts: provider.allowedHosts,
|
|
337
|
+
cache,
|
|
338
|
+
telemetry,
|
|
339
|
+
identityScope,
|
|
340
|
+
...(proxyPolicy
|
|
341
|
+
? {
|
|
342
|
+
proxyIntent: {
|
|
343
|
+
mode: proxyPolicy.mode,
|
|
344
|
+
...proxyClientOptions,
|
|
345
|
+
...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
|
|
346
|
+
},
|
|
347
|
+
}
|
|
348
|
+
: {}),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/** Shared predicate for the SBSD challenge runtime and the ceremony egress lease. */
|
|
352
|
+
function declaresAkamaiSbsdResolver(provider) {
|
|
353
|
+
return provider.resolver?.kinds.some((kind) => kind === "akamai_sbsd") === true;
|
|
354
|
+
}
|
|
355
|
+
function createStealthChallengeDetection(provider, resolverRuntime, resolverOverride, resolverOptions, trace, signal) {
|
|
356
|
+
const resolverDeclared = declaresAkamaiSbsdResolver(provider);
|
|
357
|
+
const detectOnly = provider.stealth?.challengeDetection?.akamaiSbsd === true;
|
|
358
|
+
if (!resolverDeclared && !detectOnly) {
|
|
359
|
+
return undefined;
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
akamaiSbsd: {
|
|
363
|
+
allowedHosts: provider.allowedHosts ?? [],
|
|
364
|
+
// The profile belongs to the SBSD resolver; a resolver declared for other kinds
|
|
365
|
+
// may name a different browser without affecting detect-only classification.
|
|
366
|
+
...(resolverDeclared && provider.resolver?.clientProfile
|
|
367
|
+
? { clientProfile: provider.resolver.clientProfile }
|
|
368
|
+
: {}),
|
|
369
|
+
...(resolverDeclared && resolverRuntime
|
|
370
|
+
? {
|
|
371
|
+
async solve(challenge, transport, solveSignal) {
|
|
372
|
+
const resolver = resolverRuntime.bindResolverSignal((resolverOverride
|
|
373
|
+
? bindResolverTelemetry(resolverOverride, resolverOptions.telemetry)
|
|
374
|
+
: undefined) ??
|
|
375
|
+
resolverRuntime.createResolverClientFromEnv(provider.resolver, undefined, {
|
|
376
|
+
allowedHosts: resolverOptions.allowedHosts,
|
|
377
|
+
cache: resolverOptions.cache,
|
|
378
|
+
telemetry: resolverOptions.telemetry,
|
|
379
|
+
identityScope: resolverOptions.identityScope,
|
|
380
|
+
// No proxyIntent: the transport is already bound to the initiating
|
|
381
|
+
// request's lease, and a second identity resolution would allocate
|
|
382
|
+
// again (and fail closed without allocator credentials) for nothing
|
|
383
|
+
// the SBSD adapters consume.
|
|
384
|
+
createTransport: () => transport,
|
|
385
|
+
}), signal);
|
|
386
|
+
// Same span and recorder threading as the instrumented ctx.resolver.solve.
|
|
387
|
+
const recorder = getTraceRecorder(trace);
|
|
388
|
+
const solve = () => resolver.solve(challenge, solveSignal, recorder ?? undefined);
|
|
389
|
+
return recorder
|
|
390
|
+
? recorder.runSpan("resolver.solve", solve, {
|
|
391
|
+
attributes: { challenge_kind: challenge.kind },
|
|
392
|
+
})
|
|
393
|
+
: solve();
|
|
394
|
+
},
|
|
395
|
+
}
|
|
396
|
+
: {}),
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
}
|
|
326
400
|
function isProductionProviderBrowserMode(provider, env = process.env) {
|
|
327
401
|
if (provider.runtime !== "browser") {
|
|
328
402
|
return false;
|
|
@@ -424,16 +498,28 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
424
498
|
engineCredentials: engineProxyCredentials,
|
|
425
499
|
};
|
|
426
500
|
const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
|
|
501
|
+
const cache = createProviderCache({ providerId: provider.id });
|
|
427
502
|
let wrappedContext;
|
|
503
|
+
const { capabilityModules } = options;
|
|
504
|
+
const resolverOptions = createResolverRuntimeOptions(provider, cache, resolverIdentityScope, proxyPolicy, proxyClientOptions, stealthProfile, scope.resolverTelemetry);
|
|
505
|
+
const challengeRuntime = createStealthChallengeDetection(provider, capabilityModules.resolver, options.resolver, resolverOptions, scope.trace, signal);
|
|
428
506
|
const stealthClientOptions = {
|
|
429
507
|
upstream: proxyClientOptions.upstream,
|
|
430
508
|
affinityKey: proxyClientOptions.affinityKey,
|
|
431
509
|
telemetry: scope.telemetry.proxy,
|
|
432
510
|
engineCredentials: engineProxyCredentials,
|
|
433
511
|
...(signal ? { signal } : {}),
|
|
434
|
-
|
|
512
|
+
// A declared resolver without a `stealth` block still gets the default Chrome client
|
|
513
|
+
// (auth FlowContext is not capability-gated), so the runtime must ride along.
|
|
514
|
+
...(provider.stealth || challengeRuntime
|
|
515
|
+
? {
|
|
516
|
+
stealth: {
|
|
517
|
+
...(provider.stealth ?? {}),
|
|
518
|
+
...(challengeRuntime ? { challengeRuntime } : {}),
|
|
519
|
+
},
|
|
520
|
+
}
|
|
521
|
+
: {}),
|
|
435
522
|
};
|
|
436
|
-
const { capabilityModules } = options;
|
|
437
523
|
const logStealthCleanupError = (error) => logProviderCleanupError(options.logger, provider, "operation", operationId, request.requestId, "stealth", error);
|
|
438
524
|
const env = createEnvContext([
|
|
439
525
|
...providerSecretNames(provider),
|
|
@@ -450,7 +536,6 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
450
536
|
headers: request.headers ?? {},
|
|
451
537
|
};
|
|
452
538
|
const requestState = state.forConnection(requestContext.connectionId);
|
|
453
|
-
const cache = createProviderCache({ providerId: provider.id });
|
|
454
539
|
const bindings = {
|
|
455
540
|
env,
|
|
456
541
|
credential,
|
|
@@ -499,22 +584,13 @@ function createProviderContext(provider, request, operationId, options, state =
|
|
|
499
584
|
ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
|
|
500
585
|
stt: options.stt ?? createSttClientFromEnv(provider.stt),
|
|
501
586
|
resolver: capabilityModules.resolver
|
|
502
|
-
? capabilityModules.resolver.bindResolverSignal(options.resolver
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
proxyIntent: {
|
|
510
|
-
mode: proxyPolicy.mode,
|
|
511
|
-
...proxyClientOptions,
|
|
512
|
-
...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
|
|
513
|
-
},
|
|
514
|
-
}
|
|
515
|
-
: {}),
|
|
516
|
-
}), signal)
|
|
517
|
-
: bindResolverSignalWithoutRuntime(options.resolver ??
|
|
587
|
+
? capabilityModules.resolver.bindResolverSignal((options.resolver
|
|
588
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
589
|
+
: undefined) ??
|
|
590
|
+
capabilityModules.resolver.createResolverClientFromEnv(provider.resolver, undefined, resolverOptions), signal)
|
|
591
|
+
: bindResolverSignalWithoutRuntime((options.resolver
|
|
592
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
593
|
+
: undefined) ??
|
|
518
594
|
createUnsupportedResolverClient("Provider does not declare resolver capability"), signal),
|
|
519
595
|
choice: createProviderChoiceContext({
|
|
520
596
|
providerId: provider.id,
|
|
@@ -564,7 +640,7 @@ export function resolveAuthFlowProxyAffinityKey(provider, request) {
|
|
|
564
640
|
request.providerId ??
|
|
565
641
|
provider.id);
|
|
566
642
|
}
|
|
567
|
-
function createAuthFlowContext(provider, request, options, state, scope, signal) {
|
|
643
|
+
function createAuthFlowContext(provider, request, route, options, state, scope, signal) {
|
|
568
644
|
const baseUrl = getProviderBaseUrl(provider);
|
|
569
645
|
const stealthBaseUrl = getProviderStealthBaseUrl(provider);
|
|
570
646
|
const stealthProfile = getProviderStealthProfile(provider);
|
|
@@ -578,16 +654,49 @@ function createAuthFlowContext(provider, request, options, state, scope, signal)
|
|
|
578
654
|
telemetry: scope.telemetry.proxy,
|
|
579
655
|
engineCredentials: engineProxyCredentials,
|
|
580
656
|
};
|
|
657
|
+
// The lease pins the proxy egress a challenged ceremony solved on, so only providers
|
|
658
|
+
// that declare the akamai_sbsd resolver kind carry one (same predicate as the challenge
|
|
659
|
+
// runtime). `abort` never evaluates the key or tenant: a user must be able to cancel a
|
|
660
|
+
// stranded flow even when engine provisioning is broken, and an abort is not a
|
|
661
|
+
// continuation of the ceremony the lease pins.
|
|
662
|
+
const ceremonyEgressLease = route !== "abort" &&
|
|
663
|
+
declaresAkamaiSbsdResolver(provider) &&
|
|
664
|
+
proxyPolicy &&
|
|
665
|
+
proxyPolicy.mode !== "disabled"
|
|
666
|
+
? createCeremonyEgressLeaseRuntime({
|
|
667
|
+
tenantId: request.tenantId,
|
|
668
|
+
providerId: provider.id,
|
|
669
|
+
flowId: request.flowId,
|
|
670
|
+
affinityKey: proxyClientOptions.affinityKey,
|
|
671
|
+
...(request.engine?.egressLease ? { handle: request.engine.egressLease } : {}),
|
|
672
|
+
})
|
|
673
|
+
: undefined;
|
|
674
|
+
if (route !== "abort" && request.engine?.egressLease && !ceremonyEgressLease) {
|
|
675
|
+
throw new SDKError("An egress lease was supplied for an auth flow that does not use a ceremony lease", { code: "EGRESS_LEASE_INVALID" });
|
|
676
|
+
}
|
|
581
677
|
const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
|
|
678
|
+
const cache = createProviderCache({ providerId: provider.id });
|
|
679
|
+
const { capabilityModules } = options;
|
|
680
|
+
const resolverOptions = createResolverRuntimeOptions(provider, cache, resolverIdentityScope, proxyPolicy, proxyClientOptions, stealthProfile, scope.resolverTelemetry);
|
|
681
|
+
const challengeRuntime = createStealthChallengeDetection(provider, capabilityModules.resolver, options.resolver, resolverOptions, scope.trace, signal);
|
|
582
682
|
const stealthClientOptions = {
|
|
583
683
|
upstream: proxyClientOptions.upstream,
|
|
584
684
|
affinityKey: proxyClientOptions.affinityKey,
|
|
585
685
|
telemetry: scope.telemetry.proxy,
|
|
586
686
|
engineCredentials: engineProxyCredentials,
|
|
687
|
+
...(ceremonyEgressLease ? { [ENGINE_CEREMONY_EGRESS_LEASE]: ceremonyEgressLease } : {}),
|
|
587
688
|
...(signal ? { signal } : {}),
|
|
588
|
-
|
|
689
|
+
// A declared resolver without a `stealth` block still gets the default Chrome client
|
|
690
|
+
// (auth FlowContext is not capability-gated), so the runtime must ride along.
|
|
691
|
+
...(provider.stealth || challengeRuntime
|
|
692
|
+
? {
|
|
693
|
+
stealth: {
|
|
694
|
+
...(provider.stealth ?? {}),
|
|
695
|
+
...(challengeRuntime ? { challengeRuntime } : {}),
|
|
696
|
+
},
|
|
697
|
+
}
|
|
698
|
+
: {}),
|
|
589
699
|
};
|
|
590
|
-
const { capabilityModules } = options;
|
|
591
700
|
const logStealthCleanupError = (error) => logProviderCleanupError(options.logger, provider, "auth", "flow", request.requestId, "stealth", error);
|
|
592
701
|
const credential = request.connection
|
|
593
702
|
? createCredentialContext({
|
|
@@ -597,7 +706,6 @@ function createAuthFlowContext(provider, request, options, state, scope, signal)
|
|
|
597
706
|
values: request.connection.secrets,
|
|
598
707
|
})
|
|
599
708
|
: undefined;
|
|
600
|
-
const cache = createProviderCache({ providerId: provider.id });
|
|
601
709
|
const context = wrapWithInstrumentation({
|
|
602
710
|
flowId: request.flowId,
|
|
603
711
|
connectionId: resolveOperationConnectionId(request),
|
|
@@ -636,28 +744,23 @@ function createAuthFlowContext(provider, request, options, state, scope, signal)
|
|
|
636
744
|
ocr: options.ocr ?? createOcrClientFromEnv(provider.ocr),
|
|
637
745
|
stt: options.stt ?? createSttClientFromEnv(provider.stt),
|
|
638
746
|
resolver: capabilityModules.resolver
|
|
639
|
-
? capabilityModules.resolver.bindResolverSignal(options.resolver
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
proxyIntent: {
|
|
647
|
-
mode: proxyPolicy.mode,
|
|
648
|
-
...proxyClientOptions,
|
|
649
|
-
...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
|
|
650
|
-
},
|
|
651
|
-
}
|
|
652
|
-
: {}),
|
|
653
|
-
}), signal)
|
|
654
|
-
: bindResolverSignalWithoutRuntime(options.resolver ??
|
|
747
|
+
? capabilityModules.resolver.bindResolverSignal((options.resolver
|
|
748
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
749
|
+
: undefined) ??
|
|
750
|
+
capabilityModules.resolver.createResolverClientFromEnv(provider.resolver, undefined, resolverOptions), signal)
|
|
751
|
+
: bindResolverSignalWithoutRuntime((options.resolver
|
|
752
|
+
? bindResolverTelemetry(options.resolver, resolverOptions.telemetry)
|
|
753
|
+
: undefined) ??
|
|
655
754
|
createUnsupportedResolverClient("Provider does not declare resolver capability"), signal),
|
|
656
755
|
auth: createAuthFlowHelpers({ signal }),
|
|
657
756
|
});
|
|
658
757
|
return {
|
|
659
758
|
context,
|
|
660
759
|
getPatch: flowContextStore.getPatch,
|
|
760
|
+
getEngineState() {
|
|
761
|
+
const egressLease = ceremonyEgressLease?.handle();
|
|
762
|
+
return egressLease ? { egressLease } : undefined;
|
|
763
|
+
},
|
|
661
764
|
};
|
|
662
765
|
}
|
|
663
766
|
const defaultProviderServerLogger = (event) => {
|
|
@@ -1199,8 +1302,10 @@ function createRequestScope(input) {
|
|
|
1199
1302
|
})
|
|
1200
1303
|
: createTraceContext();
|
|
1201
1304
|
const proxyCollector = new ProxyTelemetryCollector();
|
|
1305
|
+
const resolverCollector = new ResolverTelemetryCollector();
|
|
1202
1306
|
const telemetry = new RequestTelemetry(trace);
|
|
1203
1307
|
telemetry.register(proxyCollector);
|
|
1308
|
+
telemetry.register(resolverCollector);
|
|
1204
1309
|
let rootRunner = (fn) => fn();
|
|
1205
1310
|
let resolveRoot;
|
|
1206
1311
|
const rootTerminal = new Promise((resolve) => {
|
|
@@ -1275,6 +1380,7 @@ function createRequestScope(input) {
|
|
|
1275
1380
|
const scope = {
|
|
1276
1381
|
trace,
|
|
1277
1382
|
telemetry,
|
|
1383
|
+
resolverTelemetry: resolverCollector,
|
|
1278
1384
|
enrich(enrichment) {
|
|
1279
1385
|
if (terminalOutcome)
|
|
1280
1386
|
return;
|
|
@@ -1384,14 +1490,34 @@ function createRequestScope(input) {
|
|
|
1384
1490
|
};
|
|
1385
1491
|
return scope;
|
|
1386
1492
|
}
|
|
1387
|
-
|
|
1493
|
+
// A raw `Response` result skips `toErrorResponse`, so its body stays
|
|
1494
|
+
// provider-owned, but the observability header is still SDK-owned: derive it
|
|
1495
|
+
// from the status. Only timeouts, rate limits, and 5xx are retryable;
|
|
1496
|
+
// `isRetryableCategory` would otherwise mark every other 4xx (`upstream_http`)
|
|
1497
|
+
// as retryable.
|
|
1498
|
+
function rawResponseErrorObservability(status) {
|
|
1499
|
+
return {
|
|
1500
|
+
category: categoryForStatus(status),
|
|
1501
|
+
taxonomyVersion: PROVIDER_OBSERVABILITY_TAXONOMY_VERSION,
|
|
1502
|
+
retryable: status === 408 || status === 429 || status >= 500,
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
// `rawStatusFallback` is decided by the caller from the outcome, not from a
|
|
1506
|
+
// missing snapshot: a failed outcome whose thrown value is `undefined` also has
|
|
1507
|
+
// no `errorObservability`, and its 500 carries the SDK envelope, not a raw body.
|
|
1508
|
+
function responseWithRequestScopeHeaders(response, finished, rawStatusFallback) {
|
|
1388
1509
|
const headers = new Headers(response.headers);
|
|
1389
1510
|
headers.delete(PROVIDER_TELEMETRY_HEADER);
|
|
1390
1511
|
if (finished.providerTelemetryHeader) {
|
|
1391
1512
|
headers.set(PROVIDER_TELEMETRY_HEADER, finished.providerTelemetryHeader);
|
|
1392
1513
|
}
|
|
1393
|
-
|
|
1394
|
-
|
|
1514
|
+
headers.delete(ERROR_OBSERVABILITY_HEADER);
|
|
1515
|
+
const errorObservability = finished.errorObservability ??
|
|
1516
|
+
(rawStatusFallback && response.status >= 400
|
|
1517
|
+
? rawResponseErrorObservability(response.status)
|
|
1518
|
+
: undefined);
|
|
1519
|
+
if (errorObservability) {
|
|
1520
|
+
headers.set(ERROR_OBSERVABILITY_HEADER, JSON.stringify(errorObservability));
|
|
1395
1521
|
}
|
|
1396
1522
|
return new Response(response.body, {
|
|
1397
1523
|
headers,
|
|
@@ -1402,7 +1528,7 @@ function responseWithRequestScopeHeaders(response, finished) {
|
|
|
1402
1528
|
function finalizeRequestResponse(scope, response, outcome) {
|
|
1403
1529
|
try {
|
|
1404
1530
|
const error = outcome.kind === "failed" ? outcome.error : undefined;
|
|
1405
|
-
const finalResponse = responseWithRequestScopeHeaders(response, scope.snapshotHeaders(error));
|
|
1531
|
+
const finalResponse = responseWithRequestScopeHeaders(response, scope.snapshotHeaders(error), outcome.kind === "completed");
|
|
1406
1532
|
scope.terminalize(outcome);
|
|
1407
1533
|
return finalResponse;
|
|
1408
1534
|
}
|
|
@@ -1679,7 +1805,7 @@ function getSseTransport(operation) {
|
|
|
1679
1805
|
function getHttpStreamTransport(operation) {
|
|
1680
1806
|
return operation.transport?.kind === "http-stream" ? operation.transport : undefined;
|
|
1681
1807
|
}
|
|
1682
|
-
function toAuthFlowResponse(result, contextPatch) {
|
|
1808
|
+
function toAuthFlowResponse(result, contextPatch, engine) {
|
|
1683
1809
|
if (result instanceof Response) {
|
|
1684
1810
|
return result;
|
|
1685
1811
|
}
|
|
@@ -1689,6 +1815,7 @@ function toAuthFlowResponse(result, contextPatch) {
|
|
|
1689
1815
|
return {
|
|
1690
1816
|
data: result,
|
|
1691
1817
|
...(contextPatch ? { contextPatch } : {}),
|
|
1818
|
+
...(engine ? { engine } : {}),
|
|
1692
1819
|
};
|
|
1693
1820
|
}
|
|
1694
1821
|
function authFlowLocaleFromHeaders(headers) {
|
|
@@ -1823,8 +1950,9 @@ async function handleAuthFlow(provider, request, route, options, state, scope, s
|
|
|
1823
1950
|
// depend on declared secrets (client ids/secrets), so fail structured before
|
|
1824
1951
|
// any flow code runs instead of at whatever point the ceremony first reads
|
|
1825
1952
|
// the env. `abort` stays exempt: a user must always be able to cancel a
|
|
1826
|
-
// stranded flow even when provisioning is broken
|
|
1827
|
-
|
|
1953
|
+
// stranded flow even when provisioning is broken (createAuthFlowContext
|
|
1954
|
+
// applies the same exemption to the engine ceremony lease).
|
|
1955
|
+
const { context, getPatch, getEngineState } = createAuthFlowContext(provider, request, route, options, state, scope, signal);
|
|
1828
1956
|
try {
|
|
1829
1957
|
if (route !== "abort") {
|
|
1830
1958
|
assertRequiredSecretsPresent(provider, context.env);
|
|
@@ -1855,11 +1983,11 @@ async function handleAuthFlow(provider, request, route, options, state, scope, s
|
|
|
1855
1983
|
isAuthTurn(result)
|
|
1856
1984
|
? materializeAuthFlowTurn(provider, request, result)
|
|
1857
1985
|
: result;
|
|
1858
|
-
return toAuthFlowResponse(materializedResult, getPatch());
|
|
1986
|
+
return toAuthFlowResponse(materializedResult, getPatch(), getEngineState());
|
|
1859
1987
|
}
|
|
1860
1988
|
catch (error) {
|
|
1861
1989
|
if (error instanceof AuthAbortError) {
|
|
1862
|
-
return toAuthFlowResponse(error.turn, getPatch());
|
|
1990
|
+
return toAuthFlowResponse(error.turn, getPatch(), getEngineState());
|
|
1863
1991
|
}
|
|
1864
1992
|
throw error;
|
|
1865
1993
|
}
|
|
@@ -2228,7 +2356,7 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
2228
2356
|
const handled = await handleOperation(provider, body, operation, options, state, requestScope, c.req.raw.signal);
|
|
2229
2357
|
const response = handled instanceof Response ? handled : c.json(handled);
|
|
2230
2358
|
return streaming
|
|
2231
|
-
? responseWithRequestScopeHeaders(response, requestScope.snapshotHeaders())
|
|
2359
|
+
? responseWithRequestScopeHeaders(response, requestScope.snapshotHeaders(), true)
|
|
2232
2360
|
: response;
|
|
2233
2361
|
};
|
|
2234
2362
|
const response = streaming
|
package/dist/server/types.d.ts
CHANGED
|
@@ -115,6 +115,9 @@ export declare const AuthFlowRequestSchema: z.ZodObject<{
|
|
|
115
115
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
116
116
|
input: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
117
117
|
context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
118
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
119
|
+
egressLease: z.ZodOptional<z.ZodString>;
|
|
120
|
+
}, z.core.$strict>>;
|
|
118
121
|
connection: z.ZodOptional<z.ZodObject<{
|
|
119
122
|
id: z.ZodString;
|
|
120
123
|
mode: z.ZodEnum<{
|
|
@@ -133,6 +136,9 @@ export declare const AuthFlowRequestSchema: z.ZodObject<{
|
|
|
133
136
|
export declare const AuthFlowSuccessResponseSchema: z.ZodObject<{
|
|
134
137
|
data: z.ZodUnknown;
|
|
135
138
|
contextPatch: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodUnknown>>>;
|
|
139
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
140
|
+
egressLease: z.ZodOptional<z.ZodString>;
|
|
141
|
+
}, z.core.$strict>>;
|
|
136
142
|
}, z.core.$strip>;
|
|
137
143
|
export declare const AuthFlowErrorResponseSchema: z.ZodObject<{
|
|
138
144
|
error: z.ZodObject<{
|
package/dist/server/types.js
CHANGED
|
@@ -85,10 +85,24 @@ export const AuthFlowRequestSchema = z.object({
|
|
|
85
85
|
headers: z.record(z.string(), z.string()).optional(),
|
|
86
86
|
input: z.record(z.string(), z.unknown()).optional(),
|
|
87
87
|
context: z.record(z.string(), z.unknown()).optional(),
|
|
88
|
+
/** Opaque engine state. This is never projected into FlowContext or provider contextPatch. */
|
|
89
|
+
engine: z
|
|
90
|
+
.object({
|
|
91
|
+
egressLease: z.string().min(1).max(16_384).optional(),
|
|
92
|
+
})
|
|
93
|
+
.strict()
|
|
94
|
+
.optional(),
|
|
88
95
|
connection: OperationConnectionSchema.optional(),
|
|
89
96
|
});
|
|
90
97
|
export const AuthFlowSuccessResponseSchema = z.object({
|
|
91
98
|
data: z.unknown(),
|
|
92
99
|
contextPatch: z.record(z.string(), z.unknown().nullable()).optional(),
|
|
100
|
+
/** Opaque engine state to carry verbatim to the next auth turn. */
|
|
101
|
+
engine: z
|
|
102
|
+
.object({
|
|
103
|
+
egressLease: z.string().min(1).max(16_384).optional(),
|
|
104
|
+
})
|
|
105
|
+
.strict()
|
|
106
|
+
.optional(),
|
|
93
107
|
});
|
|
94
108
|
export const AuthFlowErrorResponseSchema = OperationErrorResponseSchema;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { StealthProfile, StealthProfileDescriptor, StealthProfileSelection } from "../types.js";
|
|
1
|
+
import type { StealthBrowser, StealthProfile, StealthProfileDescriptor, StealthProfileSelection } from "../types.js";
|
|
2
2
|
export declare const DEFAULT_STEALTH_BROWSER: "chrome";
|
|
3
3
|
export declare const DEFAULT_STEALTH_OS: "macos";
|
|
4
4
|
/** Internal detector used to keep version-pinned string failures actionable. */
|
|
@@ -6,4 +6,10 @@ export declare function getVersionPinnedStealthReplacement(name: string): string
|
|
|
6
6
|
/** Resolve omitted axes and validate that the resulting pair is supported. */
|
|
7
7
|
export declare function resolveStealthProfileSelection(selection: StealthProfileSelection | undefined, base?: StealthProfileDescriptor): StealthProfileDescriptor;
|
|
8
8
|
export declare function getStealthProfile(selection?: StealthProfileSelection): StealthProfile;
|
|
9
|
+
/**
|
|
10
|
+
* The transport owns the browser version (Chromium follows the pinned wreq-js build), so a
|
|
11
|
+
* resolver `clientProfile` such as `safari17_0` or `chrome_149` only has to name the same
|
|
12
|
+
* browser family as the stealth session it runs on.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolverClientProfileFamily(clientProfile: string): StealthBrowser | undefined;
|
|
9
15
|
export declare function listStealthProfiles(): StealthProfileDescriptor[];
|