@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.
@@ -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";
@@ -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
- return response instanceof Response ? response : c.json(response);
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
- return response instanceof Response ? response : c.json(response);
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
- return response instanceof Response ? response : c.json(response);
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
- return response instanceof Response ? response : c.json(response);
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
- return response instanceof Response ? response : c.json(response);
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
  });
@@ -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
- export interface HealthJourneyDefinition {
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
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.2.0-beta.37",
2
+ "version": "2.2.0-beta.39",
3
3
  "name": "@apifuse/provider-sdk",
4
4
  "private": false,
5
5
  "type": "module",