@apifuse/provider-sdk 2.2.0-beta.55 → 2.2.0-beta.57

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.
@@ -6,10 +6,24 @@ export type {
6
6
  SmartproxyAllocatorBodyClass,
7
7
  } from "../config/loader.js";
8
8
  export type {
9
+ ProxyTelemetryHeaderPayload,
10
+ ProxyHash,
9
11
  ProxyTelemetryLogPayload,
10
12
  ProxyTelemetryResolvedPayload,
11
13
  ProxyTelemetryUnresolvedPayload,
12
14
  } from "../runtime/proxy-telemetry.js";
15
+ export {
16
+ RequestTelemetry,
17
+ closedEnum,
18
+ type ClosedEnum,
19
+ type GatewayIngestible,
20
+ type RequestTelemetryLogPayload,
21
+ type SpanIndex,
22
+ type TelemetryContributor,
23
+ type TelemetryKey,
24
+ type TenantNeutral,
25
+ } from "../runtime/request-telemetry.js";
26
+ export type { Span, TraceContext } from "../runtime/trace.js";
13
27
  export {
14
28
  createServerApp,
15
29
  createServerAppAsync,
@@ -72,6 +72,14 @@ import {
72
72
  ProxyTelemetryCollector,
73
73
  type ProxyTelemetryLogPayload,
74
74
  } from "../runtime/proxy-telemetry.js";
75
+ import {
76
+ closedEnum,
77
+ RequestTelemetry,
78
+ tenantOpaqueKeys,
79
+ type ClosedEnum,
80
+ type TenantNeutral,
81
+ type TenantOpaqueKeys,
82
+ } from "../runtime/request-telemetry.js";
75
83
  import type * as ResolverRuntimeModule from "../runtime/resolver.js";
76
84
  import {
77
85
  createUnsupportedResolverClient,
@@ -126,6 +134,7 @@ import type {
126
134
  OcrContext,
127
135
  ProviderErrorStatus,
128
136
  ProviderContext,
137
+ ProviderCacheResponseMeta,
129
138
  ProviderDefinition,
130
139
  ProviderFilesContext,
131
140
  ProviderProxyPolicy,
@@ -195,6 +204,28 @@ function providerErrorCode(error: unknown): string | undefined {
195
204
 
196
205
  const AUTH_FLOW_LOCALES = ["en", "ko", "ja"] as const;
197
206
  const retryResponseMeta = new WeakMap<ProviderContext, HttpRetrySummary>();
207
+ type RetryLastErrorCode =
208
+ // runtime/http.ts:178-179 preserves ambient cancellation.
209
+ | "transport_cancelled"
210
+ // runtime/http.ts:180-196 normalizes timeout aborts and timeout-shaped errors.
211
+ | "transport_timeout"
212
+ // runtime/http.ts:198-225 normalizes other native fetch failures.
213
+ | "transport_network_error"
214
+ // runtime/http.ts:119-126,763-771,829-837 creates upstream status errors.
215
+ | "upstream_http_error"
216
+ // runtime/proxy-retry-policy.ts:64-84 forwards other coded TransportErrors; the builder closes them.
217
+ | "other";
218
+ const RETRY_LAST_ERROR_CODES = [
219
+ "transport_cancelled",
220
+ "transport_timeout",
221
+ "transport_network_error",
222
+ "upstream_http_error",
223
+ "other",
224
+ ] as const satisfies readonly RetryLastErrorCode[];
225
+
226
+ function tenantRetryLastErrorCode(value: string): RetryLastErrorCode {
227
+ return RETRY_LAST_ERROR_CODES.find((candidate) => candidate === value) ?? "other";
228
+ }
198
229
  const STATEFUL_INTERNAL_OPERATIONS_ROUTE = "/__apifuse/stateful/operations";
199
230
  const STATEFUL_FORWARDING_SOURCE_POD_HEADER = "x-apifuse-stateful-source-pod";
200
231
  const DEFAULT_STATEFUL_FORWARDING_MAX_SKEW_MS = 5 * 60_000;
@@ -682,7 +713,7 @@ function providerSecretNames(provider: ProviderDefinition): string[] {
682
713
 
683
714
  type RequestScopeContext = {
684
715
  trace: RuntimeTraceContext;
685
- proxyTelemetry: ProxyTelemetryCollector;
716
+ telemetry: RequestTelemetry;
686
717
  };
687
718
 
688
719
  function createProviderContext(
@@ -702,7 +733,7 @@ function createProviderContext(
702
733
  const proxyClientOptions = {
703
734
  upstream: { proxy: provider.proxy },
704
735
  affinityKey: resolveProviderProxyAffinityKey(provider, request, operationId),
705
- telemetry: scope.proxyTelemetry,
736
+ telemetry: scope.telemetry.proxy,
706
737
  engineCredentials: engineProxyCredentials,
707
738
  };
708
739
  const resolverIdentityScope = resolveProviderResolverIdentityScope(
@@ -714,7 +745,7 @@ function createProviderContext(
714
745
  const stealthClientOptions = {
715
746
  upstream: proxyClientOptions.upstream,
716
747
  affinityKey: proxyClientOptions.affinityKey,
717
- telemetry: scope.proxyTelemetry,
748
+ telemetry: scope.telemetry.proxy,
718
749
  engineCredentials: engineProxyCredentials,
719
750
  ...(signal ? { signal } : {}),
720
751
  ...(provider.stealth ? { stealth: provider.stealth } : {}),
@@ -917,7 +948,7 @@ function createAuthFlowContext(
917
948
  const proxyClientOptions = {
918
949
  upstream: { proxy: provider.proxy },
919
950
  affinityKey: resolveAuthFlowProxyAffinityKey(provider, request),
920
- telemetry: scope.proxyTelemetry,
951
+ telemetry: scope.telemetry.proxy,
921
952
  engineCredentials: engineProxyCredentials,
922
953
  };
923
954
  const resolverIdentityScope = resolveProviderResolverIdentityScope(
@@ -928,7 +959,7 @@ function createAuthFlowContext(
928
959
  const stealthClientOptions = {
929
960
  upstream: proxyClientOptions.upstream,
930
961
  affinityKey: proxyClientOptions.affinityKey,
931
- telemetry: scope.proxyTelemetry,
962
+ telemetry: scope.telemetry.proxy,
932
963
  engineCredentials: engineProxyCredentials,
933
964
  ...(signal ? { signal } : {}),
934
965
  ...(provider.stealth ? { stealth: provider.stealth } : {}),
@@ -1614,7 +1645,7 @@ function logProviderError(
1614
1645
  status: number,
1615
1646
  cost: ProviderRequestCost,
1616
1647
  declaredErrorCode: OperationErrorCode | undefined,
1617
- proxyTelemetry: ProxyTelemetryCollector | undefined,
1648
+ telemetry: RequestTelemetry | undefined,
1618
1649
  observabilityDetails: ErrorObservabilityDetails,
1619
1650
  correlation: RequestCorrelationIds = {},
1620
1651
  ): void {
@@ -1637,7 +1668,7 @@ function logProviderError(
1637
1668
  typeof providerCode === "string" &&
1638
1669
  !SDK_OWNED_PROVIDER_ERROR_CODES.has(providerCode) &&
1639
1670
  declaredErrorCode === undefined;
1640
- const proxy = proxyTelemetry?.toLogPayload();
1671
+ const telemetryPayload = telemetry?.toLogPayload();
1641
1672
  const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
1642
1673
  // The logger is caller-supplied and may mutate the event synchronously.
1643
1674
  // Give it an independent snapshot so those mutations cannot corrupt the
@@ -1662,7 +1693,7 @@ function logProviderError(
1662
1693
  : {}),
1663
1694
  status,
1664
1695
  ...cost,
1665
- ...(proxy ? { proxy } : {}),
1696
+ ...(telemetryPayload ?? {}),
1666
1697
  code,
1667
1698
  errorClass,
1668
1699
  message,
@@ -1716,10 +1747,10 @@ function logProviderSuccess(
1716
1747
  requestId: string | undefined,
1717
1748
  status: number,
1718
1749
  cost: ProviderRequestCost,
1719
- proxyTelemetry?: ProxyTelemetryCollector,
1750
+ telemetry?: RequestTelemetry,
1720
1751
  correlation: RequestCorrelationIds = {},
1721
1752
  ): void {
1722
- const proxy = proxyTelemetry?.toLogPayload();
1753
+ const telemetryPayload = telemetry?.toLogPayload();
1723
1754
  const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
1724
1755
  emit({
1725
1756
  level: "info",
@@ -1738,7 +1769,7 @@ function logProviderSuccess(
1738
1769
  : {}),
1739
1770
  status,
1740
1771
  ...cost,
1741
- ...(proxy ? { proxy } : {}),
1772
+ ...(telemetryPayload ?? {}),
1742
1773
  });
1743
1774
  }
1744
1775
 
@@ -1834,7 +1865,6 @@ function createRequestScope(input: {
1834
1865
  }): RequestScope {
1835
1866
  const requestCost = startRequestCost();
1836
1867
  const traceConfig = resolveTraceConfigFromEnv();
1837
- const proxyTelemetry = new ProxyTelemetryCollector();
1838
1868
  const details = {
1839
1869
  route: input.route,
1840
1870
  requestId: input.requestId,
@@ -1857,6 +1887,9 @@ function createRequestScope(input: {
1857
1887
  ...(initialTraceId ? { traceId: initialTraceId } : {}),
1858
1888
  })
1859
1889
  : createTraceContext();
1890
+ const proxyCollector = new ProxyTelemetryCollector();
1891
+ const telemetry = new RequestTelemetry(trace);
1892
+ telemetry.register(proxyCollector);
1860
1893
  let rootRunner: <T>(fn: () => Promise<T>) => Promise<T> = (fn) => fn();
1861
1894
  let resolveRoot!: (outcome: RequestTerminalOutcome) => void;
1862
1895
  const rootTerminal = new Promise<RequestTerminalOutcome>((resolve) => {
@@ -1904,7 +1937,7 @@ function createRequestScope(input: {
1904
1937
  await Promise.all(streamCleanups.map(runCleanupEntry));
1905
1938
  };
1906
1939
  const headerSnapshot = (error?: unknown): RequestScopeFinishResult => {
1907
- const providerTelemetryHeader = proxyTelemetry.toHeaderValue();
1940
+ const providerTelemetryHeader = telemetry.toHeaderValue();
1908
1941
  const declaredErrorCode = error === undefined ? undefined : input.declaredErrorCode?.(error);
1909
1942
  const errorObservability =
1910
1943
  error === undefined ? undefined : errorObservabilityDetails(error, declaredErrorCode);
@@ -1933,7 +1966,7 @@ function createRequestScope(input: {
1933
1966
 
1934
1967
  const scope: RequestScope = {
1935
1968
  trace,
1936
- proxyTelemetry,
1969
+ telemetry,
1937
1970
  enrich(enrichment): void {
1938
1971
  if (terminalOutcome) return;
1939
1972
  if (enrichment.route !== undefined) details.route = enrichment.route;
@@ -2004,7 +2037,7 @@ function createRequestScope(input: {
2004
2037
  details.requestId,
2005
2038
  status,
2006
2039
  cost,
2007
- proxyTelemetry,
2040
+ telemetry,
2008
2041
  details.correlation,
2009
2042
  );
2010
2043
  } else {
@@ -2018,7 +2051,7 @@ function createRequestScope(input: {
2018
2051
  status,
2019
2052
  cost,
2020
2053
  declaredErrorCode,
2021
- proxyTelemetry,
2054
+ telemetry,
2022
2055
  finishedResult.errorObservability as ErrorObservabilityDetails,
2023
2056
  details.correlation,
2024
2057
  );
@@ -2108,19 +2141,58 @@ function toJsonSuccessResponse(
2108
2141
 
2109
2142
  const cacheMeta = ctx && "cache" in ctx ? ctx.cache.responseMeta() : undefined;
2110
2143
  const retryMeta = ctx ? retryResponseMeta.get(ctx) : undefined;
2144
+ type TenantCacheMeta = {
2145
+ hit: boolean;
2146
+ stale: boolean;
2147
+ keys: TenantOpaqueKeys;
2148
+ source?: ClosedEnum<NonNullable<ProviderCacheResponseMeta["source"]>>;
2149
+ };
2150
+ type TenantRetryMeta = {
2151
+ attempts: number;
2152
+ retries: number;
2153
+ preset?: ClosedEnum<NonNullable<HttpRetrySummary["preset"]>>;
2154
+ transport: ClosedEnum<HttpRetrySummary["transport"]>;
2155
+ lastErrorCode?: ClosedEnum<RetryLastErrorCode>;
2156
+ lastStatus?: number;
2157
+ };
2158
+ const cache: TenantNeutral<TenantCacheMeta> | undefined = cacheMeta
2159
+ ? {
2160
+ hit: cacheMeta.hit,
2161
+ stale: cacheMeta.stale,
2162
+ // TODO(owner): keep or remove implementation-shaped cache keys from tenant meta.
2163
+ keys: tenantOpaqueKeys(cacheMeta.keys),
2164
+ ...(cacheMeta.source ? { source: closedEnum(cacheMeta.source) } : {}),
2165
+ }
2166
+ : undefined;
2167
+ const retry: TenantNeutral<TenantRetryMeta> | undefined = retryMeta
2168
+ ? {
2169
+ attempts: retryMeta.attempts,
2170
+ retries: retryMeta.retries,
2171
+ ...(retryMeta.preset ? { preset: closedEnum(retryMeta.preset) } : {}),
2172
+ transport: closedEnum(retryMeta.transport),
2173
+ ...(retryMeta.lastErrorCode
2174
+ ? {
2175
+ lastErrorCode: closedEnum(tenantRetryLastErrorCode(retryMeta.lastErrorCode)),
2176
+ }
2177
+ : {}),
2178
+ ...(retryMeta.lastStatus ? { lastStatus: retryMeta.lastStatus } : {}),
2179
+ }
2180
+ : undefined;
2111
2181
  const meta =
2112
2182
  cacheMeta || retryMeta
2113
2183
  ? {
2114
- ...(cacheMeta
2184
+ ...(cache
2115
2185
  ? {
2116
- cached: cacheMeta.hit,
2117
- stale: cacheMeta.stale,
2118
- cache: cacheMeta,
2186
+ cached: cache.hit,
2187
+ stale: cache.stale,
2188
+ cache,
2119
2189
  }
2120
2190
  : {}),
2121
- ...(retryMeta ? { retry: retryMeta } : {}),
2191
+ ...(retry ? { retry } : {}),
2122
2192
  }
2123
2193
  : undefined;
2194
+ const _neutralMeta: TenantNeutral<NonNullable<typeof meta>> | undefined = meta;
2195
+ void _neutralMeta;
2124
2196
  return {
2125
2197
  data: result,
2126
2198
  ...(meta ? { meta } : {}),