@apifuse/provider-sdk 2.2.0-beta.37 → 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 +8 -0
- package/dist/declaration-validation.d.ts +9 -0
- package/dist/declaration-validation.js +51 -3
- package/dist/define.d.ts +2 -2
- package/dist/define.js +37 -22
- package/dist/health-scenario.d.ts +1842 -0
- package/dist/health-scenario.js +624 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -0
- package/dist/provider.d.ts +3 -0
- package/dist/provider.js +1 -0
- 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 +3 -1
- package/dist/server/serve-implementation.js +81 -30
- package/dist/server/types.d.ts +4 -4
- package/dist/types.d.ts +10 -8
- package/package.json +1 -1
- package/src/declaration-validation.ts +71 -7
- package/src/define.ts +61 -38
- package/src/health-scenario.ts +875 -0
- package/src/index.ts +78 -0
- package/src/provider.ts +75 -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/src/types.ts +11 -8
|
@@ -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";
|
|
@@ -34,8 +35,8 @@ export declare const ProviderServerStatefulForwardEnvelopeSchema: z.ZodObject<{
|
|
|
34
35
|
connection: z.ZodOptional<z.ZodObject<{
|
|
35
36
|
id: z.ZodString;
|
|
36
37
|
mode: z.ZodEnum<{
|
|
37
|
-
none: "none";
|
|
38
38
|
credentials: "credentials";
|
|
39
|
+
none: "none";
|
|
39
40
|
oauth2: "oauth2";
|
|
40
41
|
"platform-managed": "platform-managed";
|
|
41
42
|
oauth2_proxied: "oauth2_proxied";
|
|
@@ -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";
|
|
@@ -21,7 +21,7 @@ import { wrapWithInstrumentation } from "../runtime/instrumentation.js";
|
|
|
21
21
|
import { getProviderBaseUrl } from "../runtime/provider.js";
|
|
22
22
|
import { createOcrClientFromEnv } from "../runtime/ocr.js";
|
|
23
23
|
import { PROXY_AUTH_IP_DENIED_CODE, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_EXHAUSTED_CODE, } from "../runtime/proxy-errors.js";
|
|
24
|
-
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector } from "../runtime/proxy-telemetry.js";
|
|
24
|
+
import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector, } from "../runtime/proxy-telemetry.js";
|
|
25
25
|
import { createUnsupportedResolverClient } from "../runtime/resolver-shared.js";
|
|
26
26
|
import { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "../runtime/secrets.js";
|
|
27
27
|
import { createProviderRuntimeStateFromEnv, createUnsupportedProviderRuntimeState, } from "../runtime/state.js";
|
|
@@ -348,7 +348,7 @@ function resolveOperationConnectionId(request) {
|
|
|
348
348
|
// absent so it can never override a valid id or key a real scope. Requests
|
|
349
349
|
// without any usable id fall back to the documented missing-connection
|
|
350
350
|
// sentinel scope instead of scoping context/affinity/state under "".
|
|
351
|
-
return normalizeConnectionId(request.connection?.id) ?? normalizeConnectionId(request.connectionId);
|
|
351
|
+
return (normalizeConnectionId(request.connection?.id) ?? normalizeConnectionId(request.connectionId));
|
|
352
352
|
}
|
|
353
353
|
function normalizeConnectionId(id) {
|
|
354
354
|
return id === "" ? undefined : id;
|
|
@@ -512,7 +512,7 @@ export function resolveAuthFlowProxyAffinityKey(provider, request) {
|
|
|
512
512
|
request.providerId ??
|
|
513
513
|
provider.id);
|
|
514
514
|
}
|
|
515
|
-
function createAuthFlowContext(provider, request, options, state, signal) {
|
|
515
|
+
function createAuthFlowContext(provider, request, options, state, proxyTelemetry, signal) {
|
|
516
516
|
const baseUrl = getProviderBaseUrl(provider);
|
|
517
517
|
const stealthBaseUrl = getProviderStealthBaseUrl(provider);
|
|
518
518
|
const stealthProfile = getProviderStealthProfile(provider);
|
|
@@ -522,11 +522,13 @@ function createAuthFlowContext(provider, request, options, state, signal) {
|
|
|
522
522
|
const proxyClientOptions = {
|
|
523
523
|
upstream: { proxy: provider.proxy },
|
|
524
524
|
affinityKey: resolveAuthFlowProxyAffinityKey(provider, request),
|
|
525
|
+
telemetry: proxyTelemetry,
|
|
525
526
|
};
|
|
526
527
|
const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
|
|
527
528
|
const stealthClientOptions = {
|
|
528
529
|
upstream: proxyClientOptions.upstream,
|
|
529
530
|
affinityKey: proxyClientOptions.affinityKey,
|
|
531
|
+
telemetry: proxyTelemetry,
|
|
530
532
|
};
|
|
531
533
|
const { capabilityModules } = options;
|
|
532
534
|
const logStealthCleanupError = (error) => logProviderCleanupError(options.logger, provider, "auth", "flow", request.requestId, "stealth", error);
|
|
@@ -947,7 +949,7 @@ function providerErrorCauseChain(error) {
|
|
|
947
949
|
}
|
|
948
950
|
return frames.length > 0 ? frames : undefined;
|
|
949
951
|
}
|
|
950
|
-
function logProviderError(logger, provider, kind, route, requestId, error, status, cost, declaredErrorCode) {
|
|
952
|
+
function logProviderError(logger, provider, kind, route, requestId, error, status, cost, declaredErrorCode, proxyTelemetry) {
|
|
951
953
|
const code = isProviderError(error)
|
|
952
954
|
? (error.code ?? "provider_error")
|
|
953
955
|
: error instanceof z.ZodError
|
|
@@ -965,6 +967,7 @@ function logProviderError(logger, provider, kind, route, requestId, error, statu
|
|
|
965
967
|
typeof error.code === "string" &&
|
|
966
968
|
!SDK_OWNED_PROVIDER_ERROR_CODES.has(error.code) &&
|
|
967
969
|
declaredErrorCode === undefined;
|
|
970
|
+
const proxy = proxyTelemetry?.toLogPayload();
|
|
968
971
|
const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
969
972
|
emit({
|
|
970
973
|
level: status >= 500 ? "error" : "warn",
|
|
@@ -975,6 +978,7 @@ function logProviderError(logger, provider, kind, route, requestId, error, statu
|
|
|
975
978
|
...(requestId ? { requestId } : {}),
|
|
976
979
|
status,
|
|
977
980
|
...cost,
|
|
981
|
+
...(proxy ? { proxy } : {}),
|
|
978
982
|
code,
|
|
979
983
|
errorClass,
|
|
980
984
|
message,
|
|
@@ -1008,7 +1012,8 @@ function logProviderCleanupError(logger, provider, kind, operationId, requestId,
|
|
|
1008
1012
|
message,
|
|
1009
1013
|
});
|
|
1010
1014
|
}
|
|
1011
|
-
function logProviderSuccess(logger, provider, kind, route, requestId, status, cost) {
|
|
1015
|
+
function logProviderSuccess(logger, provider, kind, route, requestId, status, cost, proxyTelemetry) {
|
|
1016
|
+
const proxy = proxyTelemetry?.toLogPayload();
|
|
1012
1017
|
const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
|
|
1013
1018
|
emit({
|
|
1014
1019
|
level: "info",
|
|
@@ -1019,6 +1024,7 @@ function logProviderSuccess(logger, provider, kind, route, requestId, status, co
|
|
|
1019
1024
|
...(requestId ? { requestId } : {}),
|
|
1020
1025
|
status,
|
|
1021
1026
|
...cost,
|
|
1027
|
+
...(proxy ? { proxy } : {}),
|
|
1022
1028
|
});
|
|
1023
1029
|
}
|
|
1024
1030
|
function toJsonSuccessResponse(result, ctx) {
|
|
@@ -1395,7 +1401,7 @@ function responseWithProviderTelemetry(response, proxyTelemetry) {
|
|
|
1395
1401
|
statusText: response.statusText,
|
|
1396
1402
|
});
|
|
1397
1403
|
}
|
|
1398
|
-
async function handleAuthFlow(provider, request, route, options, state, signal) {
|
|
1404
|
+
async function handleAuthFlow(provider, request, route, options, state, proxyTelemetry, signal) {
|
|
1399
1405
|
const flow = provider.auth?.flow;
|
|
1400
1406
|
if (!flow) {
|
|
1401
1407
|
throw new ProviderError("Auth flow is not configured", {
|
|
@@ -1407,7 +1413,7 @@ async function handleAuthFlow(provider, request, route, options, state, signal)
|
|
|
1407
1413
|
// any flow code runs instead of at whatever point the ceremony first reads
|
|
1408
1414
|
// the env. `abort` stays exempt: a user must always be able to cancel a
|
|
1409
1415
|
// stranded flow even when provisioning is broken.
|
|
1410
|
-
const { context, getPatch } = createAuthFlowContext(provider, request, options, state, signal);
|
|
1416
|
+
const { context, getPatch } = createAuthFlowContext(provider, request, options, state, proxyTelemetry, signal);
|
|
1411
1417
|
try {
|
|
1412
1418
|
if (route !== "abort") {
|
|
1413
1419
|
assertRequiredSecretsPresent(provider, context.env);
|
|
@@ -1752,20 +1758,20 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
1752
1758
|
body.headers = { ...requestHeaders, ...body.headers };
|
|
1753
1759
|
const response = await handleOperation(provider, body, operation, options, state, proxyTelemetry, c.req.raw.signal);
|
|
1754
1760
|
if (response instanceof Response) {
|
|
1755
|
-
logProviderSuccess(logger, provider, "operation", operation, body.requestId, response.status, finishRequestCost(requestCost));
|
|
1761
|
+
logProviderSuccess(logger, provider, "operation", operation, body.requestId, response.status, finishRequestCost(requestCost), proxyTelemetry);
|
|
1756
1762
|
return responseWithProviderTelemetry(response, proxyTelemetry);
|
|
1757
1763
|
}
|
|
1758
1764
|
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1759
1765
|
if (telemetryHeader)
|
|
1760
1766
|
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1761
|
-
logProviderSuccess(logger, provider, "operation", operation, body.requestId, 200, finishRequestCost(requestCost));
|
|
1767
|
+
logProviderSuccess(logger, provider, "operation", operation, body.requestId, 200, finishRequestCost(requestCost), proxyTelemetry);
|
|
1762
1768
|
return c.json(response);
|
|
1763
1769
|
}
|
|
1764
1770
|
catch (error) {
|
|
1765
1771
|
const declaredErrorCode = declaredErrorCodeFor(error, operation, operationErrorCodes);
|
|
1766
1772
|
const status = toStatusCode(error, declaredErrorCode);
|
|
1767
1773
|
const requestId = extractRequestId(rawBody);
|
|
1768
|
-
logProviderError(logger, provider, "operation", operation, requestId, error, status, finishRequestCost(requestCost), declaredErrorCode);
|
|
1774
|
+
logProviderError(logger, provider, "operation", operation, requestId, error, status, finishRequestCost(requestCost), declaredErrorCode, proxyTelemetry);
|
|
1769
1775
|
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1770
1776
|
if (telemetryHeader)
|
|
1771
1777
|
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
@@ -1774,6 +1780,7 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
1774
1780
|
});
|
|
1775
1781
|
app.post("/auth/start", async (c) => {
|
|
1776
1782
|
let rawBody;
|
|
1783
|
+
const proxyTelemetry = new ProxyTelemetryCollector();
|
|
1777
1784
|
const requestCost = startRequestCost();
|
|
1778
1785
|
try {
|
|
1779
1786
|
rawBody = await c.req.raw
|
|
@@ -1781,19 +1788,28 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
1781
1788
|
.json()
|
|
1782
1789
|
.catch(() => undefined);
|
|
1783
1790
|
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1784
|
-
const response = await handleAuthFlow(provider, body, "start", options, state, c.req.raw.signal);
|
|
1785
|
-
logProviderSuccess(logger, provider, "auth", "start", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
|
|
1786
|
-
|
|
1791
|
+
const response = await handleAuthFlow(provider, body, "start", options, state, proxyTelemetry, c.req.raw.signal);
|
|
1792
|
+
logProviderSuccess(logger, provider, "auth", "start", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost), proxyTelemetry);
|
|
1793
|
+
if (response instanceof Response)
|
|
1794
|
+
return responseWithProviderTelemetry(response, proxyTelemetry);
|
|
1795
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1796
|
+
if (telemetryHeader)
|
|
1797
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1798
|
+
return c.json(response);
|
|
1787
1799
|
}
|
|
1788
1800
|
catch (error) {
|
|
1789
1801
|
const status = toStatusCode(error);
|
|
1790
1802
|
const requestId = extractRequestId(rawBody);
|
|
1791
|
-
logProviderError(logger, provider, "auth", "start", requestId, error, status, finishRequestCost(requestCost));
|
|
1803
|
+
logProviderError(logger, provider, "auth", "start", requestId, error, status, finishRequestCost(requestCost), undefined, proxyTelemetry);
|
|
1804
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1805
|
+
if (telemetryHeader)
|
|
1806
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1792
1807
|
return responseWithErrorObservability(c.json(toErrorResponse(error, requestId), status), error);
|
|
1793
1808
|
}
|
|
1794
1809
|
});
|
|
1795
1810
|
app.post("/auth/continue", async (c) => {
|
|
1796
1811
|
let rawBody;
|
|
1812
|
+
const proxyTelemetry = new ProxyTelemetryCollector();
|
|
1797
1813
|
const requestCost = startRequestCost();
|
|
1798
1814
|
try {
|
|
1799
1815
|
rawBody = await c.req.raw
|
|
@@ -1801,19 +1817,28 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
1801
1817
|
.json()
|
|
1802
1818
|
.catch(() => undefined);
|
|
1803
1819
|
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1804
|
-
const response = await handleAuthFlow(provider, body, "continue", options, state, c.req.raw.signal);
|
|
1805
|
-
logProviderSuccess(logger, provider, "auth", "continue", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
|
|
1806
|
-
|
|
1820
|
+
const response = await handleAuthFlow(provider, body, "continue", options, state, proxyTelemetry, c.req.raw.signal);
|
|
1821
|
+
logProviderSuccess(logger, provider, "auth", "continue", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost), proxyTelemetry);
|
|
1822
|
+
if (response instanceof Response)
|
|
1823
|
+
return responseWithProviderTelemetry(response, proxyTelemetry);
|
|
1824
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1825
|
+
if (telemetryHeader)
|
|
1826
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1827
|
+
return c.json(response);
|
|
1807
1828
|
}
|
|
1808
1829
|
catch (error) {
|
|
1809
1830
|
const status = toStatusCode(error);
|
|
1810
1831
|
const requestId = extractRequestId(rawBody);
|
|
1811
|
-
logProviderError(logger, provider, "auth", "continue", requestId, error, status, finishRequestCost(requestCost));
|
|
1832
|
+
logProviderError(logger, provider, "auth", "continue", requestId, error, status, finishRequestCost(requestCost), undefined, proxyTelemetry);
|
|
1833
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1834
|
+
if (telemetryHeader)
|
|
1835
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1812
1836
|
return responseWithErrorObservability(c.json(toErrorResponse(error, requestId), status), error);
|
|
1813
1837
|
}
|
|
1814
1838
|
});
|
|
1815
1839
|
app.post("/auth/poll", async (c) => {
|
|
1816
1840
|
let rawBody;
|
|
1841
|
+
const proxyTelemetry = new ProxyTelemetryCollector();
|
|
1817
1842
|
const requestCost = startRequestCost();
|
|
1818
1843
|
try {
|
|
1819
1844
|
rawBody = await c.req.raw
|
|
@@ -1821,19 +1846,28 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
1821
1846
|
.json()
|
|
1822
1847
|
.catch(() => undefined);
|
|
1823
1848
|
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1824
|
-
const response = await handleAuthFlow(provider, body, "poll", options, state, c.req.raw.signal);
|
|
1825
|
-
logProviderSuccess(logger, provider, "auth", "poll", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
|
|
1826
|
-
|
|
1849
|
+
const response = await handleAuthFlow(provider, body, "poll", options, state, proxyTelemetry, c.req.raw.signal);
|
|
1850
|
+
logProviderSuccess(logger, provider, "auth", "poll", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost), proxyTelemetry);
|
|
1851
|
+
if (response instanceof Response)
|
|
1852
|
+
return responseWithProviderTelemetry(response, proxyTelemetry);
|
|
1853
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1854
|
+
if (telemetryHeader)
|
|
1855
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1856
|
+
return c.json(response);
|
|
1827
1857
|
}
|
|
1828
1858
|
catch (error) {
|
|
1829
1859
|
const status = toStatusCode(error);
|
|
1830
1860
|
const requestId = extractRequestId(rawBody);
|
|
1831
|
-
logProviderError(logger, provider, "auth", "poll", requestId, error, status, finishRequestCost(requestCost));
|
|
1861
|
+
logProviderError(logger, provider, "auth", "poll", requestId, error, status, finishRequestCost(requestCost), undefined, proxyTelemetry);
|
|
1862
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1863
|
+
if (telemetryHeader)
|
|
1864
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1832
1865
|
return responseWithErrorObservability(c.json(toErrorResponse(error, requestId), status), error);
|
|
1833
1866
|
}
|
|
1834
1867
|
});
|
|
1835
1868
|
app.post("/auth/refresh", async (c) => {
|
|
1836
1869
|
let rawBody;
|
|
1870
|
+
const proxyTelemetry = new ProxyTelemetryCollector();
|
|
1837
1871
|
const requestCost = startRequestCost();
|
|
1838
1872
|
try {
|
|
1839
1873
|
rawBody = await c.req.raw
|
|
@@ -1841,19 +1875,28 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
1841
1875
|
.json()
|
|
1842
1876
|
.catch(() => undefined);
|
|
1843
1877
|
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1844
|
-
const response = await handleAuthFlow(provider, body, "refresh", options, state, c.req.raw.signal);
|
|
1845
|
-
logProviderSuccess(logger, provider, "auth", "refresh", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
|
|
1846
|
-
|
|
1878
|
+
const response = await handleAuthFlow(provider, body, "refresh", options, state, proxyTelemetry, c.req.raw.signal);
|
|
1879
|
+
logProviderSuccess(logger, provider, "auth", "refresh", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost), proxyTelemetry);
|
|
1880
|
+
if (response instanceof Response)
|
|
1881
|
+
return responseWithProviderTelemetry(response, proxyTelemetry);
|
|
1882
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1883
|
+
if (telemetryHeader)
|
|
1884
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1885
|
+
return c.json(response);
|
|
1847
1886
|
}
|
|
1848
1887
|
catch (error) {
|
|
1849
1888
|
const status = toStatusCode(error);
|
|
1850
1889
|
const requestId = extractRequestId(rawBody);
|
|
1851
|
-
logProviderError(logger, provider, "auth", "refresh", requestId, error, status, finishRequestCost(requestCost));
|
|
1890
|
+
logProviderError(logger, provider, "auth", "refresh", requestId, error, status, finishRequestCost(requestCost), undefined, proxyTelemetry);
|
|
1891
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1892
|
+
if (telemetryHeader)
|
|
1893
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1852
1894
|
return responseWithErrorObservability(c.json(toErrorResponse(error, requestId), status), error);
|
|
1853
1895
|
}
|
|
1854
1896
|
});
|
|
1855
1897
|
app.post("/auth/disconnect", async (c) => {
|
|
1856
1898
|
let rawBody;
|
|
1899
|
+
const proxyTelemetry = new ProxyTelemetryCollector();
|
|
1857
1900
|
const requestCost = startRequestCost();
|
|
1858
1901
|
try {
|
|
1859
1902
|
rawBody = await c.req.raw
|
|
@@ -1861,14 +1904,22 @@ function createServerAppWithCapabilityModules(provider, serverOptions, capabilit
|
|
|
1861
1904
|
.json()
|
|
1862
1905
|
.catch(() => undefined);
|
|
1863
1906
|
const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
|
|
1864
|
-
const response = await handleAuthFlow(provider, body, "abort", options, state, c.req.raw.signal);
|
|
1865
|
-
logProviderSuccess(logger, provider, "auth", "disconnect", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
|
|
1866
|
-
|
|
1907
|
+
const response = await handleAuthFlow(provider, body, "abort", options, state, proxyTelemetry, c.req.raw.signal);
|
|
1908
|
+
logProviderSuccess(logger, provider, "auth", "disconnect", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost), proxyTelemetry);
|
|
1909
|
+
if (response instanceof Response)
|
|
1910
|
+
return responseWithProviderTelemetry(response, proxyTelemetry);
|
|
1911
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1912
|
+
if (telemetryHeader)
|
|
1913
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1914
|
+
return c.json(response);
|
|
1867
1915
|
}
|
|
1868
1916
|
catch (error) {
|
|
1869
1917
|
const status = toStatusCode(error);
|
|
1870
1918
|
const requestId = extractRequestId(rawBody);
|
|
1871
|
-
logProviderError(logger, provider, "auth", "disconnect", requestId, error, status, finishRequestCost(requestCost));
|
|
1919
|
+
logProviderError(logger, provider, "auth", "disconnect", requestId, error, status, finishRequestCost(requestCost), undefined, proxyTelemetry);
|
|
1920
|
+
const telemetryHeader = proxyTelemetry.toHeaderValue();
|
|
1921
|
+
if (telemetryHeader)
|
|
1922
|
+
c.header(PROVIDER_TELEMETRY_HEADER, telemetryHeader);
|
|
1872
1923
|
return responseWithErrorObservability(c.json(toErrorResponse(error, requestId), status), error);
|
|
1873
1924
|
}
|
|
1874
1925
|
});
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const ConnectionModeSchema: z.ZodEnum<{
|
|
3
|
-
none: "none";
|
|
4
3
|
credentials: "credentials";
|
|
4
|
+
none: "none";
|
|
5
5
|
oauth2: "oauth2";
|
|
6
6
|
"platform-managed": "platform-managed";
|
|
7
7
|
oauth2_proxied: "oauth2_proxied";
|
|
@@ -9,8 +9,8 @@ export declare const ConnectionModeSchema: z.ZodEnum<{
|
|
|
9
9
|
export declare const OperationConnectionSchema: z.ZodObject<{
|
|
10
10
|
id: z.ZodString;
|
|
11
11
|
mode: z.ZodEnum<{
|
|
12
|
-
none: "none";
|
|
13
12
|
credentials: "credentials";
|
|
13
|
+
none: "none";
|
|
14
14
|
oauth2: "oauth2";
|
|
15
15
|
"platform-managed": "platform-managed";
|
|
16
16
|
oauth2_proxied: "oauth2_proxied";
|
|
@@ -27,8 +27,8 @@ export declare const OperationRequestSchema: z.ZodObject<{
|
|
|
27
27
|
connection: z.ZodOptional<z.ZodObject<{
|
|
28
28
|
id: z.ZodString;
|
|
29
29
|
mode: z.ZodEnum<{
|
|
30
|
-
none: "none";
|
|
31
30
|
credentials: "credentials";
|
|
31
|
+
none: "none";
|
|
32
32
|
oauth2: "oauth2";
|
|
33
33
|
"platform-managed": "platform-managed";
|
|
34
34
|
oauth2_proxied: "oauth2_proxied";
|
|
@@ -118,8 +118,8 @@ export declare const AuthFlowRequestSchema: z.ZodObject<{
|
|
|
118
118
|
connection: z.ZodOptional<z.ZodObject<{
|
|
119
119
|
id: z.ZodString;
|
|
120
120
|
mode: z.ZodEnum<{
|
|
121
|
-
none: "none";
|
|
122
121
|
credentials: "credentials";
|
|
122
|
+
none: "none";
|
|
123
123
|
oauth2: "oauth2";
|
|
124
124
|
"platform-managed": "platform-managed";
|
|
125
125
|
oauth2_proxied: "oauth2_proxied";
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type ms from "ms";
|
|
2
|
+
import type { HealthScenario } from "./health-scenario.js";
|
|
2
3
|
import type { SerializedCookieJar } from "tough-cookie";
|
|
3
4
|
import type { infer as ZodInfer, ZodType } from "zod";
|
|
4
5
|
/** Minimal Standard Schema v1 shape accepted by provider operations. */
|
|
@@ -549,7 +550,7 @@ export interface HealthJourneyRunResult {
|
|
|
549
550
|
label?: string;
|
|
550
551
|
metadata?: Record<string, unknown>;
|
|
551
552
|
}
|
|
552
|
-
|
|
553
|
+
interface HealthJourneyDefinitionBase {
|
|
553
554
|
id: string;
|
|
554
555
|
title?: string;
|
|
555
556
|
description?: string;
|
|
@@ -561,14 +562,14 @@ export interface HealthJourneyDefinition {
|
|
|
561
562
|
requiredSecrets?: readonly string[];
|
|
562
563
|
manualTrigger?: HealthJourneyManualTriggerPolicy;
|
|
563
564
|
steps: readonly [HealthJourneyStep, ...HealthJourneyStep[]];
|
|
564
|
-
/**
|
|
565
|
-
* Required: a journey always declares `coversOperations`, and the health
|
|
566
|
-
* monitor reports a run-less journey as `journey_run_missing`. Declaration
|
|
567
|
-
* validation rejects a missing `run` (`health-journey-executable`), so this
|
|
568
|
-
* is typed required to fail at compile time rather than at boot.
|
|
569
|
-
*/
|
|
570
|
-
run: (ctx: HealthJourneyRunContext) => Promise<HealthJourneyRunResult | undefined>;
|
|
571
565
|
}
|
|
566
|
+
export type HealthJourneyDefinition = HealthJourneyDefinitionBase & ({
|
|
567
|
+
run: (ctx: HealthJourneyRunContext) => Promise<HealthJourneyRunResult | undefined>;
|
|
568
|
+
scenario?: never;
|
|
569
|
+
} | {
|
|
570
|
+
scenario: HealthScenario;
|
|
571
|
+
run?: never;
|
|
572
|
+
});
|
|
572
573
|
/**
|
|
573
574
|
* Health-check authoring surface owned by `@apifuse/provider-sdk`.
|
|
574
575
|
*
|
|
@@ -2051,3 +2052,4 @@ export interface ProviderDefinition {
|
|
|
2051
2052
|
healthProbe?: ProviderHealthProbeConfig;
|
|
2052
2053
|
healthJourneys?: readonly HealthJourneyDefinition[];
|
|
2053
2054
|
}
|
|
2055
|
+
export {};
|
package/package.json
CHANGED