@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 +4 -0
- package/dist/declaration-validation.d.ts +7 -0
- package/dist/declaration-validation.js +22 -0
- package/dist/define.d.ts +2 -2
- package/dist/define.js +32 -22
- package/dist/index.d.ts +2 -1
- package/dist/runtime/executor.d.ts +2 -2
- package/dist/runtime/executor.js +3 -1
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +41 -1
- package/dist/runtime/proxy-telemetry.js +59 -56
- package/dist/server/index.d.ts +2 -0
- package/dist/server/serve-implementation.d.ts +2 -0
- package/dist/server/serve-implementation.js +81 -30
- package/package.json +1 -1
- package/src/declaration-validation.ts +41 -4
- package/src/define.ts +52 -38
- package/src/index.ts +4 -0
- package/src/runtime/executor.ts +11 -6
- package/src/runtime/instrumentation.ts +5 -2
- package/src/runtime/proxy-telemetry.ts +100 -99
- package/src/server/index.ts +8 -0
- package/src/server/serve-implementation.ts +90 -8
package/CHANGELOG.md
CHANGED
|
@@ -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,
|
|
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 {
|
|
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
|
|
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
|
|
1961
|
-
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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:
|
|
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>;
|
package/dist/runtime/executor.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -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";
|