@apifuse/provider-sdk 2.2.0-beta.55 → 2.2.0-beta.56
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/bin/apifuse-pack-types.ts +121 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/runtime/proxy-telemetry.d.ts +53 -2
- package/dist/runtime/proxy-telemetry.js +106 -65
- package/dist/runtime/request-telemetry.d.ts +70 -0
- package/dist/runtime/request-telemetry.js +228 -0
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.js +1 -0
- package/dist/server/serve-implementation.js +58 -20
- package/package.json +1 -1
- package/src/index.ts +13 -0
- package/src/runtime/proxy-telemetry.ts +160 -74
- package/src/runtime/request-telemetry.ts +376 -0
- package/src/server/index.ts +14 -0
- package/src/server/serve-implementation.ts +93 -21
package/src/server/index.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
...(
|
|
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
|
-
|
|
1750
|
+
telemetry?: RequestTelemetry,
|
|
1720
1751
|
correlation: RequestCorrelationIds = {},
|
|
1721
1752
|
): void {
|
|
1722
|
-
const
|
|
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
|
-
...(
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
...(
|
|
2184
|
+
...(cache
|
|
2115
2185
|
? {
|
|
2116
|
-
cached:
|
|
2117
|
-
stale:
|
|
2118
|
-
cache
|
|
2186
|
+
cached: cache.hit,
|
|
2187
|
+
stale: cache.stale,
|
|
2188
|
+
cache,
|
|
2119
2189
|
}
|
|
2120
2190
|
: {}),
|
|
2121
|
-
...(
|
|
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 } : {}),
|