@apifuse/provider-sdk 2.2.0-beta.38 → 2.2.0-beta.39

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @apifuse/provider-sdk Changelog
2
2
 
3
+ ## 2.2.0-beta.39
4
+
5
+ - Release candidate for main commit ecbe349c44e15c873b7c58b42e14610db029eb5f.
6
+
3
7
  ## 2.2.0-beta.38
4
8
 
5
9
  - Release candidate for main commit 448775077dbc9ab907209f1feee4e6e4e5ef4283.
@@ -23,3 +23,10 @@ export type DeclarationViolation = {
23
23
  export declare function declarationInvalidError(violations: readonly DeclarationViolation[]): ProviderError;
24
24
  /** Enforces declaration rules whose runtime behavior would otherwise fail open. */
25
25
  export declare function validateFailClosedDeclaration(provider: ProviderDefinition): void;
26
+ type ProviderDeclarationRulesInput = Pick<ProviderDefinition, "healthJourneys" | "proxy">;
27
+ type OperationDeclarationRulesInput = Pick<ProviderDefinition, "operations">;
28
+ /** Enforces fail-closed rules that only depend on the provider declaration. */
29
+ export declare function validateFailClosedProviderDeclaration(provider: ProviderDeclarationRulesInput): void;
30
+ /** Enforces fail-closed rules that depend on the operation implementation. */
31
+ export declare function validateFailClosedOperationDeclaration(provider: OperationDeclarationRulesInput): void;
32
+ export {};
@@ -34,6 +34,28 @@ export function validateFailClosedDeclaration(provider) {
34
34
  if (violations.length > 0)
35
35
  throw declarationInvalidError(violations);
36
36
  }
37
+ /** Enforces fail-closed rules that only depend on the provider declaration. */
38
+ export function validateFailClosedProviderDeclaration(provider) {
39
+ const violations = [];
40
+ collectProviderDeclarationViolations(provider, violations);
41
+ if (violations.length > 0)
42
+ throw declarationInvalidError(violations);
43
+ }
44
+ /** Enforces fail-closed rules that depend on the operation implementation. */
45
+ export function validateFailClosedOperationDeclaration(provider) {
46
+ const violations = [];
47
+ collectOperationDeclarationViolations(provider, violations);
48
+ if (violations.length > 0)
49
+ throw declarationInvalidError(violations);
50
+ }
51
+ function collectProviderDeclarationViolations(provider, violations) {
52
+ validateHealthDeclaration(provider, violations);
53
+ validateProxyDeclaration(provider, violations);
54
+ }
55
+ function collectOperationDeclarationViolations(provider, violations) {
56
+ validateSchemaDeclaration(provider, violations);
57
+ validateOperationDeclaration(provider, violations);
58
+ }
37
59
  function validateHealthDeclaration(provider, violations) {
38
60
  for (const [index, journey] of (provider.healthJourneys ?? []).entries()) {
39
61
  if (!journey || typeof journey !== "object")
package/dist/define.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AuthConfig, BrowserEngine, ContextDeclaration, CredentialDeclaration, HealthJourneyDefinition, HealthJourneySchedule, HealthScheduleRandomization, InferSchemaOutput, NativeProviderConfig, OperationDefinition, OperationHandlerResult, OperationHttpStreamTransport, OperationSseTransport, OperationWebSocketTransport, ProviderAccessConfig, ProviderDefinition, ProviderContext, ProviderContextFor, ProviderOcrConfig, ProviderDeploymentOverrides, ProviderHealthMonitorConfig, ProviderProxyConfig, ProviderPublicProfile, ProviderResolverConfig, ProviderReviewed, ProviderSecretDeclaration, ProviderStreamEvent, ProviderSttConfig, SchemaLike, SmsOtpMatcherDefinition, StealthPlatform } from "./types.js";
1
+ import type { AuthConfig, BrowserEngine, ContextDeclaration, CredentialDeclaration, HealthJourneyDefinition, HealthJourneySchedule, HealthScheduleRandomization, InferSchemaOutput, NativeProviderConfig, OperationDefinition, OperationHandlerResult, OperationHttpStreamTransport, OperationSseTransport, OperationWebSocketTransport, ProviderAccessConfig, ProviderContext, ProviderContextFor, ProviderDefinition, ProviderDeploymentOverrides, ProviderHealthMonitorConfig, ProviderOcrConfig, ProviderProxyConfig, ProviderPublicProfile, ProviderResolverConfig, ProviderReviewed, ProviderSecretDeclaration, ProviderStreamEvent, ProviderSttConfig, SchemaLike, SmsOtpMatcherDefinition, StealthPlatform } from "./types.js";
2
2
  type ProviderImplementationSourceAccess = "official_api" | "private_api" | "browser_flow" | "hybrid";
3
3
  type ProviderImplementationCredentialStrategy = "apifuse_managed" | "workspace_secret" | "user_oauth" | "user_session" | "none";
4
4
  interface ProviderImplementationProfile {
@@ -125,7 +125,7 @@ export declare function defineHealthJourney(config: HealthJourneyDefinition): He
125
125
  /** The second authoring phase for a declaration established by defineProvider. */
126
126
  export type ProviderBuilder<TDeclaration extends ProviderDeclaration> = <TOperations extends Record<string, ProviderOperation>>(implementation: {
127
127
  operations: OperationMapConfig<TOperations, ProviderContextFor<TDeclaration>>;
128
- }) => ProviderDefinition & {
128
+ }) => Omit<ProviderDefinition, "operations"> & {
129
129
  operations: OperationMapConfig<TOperations, ProviderContextFor<TDeclaration>>;
130
130
  };
131
131
  /** Extract the declaration-derived operation context from a provider builder. */
package/dist/define.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import ms from "ms";
2
- import { validateFailClosedDeclaration } from "./declaration-validation.js";
2
+ import { validateFailClosedOperationDeclaration, validateFailClosedProviderDeclaration, } from "./declaration-validation.js";
3
3
  import { SDK_RUNTIME_OWNED_ERROR_CODES } from "./error-resolution.js";
4
4
  import { ProviderError, ValidationError } from "./errors.js";
5
5
  import { NativeEgressPolicyValidationError, validateNativeProviderConfig, } from "./native-egress-policy.js";
@@ -553,13 +553,12 @@ function validateProxiedOAuthAuth(auth, providerId) {
553
553
  validateProxiedOAuthParams(config.authorizeParams, "authorizeParams", providerId);
554
554
  validateProxiedOAuthParams(config.tokenParams, "tokenParams", providerId);
555
555
  }
556
- function validateProviderShape(config) {
556
+ function validateProviderDeclarationShape(config) {
557
557
  assertObjectConfig(config);
558
558
  assertRequiredField(config, "id");
559
559
  assertRequiredField(config, "version", String(config.id));
560
560
  assertRequiredField(config, "runtime", String(config.id));
561
561
  assertRequiredField(config, "meta", String(config.id));
562
- assertRequiredField(config, "operations", String(config.id));
563
562
  if (typeof config.runtime === "string")
564
563
  assertLiteralField(config.runtime, "runtime", VALID_RUNTIMES, String(config.id));
565
564
  if (config.native !== undefined && config.runtime === "browser") {
@@ -629,6 +628,10 @@ function validateProviderShape(config) {
629
628
  }
630
629
  }
631
630
  }
631
+ function validateProviderImplementationShape(config) {
632
+ const configRecord = config;
633
+ assertRequiredField(configRecord, "operations", String(config.id));
634
+ }
632
635
  function validateProviderProxy(config) {
633
636
  const proxy = config.proxy;
634
637
  if (proxy === undefined || typeof proxy === "boolean") {
@@ -1951,38 +1954,24 @@ function validateProviderDeployment(providerId, deployment) {
1951
1954
  }
1952
1955
  /** Establish a provider declaration before its operations are contextually typed. */
1953
1956
  export function defineProvider(declaration) {
1957
+ validateProviderDeclaration(declaration);
1954
1958
  const buildProvider = (implementation) => finalizeProvider({
1955
1959
  ...declaration,
1956
1960
  ...implementation,
1957
1961
  });
1958
1962
  return buildProvider;
1959
1963
  }
1960
- function finalizeProvider(config) {
1961
- validateProviderShape(config);
1962
- const operations = resolveOperationFixtureRequests(config.operations);
1964
+ function validateProviderDeclaration(config) {
1965
+ validateProviderDeclarationShape(config);
1963
1966
  if (!CONNECTOR_ID_REGEX.test(config.id))
1964
1967
  throw new ProviderError(`Invalid provider id: "${config.id}"`, {
1965
1968
  fix: 'Use lowercase alphanumeric with dashes, e.g., "korea-air-quality"',
1966
1969
  });
1967
- if (Object.keys(config.operations).length === 0)
1968
- throw new ProviderError(`Provider "${config.id}" must define at least one operation`, {
1969
- fix: "Add at least one operation to the operations object",
1970
- });
1971
- validateOperationIds(config.id, config.operations);
1972
- validateOperationAnnotations(config.id, config.operations);
1973
- validateOperationObservability(config.id, config.operations);
1974
- validateOperationErrorCodes(config.id, config.operations);
1975
- validateOperationTransports(config.id, config.operations);
1976
- validateOperationContracts(config.id, config.operations);
1977
- validateToolRouterMetadata(config.id, config.operations);
1978
- const journeyCoveredOperations = validateHealthJourneys(config.id, config.operations, config.healthJourneys);
1979
- validateOperationHealthChecks(config.id, config.operations, journeyCoveredOperations);
1980
1970
  if (config.healthMonitor !== undefined && config.healthProbe !== undefined)
1981
1971
  throw new ValidationError(`Provider "${config.id}" declares both healthMonitor and healthProbe. They are aliases; declare exactly one.`, {
1982
1972
  fix: "Keep healthProbe (the new name) and delete the healthMonitor block.",
1983
1973
  });
1984
1974
  validateProviderHealthMonitor(config.id, config.healthProbe ?? config.healthMonitor, config.healthProbe !== undefined ? "healthProbe" : "healthMonitor");
1985
- validateOperationFixtures(config.id, operations);
1986
1975
  validateProviderDeployment(config.id, config.deployment);
1987
1976
  try {
1988
1977
  validateNativeProviderConfig(config.native);
@@ -2002,6 +1991,25 @@ function finalizeProvider(config) {
2002
1991
  });
2003
1992
  if (config.browser && config.runtime !== "browser")
2004
1993
  throw new ProviderError(`Provider "${config.id}" cannot define browser config unless runtime is "browser"`, { fix: 'Set runtime: "browser" or remove the browser config' });
1994
+ validateFailClosedProviderDeclaration(config);
1995
+ }
1996
+ function finalizeProvider(config) {
1997
+ validateProviderImplementationShape(config);
1998
+ const operations = resolveOperationFixtureRequests(config.operations);
1999
+ if (Object.keys(config.operations).length === 0)
2000
+ throw new ProviderError(`Provider "${config.id}" must define at least one operation`, {
2001
+ fix: "Add at least one operation to the operations object",
2002
+ });
2003
+ validateOperationIds(config.id, config.operations);
2004
+ validateOperationAnnotations(config.id, config.operations);
2005
+ validateOperationObservability(config.id, config.operations);
2006
+ validateOperationErrorCodes(config.id, config.operations);
2007
+ validateOperationTransports(config.id, config.operations);
2008
+ validateOperationContracts(config.id, config.operations);
2009
+ validateToolRouterMetadata(config.id, config.operations);
2010
+ const journeyCoveredOperations = validateHealthJourneys(config.id, config.operations, config.healthJourneys);
2011
+ validateOperationHealthChecks(config.id, config.operations, journeyCoveredOperations);
2012
+ validateOperationFixtures(config.id, operations);
2005
2013
  const provider = {
2006
2014
  id: config.id,
2007
2015
  version: config.version,
@@ -2024,13 +2032,15 @@ function finalizeProvider(config) {
2024
2032
  credential: config.credential,
2025
2033
  context: config.context,
2026
2034
  meta: config.meta,
2027
- operations: operations,
2035
+ operations,
2028
2036
  // Transitional healthMonitor → healthProbe alias: mirror whichever field
2029
2037
  // was declared onto both so old and new consumers keep working.
2030
2038
  healthMonitor: config.healthMonitor ?? config.healthProbe,
2031
2039
  healthProbe: config.healthProbe ?? config.healthMonitor,
2032
2040
  healthJourneys: config.healthJourneys,
2033
2041
  };
2034
- validateFailClosedDeclaration(provider);
2042
+ // Declaration validation never invokes handlers, so their declaration-bound
2043
+ // context parameter is irrelevant to the runtime ProviderDefinition shape.
2044
+ validateFailClosedOperationDeclaration(provider);
2035
2045
  return provider;
2036
2046
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./auth.js";
2
2
  export * from "./ceremonies/index.js";
3
3
  export * from "./choice-token.js";
4
- export type { ApiFuseConfig, BrowserConfig, ProxyProtocol, ProxyResolutionOptions, ProxyResolutionSource, ProxyVendorName, ResolvedProxyConfig, SessionConfig, } from "./config/loader.js";
4
+ export type { ApiFuseConfig, BrowserConfig, ProxyCacheStatus, ProxyProtocol, ProxyResolutionOptions, ProxyResolutionSource, ProxyUserAgentSource, ProxyVendorName, ResolvedProxyConfig, SessionConfig, SmartproxyAllocatorBodyClass, } from "./config/loader.js";
5
5
  export { defineConfig, loadApiFuseConfig, resolveProxy } from "./config/loader.js";
6
6
  export { canonicalJson, digestProviderContract, extractProviderContract, type JsonPrimitive, type JsonValue, PROVIDER_CONTRACT_SCHEMA_VERSION, type ProviderContractOperation, type ProviderContractSnapshot, } from "./contract.js";
7
7
  export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, type AuthStartNoInputGuard, type ProviderBuilder, type ProviderContextOf, type ProviderDeclaration, } from "./define.js";
@@ -31,6 +31,7 @@ export { generateInsights } from "./runtime/insights.js";
31
31
  export { type InstrumentationOptions, type InstrumentedProviderContext, wrapWithInstrumentation, } from "./runtime/instrumentation.js";
32
32
  export type { PrevalidateResult } from "./runtime/prevalidate.js";
33
33
  export { getProviderBaseUrl } from "./runtime/provider.js";
34
+ export type { ProxyTelemetryLogPayload } from "./runtime/proxy-telemetry.js";
34
35
  export { APIFUSE__CDP_POOL__URL, APIFUSE__RESOLVER__2CAPTCHA__API_KEY, APIFUSE__RESOLVER__CAPMONSTER__API_KEY, APIFUSE__RESOLVER__CAPSOLVER__API_KEY, APIFUSE__RESOLVER__TIMEOUT_MS, DEFAULT_RESOLVER_TIMEOUT_MS, } from "./runtime/resolver-config.js";
35
36
  export { createUnsupportedResolverClient } from "./runtime/resolver-shared.js";
36
37
  export type { ResolverRuntimeOptions } from "./runtime/resolver.js";
@@ -1,4 +1,4 @@
1
- import type { ProviderContext, ProviderDefinition } from "../types.js";
1
+ import type { ProviderDefinition } from "../types.js";
2
2
  export declare function isStreamingOperation(provider: ProviderDefinition, operationId: string): boolean;
3
3
  /**
4
4
  * Execute a provider operation by calling its handler.
@@ -11,6 +11,6 @@ export declare function isStreamingOperation(provider: ProviderDefinition, opera
11
11
  *
12
12
  * @see openspec/provider-sdk/03-sdk-core.md §3.6
13
13
  */
14
- export declare function executeOperation(provider: ProviderDefinition, operationId: string, ctx: ProviderContext, input: unknown, _options?: {
14
+ export declare function executeOperation<const TProvider extends ProviderDefinition, const TOperationId extends keyof TProvider["operations"] & string>(provider: TProvider, operationId: TOperationId, ctx: NoInfer<Parameters<TProvider["operations"][TOperationId]["handler"]>[0]>, input: unknown, _options?: {
15
15
  skipAuth?: boolean;
16
16
  }): Promise<unknown>;
@@ -30,7 +30,9 @@ export async function executeOperation(provider, operationId, ctx, input, _optio
30
30
  // handler, so every invocation path (serve /v1, self-test probes, perf,
31
31
  // record) fails with the same structured MISSING_SECRET error instead of a
32
32
  // handler-specific crash. Providers must not re-check presence locally.
33
- assertRequiredSecretsPresent(provider, ctx.env);
33
+ if (provider.secrets?.some((secret) => secret.required === true)) {
34
+ assertRequiredSecretsPresent(provider, "env" in ctx ? ctx.env : { get: () => undefined });
35
+ }
34
36
  const validatedInput = await parseSchema(operation.input, input, `operations.${operationId}.input`);
35
37
  const execute = () => ctx.trace.span(`handler:${operationId}`, () => Promise.resolve(operation.handler(ctx, validatedInput)));
36
38
  let result;
@@ -2,7 +2,7 @@ import type { ProviderContext } from "../types.js";
2
2
  import { type CreateTraceContextOptions, type TraceContext } from "./trace.js";
3
3
  export interface InstrumentationOptions extends CreateTraceContextOptions {
4
4
  }
5
- export type InstrumentedProviderContext<T extends ProviderContext> = Omit<T, "trace"> & {
5
+ export type InstrumentedProviderContext<T extends Pick<ProviderContext, "trace">> = Omit<T, "trace"> & {
6
6
  trace: TraceContext;
7
7
  };
8
- export declare function wrapWithInstrumentation<T extends ProviderContext>(ctx: T, options?: InstrumentationOptions): InstrumentedProviderContext<T>;
8
+ export declare function wrapWithInstrumentation<T extends Pick<ProviderContext, "trace">>(ctx: T, options?: InstrumentationOptions): InstrumentedProviderContext<T>;
@@ -1,9 +1,49 @@
1
- import type { ProxyAttemptTelemetryEvent, ProxyResolutionTelemetryEvent, ProxyTelemetrySink, ProxyVendorFailoverTelemetryEvent } from "../config/loader.js";
1
+ import type { ProxyAttemptTelemetryEvent, ProxyCacheStatus, ProxyProtocol, ProxyResolutionTelemetryEvent, ProxyTelemetrySink, ProxyUserAgentSource, ProxyVendorFailoverTelemetryEvent, ProxyVendorName, SmartproxyAllocatorBodyClass } from "../config/loader.js";
2
2
  export declare const PROVIDER_TELEMETRY_HEADER = "X-ApiFuse-Provider-Telemetry";
3
+ export type ProxyTelemetryLogPayload = {
4
+ provider: ProxyVendorName;
5
+ userAgentSource?: ProxyUserAgentSource;
6
+ protocol?: ProxyProtocol;
7
+ cacheStatus: ProxyCacheStatus;
8
+ cacheHit: boolean;
9
+ resolutionMs: number;
10
+ allocatorMs?: number;
11
+ allocatorStatus?: number;
12
+ allocatorBodyClass?: SmartproxyAllocatorBodyClass;
13
+ allocatorAttempts?: number;
14
+ lockWaitMs?: number;
15
+ redisReadMs?: number;
16
+ redisWriteMs?: number;
17
+ poolAgeMs?: number;
18
+ poolExpiresInMs?: number;
19
+ attempts: number;
20
+ refreshes?: number;
21
+ attemptSamples?: {
22
+ n: number;
23
+ a: number;
24
+ i?: number;
25
+ h?: string;
26
+ o: ProxyAttemptTelemetryEvent["outcome"];
27
+ c?: string;
28
+ s?: number;
29
+ d?: number;
30
+ }[];
31
+ /** Distinct vendors attempted across the resolution chain, in order seen. */
32
+ vendors?: ProxyVendorName[];
33
+ /** Cross-vendor failover events (bounded). */
34
+ failovers?: {
35
+ v: ProxyVendorName;
36
+ nx?: ProxyVendorName;
37
+ p: ProxyVendorFailoverTelemetryEvent["phase"];
38
+ r: ProxyVendorFailoverTelemetryEvent["reason"];
39
+ a?: number;
40
+ }[];
41
+ };
3
42
  export declare class ProxyTelemetryCollector implements ProxyTelemetrySink {
4
43
  #private;
5
44
  recordProxyResolution(event: ProxyResolutionTelemetryEvent): void;
6
45
  recordProxyVendorFailover(event: ProxyVendorFailoverTelemetryEvent): void;
7
46
  recordProxyAttempt(event: ProxyAttemptTelemetryEvent): void;
47
+ toLogPayload(): ProxyTelemetryLogPayload | undefined;
8
48
  toHeaderValue(): string | undefined;
9
49
  }
@@ -86,7 +86,7 @@ export class ProxyTelemetryCollector {
86
86
  : { durationMs: Math.max(0, Math.floor(event.durationMs)) }),
87
87
  });
88
88
  }
89
- toHeaderValue() {
89
+ toLogPayload() {
90
90
  const [first, ...rest] = this.#events;
91
91
  if (!first)
92
92
  return undefined;
@@ -116,62 +116,65 @@ export class ProxyTelemetryCollector {
116
116
  attempts: acc.attempts + event.attempts,
117
117
  refreshes: sumOptional(acc.refreshes, event.refreshes),
118
118
  }), first);
119
- const payload = {
120
- v: 1,
121
- proxy: {
122
- provider: serving.provider,
123
- ...(aggregate.userAgentSource ? { userAgentSource: aggregate.userAgentSource } : {}),
124
- ...(serving.protocol ? { protocol: serving.protocol } : {}),
125
- cacheStatus: aggregate.cacheStatus,
126
- cacheHit: aggregate.cacheHit,
127
- resolutionMs: aggregate.resolutionMs,
128
- ...(aggregate.allocatorMs !== undefined ? { allocatorMs: aggregate.allocatorMs } : {}),
129
- ...(aggregate.allocatorStatus !== undefined
130
- ? { allocatorStatus: aggregate.allocatorStatus }
131
- : {}),
132
- ...(aggregate.allocatorBodyClass !== undefined
133
- ? { allocatorBodyClass: aggregate.allocatorBodyClass }
134
- : {}),
135
- ...(aggregate.allocatorAttempts !== undefined
136
- ? { allocatorAttempts: aggregate.allocatorAttempts }
137
- : {}),
138
- ...(aggregate.lockWaitMs !== undefined ? { lockWaitMs: aggregate.lockWaitMs } : {}),
139
- ...(aggregate.redisReadMs !== undefined ? { redisReadMs: aggregate.redisReadMs } : {}),
140
- ...(aggregate.redisWriteMs !== undefined ? { redisWriteMs: aggregate.redisWriteMs } : {}),
141
- ...(aggregate.poolAgeMs !== undefined ? { poolAgeMs: aggregate.poolAgeMs } : {}),
142
- ...(aggregate.poolExpiresInMs !== undefined
143
- ? { poolExpiresInMs: aggregate.poolExpiresInMs }
144
- : {}),
145
- attempts: aggregate.attempts,
146
- ...(aggregate.refreshes !== undefined ? { refreshes: aggregate.refreshes } : {}),
147
- ...(this.#attempts.length > 0
148
- ? {
149
- attemptSamples: this.#attempts.map((attempt, index) => ({
150
- n: index + 1,
151
- a: attempt.attempt,
152
- ...(attempt.poolIndex === undefined ? {} : { i: attempt.poolIndex }),
153
- ...(attempt.proxyHash ? { h: attempt.proxyHash } : {}),
154
- o: attempt.outcome,
155
- ...(attempt.errorCode ? { c: attempt.errorCode } : {}),
156
- ...(attempt.status === undefined ? {} : { s: attempt.status }),
157
- ...(attempt.durationMs === undefined ? {} : { d: attempt.durationMs }),
158
- })),
159
- }
160
- : {}),
161
- ...(vendors.length > 1 ? { vendors } : {}),
162
- ...(this.#failovers.length > 0
163
- ? {
164
- failovers: this.#failovers.map((failover) => ({
165
- v: failover.vendor,
166
- ...(failover.nextVendor ? { nx: failover.nextVendor } : {}),
167
- p: failover.phase,
168
- r: failover.reason,
169
- ...(failover.attempt === undefined ? {} : { a: failover.attempt }),
170
- })),
171
- }
172
- : {}),
173
- },
119
+ return {
120
+ provider: serving.provider,
121
+ ...(aggregate.userAgentSource ? { userAgentSource: aggregate.userAgentSource } : {}),
122
+ ...(serving.protocol ? { protocol: serving.protocol } : {}),
123
+ cacheStatus: aggregate.cacheStatus,
124
+ cacheHit: aggregate.cacheHit,
125
+ resolutionMs: aggregate.resolutionMs,
126
+ ...(aggregate.allocatorMs !== undefined ? { allocatorMs: aggregate.allocatorMs } : {}),
127
+ ...(aggregate.allocatorStatus !== undefined
128
+ ? { allocatorStatus: aggregate.allocatorStatus }
129
+ : {}),
130
+ ...(aggregate.allocatorBodyClass !== undefined
131
+ ? { allocatorBodyClass: aggregate.allocatorBodyClass }
132
+ : {}),
133
+ ...(aggregate.allocatorAttempts !== undefined
134
+ ? { allocatorAttempts: aggregate.allocatorAttempts }
135
+ : {}),
136
+ ...(aggregate.lockWaitMs !== undefined ? { lockWaitMs: aggregate.lockWaitMs } : {}),
137
+ ...(aggregate.redisReadMs !== undefined ? { redisReadMs: aggregate.redisReadMs } : {}),
138
+ ...(aggregate.redisWriteMs !== undefined ? { redisWriteMs: aggregate.redisWriteMs } : {}),
139
+ ...(aggregate.poolAgeMs !== undefined ? { poolAgeMs: aggregate.poolAgeMs } : {}),
140
+ ...(aggregate.poolExpiresInMs !== undefined
141
+ ? { poolExpiresInMs: aggregate.poolExpiresInMs }
142
+ : {}),
143
+ attempts: aggregate.attempts,
144
+ ...(aggregate.refreshes !== undefined ? { refreshes: aggregate.refreshes } : {}),
145
+ ...(this.#attempts.length > 0
146
+ ? {
147
+ attemptSamples: this.#attempts.map((attempt, index) => ({
148
+ n: index + 1,
149
+ a: attempt.attempt,
150
+ ...(attempt.poolIndex === undefined ? {} : { i: attempt.poolIndex }),
151
+ ...(attempt.proxyHash ? { h: attempt.proxyHash } : {}),
152
+ o: attempt.outcome,
153
+ ...(attempt.errorCode ? { c: attempt.errorCode } : {}),
154
+ ...(attempt.status === undefined ? {} : { s: attempt.status }),
155
+ ...(attempt.durationMs === undefined ? {} : { d: attempt.durationMs }),
156
+ })),
157
+ }
158
+ : {}),
159
+ ...(vendors.length > 1 ? { vendors } : {}),
160
+ ...(this.#failovers.length > 0
161
+ ? {
162
+ failovers: this.#failovers.map((failover) => ({
163
+ v: failover.vendor,
164
+ ...(failover.nextVendor ? { nx: failover.nextVendor } : {}),
165
+ p: failover.phase,
166
+ r: failover.reason,
167
+ ...(failover.attempt === undefined ? {} : { a: failover.attempt }),
168
+ })),
169
+ }
170
+ : {}),
174
171
  };
172
+ }
173
+ toHeaderValue() {
174
+ const proxy = this.toLogPayload();
175
+ if (!proxy)
176
+ return undefined;
177
+ const payload = { v: 1, proxy };
175
178
  const encoded = encodeBase64Url(JSON.stringify(payload));
176
179
  if (encoded.length > MAX_HEADER_BYTES)
177
180
  return undefined;
@@ -1,3 +1,5 @@
1
+ export type { ProxyCacheStatus, ProxyProtocol, ProxyUserAgentSource, ProxyVendorName, SmartproxyAllocatorBodyClass, } from "../config/loader.js";
2
+ export type { ProxyTelemetryLogPayload } from "../runtime/proxy-telemetry.js";
1
3
  export { createServerApp, createServerAppAsync, ERROR_OBSERVABILITY_HEADER, type ErrorObservabilityDetails, type ProviderServerCloseOptions, type ProviderServerHandle, type ProviderServerLogEvent, type ProviderServerLogger, type ProviderServerOperationExecutor, type ProviderServerOperationExecutorInput, type ProviderServerOptions, type ProviderServerStatefulForwardEnvelope, type ServeOptions, serve, } from "./serve.js";
2
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, type SelfTestAppOptions, type SelfTestAuthFlowInvoke, type SelfTestAuthFlowRoute, type SelfTestCaseResult, type SelfTestCaseStatus, type SelfTestOperationInvoke, type SelfTestRequest, SelfTestRequestSchema, type SelfTestResponse, } from "./self-test.js";
3
5
  export { type InputDateTokenCalendar, resolveHealthCheckInputDateTokens, } from "./self-test-input-tokens.js";
@@ -1,6 +1,7 @@
1
1
  import { Hono } from "hono";
2
2
  import { z } from "zod";
3
3
  import { type ProviderErrorCategory } from "../observability.js";
4
+ import { type ProxyTelemetryLogPayload } from "../runtime/proxy-telemetry.js";
4
5
  import type { OcrContext, ProviderContext, ProviderDefinition, ProviderRuntimeState, ResolverContext, SttContext } from "../types.js";
5
6
  import type { SelfTestCancellationLogEvent } from "./self-test.js";
6
7
  import { type AuthFlowRequest, type OperationRequest } from "./types.js";
@@ -76,6 +77,7 @@ type ProviderServerLogEventBase = ProviderRequestCost & {
76
77
  route: string;
77
78
  requestId?: string;
78
79
  status: number;
80
+ proxy?: ProxyTelemetryLogPayload;
79
81
  };
80
82
  export type ProviderServerLogEvent = (ProviderServerLogEventBase & {
81
83
  level: "info";