@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/src/index.ts CHANGED
@@ -6,12 +6,15 @@ export * from "./choice-token.js";
6
6
  export type {
7
7
  ApiFuseConfig,
8
8
  BrowserConfig,
9
+ ProxyCacheStatus,
9
10
  ProxyProtocol,
10
11
  ProxyResolutionOptions,
11
12
  ProxyResolutionSource,
13
+ ProxyUserAgentSource,
12
14
  ProxyVendorName,
13
15
  ResolvedProxyConfig,
14
16
  SessionConfig,
17
+ SmartproxyAllocatorBodyClass,
15
18
  } from "./config/loader.js";
16
19
  export { defineConfig, loadApiFuseConfig, resolveProxy } from "./config/loader.js";
17
20
  export {
@@ -38,6 +41,80 @@ export {
38
41
  type ProviderContextOf,
39
42
  type ProviderDeclaration,
40
43
  } from "./define.js";
44
+ export {
45
+ AssertionExpressionSchema,
46
+ AssertionPredicateSchema,
47
+ AssertStepSchema,
48
+ BoundedJsonPathSchema,
49
+ CandidateBlockSchema,
50
+ CandidatePolicySchema,
51
+ CredentialRefDeclarationSchema,
52
+ defineHealthScenario,
53
+ HealthScenarioSchema,
54
+ HealthStepSchema,
55
+ ExtractStepSchema,
56
+ FindFirstSchema,
57
+ GuardStepSchema,
58
+ JournalPolicySchema,
59
+ JsonTemplateSchema,
60
+ ManualTriggerPolicySchema,
61
+ OperandSchema,
62
+ OperationStepSchema,
63
+ QuantifierSchema,
64
+ ReferenceSchema,
65
+ RetryPolicySchema,
66
+ SafeRegexSchema,
67
+ ScopedAssertionExpressionSchema,
68
+ ScopedAssertionPredicateSchema,
69
+ ScopedItemReferenceSchema,
70
+ ScopedOperandSchema,
71
+ StepReferenceSchema,
72
+ RelativeDateNodeSchema,
73
+ ValueTypeSchema,
74
+ } from "./health-scenario.js";
75
+ export type {
76
+ AssertionExpression,
77
+ AssertionPredicate,
78
+ AttemptReference,
79
+ AssertResult,
80
+ AssertStep,
81
+ BoundedJsonPath,
82
+ CandidateBlock,
83
+ CandidatePolicy,
84
+ CandidateReference,
85
+ CredentialReference,
86
+ CredentialRefDeclaration,
87
+ EstablishedConnectionReference,
88
+ ExtractStep,
89
+ FindFirst,
90
+ GuardAttribution,
91
+ GuardReasonCode,
92
+ GuardResult,
93
+ GuardStep,
94
+ HealthScenario,
95
+ HealthStep,
96
+ JsonTemplate,
97
+ JournalPolicy,
98
+ ManualTriggerPolicy,
99
+ NonEmpty,
100
+ OperationResult,
101
+ OperationStep,
102
+ Operand,
103
+ Quantifier,
104
+ ReferenceNode,
105
+ Reference,
106
+ RelativeDateNode,
107
+ RetryPolicy,
108
+ SafeRegex,
109
+ ScopedAssertionExpression,
110
+ ScopedAssertionPredicate,
111
+ ScopedItemReference,
112
+ ScopedOperand,
113
+ StepBase,
114
+ StepReference,
115
+ ExtractResult,
116
+ ValueType,
117
+ } from "./health-scenario.js";
41
118
  export type { DevServerOptions } from "./dev.js";
42
119
  export { createDevServer, startDevServer } from "./dev.js";
43
120
  export * from "./errors.js";
@@ -100,6 +177,7 @@ export {
100
177
  } from "./runtime/instrumentation.js";
101
178
  export type { PrevalidateResult } from "./runtime/prevalidate.js";
102
179
  export { getProviderBaseUrl } from "./runtime/provider.js";
180
+ export type { ProxyTelemetryLogPayload } from "./runtime/proxy-telemetry.js";
103
181
  export {
104
182
  APIFUSE__CDP_POOL__URL,
105
183
  APIFUSE__RESOLVER__2CAPTCHA__API_KEY,
package/src/provider.ts CHANGED
@@ -40,6 +40,81 @@ export type {
40
40
  ProviderContextOf,
41
41
  ProviderDeclaration,
42
42
  } from "./define.js";
43
+ export type { JsonPrimitive, JsonValue } from "./contract-json.js";
44
+ export {
45
+ AssertionExpressionSchema,
46
+ AssertionPredicateSchema,
47
+ AssertStepSchema,
48
+ BoundedJsonPathSchema,
49
+ CandidateBlockSchema,
50
+ CandidatePolicySchema,
51
+ CredentialRefDeclarationSchema,
52
+ defineHealthScenario,
53
+ HealthScenarioSchema,
54
+ HealthStepSchema,
55
+ ExtractStepSchema,
56
+ FindFirstSchema,
57
+ GuardStepSchema,
58
+ JournalPolicySchema,
59
+ JsonTemplateSchema,
60
+ ManualTriggerPolicySchema,
61
+ OperandSchema,
62
+ OperationStepSchema,
63
+ QuantifierSchema,
64
+ ReferenceSchema,
65
+ RetryPolicySchema,
66
+ SafeRegexSchema,
67
+ ScopedAssertionExpressionSchema,
68
+ ScopedAssertionPredicateSchema,
69
+ ScopedItemReferenceSchema,
70
+ ScopedOperandSchema,
71
+ StepReferenceSchema,
72
+ RelativeDateNodeSchema,
73
+ ValueTypeSchema,
74
+ } from "./health-scenario.js";
75
+ export type {
76
+ AssertionExpression,
77
+ AssertionPredicate,
78
+ AttemptReference,
79
+ AssertResult,
80
+ AssertStep,
81
+ BoundedJsonPath,
82
+ CandidateBlock,
83
+ CandidatePolicy,
84
+ CandidateReference,
85
+ CredentialReference,
86
+ CredentialRefDeclaration,
87
+ EstablishedConnectionReference,
88
+ ExtractStep,
89
+ FindFirst,
90
+ GuardAttribution,
91
+ GuardReasonCode,
92
+ GuardResult,
93
+ GuardStep,
94
+ HealthScenario,
95
+ HealthStep,
96
+ JsonTemplate,
97
+ JournalPolicy,
98
+ ManualTriggerPolicy,
99
+ NonEmpty,
100
+ OperationResult,
101
+ OperationStep,
102
+ Operand,
103
+ Quantifier,
104
+ ReferenceNode,
105
+ Reference,
106
+ RelativeDateNode,
107
+ RetryPolicy,
108
+ SafeRegex,
109
+ ScopedAssertionExpression,
110
+ ScopedAssertionPredicate,
111
+ ScopedItemReference,
112
+ ScopedOperand,
113
+ StepBase,
114
+ StepReference,
115
+ ExtractResult,
116
+ ValueType,
117
+ } from "./health-scenario.js";
43
118
  export {
44
119
  AuthError,
45
120
  HttpRedirectError,
@@ -7,7 +7,7 @@ import {
7
7
  } from "../errors.js";
8
8
  import { z } from "zod";
9
9
  import { parseSchema } from "../schema.js";
10
- import type { ProviderContext, ProviderDefinition } from "../types.js";
10
+ import type { ProviderDefinition } from "../types.js";
11
11
  import { assertRequiredSecretsPresent } from "./secrets.js";
12
12
 
13
13
  export function isStreamingOperation(provider: ProviderDefinition, operationId: string): boolean {
@@ -26,10 +26,13 @@ export function isStreamingOperation(provider: ProviderDefinition, operationId:
26
26
  *
27
27
  * @see openspec/provider-sdk/03-sdk-core.md §3.6
28
28
  */
29
- export async function executeOperation(
30
- provider: ProviderDefinition,
31
- operationId: string,
32
- ctx: ProviderContext,
29
+ export async function executeOperation<
30
+ const TProvider extends ProviderDefinition,
31
+ const TOperationId extends keyof TProvider["operations"] & string,
32
+ >(
33
+ provider: TProvider,
34
+ operationId: TOperationId,
35
+ ctx: NoInfer<Parameters<TProvider["operations"][TOperationId]["handler"]>[0]>,
33
36
  input: unknown,
34
37
  _options?: { skipAuth?: boolean },
35
38
  ): Promise<unknown> {
@@ -47,7 +50,9 @@ export async function executeOperation(
47
50
  // handler, so every invocation path (serve /v1, self-test probes, perf,
48
51
  // record) fails with the same structured MISSING_SECRET error instead of a
49
52
  // handler-specific crash. Providers must not re-check presence locally.
50
- assertRequiredSecretsPresent(provider, ctx.env);
53
+ if (provider.secrets?.some((secret) => secret.required === true)) {
54
+ assertRequiredSecretsPresent(provider, "env" in ctx ? ctx.env : { get: () => undefined });
55
+ }
51
56
 
52
57
  const validatedInput = await parseSchema(
53
58
  operation.input,
@@ -27,7 +27,10 @@ import { RESOLVER_INSTRUMENTATION_METADATA } from "./resolver-shared.js";
27
27
 
28
28
  export interface InstrumentationOptions extends CreateTraceContextOptions {}
29
29
 
30
- export type InstrumentedProviderContext<T extends ProviderContext> = Omit<T, "trace"> & {
30
+ export type InstrumentedProviderContext<T extends Pick<ProviderContext, "trace">> = Omit<
31
+ T,
32
+ "trace"
33
+ > & {
31
34
  trace: TraceContext;
32
35
  };
33
36
 
@@ -850,7 +853,7 @@ function hasTraceOverrides(options: InstrumentationOptions): boolean {
850
853
  return options.maxSpans !== undefined || options.onSpan !== undefined;
851
854
  }
852
855
 
853
- export function wrapWithInstrumentation<T extends ProviderContext>(
856
+ export function wrapWithInstrumentation<T extends Pick<ProviderContext, "trace">>(
854
857
  ctx: T,
855
858
  options: InstrumentationOptions = {},
856
859
  ): InstrumentedProviderContext<T> {
@@ -12,51 +12,49 @@ import type {
12
12
 
13
13
  export const PROVIDER_TELEMETRY_HEADER = "X-ApiFuse-Provider-Telemetry";
14
14
 
15
- type ProviderTelemetryHeader = {
16
- v: 1;
17
- proxy?: {
18
- provider: ProxyVendorName;
19
- userAgentSource?: ProxyUserAgentSource;
20
- protocol?: ProxyProtocol;
21
- cacheStatus: ProxyCacheStatus;
22
- cacheHit: boolean;
23
- resolutionMs: number;
24
- allocatorMs?: number;
25
- allocatorStatus?: number;
26
- allocatorBodyClass?: SmartproxyAllocatorBodyClass;
27
- allocatorAttempts?: number;
28
- lockWaitMs?: number;
29
- redisReadMs?: number;
30
- redisWriteMs?: number;
31
- poolAgeMs?: number;
32
- poolExpiresInMs?: number;
33
- attempts: number;
34
- refreshes?: number;
35
- attemptSamples?: CompactProxyAttemptSample[];
36
- /** Distinct vendors attempted across the resolution chain, in order seen. */
37
- vendors?: ProxyVendorName[];
38
- /** Cross-vendor failover events (bounded). */
39
- failovers?: CompactVendorFailoverSample[];
40
- };
15
+ export type ProxyTelemetryLogPayload = {
16
+ provider: ProxyVendorName;
17
+ userAgentSource?: ProxyUserAgentSource;
18
+ protocol?: ProxyProtocol;
19
+ cacheStatus: ProxyCacheStatus;
20
+ cacheHit: boolean;
21
+ resolutionMs: number;
22
+ allocatorMs?: number;
23
+ allocatorStatus?: number;
24
+ allocatorBodyClass?: SmartproxyAllocatorBodyClass;
25
+ allocatorAttempts?: number;
26
+ lockWaitMs?: number;
27
+ redisReadMs?: number;
28
+ redisWriteMs?: number;
29
+ poolAgeMs?: number;
30
+ poolExpiresInMs?: number;
31
+ attempts: number;
32
+ refreshes?: number;
33
+ attemptSamples?: {
34
+ n: number;
35
+ a: number;
36
+ i?: number;
37
+ h?: string;
38
+ o: ProxyAttemptTelemetryEvent["outcome"];
39
+ c?: string;
40
+ s?: number;
41
+ d?: number;
42
+ }[];
43
+ /** Distinct vendors attempted across the resolution chain, in order seen. */
44
+ vendors?: ProxyVendorName[];
45
+ /** Cross-vendor failover events (bounded). */
46
+ failovers?: {
47
+ v: ProxyVendorName;
48
+ nx?: ProxyVendorName;
49
+ p: ProxyVendorFailoverTelemetryEvent["phase"];
50
+ r: ProxyVendorFailoverTelemetryEvent["reason"];
51
+ a?: number;
52
+ }[];
41
53
  };
42
54
 
43
- type CompactProxyAttemptSample = {
44
- n: number;
45
- a: number;
46
- i?: number;
47
- h?: string;
48
- o: "ok" | "error";
49
- c?: string;
50
- s?: number;
51
- d?: number;
52
- };
53
-
54
- type CompactVendorFailoverSample = {
55
- v: ProxyVendorName;
56
- nx?: ProxyVendorName;
57
- p: "resolution" | "transport";
58
- r: ProxyVendorFailoverTelemetryEvent["reason"];
59
- a?: number;
55
+ type ProviderTelemetryHeader = {
56
+ v: 1;
57
+ proxy?: ProxyTelemetryLogPayload;
60
58
  };
61
59
 
62
60
  const MAX_HEADER_BYTES = 4_096;
@@ -163,7 +161,7 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
163
161
  });
164
162
  }
165
163
 
166
- toHeaderValue(): string | undefined {
164
+ toLogPayload(): ProxyTelemetryLogPayload | undefined {
167
165
  const [first, ...rest] = this.#events;
168
166
  if (!first) return undefined;
169
167
 
@@ -196,62 +194,65 @@ export class ProxyTelemetryCollector implements ProxyTelemetrySink {
196
194
  }),
197
195
  first,
198
196
  );
199
- const payload: ProviderTelemetryHeader = {
200
- v: 1,
201
- proxy: {
202
- provider: serving.provider,
203
- ...(aggregate.userAgentSource ? { userAgentSource: aggregate.userAgentSource } : {}),
204
- ...(serving.protocol ? { protocol: serving.protocol } : {}),
205
- cacheStatus: aggregate.cacheStatus,
206
- cacheHit: aggregate.cacheHit,
207
- resolutionMs: aggregate.resolutionMs,
208
- ...(aggregate.allocatorMs !== undefined ? { allocatorMs: aggregate.allocatorMs } : {}),
209
- ...(aggregate.allocatorStatus !== undefined
210
- ? { allocatorStatus: aggregate.allocatorStatus }
211
- : {}),
212
- ...(aggregate.allocatorBodyClass !== undefined
213
- ? { allocatorBodyClass: aggregate.allocatorBodyClass }
214
- : {}),
215
- ...(aggregate.allocatorAttempts !== undefined
216
- ? { allocatorAttempts: aggregate.allocatorAttempts }
217
- : {}),
218
- ...(aggregate.lockWaitMs !== undefined ? { lockWaitMs: aggregate.lockWaitMs } : {}),
219
- ...(aggregate.redisReadMs !== undefined ? { redisReadMs: aggregate.redisReadMs } : {}),
220
- ...(aggregate.redisWriteMs !== undefined ? { redisWriteMs: aggregate.redisWriteMs } : {}),
221
- ...(aggregate.poolAgeMs !== undefined ? { poolAgeMs: aggregate.poolAgeMs } : {}),
222
- ...(aggregate.poolExpiresInMs !== undefined
223
- ? { poolExpiresInMs: aggregate.poolExpiresInMs }
224
- : {}),
225
- attempts: aggregate.attempts,
226
- ...(aggregate.refreshes !== undefined ? { refreshes: aggregate.refreshes } : {}),
227
- ...(this.#attempts.length > 0
228
- ? {
229
- attemptSamples: this.#attempts.map((attempt, index) => ({
230
- n: index + 1,
231
- a: attempt.attempt,
232
- ...(attempt.poolIndex === undefined ? {} : { i: attempt.poolIndex }),
233
- ...(attempt.proxyHash ? { h: attempt.proxyHash } : {}),
234
- o: attempt.outcome,
235
- ...(attempt.errorCode ? { c: attempt.errorCode } : {}),
236
- ...(attempt.status === undefined ? {} : { s: attempt.status }),
237
- ...(attempt.durationMs === undefined ? {} : { d: attempt.durationMs }),
238
- })),
239
- }
240
- : {}),
241
- ...(vendors.length > 1 ? { vendors } : {}),
242
- ...(this.#failovers.length > 0
243
- ? {
244
- failovers: this.#failovers.map((failover) => ({
245
- v: failover.vendor,
246
- ...(failover.nextVendor ? { nx: failover.nextVendor } : {}),
247
- p: failover.phase,
248
- r: failover.reason,
249
- ...(failover.attempt === undefined ? {} : { a: failover.attempt }),
250
- })),
251
- }
252
- : {}),
253
- },
197
+ return {
198
+ provider: serving.provider,
199
+ ...(aggregate.userAgentSource ? { userAgentSource: aggregate.userAgentSource } : {}),
200
+ ...(serving.protocol ? { protocol: serving.protocol } : {}),
201
+ cacheStatus: aggregate.cacheStatus,
202
+ cacheHit: aggregate.cacheHit,
203
+ resolutionMs: aggregate.resolutionMs,
204
+ ...(aggregate.allocatorMs !== undefined ? { allocatorMs: aggregate.allocatorMs } : {}),
205
+ ...(aggregate.allocatorStatus !== undefined
206
+ ? { allocatorStatus: aggregate.allocatorStatus }
207
+ : {}),
208
+ ...(aggregate.allocatorBodyClass !== undefined
209
+ ? { allocatorBodyClass: aggregate.allocatorBodyClass }
210
+ : {}),
211
+ ...(aggregate.allocatorAttempts !== undefined
212
+ ? { allocatorAttempts: aggregate.allocatorAttempts }
213
+ : {}),
214
+ ...(aggregate.lockWaitMs !== undefined ? { lockWaitMs: aggregate.lockWaitMs } : {}),
215
+ ...(aggregate.redisReadMs !== undefined ? { redisReadMs: aggregate.redisReadMs } : {}),
216
+ ...(aggregate.redisWriteMs !== undefined ? { redisWriteMs: aggregate.redisWriteMs } : {}),
217
+ ...(aggregate.poolAgeMs !== undefined ? { poolAgeMs: aggregate.poolAgeMs } : {}),
218
+ ...(aggregate.poolExpiresInMs !== undefined
219
+ ? { poolExpiresInMs: aggregate.poolExpiresInMs }
220
+ : {}),
221
+ attempts: aggregate.attempts,
222
+ ...(aggregate.refreshes !== undefined ? { refreshes: aggregate.refreshes } : {}),
223
+ ...(this.#attempts.length > 0
224
+ ? {
225
+ attemptSamples: this.#attempts.map((attempt, index) => ({
226
+ n: index + 1,
227
+ a: attempt.attempt,
228
+ ...(attempt.poolIndex === undefined ? {} : { i: attempt.poolIndex }),
229
+ ...(attempt.proxyHash ? { h: attempt.proxyHash } : {}),
230
+ o: attempt.outcome,
231
+ ...(attempt.errorCode ? { c: attempt.errorCode } : {}),
232
+ ...(attempt.status === undefined ? {} : { s: attempt.status }),
233
+ ...(attempt.durationMs === undefined ? {} : { d: attempt.durationMs }),
234
+ })),
235
+ }
236
+ : {}),
237
+ ...(vendors.length > 1 ? { vendors } : {}),
238
+ ...(this.#failovers.length > 0
239
+ ? {
240
+ failovers: this.#failovers.map((failover) => ({
241
+ v: failover.vendor,
242
+ ...(failover.nextVendor ? { nx: failover.nextVendor } : {}),
243
+ p: failover.phase,
244
+ r: failover.reason,
245
+ ...(failover.attempt === undefined ? {} : { a: failover.attempt }),
246
+ })),
247
+ }
248
+ : {}),
254
249
  };
250
+ }
251
+
252
+ toHeaderValue(): string | undefined {
253
+ const proxy = this.toLogPayload();
254
+ if (!proxy) return undefined;
255
+ const payload: ProviderTelemetryHeader = { v: 1, proxy };
255
256
 
256
257
  const encoded = encodeBase64Url(JSON.stringify(payload));
257
258
  if (encoded.length > MAX_HEADER_BYTES) return undefined;
@@ -1,3 +1,11 @@
1
+ export type {
2
+ ProxyCacheStatus,
3
+ ProxyProtocol,
4
+ ProxyUserAgentSource,
5
+ ProxyVendorName,
6
+ SmartproxyAllocatorBodyClass,
7
+ } from "../config/loader.js";
8
+ export type { ProxyTelemetryLogPayload } from "../runtime/proxy-telemetry.js";
1
9
  export {
2
10
  createServerApp,
3
11
  createServerAppAsync,