@apifuse/provider-sdk 2.2.0-beta.13 → 2.2.0-beta.15

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.
Files changed (44) hide show
  1. package/AUTHORING.md +70 -6
  2. package/CHANGELOG.md +12 -0
  3. package/dist/define.js +9 -0
  4. package/dist/errors.d.ts +13 -0
  5. package/dist/errors.js +25 -0
  6. package/dist/index.d.ts +3 -3
  7. package/dist/index.js +2 -2
  8. package/dist/native-egress-policy.d.ts +27 -0
  9. package/dist/native-egress-policy.js +225 -0
  10. package/dist/provider.d.ts +3 -3
  11. package/dist/provider.js +2 -2
  12. package/dist/runtime/executor.js +17 -2
  13. package/dist/runtime/http.js +189 -9
  14. package/dist/runtime/native-network.d.ts +39 -4
  15. package/dist/runtime/native-network.js +365 -20
  16. package/dist/runtime/redirects.d.ts +29 -0
  17. package/dist/runtime/redirects.js +36 -0
  18. package/dist/runtime/stealth.js +16 -44
  19. package/dist/server/index.d.ts +1 -1
  20. package/dist/server/index.js +1 -1
  21. package/dist/server/serve.d.ts +9 -0
  22. package/dist/server/serve.js +190 -51
  23. package/dist/server/types.d.ts +3 -0
  24. package/dist/server/types.js +1 -0
  25. package/dist/stateful/stateful-provider-owner-forwarder.js +9 -1
  26. package/dist/testing/run.js +32 -13
  27. package/dist/types.d.ts +23 -2
  28. package/package.json +1 -1
  29. package/src/define.ts +11 -0
  30. package/src/errors.ts +37 -0
  31. package/src/index.ts +12 -1
  32. package/src/native-egress-policy.ts +285 -0
  33. package/src/provider.ts +7 -0
  34. package/src/runtime/executor.ts +22 -2
  35. package/src/runtime/http.ts +217 -9
  36. package/src/runtime/native-network.ts +474 -22
  37. package/src/runtime/redirects.ts +66 -0
  38. package/src/runtime/stealth.ts +20 -47
  39. package/src/server/index.ts +2 -0
  40. package/src/server/serve.ts +226 -68
  41. package/src/server/types.ts +1 -0
  42. package/src/stateful/stateful-provider-owner-forwarder.ts +9 -1
  43. package/src/testing/run.ts +39 -14
  44. package/src/types.ts +32 -2
package/AUTHORING.md CHANGED
@@ -393,6 +393,70 @@ External contributors are expected to submit standalone Provider source plus:
393
393
  Maintainers own monorepo import under `providers/<id>/`, registry generation,
394
394
  deployment projection checks, and release workflows.
395
395
 
396
+ ### Error responses
397
+
398
+ Provider-server failures use a stable public envelope:
399
+
400
+ ```json
401
+ {
402
+ "error": {
403
+ "code": "UPSTREAM_ERROR",
404
+ "message": "The upstream service failed",
405
+ "requestId": "req_123",
406
+ "retryable": true,
407
+ "details": { "providerReason": "temporarily_unavailable" }
408
+ }
409
+ }
410
+ ```
411
+
412
+ `retryable` is always present on responses emitted by the current SDK. Set
413
+ `retryable` in the `ProviderError` options when the provider knows the answer;
414
+ an explicit `true` or `false` wins over SDK derivation. When it is omitted, the
415
+ SDK derives the value for its known error classes and otherwise defaults to
416
+ `false`. During stateful rolling upgrades, the forwarding client also accepts
417
+ an older owner response that omits `retryable` and treats it as `false` without
418
+ loosening the emitted response contract. Existing optional `fix` guidance is
419
+ also preserved when a `ProviderError` supplies it.
420
+
421
+ `details` belongs exclusively to the provider. The server passes
422
+ `ProviderError.options.details` through verbatim, including strings and arrays,
423
+ and never merges, overwrites, or wraps it. Do not put SDK taxonomy fields there.
424
+ SDK-owned validation and masked-internal-error paths retain their own diagnostic
425
+ details.
426
+
427
+ SDK observability is emitted separately in the
428
+ `X-ApiFuse-Error-Observability` response header as compact, single-line JSON:
429
+
430
+ ```json
431
+ {"category":"upstream_http","taxonomyVersion":"2026-05-26","retryable":true,"upstreamStatus":502}
432
+ ```
433
+
434
+ Treat this header as telemetry, not as provider-controlled public error detail.
435
+ Its category, taxonomy version, retryability, and optional upstream status match
436
+ the structured `provider_request_failed` log event.
437
+
438
+ Registered error-code mappings take precedence for every `ProviderError`,
439
+ including `ValidationError`:
440
+
441
+ | Error code or fallback | HTTP status |
442
+ | --- | ---: |
443
+ | `AUTH_REQUIRED`, `reauth_required` | 401 |
444
+ | `MISSING_SECRET` | 400 |
445
+ | `NOT_FOUND`, `not_found`, `NO_DATA` | 404 |
446
+ | `RATE_LIMITED`, `UPSTREAM_RATE_LIMIT`, `LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR` | 429 |
447
+ | `UPSTREAM_ERROR`, `BLOCKED` | 502 |
448
+ | `STT_UNAVAILABLE`, `UNSUPPORTED_STT_BACKEND`, `STATEFUL_FORWARDING_REPLAY_CACHE_FULL` | 503 |
449
+ | Unregistered input `ValidationError` code | 400 |
450
+ | Other unregistered `ProviderError` code | 500 |
451
+
452
+ An unregistered non-validation `ProviderError` code returns HTTP 500 and emits
453
+ the greppable `unregistered_provider_error_code` signal with the code in the
454
+ structured failure log. Before publishing a new code, register its status in
455
+ the SDK mapping and add it to the mapping tests; declaring it only in operation
456
+ documentation does not change runtime status selection. The HTTP 400
457
+ `ValidationError` behavior is only the fallback for unregistered input
458
+ validation codes; a registered code such as `NOT_FOUND` retains its mapped 404.
459
+
396
460
  ### Declared secrets are SDK-enforced
397
461
 
398
462
  Environment/secret presence validation is single-sourced in the SDK. Declare
@@ -411,12 +475,12 @@ secrets: [
411
475
  The runtime validates every `required: true` declaration before any operation
412
476
  handler or auth-flow handler (except `abort`) runs. When a required secret is
413
477
  unset or whitespace-only, the invocation fails with the canonical structured
414
- error — code `MISSING_SECRET`, HTTP 400, `details.category:
415
- "credential_unavailable"`, `retryable: false`, and a `fix` naming every missing
416
- secret across `/v1/{operation}`, self-test probes, `apifuse perf`, and
417
- `apifuse record`. The server also emits a `provider_secrets_missing` warn log
418
- at boot so unprovisioned deployments are visible immediately without crashing
419
- the pod.
478
+ error — code `MISSING_SECRET`, HTTP 400, top-level `retryable: false`, and a
479
+ `fix` naming every missing secret — across `/v1/{operation}`, self-test probes,
480
+ `apifuse perf`, and `apifuse record`. Its error-observability header carries the
481
+ `credential_unavailable` category. The server also emits a
482
+ `provider_secrets_missing` warn log at boot so unprovisioned deployments are
483
+ visible immediately without crashing the pod.
420
484
 
421
485
  Provider-local presence re-validation is **deprecated**: do not write
422
486
  `requireServiceKey`/`requireApiKey`-style guards that re-check `ctx.env.get()`
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @apifuse/provider-sdk Changelog
2
2
 
3
+ ## 2.2.0-beta.15
4
+
5
+ - Release candidate for main commit b5ebd25e48f6502e4ddb775d4e0a25f5c8276712.
6
+
7
+ ## 2.2.0-beta.14
8
+
9
+ - Release candidate for main commit 3491acd253ca17b517985e8a618f1c2904a664a9.
10
+
3
11
  ## 2.2.0-beta.13
4
12
 
5
13
  - Release candidate for main commit 75e840d0614aea3b99a1e5cef4f93f8cdccf0507.
@@ -82,6 +90,10 @@
82
90
 
83
91
  ## Unreleased
84
92
 
93
+ - Add an opt-in same-origin redirect hop policy to `ctx.http`, with bounded manual following and typed failures before a refused target is requested.
94
+ - Enforce provider-declared native TCP/TLS egress before proxy or socket setup, with revocable and expiring dynamic grants plus typed authorization failures; providers without a native egress declaration retain legacy behavior.
95
+ - **Breaking:** Provider error `details` is now passed through verbatim; SDK observability fields (`category`, `taxonomyVersion`, `upstreamStatus`, and derived `retryable`) are no longer merged into the public body. Emitted error envelopes now require top-level `retryable`, while inbound stateful forwarding tolerates an older owner response that omits it and defaults it to `false`. The removed observability metadata is available in the new `X-ApiFuse-Error-Observability` response header.
96
+ - Unregistered `ProviderError` codes now default to HTTP 500 instead of 400 and emit an `unregistered_provider_error_code` structured-log signal; registered mappings remain unchanged and take precedence over the HTTP 400 fallback for unregistered input `ValidationError` codes.
85
97
  - Add an opt-in native connection idle read timeout with a typed error, independently from TCP/SOCKS/TLS establishment deadlines.
86
98
  - Add opt-in `maxBodyBytes` enforcement to stealth fetches and redirect hops, aborting oversized decoded response streams with `response_too_large`.
87
99
  - Resolve relative date tokens in fixture requests before input-schema validation, add KST capture-date `fixtures.recordedAt` metadata, and support explicit KST/UTC calendars in the shared health-input resolver.
package/dist/define.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import ms from "ms";
2
2
  import { ProviderError, ValidationError } from "./errors.js";
3
+ import { NativeEgressPolicyValidationError, validateNativeProviderConfig, } from "./native-egress-policy.js";
3
4
  import { safeParseSchemaSync } from "./schema.js";
4
5
  import { resolveHealthCheckInputDateTokens } from "./server/self-test-input-tokens.js";
5
6
  import { HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MAX, HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MIN, HEALTH_CHECK_TIMEOUT_MS_MAX, HEALTH_CHECK_TIMEOUT_MS_MIN, OPERATION_TIMEOUT_MS_MAX, OPERATION_TIMEOUT_MS_MIN, STREAM_CHUNK_BYTES_MAX, STREAM_CHUNK_BYTES_MIN, STREAM_HEARTBEAT_MS_MAX, STREAM_HEARTBEAT_MS_MIN, STREAM_IDLE_TIMEOUT_MS_MAX, STREAM_IDLE_TIMEOUT_MS_MIN, STREAM_MAX_DURATION_MS_MAX, STREAM_MAX_DURATION_MS_MIN, } from "./types.js";
@@ -1407,6 +1408,14 @@ export function defineProvider(config) {
1407
1408
  validateProviderHealthMonitor(config.id, config.healthProbe ?? config.healthMonitor, config.healthProbe !== undefined ? "healthProbe" : "healthMonitor");
1408
1409
  validateOperationFixtures(config.id, operations);
1409
1410
  validateProviderDeployment(config.id, config.deployment);
1411
+ try {
1412
+ validateNativeProviderConfig(config.native);
1413
+ }
1414
+ catch (error) {
1415
+ if (error instanceof NativeEgressPolicyValidationError)
1416
+ throw new ValidationError(error.message);
1417
+ throw error;
1418
+ }
1410
1419
  validateProviderProxy(config);
1411
1420
  validateProviderStt(config);
1412
1421
  if (config.runtime === "browser" && !config.browser)
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ProviderErrorCategory } from "./observability.js";
2
+ import type { HttpRedirectFailureReason } from "./types.js";
2
3
  export type ProviderErrorOptions = {
3
4
  fix?: string;
4
5
  code?: string;
@@ -44,9 +45,21 @@ export declare class TransportError extends ProviderError {
44
45
  readonly upstreamStatus?: number;
45
46
  constructor(message: string, options?: TransportErrorOptions);
46
47
  }
48
+ export type HttpRedirectErrorOptions = TransportErrorOptions & {
49
+ reason: HttpRedirectFailureReason;
50
+ /** Redacted redirect target suitable for provider diagnostics. */
51
+ target?: string;
52
+ };
53
+ /** Raised when an opt-in ctx.http redirect policy refuses or cannot resolve a hop. */
54
+ export declare class HttpRedirectError extends TransportError {
55
+ readonly reason: HttpRedirectFailureReason;
56
+ readonly target?: string;
57
+ constructor(message: string, options: HttpRedirectErrorOptions);
58
+ }
47
59
  export declare function isProviderError(value: unknown): value is ProviderError;
48
60
  export declare function isSessionExpiredError(value: unknown): value is SessionExpiredError;
49
61
  export declare function isTransportError(value: unknown): value is TransportError;
62
+ export declare function isValidationError(value: unknown): value is ValidationError;
50
63
  export declare class ProviderSecretError extends ProviderError {
51
64
  constructor(message: string, options?: ProviderErrorOptions);
52
65
  }
package/dist/errors.js CHANGED
@@ -8,6 +8,7 @@ const PROVIDER_ERROR_BRAND = Symbol.for("@apifuse/provider-sdk/error-brand@1");
8
8
  const PROVIDER_ERROR_BRAND_VALUE = 1;
9
9
  const SESSION_EXPIRED_BRAND = Symbol.for("@apifuse/provider-sdk/error-kind/session-expired@1");
10
10
  const TRANSPORT_BRAND = Symbol.for("@apifuse/provider-sdk/error-kind/transport@1");
11
+ const VALIDATION_BRAND = Symbol.for("@apifuse/provider-sdk/error-kind/validation@1");
11
12
  // Defines a non-enumerable, non-writable, non-configurable own data property.
12
13
  // Immutable + own means a guard can trust it via a single descriptor read
13
14
  // without invoking attacker-controlled getters or accepting inherited brands.
@@ -96,6 +97,7 @@ export class ValidationError extends ProviderError {
96
97
  super(message, options);
97
98
  this.name = "ValidationError";
98
99
  this.zodError = options?.zodError;
100
+ defineErrorBrand(this, VALIDATION_BRAND, true);
99
101
  }
100
102
  }
101
103
  export class TransportError extends ProviderError {
@@ -109,6 +111,25 @@ export class TransportError extends ProviderError {
109
111
  defineErrorBrand(this, TRANSPORT_BRAND, true);
110
112
  }
111
113
  }
114
+ /** Raised when an opt-in ctx.http redirect policy refuses or cannot resolve a hop. */
115
+ export class HttpRedirectError extends TransportError {
116
+ reason;
117
+ target;
118
+ constructor(message, options) {
119
+ const { reason, target, ...transportOptions } = options;
120
+ super(message, {
121
+ ...transportOptions,
122
+ code: `http_redirect_${reason}`,
123
+ details: {
124
+ reason,
125
+ ...(target ? { target } : {}),
126
+ },
127
+ });
128
+ this.name = "HttpRedirectError";
129
+ this.reason = reason;
130
+ this.target = target;
131
+ }
132
+ }
112
133
  // Cross-module type guards. Prefer these over `instanceof` at any boundary that
113
134
  // may receive an error from a different copy/entrypoint of the SDK (see the HTTP
114
135
  // server error boundary). They recognize branded errors regardless of which
@@ -122,6 +143,10 @@ export function isSessionExpiredError(value) {
122
143
  export function isTransportError(value) {
123
144
  return isProviderError(value) && hasOwnBrand(value, TRANSPORT_BRAND, true);
124
145
  }
146
+ export function isValidationError(value) {
147
+ return (isProviderError(value) &&
148
+ (hasOwnBrand(value, VALIDATION_BRAND, true) || value.name === "ValidationError"));
149
+ }
125
150
  export class ProviderSecretError extends ProviderError {
126
151
  constructor(message, options) {
127
152
  super(message, { code: "provider_secret_error", ...options });
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ export { type CreateCredentialContextOptions, createCredentialContext, } from ".
22
22
  export { createEnvContext } from "./runtime/env.js";
23
23
  export { executeOperation } from "./runtime/executor.js";
24
24
  export { createHttpClient } from "./runtime/http.js";
25
- export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, type NativeGatewayProxy, type NativeGatewayProxyResolutionInput, type NativeGatewayProxySynthesizer, type NativeGatewayProxySynthesisInput, type NativeNetworkClientOptions, type NativeNetworkErrorCode, } from "./runtime/native-network.js";
25
+ export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, type NativeGatewayProxy, type NativeGatewayProxyResolutionInput, type NativeGatewayProxySynthesizer, type NativeGatewayProxySynthesisInput, type NativeNetworkClientOptions, type NativeNetworkErrorCode, } from "./runtime/native-network.js";
26
26
  export type { Insight, InsightSeverity } from "./runtime/insights.js";
27
27
  export { generateInsights } from "./runtime/insights.js";
28
28
  export { type InstrumentationOptions, type InstrumentedProviderContext, wrapWithInstrumentation, } from "./runtime/instrumentation.js";
@@ -34,10 +34,10 @@ export { createStealthClient } from "./runtime/stealth.js";
34
34
  export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
35
35
  export { type CreateTraceContextOptions, createTraceContext, type Span, type TraceContext, } from "./runtime/trace.js";
36
36
  export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, z, } from "./schema.js";
37
- export { createServerApp, type ServeOptions, serve } from "./server/index.js";
37
+ export { createServerApp, ERROR_OBSERVABILITY_HEADER, type ServeOptions, serve, } from "./server/index.js";
38
38
  export { getStealthProfile, listStealthProfiles } from "./stealth/profiles.js";
39
39
  export * from "./stream.js";
40
- export type { ApiFuseResponse, AuthConfig, AuthContext, AuthFlowDefinition, AuthFlowInputHandler, AuthFlowStartHandler, AuthMode, AuthTurn, Bcp47Locale, BrowserEngine, BrowserOptions, BrowserResourceBody, BrowserResourceDecision, BrowserResourceMethod, BrowserResourcePolicy, BrowserResourceRequest, BrowserResourceRoute, ConnectionMode, ContextDeclaration, CookieJar, ContextScratchpad, CredentialContext, CredentialDeclaration, E164PhoneNumber, EnvContext, FlowContext, FlowContextStore, HealthCheckAssertionContext, HealthCheckCase, HealthCheckCaseResult, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyGatewayContext, HealthJourneyJournalContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthJourneySchedule, HealthScheduleRandomization, HealthJourneySmsContext, HealthJourneyStep, HttpClient, HttpMethod, HttpResponse, HttpRetryOptions, HttpRetrySummary, HttpStreamResponse, IanaTimeZone, InferSchemaOutput, Iso3166Alpha2CountryCode, Iso4217CurrencyCode, Iso8601Duration, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnection, NativeNetworkConnectInput, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProviderContext, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OperationAnnotations, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDeprecationMetadata, OperationDocMeta, OperationErrorCode, OperationHandlerResult, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, OperationTransportKind, ProbeInterval, ProviderAccessConfig, ProviderAccessVisibility, ProviderCache, ProviderCacheGetOrSetOptions, ProviderCacheKeyOptions, ProviderCacheLookupMeta, ProviderCacheResponseMeta, ProviderCacheResult, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderHealthMonitorConfig, ProviderHealthProbeConfig, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderLogoSource, ProviderMeta, ProviderProxyConfig, ProviderProxyMode, ProviderProxyPolicy, ProviderProxyProvider, ProviderProxySessionAffinity, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderReviewed, ProviderResolvedFile, ProviderRuntimeState, ProviderSecretDeclaration, ProviderStateDurationString, ProviderStateNamespace, ProviderStreamEvent, ProviderSttConfig, ProviderSttMode, ProviderSupportLevel, RequestOptions, Rfc3339Instant, SchemaLike, SmsOrigin, SmsOtpExtractionPattern, SmsOtpMatcherDefinition, SseMessage, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, StealthClient, StealthCookieStore, StealthCookieStoreV1, StealthFetchOptions, StealthPlatform, StealthProfile, StealthRedirectHop, StealthRedirectRunOptions, StealthRedirectRunResult, StealthResponse, StealthSession, StealthSessionCookies, SttAudioInput, SttContext, SttPromptPolicy, SttSegment, SttTranscribeMode, SttTranscribeRequest, SttTranscript, SttUnsupportedOptionPolicy, SttUsage, SttVerificationCodeOptions, SttWarning, TraceConfig, TraceSpan, VerificationCodeCandidate, VerificationCodeCandidateSource, VerificationCodeExtractionResult, } from "./types.js";
40
+ export type { ApiFuseResponse, AuthConfig, AuthContext, AuthFlowDefinition, AuthFlowInputHandler, AuthFlowStartHandler, AuthMode, AuthTurn, Bcp47Locale, BrowserEngine, BrowserOptions, BrowserResourceBody, BrowserResourceDecision, BrowserResourceMethod, BrowserResourcePolicy, BrowserResourceRequest, BrowserResourceRoute, ConnectionMode, ContextDeclaration, CookieJar, ContextScratchpad, CredentialContext, CredentialDeclaration, E164PhoneNumber, EnvContext, FlowContext, FlowContextStore, HealthCheckAssertionContext, HealthCheckCase, HealthCheckCaseResult, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyGatewayContext, HealthJourneyJournalContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthJourneySchedule, HealthScheduleRandomization, HealthJourneySmsContext, HealthJourneyStep, HttpClient, HttpMethod, HttpRedirectFailureReason, HttpRedirectPolicy, HttpRedirectPolicyMode, HttpResponse, HttpRetryOptions, HttpRetrySummary, HttpStreamResponse, IanaTimeZone, InferSchemaOutput, Iso3166Alpha2CountryCode, Iso4217CurrencyCode, Iso8601Duration, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnection, NativeNetworkConnectInput, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProviderContext, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OperationAnnotations, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDeprecationMetadata, OperationDocMeta, OperationErrorCode, OperationHandlerResult, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, OperationTransportKind, ProbeInterval, ProviderAccessConfig, ProviderAccessVisibility, ProviderCache, ProviderCacheGetOrSetOptions, ProviderCacheKeyOptions, ProviderCacheLookupMeta, ProviderCacheResponseMeta, ProviderCacheResult, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderHealthMonitorConfig, ProviderHealthProbeConfig, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderLogoSource, ProviderMeta, ProviderProxyConfig, ProviderProxyMode, ProviderProxyPolicy, ProviderProxyProvider, ProviderProxySessionAffinity, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderReviewed, ProviderResolvedFile, ProviderRuntimeState, ProviderSecretDeclaration, ProviderStateDurationString, ProviderStateNamespace, ProviderStreamEvent, ProviderSttConfig, ProviderSttMode, ProviderSupportLevel, RequestOptions, RedirectRunReason, Rfc3339Instant, SchemaLike, SmsOrigin, SmsOtpExtractionPattern, SmsOtpMatcherDefinition, SseMessage, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, StealthClient, StealthCookieStore, StealthCookieStoreV1, StealthFetchOptions, StealthPlatform, StealthProfile, StealthRedirectHop, StealthRedirectRunOptions, StealthRedirectRunResult, StealthResponse, StealthSession, StealthSessionCookies, SttAudioInput, SttContext, SttPromptPolicy, SttSegment, SttTranscribeMode, SttTranscribeRequest, SttTranscript, SttUnsupportedOptionPolicy, SttUsage, SttVerificationCodeOptions, SttWarning, TraceConfig, TraceSpan, VerificationCodeCandidate, VerificationCodeCandidateSource, VerificationCodeExtractionResult, } from "./types.js";
41
41
  export { DEFAULT_OPERATION_TRANSPORT, HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, PROBE_INTERVALS, STREAM_CHUNK_BYTES_MAX, STREAM_CHUNK_BYTES_MIN, STREAM_HEARTBEAT_MS_MAX, STREAM_HEARTBEAT_MS_MIN, STREAM_IDLE_TIMEOUT_MS_MAX, STREAM_IDLE_TIMEOUT_MS_MIN, STREAM_MAX_DURATION_MS_MAX, STREAM_MAX_DURATION_MS_MIN, } from "./types.js";
42
42
  export * from "./utils/date.js";
43
43
  export * from "./utils/parse.js";
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ export { createCredentialContext, } from "./runtime/credential.js";
20
20
  export { createEnvContext } from "./runtime/env.js";
21
21
  export { executeOperation } from "./runtime/executor.js";
22
22
  export { createHttpClient } from "./runtime/http.js";
23
- export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, } from "./runtime/native-network.js";
23
+ export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, } from "./runtime/native-network.js";
24
24
  export { generateInsights } from "./runtime/insights.js";
25
25
  export { wrapWithInstrumentation, } from "./runtime/instrumentation.js";
26
26
  export { prevalidate } from "./runtime/prevalidate.js";
@@ -31,7 +31,7 @@ export { createStealthClient } from "./runtime/stealth.js";
31
31
  export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
32
32
  export { createTraceContext, } from "./runtime/trace.js";
33
33
  export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, sensitive, z, } from "./schema.js";
34
- export { createServerApp, serve } from "./server/index.js";
34
+ export { createServerApp, ERROR_OBSERVABILITY_HEADER, serve, } from "./server/index.js";
35
35
  export { getStealthProfile, listStealthProfiles } from "./stealth/profiles.js";
36
36
  export * from "./stream.js";
37
37
  export { DEFAULT_OPERATION_TRANSPORT, HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, PROBE_INTERVALS, STREAM_CHUNK_BYTES_MAX, STREAM_CHUNK_BYTES_MIN, STREAM_HEARTBEAT_MS_MAX, STREAM_HEARTBEAT_MS_MIN, STREAM_IDLE_TIMEOUT_MS_MAX, STREAM_IDLE_TIMEOUT_MS_MIN, STREAM_MAX_DURATION_MS_MAX, STREAM_MAX_DURATION_MS_MIN, } from "./types.js";
@@ -0,0 +1,27 @@
1
+ import type { NativeTcpPortRange, NativeTcpTlsMode } from "./types.js";
2
+ export type StaticEgressRuleSnapshot = {
3
+ readonly host: string;
4
+ readonly ports: readonly number[];
5
+ readonly tls: NativeTcpTlsMode;
6
+ };
7
+ export type DynamicEgressRuleSnapshot = {
8
+ readonly sourceHost?: string;
9
+ readonly sourceHostSuffixes: readonly string[];
10
+ readonly sourcePorts: readonly number[];
11
+ readonly sourcePortRanges: readonly NativeTcpPortRange[];
12
+ readonly targetHostSuffixes: readonly string[];
13
+ readonly targetPorts: readonly number[];
14
+ readonly targetPortRanges: readonly NativeTcpPortRange[];
15
+ readonly tls: NativeTcpTlsMode;
16
+ readonly ttlMs?: number;
17
+ readonly maxGrants?: number;
18
+ };
19
+ export type NativeEgressPolicySnapshot = {
20
+ readonly staticRules: readonly StaticEgressRuleSnapshot[];
21
+ readonly dynamicRules: readonly DynamicEgressRuleSnapshot[];
22
+ };
23
+ export declare class NativeEgressPolicyValidationError extends Error {
24
+ constructor(message: string);
25
+ }
26
+ export declare function parseNativeEgressPolicy(value: unknown): NativeEgressPolicySnapshot;
27
+ export declare function validateNativeProviderConfig(value: unknown): void;
@@ -0,0 +1,225 @@
1
+ const NATIVE_PROVIDER_FIELD_RECORD = {
2
+ network: true,
3
+ };
4
+ const NATIVE_NETWORK_FIELD_RECORD = {
5
+ tcp: true,
6
+ dynamicTcp: true,
7
+ };
8
+ const NATIVE_TCP_RULE_FIELD_RECORD = {
9
+ host: true,
10
+ ports: true,
11
+ tls: true,
12
+ };
13
+ const NATIVE_DYNAMIC_TCP_RULE_FIELD_RECORD = {
14
+ sourceHost: true,
15
+ sourceHostSuffixes: true,
16
+ sourcePorts: true,
17
+ sourcePortRanges: true,
18
+ targetHostSuffixes: true,
19
+ targetPorts: true,
20
+ targetPortRanges: true,
21
+ tls: true,
22
+ ttlMs: true,
23
+ maxGrants: true,
24
+ };
25
+ const NATIVE_TCP_PORT_RANGE_FIELD_RECORD = {
26
+ start: true,
27
+ end: true,
28
+ };
29
+ const NATIVE_PROVIDER_FIELDS = Object.keys(NATIVE_PROVIDER_FIELD_RECORD);
30
+ const NATIVE_NETWORK_FIELDS = Object.keys(NATIVE_NETWORK_FIELD_RECORD);
31
+ const NATIVE_TCP_RULE_FIELDS = Object.keys(NATIVE_TCP_RULE_FIELD_RECORD);
32
+ const NATIVE_DYNAMIC_TCP_RULE_FIELDS = Object.keys(NATIVE_DYNAMIC_TCP_RULE_FIELD_RECORD);
33
+ const NATIVE_TCP_PORT_RANGE_FIELDS = Object.keys(NATIVE_TCP_PORT_RANGE_FIELD_RECORD);
34
+ export class NativeEgressPolicyValidationError extends Error {
35
+ constructor(message) {
36
+ super(message);
37
+ this.name = "NativeEgressPolicyValidationError";
38
+ }
39
+ }
40
+ function fail(message) {
41
+ throw new NativeEgressPolicyValidationError(message);
42
+ }
43
+ function dataRecord(value, fieldPath, allowed) {
44
+ if (!value || typeof value !== "object" || Array.isArray(value))
45
+ fail(`${fieldPath} must be an object`);
46
+ const prototype = Reflect.getPrototypeOf(value);
47
+ if (prototype !== Object.prototype && prototype !== null)
48
+ fail(`${fieldPath} must be a plain object`);
49
+ const record = {};
50
+ for (const key of Reflect.ownKeys(value)) {
51
+ if (typeof key !== "string")
52
+ fail(`${fieldPath} must not contain symbol fields`);
53
+ if (!allowed.includes(key))
54
+ fail(`Unknown field ${fieldPath}.${key}`);
55
+ const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
56
+ if (!descriptor || !("value" in descriptor))
57
+ fail(`${fieldPath}.${key} must be a data field`);
58
+ record[key] = descriptor.value;
59
+ }
60
+ return record;
61
+ }
62
+ function dataArray(value, fieldPath) {
63
+ if (!Array.isArray(value))
64
+ fail(`${fieldPath} must be an array`);
65
+ const result = [];
66
+ for (const key of Reflect.ownKeys(value)) {
67
+ if (key === "length")
68
+ continue;
69
+ if (typeof key !== "string" || !/^(?:0|[1-9]\d*)$/.test(key))
70
+ fail(`${fieldPath} must not contain non-index fields`);
71
+ const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
72
+ if (!descriptor || !("value" in descriptor))
73
+ fail(`${fieldPath}[${key}] must be a data field`);
74
+ result[Number(key)] = descriptor.value;
75
+ }
76
+ if (result.length !== value.length)
77
+ fail(`${fieldPath} must not be sparse`);
78
+ for (let index = 0; index < result.length; index += 1) {
79
+ if (!(index in result))
80
+ fail(`${fieldPath} must not be sparse`);
81
+ }
82
+ return result;
83
+ }
84
+ function hasControlCharacter(value) {
85
+ for (let index = 0; index < value.length; index += 1) {
86
+ const code = value.charCodeAt(index);
87
+ if (code <= 31 || code === 127)
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+ function host(value, fieldPath, suffix = false) {
93
+ if (typeof value !== "string" ||
94
+ !value.trim() ||
95
+ hasControlCharacter(value) ||
96
+ /\s/.test(value) ||
97
+ value.includes("://"))
98
+ fail(`${fieldPath} must be a non-empty hostname`);
99
+ if (value.includes("*"))
100
+ fail(`${fieldPath} must be an exact ${suffix ? "DNS suffix" : "hostname"}, not a wildcard`);
101
+ const normalized = value.trim().toLowerCase().replace(/\.$/, "");
102
+ if (!normalized)
103
+ fail(`${fieldPath} must be a non-empty hostname`);
104
+ return normalized;
105
+ }
106
+ function port(value, fieldPath) {
107
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > 65_535)
108
+ fail(`${fieldPath} must be an integer from 1 to 65535`);
109
+ return value;
110
+ }
111
+ function ports(value, fieldPath) {
112
+ return dataArray(value, fieldPath).map((value, index) => port(value, `${fieldPath}[${index}]`));
113
+ }
114
+ function hostSuffixes(value, fieldPath) {
115
+ return dataArray(value, fieldPath).map((value, index) => host(value, `${fieldPath}[${index}]`, true));
116
+ }
117
+ function ranges(value, fieldPath) {
118
+ return dataArray(value, fieldPath).map((value, index) => {
119
+ const rangePath = `${fieldPath}[${index}]`;
120
+ const record = dataRecord(value, rangePath, NATIVE_TCP_PORT_RANGE_FIELDS);
121
+ const start = port(record.start, `${rangePath}.start`);
122
+ const end = port(record.end, `${rangePath}.end`);
123
+ if (start > end)
124
+ fail(`${rangePath}.start must not exceed end`);
125
+ return { start, end };
126
+ });
127
+ }
128
+ function tls(value, fieldPath) {
129
+ if (value !== "required" && value !== "allowed" && value !== "disabled")
130
+ fail(`${fieldPath} must be required, allowed, or disabled`);
131
+ return value;
132
+ }
133
+ function positiveInteger(value, fieldPath) {
134
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0)
135
+ fail(`${fieldPath} must be a positive integer`);
136
+ return value;
137
+ }
138
+ export function parseNativeEgressPolicy(value) {
139
+ try {
140
+ const policy = dataRecord(value, "native.network", NATIVE_NETWORK_FIELDS);
141
+ const staticRules = policy.tcp === undefined
142
+ ? []
143
+ : dataArray(policy.tcp, "native.network.tcp").map((value, index) => {
144
+ const fieldPath = `native.network.tcp[${index}]`;
145
+ const rule = dataRecord(value, fieldPath, NATIVE_TCP_RULE_FIELDS);
146
+ const declaredPorts = ports(rule.ports, `${fieldPath}.ports`);
147
+ if (declaredPorts.length === 0)
148
+ fail(`${fieldPath}.ports must not be empty`);
149
+ return {
150
+ host: host(rule.host, `${fieldPath}.host`),
151
+ ports: declaredPorts,
152
+ tls: tls(rule.tls, `${fieldPath}.tls`),
153
+ };
154
+ });
155
+ const dynamicRules = policy.dynamicTcp === undefined
156
+ ? []
157
+ : dataArray(policy.dynamicTcp, "native.network.dynamicTcp").map((value, index) => {
158
+ const fieldPath = `native.network.dynamicTcp[${index}]`;
159
+ const rule = dataRecord(value, fieldPath, NATIVE_DYNAMIC_TCP_RULE_FIELDS);
160
+ const sourceHost = rule.sourceHost === undefined
161
+ ? undefined
162
+ : host(rule.sourceHost, `${fieldPath}.sourceHost`);
163
+ const sourceHostSuffixes = rule.sourceHostSuffixes === undefined
164
+ ? []
165
+ : hostSuffixes(rule.sourceHostSuffixes, `${fieldPath}.sourceHostSuffixes`);
166
+ if (sourceHost === undefined && sourceHostSuffixes.length === 0)
167
+ fail(`${fieldPath} must declare sourceHost or a non-empty sourceHostSuffixes list`);
168
+ const sourcePorts = rule.sourcePorts === undefined
169
+ ? []
170
+ : ports(rule.sourcePorts, `${fieldPath}.sourcePorts`);
171
+ const sourcePortRanges = rule.sourcePortRanges === undefined
172
+ ? []
173
+ : ranges(rule.sourcePortRanges, `${fieldPath}.sourcePortRanges`);
174
+ if (sourcePorts.length === 0 && sourcePortRanges.length === 0)
175
+ fail(`${fieldPath} must declare a non-empty sourcePorts or sourcePortRanges list`);
176
+ const targetHostSuffixes = hostSuffixes(rule.targetHostSuffixes, `${fieldPath}.targetHostSuffixes`);
177
+ if (targetHostSuffixes.length === 0)
178
+ fail(`${fieldPath}.targetHostSuffixes must not be empty`);
179
+ const targetPorts = rule.targetPorts === undefined
180
+ ? []
181
+ : ports(rule.targetPorts, `${fieldPath}.targetPorts`);
182
+ const targetPortRanges = rule.targetPortRanges === undefined
183
+ ? []
184
+ : ranges(rule.targetPortRanges, `${fieldPath}.targetPortRanges`);
185
+ if (targetPorts.length === 0 && targetPortRanges.length === 0)
186
+ fail(`${fieldPath} must declare a non-empty targetPorts or targetPortRanges list`);
187
+ return {
188
+ ...(sourceHost === undefined ? {} : { sourceHost }),
189
+ sourceHostSuffixes,
190
+ sourcePorts,
191
+ sourcePortRanges,
192
+ targetHostSuffixes,
193
+ targetPorts,
194
+ targetPortRanges,
195
+ tls: tls(rule.tls, `${fieldPath}.tls`),
196
+ ...(rule.ttlMs === undefined
197
+ ? {}
198
+ : { ttlMs: positiveInteger(rule.ttlMs, `${fieldPath}.ttlMs`) }),
199
+ ...(rule.maxGrants === undefined
200
+ ? {}
201
+ : { maxGrants: positiveInteger(rule.maxGrants, `${fieldPath}.maxGrants`) }),
202
+ };
203
+ });
204
+ return { staticRules, dynamicRules };
205
+ }
206
+ catch (error) {
207
+ if (error instanceof NativeEgressPolicyValidationError)
208
+ throw error;
209
+ throw new NativeEgressPolicyValidationError("Native egress policy could not be inspected safely");
210
+ }
211
+ }
212
+ export function validateNativeProviderConfig(value) {
213
+ if (value === undefined)
214
+ return;
215
+ try {
216
+ const native = dataRecord(value, "native", NATIVE_PROVIDER_FIELDS);
217
+ if (native.network !== undefined)
218
+ parseNativeEgressPolicy(native.network);
219
+ }
220
+ catch (error) {
221
+ if (error instanceof NativeEgressPolicyValidationError)
222
+ throw error;
223
+ throw new NativeEgressPolicyValidationError("Native provider config could not be inspected safely");
224
+ }
225
+ }
@@ -3,10 +3,10 @@ export type { CredentialsAuthChallengeDefinition, CredentialsAuthChallengeReques
3
3
  export { createFormCeremony } from "./ceremonies/index.js";
4
4
  export { assertFreshProviderChoiceIssuedAt, createProviderChoiceToken, ProviderChoiceTokenError, type ProviderChoiceTokenErrorReason, type ProviderChoiceTokenPayload, parseProviderChoiceToken, } from "./choice-token.js";
5
5
  export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define.js";
6
- export { AuthError, isProviderError, isSessionExpiredError, isTransportError, ProviderError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
6
+ export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, isTransportError, ProviderError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
7
7
  export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
8
8
  export { type CreateProviderChoiceContextOptions, createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
9
9
  export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, z, } from "./schema.js";
10
- export type { AuthAbortData, AuthAbortRetry, AuthFlowTerminalContext, AuthMode, AuthSafeData, AuthSafeJson, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthScheduleRandomization, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnection, NativeNetworkConnectInput, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProviderContext, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDocMeta, OperationErrorCode, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, ProviderAccessVisibility, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderProxyPolicy, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderResolvedFile, ProviderRuntimeState, ProviderStateDurationString, ProviderStateNamespace, ProviderSupportLevel, SchemaLike, SmsOtpMatcherDefinition, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, } from "./types.js";
11
- export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, type NativeGatewayProxy, type NativeGatewayProxyResolutionInput, type NativeGatewayProxySynthesizer, type NativeGatewayProxySynthesisInput, type NativeNetworkClientOptions, type NativeNetworkErrorCode, } from "./runtime/native-network.js";
10
+ export type { AuthAbortData, AuthAbortRetry, AuthFlowTerminalContext, AuthMode, AuthSafeData, AuthSafeJson, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthScheduleRandomization, HttpRedirectFailureReason, HttpRedirectPolicy, HttpRedirectPolicyMode, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, NativeContext, NativeNetworkClient, NativeNetworkCloseReason, NativeNetworkConnection, NativeNetworkConnectInput, NativeNetworkConnectOptions, NativeNetworkDynamicGrantOptions, NativeNetworkEgressGrant, NativeProviderConfig, NativeProviderContext, NativeProxyDrainHandler, NativeProxyEgressInfo, NativeProxyExpiringEvent, NativeProxyExpiringReason, NativeTcpDynamicEgressRule, NativeTcpEgressGrant, NativeTcpEgressRule, NativeTcpPortRange, NativeTcpTlsMode, NativeTlsConnectOptions, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDocMeta, OperationErrorCode, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, ProviderAccessVisibility, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderDeploymentOverrides, ProviderFileRef, ProviderFilesContext, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderProxyPolicy, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderResolvedFile, ProviderRuntimeState, ProviderStateDurationString, ProviderStateNamespace, ProviderSupportLevel, RedirectRunReason, SchemaLike, SmsOtpMatcherDefinition, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, } from "./types.js";
11
+ export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, type NativeGatewayProxy, type NativeGatewayProxyResolutionInput, type NativeGatewayProxySynthesizer, type NativeGatewayProxySynthesisInput, type NativeNetworkClientOptions, type NativeNetworkErrorCode, } from "./runtime/native-network.js";
12
12
  export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
package/dist/provider.js CHANGED
@@ -2,9 +2,9 @@ export { AuthAbortError, credentialsAuthChallenge, createAuthFlowHelpers, define
2
2
  export { createFormCeremony } from "./ceremonies/index.js";
3
3
  export { assertFreshProviderChoiceIssuedAt, createProviderChoiceToken, ProviderChoiceTokenError, parseProviderChoiceToken, } from "./choice-token.js";
4
4
  export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define.js";
5
- export { AuthError, isProviderError, isSessionExpiredError, isTransportError, ProviderError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
5
+ export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, isTransportError, ProviderError, SessionExpiredError, TransportError, ValidationError, } from "./errors.js";
6
6
  export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
7
7
  export { createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice.js";
8
8
  export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, sensitive, z, } from "./schema.js";
9
- export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, } from "./runtime/native-network.js";
9
+ export { createNativeNetworkClient, deriveNativeCredentialAffinityKey, NativeEgressGrantExpiredError, NativeEgressNotDeclaredError, NativeIdleTimeoutError, NativeNetworkError, NativeProxyExpiredError, resolveNativeGatewayProxy, } from "./runtime/native-network.js";
10
10
  export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types.js";
@@ -1,4 +1,5 @@
1
- import { isSessionExpiredError, ProviderError, SessionExpiredError } from "../errors.js";
1
+ import { isSessionExpiredError, isValidationError, ProviderError, SessionExpiredError, ValidationError, } from "../errors.js";
2
+ import { z } from "zod";
2
3
  import { parseSchema } from "../schema.js";
3
4
  import { assertRequiredSecretsPresent } from "./secrets.js";
4
5
  export function isStreamingOperation(provider, operationId) {
@@ -59,5 +60,19 @@ export async function executeOperation(provider, operationId, ctx, input, _optio
59
60
  if (isStreamingOperation(provider, operationId)) {
60
61
  return result;
61
62
  }
62
- return parseSchema(operation.output, result, `operations.${operationId}.output`);
63
+ try {
64
+ return await parseSchema(operation.output, result, `operations.${operationId}.output`);
65
+ }
66
+ catch (cause) {
67
+ if (!(cause instanceof z.ZodError) && !isValidationError(cause)) {
68
+ throw cause;
69
+ }
70
+ throw new ValidationError(`Operation handler output failed schema validation.`, {
71
+ code: "OUTPUT_VALIDATION_FAILED",
72
+ category: "output_validation",
73
+ retryable: false,
74
+ zodError: isValidationError(cause) ? cause.zodError : cause,
75
+ ...(cause instanceof Error ? { cause } : {}),
76
+ });
77
+ }
63
78
  }