@apifuse/provider-sdk 2.2.0-beta.7 → 2.2.0-beta.70
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/AUTHORING.md +943 -51
- package/CHANGELOG.md +273 -1
- package/LICENSE +21 -0
- package/README.md +117 -29
- package/SUBMISSION.md +3 -2
- package/bin/apifuse-check.ts +293 -13
- package/bin/apifuse-dev.ts +42 -19
- package/bin/apifuse-migrate-deployment.ts +200 -0
- package/bin/apifuse-migrate-operation-declaration.ts +55 -0
- package/bin/apifuse-migrate-shape.ts +202 -0
- package/bin/apifuse-pack-check.ts +19 -6
- package/bin/apifuse-pack-smoke.ts +57 -2
- package/bin/apifuse-pack-types.ts +736 -38
- package/bin/apifuse-perf.ts +59 -23
- package/bin/apifuse-record.ts +923 -94
- package/bin/apifuse-submit-check.ts +2313 -281
- package/bin/apifuse-test.ts +3 -1
- package/bin/submit-check-delimited-text.ts +50 -0
- package/dist/auth-turn/index.d.ts +3 -3
- package/dist/auth-turn/index.js +1 -1
- package/dist/auth.d.ts +14 -0
- package/dist/auth.js +67 -0
- package/dist/ceremonies/index.d.ts +16 -0
- package/dist/ceremonies/index.js +141 -36
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +30 -0
- package/dist/cli/create.d.ts +1 -1
- package/dist/cli/create.js +8 -2
- package/dist/cli/deployment-intent.d.ts +178 -0
- package/dist/cli/deployment-intent.js +277 -0
- package/dist/cli/local-connection.d.ts +111 -0
- package/dist/cli/local-connection.js +151 -0
- package/dist/cli/migrate-deployment-intent.d.ts +132 -0
- package/dist/cli/migrate-deployment-intent.js +1552 -0
- package/dist/cli/migrate-operation-declaration.d.ts +70 -0
- package/dist/cli/migrate-operation-declaration.js +2206 -0
- package/dist/cli/migrate-operation-shape.d.ts +44 -0
- package/dist/cli/migrate-operation-shape.js +113 -0
- package/dist/cli/migrate-provider-shape.d.ts +56 -0
- package/dist/cli/migrate-provider-shape.js +580 -0
- package/dist/cli/resolver-runtime.d.ts +21 -0
- package/dist/cli/resolver-runtime.js +31 -0
- package/dist/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +141 -23
- package/dist/cli/templates/provider/Dockerfile.tpl +1 -1
- package/dist/cli/templates/provider/README.md.tpl +41 -19
- package/dist/cli/templates/provider/index.ts.tpl +6 -3
- package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/dist/cli/templates/provider/provider.json.tpl +6 -0
- package/dist/config/loader.d.ts +202 -16
- package/dist/config/loader.js +491 -141
- package/dist/contract-serialization.js +4 -8
- package/dist/contract-types.d.ts +12 -5
- package/dist/contract.js +24 -10
- package/dist/declaration-validation.d.ts +34 -0
- package/dist/declaration-validation.js +305 -0
- package/dist/define.d.ts +71 -29
- package/dist/define.js +807 -69
- package/dist/dev.d.ts +5 -0
- package/dist/dev.js +8 -1
- package/dist/engine.d.ts +129 -0
- package/dist/engine.js +209 -0
- package/dist/error-observability.d.ts +7 -0
- package/dist/error-observability.js +61 -0
- package/dist/error-resolution.d.ts +18 -0
- package/dist/error-resolution.js +243 -0
- package/dist/errors.d.ts +74 -0
- package/dist/errors.js +99 -0
- package/dist/fixture-sanitization.d.ts +28 -0
- package/dist/fixture-sanitization.js +371 -0
- package/dist/handle-meta.d.ts +90 -0
- package/dist/handle-meta.js +73 -0
- package/dist/handle.d.ts +226 -0
- package/dist/handle.js +345 -0
- package/dist/health-scenario.d.ts +1901 -0
- package/dist/health-scenario.js +653 -0
- package/dist/i18n/catalog.js +21 -1
- package/dist/i18n/error-messages.d.ts +86 -0
- package/dist/i18n/error-messages.js +192 -0
- package/dist/i18n/index.d.ts +1 -0
- package/dist/i18n/index.js +1 -0
- package/dist/i18n/keys.d.ts +12 -0
- package/dist/i18n/keys.js +76 -5
- package/dist/i18n/operation-locale-namespace.d.ts +2 -0
- package/dist/i18n/operation-locale-namespace.js +7 -0
- package/dist/index.d.ts +40 -15
- package/dist/index.js +29 -11
- package/dist/lint.d.ts +43 -11
- package/dist/lint.js +2512 -177
- package/dist/native-address.d.ts +43 -0
- package/dist/native-address.js +281 -0
- package/dist/native-egress-policy.d.ts +31 -0
- package/dist/native-egress-policy.js +288 -0
- package/dist/observability.d.ts +5 -2
- package/dist/observability.js +48 -1
- package/dist/provider.d.ts +18 -8
- package/dist/provider.js +11 -6
- package/dist/runtime/auth-flow.d.ts +6 -1
- package/dist/runtime/auth-flow.js +8 -0
- package/dist/runtime/bounded-expiring-map.d.ts +21 -0
- package/dist/runtime/bounded-expiring-map.js +64 -0
- package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
- package/dist/runtime/browser-telemetry-binding.js +83 -0
- package/dist/runtime/browser-telemetry.d.ts +76 -0
- package/dist/runtime/browser-telemetry.js +165 -0
- package/dist/runtime/browser.d.ts +4 -0
- package/dist/runtime/browser.js +688 -83
- package/dist/runtime/cache-telemetry.d.ts +71 -0
- package/dist/runtime/cache-telemetry.js +177 -0
- package/dist/runtime/cache.d.ts +3 -0
- package/dist/runtime/cache.js +245 -23
- package/dist/runtime/capability-response.d.ts +3 -0
- package/dist/runtime/capability-response.js +56 -0
- package/dist/runtime/capability-telemetry.d.ts +46 -0
- package/dist/runtime/capability-telemetry.js +68 -0
- package/dist/runtime/chrome149-header-order.d.ts +58 -0
- package/dist/runtime/chrome149-header-order.js +289 -0
- package/dist/runtime/diagnostic-env-values.d.ts +5 -0
- package/dist/runtime/diagnostic-env-values.js +57 -0
- package/dist/runtime/diagnostic-env.d.ts +14 -0
- package/dist/runtime/diagnostic-env.js +44 -0
- package/dist/runtime/diagnostic-redactor.d.ts +54 -0
- package/dist/runtime/diagnostic-redactor.js +571 -0
- package/dist/runtime/egress-lease.d.ts +65 -0
- package/dist/runtime/egress-lease.js +236 -0
- package/dist/runtime/engine-mode.d.ts +74 -0
- package/dist/runtime/engine-mode.js +152 -0
- package/dist/runtime/env.js +14 -1
- package/dist/runtime/executor.d.ts +3 -2
- package/dist/runtime/executor.js +23 -26
- package/dist/runtime/handle-wordlist.d.ts +43 -0
- package/dist/runtime/handle-wordlist.js +256 -0
- package/dist/runtime/handle.d.ts +71 -0
- package/dist/runtime/handle.js +908 -0
- package/dist/runtime/http-telemetry-binding.d.ts +10 -0
- package/dist/runtime/http-telemetry-binding.js +152 -0
- package/dist/runtime/http-telemetry-guard.d.ts +16 -0
- package/dist/runtime/http-telemetry-guard.js +202 -0
- package/dist/runtime/http-telemetry.d.ts +104 -0
- package/dist/runtime/http-telemetry.js +190 -0
- package/dist/runtime/http.d.ts +34 -0
- package/dist/runtime/http.js +680 -121
- package/dist/runtime/insights.js +2 -2
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +462 -19
- package/dist/runtime/native-network-errors.d.ts +33 -0
- package/dist/runtime/native-network-errors.js +69 -0
- package/dist/runtime/native-network.d.ts +105 -0
- package/dist/runtime/native-network.js +1433 -0
- package/dist/runtime/native-telemetry.d.ts +142 -0
- package/dist/runtime/native-telemetry.js +231 -0
- package/dist/runtime/ocr-telemetry.d.ts +82 -0
- package/dist/runtime/ocr-telemetry.js +192 -0
- package/dist/runtime/ocr.d.ts +29 -0
- package/dist/runtime/ocr.js +468 -0
- package/dist/runtime/otlp.d.ts +71 -2
- package/dist/runtime/otlp.js +398 -16
- package/dist/runtime/provider.d.ts +7 -0
- package/dist/runtime/provider.js +14 -0
- package/dist/runtime/proxy-errors.js +6 -2
- package/dist/runtime/proxy-nodemaven.d.ts +56 -0
- package/dist/runtime/proxy-nodemaven.js +147 -0
- package/dist/runtime/proxy-retry-policy.d.ts +4 -1
- package/dist/runtime/proxy-retry-policy.js +11 -2
- package/dist/runtime/proxy-telemetry.d.ts +133 -3
- package/dist/runtime/proxy-telemetry.js +218 -70
- package/dist/runtime/redirect-hop-headers.d.ts +19 -0
- package/dist/runtime/redirect-hop-headers.js +58 -0
- package/dist/runtime/redirects.d.ts +61 -0
- package/dist/runtime/redirects.js +149 -0
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +4 -2
- package/dist/runtime/request-options.d.ts +75 -1
- package/dist/runtime/request-options.js +588 -0
- package/dist/runtime/request-telemetry.d.ts +70 -0
- package/dist/runtime/request-telemetry.js +229 -0
- package/dist/runtime/resolver-config.d.ts +13 -0
- package/dist/runtime/resolver-config.js +14 -0
- package/dist/runtime/resolver-public.d.ts +3 -0
- package/dist/runtime/resolver-public.js +1 -0
- package/dist/runtime/resolver-runtime-options.d.ts +14 -0
- package/dist/runtime/resolver-runtime-options.js +33 -0
- package/dist/runtime/resolver-shared.d.ts +24 -0
- package/dist/runtime/resolver-shared.js +69 -0
- package/dist/runtime/resolver-span-attributes.d.ts +34 -0
- package/dist/runtime/resolver-span-attributes.js +93 -0
- package/dist/runtime/resolver-telemetry.d.ts +135 -0
- package/dist/runtime/resolver-telemetry.js +204 -0
- package/dist/runtime/resolver-usage.d.ts +32 -0
- package/dist/runtime/resolver-usage.js +54 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +53 -0
- package/dist/runtime/resolver-vendors/bindings.js +45 -0
- package/dist/runtime/resolver-vendors/browser.d.ts +24 -0
- package/dist/runtime/resolver-vendors/browser.js +423 -0
- package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
- package/dist/runtime/resolver-vendors/capsolver.js +544 -0
- package/dist/runtime/resolver-vendors/hosts.d.ts +23 -0
- package/dist/runtime/resolver-vendors/hosts.js +68 -0
- package/dist/runtime/resolver-vendors/hypersolutions.d.ts +27 -0
- package/dist/runtime/resolver-vendors/hypersolutions.js +369 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
- package/dist/runtime/resolver-vendors/twocaptcha.js +425 -0
- package/dist/runtime/resolver-vendors/types.d.ts +125 -0
- package/dist/runtime/resolver-vendors/types.js +106 -0
- package/dist/runtime/resolver.d.ts +79 -0
- package/dist/runtime/resolver.js +1094 -0
- package/dist/runtime/state-telemetry.d.ts +79 -0
- package/dist/runtime/state-telemetry.js +194 -0
- package/dist/runtime/state.d.ts +10 -1
- package/dist/runtime/state.js +322 -82
- package/dist/runtime/stealth-akamai-sbsd.d.ts +54 -0
- package/dist/runtime/stealth-akamai-sbsd.js +142 -0
- package/dist/runtime/stealth-cookies.d.ts +24 -0
- package/dist/runtime/stealth-cookies.js +131 -0
- package/dist/runtime/stealth-owned-headers.d.ts +39 -0
- package/dist/runtime/stealth-owned-headers.js +57 -0
- package/dist/runtime/stealth-telemetry.d.ts +92 -0
- package/dist/runtime/stealth-telemetry.js +179 -0
- package/dist/runtime/stealth.d.ts +45 -6
- package/dist/runtime/stealth.js +1775 -320
- package/dist/runtime/stt-telemetry.d.ts +77 -0
- package/dist/runtime/stt-telemetry.js +176 -0
- package/dist/runtime/stt.js +18 -19
- package/dist/runtime/timeout.d.ts +5 -0
- package/dist/runtime/timeout.js +12 -0
- package/dist/runtime/trace-config.d.ts +12 -0
- package/dist/runtime/trace-config.js +62 -0
- package/dist/runtime/trace.d.ts +17 -0
- package/dist/runtime/trace.js +176 -25
- package/dist/runtime-boundary-lint.d.ts +137 -0
- package/dist/runtime-boundary-lint.js +590 -0
- package/dist/schema.d.ts +20 -0
- package/dist/schema.js +72 -2
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/error-observability.d.ts +1 -0
- package/dist/server/error-observability.js +1 -0
- package/dist/server/error-stack-frames.d.ts +35 -0
- package/dist/server/error-stack-frames.js +219 -0
- package/dist/server/index.d.ts +21 -2
- package/dist/server/index.js +11 -2
- package/dist/server/runtime-diagnostics.d.ts +165 -0
- package/dist/server/runtime-diagnostics.js +360 -0
- package/dist/server/sdk-version.d.ts +3 -0
- package/dist/server/sdk-version.js +19 -0
- package/dist/server/self-test-input-tokens.d.ts +2 -1
- package/dist/server/self-test-input-tokens.js +18 -14
- package/dist/server/self-test-redaction.js +8 -33
- package/dist/server/self-test.d.ts +18 -3
- package/dist/server/self-test.js +139 -76
- package/dist/server/sensitive-values.d.ts +26 -0
- package/dist/server/sensitive-values.js +137 -0
- package/dist/server/serve-implementation.d.ts +285 -0
- package/dist/server/serve-implementation.js +3172 -0
- package/dist/server/serve.d.ts +1 -75
- package/dist/server/serve.js +1 -1170
- package/dist/server/state-backend-report.d.ts +70 -0
- package/dist/server/state-backend-report.js +113 -0
- package/dist/server/trace-output.d.ts +7 -0
- package/dist/server/trace-output.js +111 -0
- package/dist/server/types.d.ts +37 -5
- package/dist/server/types.js +34 -1
- package/dist/stateful/errors.d.ts +19 -0
- package/dist/stateful/errors.js +24 -0
- package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
- package/dist/stateful/http-provider-event-emitter.js +237 -0
- package/dist/stateful/http-session-owner-registry.d.ts +44 -0
- package/dist/stateful/http-session-owner-registry.js +210 -0
- package/dist/stateful/index.d.ts +18 -0
- package/dist/stateful/index.js +18 -0
- package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
- package/dist/stateful/provider-event-delivery-failures.js +43 -0
- package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
- package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
- package/dist/stateful/provider-event-pipeline.d.ts +50 -0
- package/dist/stateful/provider-event-pipeline.js +1 -0
- package/dist/stateful/provider-events.d.ts +101 -0
- package/dist/stateful/provider-events.js +289 -0
- package/dist/stateful/session-key.d.ts +15 -0
- package/dist/stateful/session-key.js +86 -0
- package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
- package/dist/stateful/stateful-provider-adapter-context.js +42 -0
- package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
- package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
- package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
- package/dist/stateful/stateful-provider-adapter.js +287 -0
- package/dist/stateful/stateful-provider-observability.d.ts +62 -0
- package/dist/stateful/stateful-provider-observability.js +161 -0
- package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +237 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +35 -0
- package/dist/stateful/stateful-provider-runtime-context.js +61 -0
- package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
- package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
- package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
- package/dist/stateful/stateful-provider-session-routing.js +345 -0
- package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
- package/dist/stateful/stateful-provider-session-runtime.js +245 -0
- package/dist/stateful-signing.d.ts +18 -0
- package/dist/stateful-signing.js +27 -0
- package/dist/stealth/profiles.d.ts +15 -4
- package/dist/stealth/profiles.js +169 -211
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.js +7 -1
- package/dist/testing/index.d.ts +2 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +509 -25
- package/dist/trace-sanitization.d.ts +6 -0
- package/dist/trace-sanitization.js +68 -0
- package/dist/types.d.ts +899 -210
- package/dist/types.js +1 -0
- package/dist/typescript-module.d.ts +39 -0
- package/dist/typescript-module.js +72 -0
- package/package.json +52 -6
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +118 -0
- package/src/ceremonies/index.ts +189 -46
- package/src/cli/commands.ts +37 -0
- package/src/cli/create.ts +8 -2
- package/src/cli/deployment-intent.ts +364 -0
- package/src/cli/local-connection.ts +221 -0
- package/src/cli/migrate-deployment-intent.ts +1908 -0
- package/src/cli/migrate-operation-declaration.ts +3026 -0
- package/src/cli/migrate-operation-shape.ts +184 -0
- package/src/cli/migrate-provider-shape.ts +778 -0
- package/src/cli/resolver-runtime.ts +72 -0
- package/src/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +141 -23
- package/src/cli/templates/provider/Dockerfile.tpl +1 -1
- package/src/cli/templates/provider/README.md.tpl +41 -19
- package/src/cli/templates/provider/index.ts.tpl +6 -3
- package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/src/cli/templates/provider/provider.json.tpl +6 -0
- package/src/config/loader.ts +774 -181
- package/src/contract-serialization.ts +5 -7
- package/src/contract-types.ts +12 -5
- package/src/contract.ts +24 -10
- package/src/declaration-validation.ts +376 -0
- package/src/define.ts +1105 -131
- package/src/dev.ts +13 -1
- package/src/engine.ts +390 -0
- package/src/error-observability.ts +64 -0
- package/src/error-resolution.ts +269 -0
- package/src/errors.ts +157 -0
- package/src/fixture-sanitization.ts +422 -0
- package/src/handle-meta.ts +143 -0
- package/src/handle.ts +694 -0
- package/src/health-scenario.ts +960 -0
- package/src/i18n/catalog.ts +23 -1
- package/src/i18n/error-messages.ts +255 -0
- package/src/i18n/index.ts +1 -0
- package/src/i18n/keys.ts +80 -6
- package/src/i18n/operation-locale-namespace.ts +10 -0
- package/src/index.ts +390 -23
- package/src/lint.ts +2975 -234
- package/src/native-address.ts +340 -0
- package/src/native-egress-policy.ts +358 -0
- package/src/observability.ts +51 -1
- package/src/provider.ts +207 -27
- package/src/runtime/auth-flow.ts +15 -0
- package/src/runtime/bounded-expiring-map.ts +67 -0
- package/src/runtime/browser-telemetry-binding.ts +92 -0
- package/src/runtime/browser-telemetry.ts +289 -0
- package/src/runtime/browser.ts +882 -99
- package/src/runtime/cache-telemetry.ts +247 -0
- package/src/runtime/cache.ts +258 -22
- package/src/runtime/capability-response.ts +53 -0
- package/src/runtime/capability-telemetry.ts +101 -0
- package/src/runtime/chrome149-header-order.ts +330 -0
- package/src/runtime/diagnostic-env-values.ts +56 -0
- package/src/runtime/diagnostic-env.ts +65 -0
- package/src/runtime/diagnostic-redactor.ts +668 -0
- package/src/runtime/egress-lease.ts +341 -0
- package/src/runtime/engine-mode.ts +233 -0
- package/src/runtime/env.ts +15 -1
- package/src/runtime/executor.ts +39 -32
- package/src/runtime/handle-wordlist.ts +266 -0
- package/src/runtime/handle.ts +1180 -0
- package/src/runtime/http-telemetry-binding.ts +162 -0
- package/src/runtime/http-telemetry-guard.ts +208 -0
- package/src/runtime/http-telemetry.ts +292 -0
- package/src/runtime/http.ts +896 -150
- package/src/runtime/insights.ts +2 -2
- package/src/runtime/instrumentation.ts +628 -28
- package/src/runtime/native-network-errors.ts +99 -0
- package/src/runtime/native-network.ts +1853 -0
- package/src/runtime/native-telemetry.ts +366 -0
- package/src/runtime/ocr-telemetry.ts +308 -0
- package/src/runtime/ocr.ts +564 -0
- package/src/runtime/otlp.ts +468 -21
- package/src/runtime/provider.ts +15 -0
- package/src/runtime/proxy-errors.ts +12 -4
- package/src/runtime/proxy-nodemaven.ts +222 -0
- package/src/runtime/proxy-retry-policy.ts +12 -1
- package/src/runtime/proxy-telemetry.ts +358 -103
- package/src/runtime/redirect-hop-headers.ts +71 -0
- package/src/runtime/redirects.ts +215 -0
- package/src/runtime/redis.ts +7 -2
- package/src/runtime/request-options.ts +728 -1
- package/src/runtime/request-telemetry.ts +375 -0
- package/src/runtime/resolver-config.ts +18 -0
- package/src/runtime/resolver-public.ts +44 -0
- package/src/runtime/resolver-runtime-options.ts +50 -0
- package/src/runtime/resolver-shared.ts +113 -0
- package/src/runtime/resolver-span-attributes.ts +139 -0
- package/src/runtime/resolver-telemetry.ts +362 -0
- package/src/runtime/resolver-usage.ts +99 -0
- package/src/runtime/resolver-vendors/bindings.ts +61 -0
- package/src/runtime/resolver-vendors/browser.ts +591 -0
- package/src/runtime/resolver-vendors/capsolver.ts +727 -0
- package/src/runtime/resolver-vendors/hosts.ts +81 -0
- package/src/runtime/resolver-vendors/hypersolutions.ts +480 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +555 -0
- package/src/runtime/resolver-vendors/types.ts +261 -0
- package/src/runtime/resolver.ts +1543 -0
- package/src/runtime/state-telemetry.ts +298 -0
- package/src/runtime/state.ts +435 -89
- package/src/runtime/stealth-akamai-sbsd.ts +207 -0
- package/src/runtime/stealth-cookies.ts +155 -0
- package/src/runtime/stealth-owned-headers.ts +67 -0
- package/src/runtime/stealth-telemetry.ts +309 -0
- package/src/runtime/stealth.ts +2275 -372
- package/src/runtime/stt-telemetry.ts +282 -0
- package/src/runtime/stt.ts +96 -91
- package/src/runtime/timeout.ts +18 -0
- package/src/runtime/trace-config.ts +78 -0
- package/src/runtime/trace.ts +257 -35
- package/src/runtime-boundary-lint.ts +707 -0
- package/src/schema.ts +80 -2
- package/src/serve.ts +6 -1
- package/src/server/error-observability.ts +1 -0
- package/src/server/error-stack-frames.ts +214 -0
- package/src/server/index.ts +184 -2
- package/src/server/runtime-diagnostics.ts +522 -0
- package/src/server/sdk-version.ts +22 -0
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/server/self-test-redaction.ts +10 -40
- package/src/server/self-test.ts +205 -89
- package/src/server/sensitive-values.ts +211 -0
- package/src/server/serve-implementation.ts +4596 -0
- package/src/server/serve.ts +1 -1685
- package/src/server/state-backend-report.ts +185 -0
- package/src/server/trace-output.ts +189 -0
- package/src/server/types.ts +34 -1
- package/src/stateful/README.md +146 -0
- package/src/stateful/errors.ts +35 -0
- package/src/stateful/http-provider-event-emitter.ts +314 -0
- package/src/stateful/http-session-owner-registry.ts +306 -0
- package/src/stateful/index.ts +18 -0
- package/src/stateful/provider-event-delivery-failures.ts +80 -0
- package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
- package/src/stateful/provider-event-pipeline.ts +61 -0
- package/src/stateful/provider-events.ts +462 -0
- package/src/stateful/session-key.ts +111 -0
- package/src/stateful/stateful-provider-adapter-context.ts +59 -0
- package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
- package/src/stateful/stateful-provider-adapter.ts +562 -0
- package/src/stateful/stateful-provider-observability.ts +261 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +310 -0
- package/src/stateful/stateful-provider-runtime-context.ts +96 -0
- package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
- package/src/stateful/stateful-provider-session-routing.ts +546 -0
- package/src/stateful/stateful-provider-session-runtime.ts +403 -0
- package/src/stateful-signing.ts +46 -0
- package/src/stealth/profiles.ts +212 -231
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +8 -1
- package/src/testing/index.ts +10 -1
- package/src/testing/run.ts +685 -19
- package/src/trace-sanitization.ts +110 -0
- package/src/types.ts +1014 -273
- package/src/typescript-module.ts +100 -0
- package/dist/choice-token.d.ts +0 -24
- package/dist/choice-token.js +0 -74
- package/dist/runtime/choice.d.ts +0 -15
- package/dist/runtime/choice.js +0 -413
- package/src/choice-token.ts +0 -165
- package/src/runtime/choice.ts +0 -686
package/dist/define.js
CHANGED
|
@@ -1,26 +1,85 @@
|
|
|
1
1
|
import ms from "ms";
|
|
2
|
+
import { validateFailClosedOperationDeclaration, validateFailClosedProviderDeclaration, } from "./declaration-validation.js";
|
|
3
|
+
import { SDK_RUNTIME_OWNED_ERROR_CODES } from "./error-resolution.js";
|
|
2
4
|
import { ProviderError, ValidationError } from "./errors.js";
|
|
5
|
+
import { engineOwnedResolverCredentialTarget, isEngineOwnedEnvName, isEngineOwnedProxyCredentialName, isEngineOwnedRuntimeEnvName, isEngineOwnedTelemetryEnvName, } from "./engine.js";
|
|
6
|
+
import { HealthScenarioSchema } from "./health-scenario.js";
|
|
7
|
+
import { kindRequiresClientProfile } from "./runtime/resolver-config.js";
|
|
8
|
+
import { NativeEgressPolicyValidationError, validateNativeProviderConfig, } from "./native-egress-policy.js";
|
|
3
9
|
import { safeParseSchemaSync } from "./schema.js";
|
|
4
|
-
import {
|
|
10
|
+
import { resolveHealthCheckInputDateTokens } from "./server/self-test-input-tokens.js";
|
|
11
|
+
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, VALID_OPERATION_ERROR_STATUSES, } from "./types.js";
|
|
5
12
|
const CONNECTOR_ID_REGEX = /^[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$/;
|
|
6
13
|
const OPERATION_ID_REGEX = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/;
|
|
7
14
|
const VALID_RUNTIMES = ["standard", "shared", "browser"];
|
|
8
|
-
const
|
|
15
|
+
const VALID_RUNTIME_TARGETS = ["vanilla", "engine"];
|
|
16
|
+
const VALID_AUTH_MODES = [
|
|
17
|
+
"none",
|
|
18
|
+
"platform-managed",
|
|
19
|
+
"credentials",
|
|
20
|
+
"oauth2",
|
|
21
|
+
"oauth2_proxied",
|
|
22
|
+
];
|
|
23
|
+
const PROXIED_OAUTH_REQUIRED_FIELDS = [
|
|
24
|
+
"authorizeUrl",
|
|
25
|
+
"tokenUrl",
|
|
26
|
+
"customScheme",
|
|
27
|
+
"rewriteProfile",
|
|
28
|
+
"clientIdEnvKey",
|
|
29
|
+
];
|
|
30
|
+
const PROXIED_OAUTH_ALLOWED_FIELDS = new Set([
|
|
31
|
+
...PROXIED_OAUTH_REQUIRED_FIELDS,
|
|
32
|
+
"pkce",
|
|
33
|
+
"authorizeParams",
|
|
34
|
+
"tokenParams",
|
|
35
|
+
]);
|
|
36
|
+
const PROXIED_OAUTH_RESERVED_AUTHORIZE_PARAMS = new Set([
|
|
37
|
+
"client_id",
|
|
38
|
+
"response_type",
|
|
39
|
+
"state",
|
|
40
|
+
"code_challenge",
|
|
41
|
+
"code_challenge_method",
|
|
42
|
+
]);
|
|
43
|
+
const PROXIED_OAUTH_PROFILE_REGEX = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
44
|
+
const PROXIED_OAUTH_ENV_KEY_REGEX = /^[A-Z][A-Z0-9_]*__[A-Z0-9_]+$/;
|
|
45
|
+
const CUSTOM_SCHEME_REGEX = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/\S+$/;
|
|
9
46
|
const VALID_PROVIDER_ACCESS_VISIBILITIES = ["public", "early_access"];
|
|
10
47
|
const VALID_PROVIDER_PROXY_MODES = ["disabled", "optional", "required"];
|
|
11
|
-
const VALID_PROVIDER_PROXY_PROVIDERS = ["smartproxy", "decodo", "custom"];
|
|
48
|
+
const VALID_PROVIDER_PROXY_PROVIDERS = ["smartproxy", "nodemaven", "decodo", "custom"];
|
|
12
49
|
const VALID_PROVIDER_PROXY_AFFINITIES = [
|
|
13
50
|
"request",
|
|
14
51
|
"operation",
|
|
15
52
|
"auth-flow",
|
|
16
53
|
"connection",
|
|
17
54
|
];
|
|
55
|
+
const VALID_PROVIDER_OCR_MODES = ["optional", "required"];
|
|
18
56
|
const VALID_PROVIDER_STT_MODES = ["optional", "required"];
|
|
19
|
-
|
|
57
|
+
function exhaustiveLiteralArray() {
|
|
58
|
+
return (values, ..._missing) => values;
|
|
59
|
+
}
|
|
60
|
+
export const VALID_PROVIDER_RESOLVER_VENDORS = exhaustiveLiteralArray()([
|
|
61
|
+
"browser",
|
|
62
|
+
"capsolver",
|
|
63
|
+
"capmonster",
|
|
64
|
+
"2captcha",
|
|
65
|
+
"hypersolutions",
|
|
66
|
+
"custom",
|
|
67
|
+
]);
|
|
68
|
+
export const VALID_PROVIDER_CHALLENGE_KINDS = exhaustiveLiteralArray()([
|
|
69
|
+
"turnstile",
|
|
70
|
+
"recaptcha_v2",
|
|
71
|
+
"recaptcha_v3",
|
|
72
|
+
"hcaptcha",
|
|
73
|
+
"cloudflare_interstitial",
|
|
74
|
+
"aws_waf",
|
|
75
|
+
"akamai_sec_cpt",
|
|
76
|
+
"akamai_sensor",
|
|
77
|
+
"akamai_sbsd",
|
|
78
|
+
]);
|
|
20
79
|
const RESERVED_OPERATION_IDS = new Set(["auth", "health"]);
|
|
21
|
-
const MCP_TOOL_NAME_REGEX = /^[A-Za-z][A-Za-z0-9_]{0,127}$/;
|
|
22
80
|
const VALID_OPERATION_RISK_CLASSES = ["read", "write", "destructive", "external-send"];
|
|
23
81
|
const VALID_OPERATION_APPROVAL_POLICIES = ["never", "risk-based", "always"];
|
|
82
|
+
const VALID_OPERATION_CONNECTION_MODES = ["none", "optional", "required"];
|
|
24
83
|
const VALID_OPERATION_TRANSPORT_KINDS = ["json", "sse", "http-stream", "websocket"];
|
|
25
84
|
const SSE_EVENT_NAME_REGEX = /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/;
|
|
26
85
|
const WEBSOCKET_SUBPROTOCOL_REGEX = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
@@ -42,13 +101,357 @@ function parsePositiveMsDuration(value) {
|
|
|
42
101
|
return undefined;
|
|
43
102
|
return parsed;
|
|
44
103
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
104
|
+
function splitAuthStartParameters(parameters) {
|
|
105
|
+
const parts = [];
|
|
106
|
+
let start = 0;
|
|
107
|
+
let round = 0;
|
|
108
|
+
let square = 0;
|
|
109
|
+
let curly = 0;
|
|
110
|
+
let quote;
|
|
111
|
+
let escaped = false;
|
|
112
|
+
let lineComment = false;
|
|
113
|
+
let blockComment = false;
|
|
114
|
+
const templateDepths = [0];
|
|
115
|
+
templateDepths.length = 0;
|
|
116
|
+
for (let index = 0; index < parameters.length; index++) {
|
|
117
|
+
const character = parameters[index];
|
|
118
|
+
const nextCharacter = parameters[index + 1];
|
|
119
|
+
if (lineComment) {
|
|
120
|
+
if (character === "\n" || character === "\r")
|
|
121
|
+
lineComment = false;
|
|
122
|
+
else
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (blockComment) {
|
|
126
|
+
if (character === "*" && nextCharacter === "/") {
|
|
127
|
+
blockComment = false;
|
|
128
|
+
index++;
|
|
129
|
+
}
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (quote) {
|
|
133
|
+
if (escaped) {
|
|
134
|
+
escaped = false;
|
|
135
|
+
}
|
|
136
|
+
else if (character === "\\") {
|
|
137
|
+
escaped = true;
|
|
138
|
+
}
|
|
139
|
+
else if (quote === "`" && character === "$" && nextCharacter === "{") {
|
|
140
|
+
curly++;
|
|
141
|
+
templateDepths.push(curly);
|
|
142
|
+
quote = undefined;
|
|
143
|
+
index++;
|
|
144
|
+
}
|
|
145
|
+
else if (character === quote) {
|
|
146
|
+
quote = undefined;
|
|
147
|
+
}
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (character === "'" || character === '"' || character === "`") {
|
|
151
|
+
quote = character;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (character === "/" && nextCharacter === "/") {
|
|
155
|
+
lineComment = true;
|
|
156
|
+
index++;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (character === "/" && nextCharacter === "*") {
|
|
160
|
+
blockComment = true;
|
|
161
|
+
index++;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (character === "/")
|
|
165
|
+
return undefined;
|
|
166
|
+
// Annex B HTML-like comments are not lexed here; give up rather than
|
|
167
|
+
// risk misreading the parameter list.
|
|
168
|
+
if (character === "<" && parameters.startsWith("!--", index + 1))
|
|
169
|
+
return undefined;
|
|
170
|
+
if (character === "-" && parameters.startsWith("->", index + 1))
|
|
171
|
+
return undefined;
|
|
172
|
+
if (character === "(")
|
|
173
|
+
round++;
|
|
174
|
+
else if (character === ")")
|
|
175
|
+
round--;
|
|
176
|
+
else if (character === "[")
|
|
177
|
+
square++;
|
|
178
|
+
else if (character === "]")
|
|
179
|
+
square--;
|
|
180
|
+
else if (character === "{")
|
|
181
|
+
curly++;
|
|
182
|
+
else if (character === "}") {
|
|
183
|
+
if (templateDepths.at(-1) === curly) {
|
|
184
|
+
templateDepths.pop();
|
|
185
|
+
curly--;
|
|
186
|
+
quote = "`";
|
|
187
|
+
}
|
|
188
|
+
else
|
|
189
|
+
curly--;
|
|
190
|
+
}
|
|
191
|
+
else if (character === "," && round === 0 && square === 0 && curly === 0) {
|
|
192
|
+
parts.push(parameters.slice(start, index));
|
|
193
|
+
start = index + 1;
|
|
194
|
+
}
|
|
195
|
+
if (round < 0 || square < 0 || curly < 0)
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
if (quote ||
|
|
199
|
+
blockComment ||
|
|
200
|
+
templateDepths.length > 0 ||
|
|
201
|
+
round !== 0 ||
|
|
202
|
+
square !== 0 ||
|
|
203
|
+
curly !== 0)
|
|
204
|
+
return undefined;
|
|
205
|
+
parts.push(parameters.slice(start));
|
|
206
|
+
return parts;
|
|
48
207
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
208
|
+
function authStartParameterList(source) {
|
|
209
|
+
let index = 0;
|
|
210
|
+
while (index < source.length && /\s/.test(source[index] ?? ""))
|
|
211
|
+
index++;
|
|
212
|
+
if (index >= source.length)
|
|
213
|
+
return undefined;
|
|
214
|
+
let openIndex = -1;
|
|
215
|
+
let parenthesizedArrow = false;
|
|
216
|
+
let asyncMethodOrArrow = false;
|
|
217
|
+
const skipTrivia = () => {
|
|
218
|
+
while (index < source.length) {
|
|
219
|
+
if (/\s/.test(source[index] ?? "")) {
|
|
220
|
+
index++;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (source[index] === "/" && source[index + 1] === "/") {
|
|
224
|
+
index += 2;
|
|
225
|
+
while (index < source.length && source[index] !== "\n" && source[index] !== "\r")
|
|
226
|
+
index++;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (source[index] === "/" && source[index + 1] === "*") {
|
|
230
|
+
const end = source.indexOf("*/", index + 2);
|
|
231
|
+
if (end < 0) {
|
|
232
|
+
index = source.length;
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
index = end + 2;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const initial = source.slice(index);
|
|
242
|
+
const isAsync = initial.startsWith("async") && !/[\w$]/.test(initial[5] ?? "");
|
|
243
|
+
if (isAsync) {
|
|
244
|
+
index += 5;
|
|
245
|
+
skipTrivia();
|
|
246
|
+
}
|
|
247
|
+
const afterAsync = source.slice(index);
|
|
248
|
+
const isFunction = afterAsync.startsWith("function") && !/[\w$]/.test(afterAsync[8] ?? "");
|
|
249
|
+
if (isFunction) {
|
|
250
|
+
index += 8;
|
|
251
|
+
skipTrivia();
|
|
252
|
+
if (source[index] === "*") {
|
|
253
|
+
index++;
|
|
254
|
+
skipTrivia();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else if (source[index] === "*") {
|
|
258
|
+
index++;
|
|
259
|
+
skipTrivia();
|
|
260
|
+
}
|
|
261
|
+
if (source[index] === "(") {
|
|
262
|
+
openIndex = index;
|
|
263
|
+
parenthesizedArrow = !isFunction;
|
|
264
|
+
asyncMethodOrArrow = isAsync && !isFunction;
|
|
265
|
+
}
|
|
266
|
+
else if (isFunction) {
|
|
267
|
+
if (!/[A-Za-z_$]/.test(source[index] ?? ""))
|
|
268
|
+
return undefined;
|
|
269
|
+
index++;
|
|
270
|
+
while (index < source.length && /[A-Za-z0-9_$]/.test(source[index] ?? ""))
|
|
271
|
+
index++;
|
|
272
|
+
skipTrivia();
|
|
273
|
+
if (source[index] !== "(")
|
|
274
|
+
return undefined;
|
|
275
|
+
openIndex = index;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
const identifierStart = index;
|
|
279
|
+
if (!/[A-Za-z_$]/.test(source[index] ?? ""))
|
|
280
|
+
return undefined;
|
|
281
|
+
index++;
|
|
282
|
+
while (index < source.length && /[A-Za-z0-9_$]/.test(source[index] ?? ""))
|
|
283
|
+
index++;
|
|
284
|
+
const firstIdentifier = source.slice(identifierStart, index);
|
|
285
|
+
skipTrivia();
|
|
286
|
+
if (source[index] === "=" && source[index + 1] === ">")
|
|
287
|
+
return undefined;
|
|
288
|
+
if (source[index] !== "(") {
|
|
289
|
+
if (firstIdentifier !== "get" && firstIdentifier !== "set")
|
|
290
|
+
return undefined;
|
|
291
|
+
if (!/[A-Za-z_$]/.test(source[index] ?? ""))
|
|
292
|
+
return undefined;
|
|
293
|
+
index++;
|
|
294
|
+
while (index < source.length && /[A-Za-z0-9_$]/.test(source[index] ?? ""))
|
|
295
|
+
index++;
|
|
296
|
+
skipTrivia();
|
|
297
|
+
}
|
|
298
|
+
if (source[index] !== "(")
|
|
299
|
+
return undefined;
|
|
300
|
+
openIndex = index;
|
|
301
|
+
}
|
|
302
|
+
if (openIndex < 0)
|
|
303
|
+
return undefined;
|
|
304
|
+
let depth = 1;
|
|
305
|
+
let square = 0;
|
|
306
|
+
let curly = 0;
|
|
307
|
+
let quote;
|
|
308
|
+
let escaped = false;
|
|
309
|
+
let lineComment = false;
|
|
310
|
+
let blockComment = false;
|
|
311
|
+
const templateDepths = [0];
|
|
312
|
+
templateDepths.length = 0;
|
|
313
|
+
for (index = openIndex + 1; index < source.length; index++) {
|
|
314
|
+
const character = source[index];
|
|
315
|
+
const nextCharacter = source[index + 1];
|
|
316
|
+
if (lineComment) {
|
|
317
|
+
if (character === "\n" || character === "\r")
|
|
318
|
+
lineComment = false;
|
|
319
|
+
else
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (blockComment) {
|
|
323
|
+
if (character === "*" && nextCharacter === "/") {
|
|
324
|
+
blockComment = false;
|
|
325
|
+
index++;
|
|
326
|
+
}
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (quote) {
|
|
330
|
+
if (escaped)
|
|
331
|
+
escaped = false;
|
|
332
|
+
else if (character === "\\")
|
|
333
|
+
escaped = true;
|
|
334
|
+
else if (quote === "`" && character === "$" && nextCharacter === "{") {
|
|
335
|
+
curly++;
|
|
336
|
+
templateDepths.push(curly);
|
|
337
|
+
quote = undefined;
|
|
338
|
+
index++;
|
|
339
|
+
}
|
|
340
|
+
else if (character === quote)
|
|
341
|
+
quote = undefined;
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (character === "'" || character === '"' || character === "`") {
|
|
345
|
+
quote = character;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (character === "/" && nextCharacter === "/") {
|
|
349
|
+
lineComment = true;
|
|
350
|
+
index++;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (character === "/" && nextCharacter === "*") {
|
|
354
|
+
blockComment = true;
|
|
355
|
+
index++;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (character === "/")
|
|
359
|
+
return undefined;
|
|
360
|
+
// Annex B HTML-like comments are not lexed here; give up rather than
|
|
361
|
+
// risk misreading the parameter list.
|
|
362
|
+
if (character === "<" && source.startsWith("!--", index + 1))
|
|
363
|
+
return undefined;
|
|
364
|
+
if (character === "-" && source.startsWith("->", index + 1))
|
|
365
|
+
return undefined;
|
|
366
|
+
if (character === "(")
|
|
367
|
+
depth++;
|
|
368
|
+
else if (character === ")") {
|
|
369
|
+
depth--;
|
|
370
|
+
if (depth === 0 && square === 0 && curly === 0) {
|
|
371
|
+
const closeIndex = index;
|
|
372
|
+
if (parenthesizedArrow) {
|
|
373
|
+
index++;
|
|
374
|
+
skipTrivia();
|
|
375
|
+
const hasArrow = source[index] === "=" && source[index + 1] === ">";
|
|
376
|
+
if (!hasArrow && (!asyncMethodOrArrow || source[index] !== "{"))
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
return source.slice(openIndex + 1, closeIndex);
|
|
380
|
+
}
|
|
381
|
+
if (depth < 0)
|
|
382
|
+
return undefined;
|
|
383
|
+
}
|
|
384
|
+
else if (character === "[")
|
|
385
|
+
square++;
|
|
386
|
+
else if (character === "]") {
|
|
387
|
+
square--;
|
|
388
|
+
if (square < 0)
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
else if (character === "{")
|
|
392
|
+
curly++;
|
|
393
|
+
else if (character === "}") {
|
|
394
|
+
if (templateDepths.at(-1) === curly) {
|
|
395
|
+
templateDepths.pop();
|
|
396
|
+
curly--;
|
|
397
|
+
quote = "`";
|
|
398
|
+
}
|
|
399
|
+
else
|
|
400
|
+
curly--;
|
|
401
|
+
if (curly < 0)
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return undefined;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Conservative defense in depth for defaulted second parameters, which
|
|
409
|
+
* JavaScript intentionally omits from Function.length. Ambiguous source is
|
|
410
|
+
* ignored so this check can never reject a valid provider on weak evidence.
|
|
411
|
+
*/
|
|
412
|
+
function authStartHasHiddenInput(start) {
|
|
413
|
+
let source;
|
|
414
|
+
try {
|
|
415
|
+
source = Function.prototype.toString.call(start);
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
if (!source ||
|
|
421
|
+
source.includes("[native code]") ||
|
|
422
|
+
/^\s*(?:async\s+)?function\s+bound\b/.test(source))
|
|
423
|
+
return false;
|
|
424
|
+
const parameters = authStartParameterList(source);
|
|
425
|
+
if (!parameters)
|
|
426
|
+
return false;
|
|
427
|
+
const parts = splitAuthStartParameters(parameters);
|
|
428
|
+
if (!parts || parts.length < 2)
|
|
429
|
+
return false;
|
|
430
|
+
// Require ordinary, readable source formatting. This intentionally fails
|
|
431
|
+
// open for minified output and for transpilers that rewrite defaults.
|
|
432
|
+
const commaIndex = parameters.indexOf(",");
|
|
433
|
+
if (commaIndex < 0 || !/\s/.test(parameters[commaIndex + 1] ?? ""))
|
|
434
|
+
return false;
|
|
435
|
+
const first = parts[0].trim();
|
|
436
|
+
const second = parts[1].trim();
|
|
437
|
+
const identifier = /^[_$A-Za-z][_$A-Za-z0-9]*/;
|
|
438
|
+
const firstName = first.match(identifier)?.[0];
|
|
439
|
+
const secondName = second.match(identifier)?.[0];
|
|
440
|
+
if (!firstName || !secondName || firstName.length < 3 || secondName.length < 3)
|
|
441
|
+
return false;
|
|
442
|
+
return /\s=\s/.test(second);
|
|
443
|
+
}
|
|
444
|
+
/** Define one factored provider operation with schema-driven handler inference. */
|
|
445
|
+
export function defineOperation() {
|
|
446
|
+
return function operation(config) {
|
|
447
|
+
return config;
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
/** Define a factored non-JSON operation with explicit transport metadata. */
|
|
451
|
+
export function defineStreamOperation() {
|
|
452
|
+
return function streamOperation(config) {
|
|
453
|
+
return config;
|
|
454
|
+
};
|
|
52
455
|
}
|
|
53
456
|
function assertObjectConfig(value) {
|
|
54
457
|
if (!value || typeof value !== "object") {
|
|
@@ -72,18 +475,105 @@ function assertLiteralField(value, field, validValues, providerId) {
|
|
|
72
475
|
});
|
|
73
476
|
}
|
|
74
477
|
}
|
|
75
|
-
function
|
|
478
|
+
function validateProxiedOAuthParams(value, field, providerId) {
|
|
479
|
+
if (value === undefined)
|
|
480
|
+
return;
|
|
481
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
482
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.${field} must be an object of string values.`);
|
|
483
|
+
}
|
|
484
|
+
for (const [key, paramValue] of Object.entries(value)) {
|
|
485
|
+
if (!key.trim() || typeof paramValue !== "string") {
|
|
486
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.${field} must contain non-empty keys and string values.`);
|
|
487
|
+
}
|
|
488
|
+
if (field === "authorizeParams" &&
|
|
489
|
+
PROXIED_OAUTH_RESERVED_AUTHORIZE_PARAMS.has(key.toLowerCase())) {
|
|
490
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.authorizeParams cannot override reserved parameter "${key}".`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function validateProxiedOAuthAuth(auth, providerId) {
|
|
495
|
+
const proxied = auth.proxied;
|
|
496
|
+
if (auth.mode !== "oauth2_proxied") {
|
|
497
|
+
if (proxied !== undefined) {
|
|
498
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied is only valid when auth.mode is "oauth2_proxied".`);
|
|
499
|
+
}
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (!proxied || typeof proxied !== "object" || Array.isArray(proxied)) {
|
|
503
|
+
throw new ValidationError(`Provider "${providerId}" with auth.mode "oauth2_proxied" must declare auth.proxied.`);
|
|
504
|
+
}
|
|
505
|
+
const config = Object.fromEntries(Object.entries(proxied));
|
|
506
|
+
for (const key of Object.keys(config)) {
|
|
507
|
+
if (!PROXIED_OAUTH_ALLOWED_FIELDS.has(key)) {
|
|
508
|
+
throw new ValidationError(`Provider "${providerId}" has unknown auth.proxied field "${key}".`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
for (const field of PROXIED_OAUTH_REQUIRED_FIELDS) {
|
|
512
|
+
if (typeof config[field] !== "string" || !config[field].trim()) {
|
|
513
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.${field} must be a non-empty string.`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
for (const field of ["authorizeUrl", "tokenUrl"]) {
|
|
517
|
+
try {
|
|
518
|
+
const endpoint = new URL(String(config[field]));
|
|
519
|
+
if (endpoint.protocol !== "https:" ||
|
|
520
|
+
endpoint.username ||
|
|
521
|
+
endpoint.password ||
|
|
522
|
+
endpoint.hash) {
|
|
523
|
+
throw new Error("invalid endpoint");
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.${field} must be an absolute HTTPS URL without credentials or a fragment.`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
const customScheme = String(config.customScheme);
|
|
531
|
+
if (!CUSTOM_SCHEME_REGEX.test(customScheme) ||
|
|
532
|
+
customScheme.toLowerCase().startsWith("http://") ||
|
|
533
|
+
customScheme.toLowerCase().startsWith("https://")) {
|
|
534
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.customScheme must be a non-HTTP custom-scheme URL prefix.`);
|
|
535
|
+
}
|
|
536
|
+
if (!PROXIED_OAUTH_PROFILE_REGEX.test(String(config.rewriteProfile))) {
|
|
537
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.rewriteProfile must be a kebab-case profile name.`);
|
|
538
|
+
}
|
|
539
|
+
if (!PROXIED_OAUTH_ENV_KEY_REGEX.test(String(config.clientIdEnvKey))) {
|
|
540
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.clientIdEnvKey must be an APIFuse-style uppercase environment key.`);
|
|
541
|
+
}
|
|
542
|
+
if (config.pkce !== undefined && config.pkce !== "S256" && config.pkce !== "none") {
|
|
543
|
+
throw new ValidationError(`Provider "${providerId}" auth.proxied.pkce must be "S256" or "none".`);
|
|
544
|
+
}
|
|
545
|
+
validateProxiedOAuthParams(config.authorizeParams, "authorizeParams", providerId);
|
|
546
|
+
validateProxiedOAuthParams(config.tokenParams, "tokenParams", providerId);
|
|
547
|
+
}
|
|
548
|
+
function validateProviderDeclarationShape(config) {
|
|
76
549
|
assertObjectConfig(config);
|
|
77
550
|
assertRequiredField(config, "id");
|
|
78
551
|
assertRequiredField(config, "version", String(config.id));
|
|
79
552
|
assertRequiredField(config, "runtime", String(config.id));
|
|
80
553
|
assertRequiredField(config, "meta", String(config.id));
|
|
81
|
-
assertRequiredField(config, "operations", String(config.id));
|
|
82
554
|
if (typeof config.runtime === "string")
|
|
83
555
|
assertLiteralField(config.runtime, "runtime", VALID_RUNTIMES, String(config.id));
|
|
556
|
+
if (config.runtimeTarget !== undefined && typeof config.runtimeTarget !== "string") {
|
|
557
|
+
throw new ValidationError(`Provider "${String(config.id)}" has invalid runtimeTarget: expected "vanilla" or "engine"`);
|
|
558
|
+
}
|
|
559
|
+
if (typeof config.runtimeTarget === "string")
|
|
560
|
+
assertLiteralField(config.runtimeTarget, "runtimeTarget", VALID_RUNTIME_TARGETS, String(config.id));
|
|
561
|
+
if (config.native !== undefined && config.runtime === "browser") {
|
|
562
|
+
throw new ValidationError(`Provider "${String(config.id)}" cannot declare capability "native" with runtime "browser"`, {
|
|
563
|
+
fix: 'Use runtime: "standard" or runtime: "shared", or remove the native declaration.',
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
if (config.native !== undefined && config.runtimeTarget === "vanilla") {
|
|
567
|
+
throw new ValidationError(`Provider "${String(config.id)}" cannot declare capability "native" with runtime target "vanilla"; native requires an engine-resident runtime`, {
|
|
568
|
+
fix: 'Set runtimeTarget: "engine", or remove the native declaration.',
|
|
569
|
+
});
|
|
570
|
+
}
|
|
84
571
|
const auth = config.auth;
|
|
85
572
|
if (auth && typeof auth === "object" && "mode" in auth && typeof auth.mode === "string")
|
|
86
573
|
assertLiteralField(auth.mode, "auth.mode", VALID_AUTH_MODES, String(config.id));
|
|
574
|
+
if (auth && typeof auth === "object" && !Array.isArray(auth)) {
|
|
575
|
+
validateProxiedOAuthAuth(Object.fromEntries(Object.entries(auth)), String(config.id));
|
|
576
|
+
}
|
|
87
577
|
if (auth && typeof auth === "object" && "exchange" in auth) {
|
|
88
578
|
throw new ProviderError(`Provider "${String(config.id)}" auth.exchange is not part of the Provider SDK auth contract`, {
|
|
89
579
|
fix: "Use the single canonical auth interface: auth.flow. Gateway calls auth.flow.start/continue/poll/abort/refresh only and persists complete turn data.credential as-is, so put login/token/session exchange inside auth.flow.continue.",
|
|
@@ -101,6 +591,19 @@ function validateProviderShape(config) {
|
|
|
101
591
|
fix: "Return a form turn from start(ctx), then receive user input in continue(ctx, input).",
|
|
102
592
|
});
|
|
103
593
|
}
|
|
594
|
+
if (auth &&
|
|
595
|
+
typeof auth === "object" &&
|
|
596
|
+
"flow" in auth &&
|
|
597
|
+
auth.flow &&
|
|
598
|
+
typeof auth.flow === "object" &&
|
|
599
|
+
"start" in auth.flow &&
|
|
600
|
+
typeof auth.flow.start === "function" &&
|
|
601
|
+
auth.flow.start.length <= 1 &&
|
|
602
|
+
authStartHasHiddenInput(auth.flow.start)) {
|
|
603
|
+
throw new ProviderError(`Provider "${String(config.id)}" auth.flow.start must not declare an input parameter`, {
|
|
604
|
+
fix: "Return a form turn from start(ctx), then receive user input in continue(ctx, input).",
|
|
605
|
+
});
|
|
606
|
+
}
|
|
104
607
|
const access = config.access;
|
|
105
608
|
if (access !== undefined) {
|
|
106
609
|
if (!access || typeof access !== "object" || Array.isArray(access)) {
|
|
@@ -127,7 +630,44 @@ function validateProviderShape(config) {
|
|
|
127
630
|
}
|
|
128
631
|
}
|
|
129
632
|
}
|
|
633
|
+
function validateProviderImplementationShape(config) {
|
|
634
|
+
const configRecord = config;
|
|
635
|
+
assertRequiredField(configRecord, "operations", String(config.id));
|
|
636
|
+
}
|
|
130
637
|
function validateProviderProxy(config) {
|
|
638
|
+
for (const secret of config.secrets ?? []) {
|
|
639
|
+
if (secret.issuer !== undefined &&
|
|
640
|
+
secret.issuer !== "apifuse" &&
|
|
641
|
+
secret.issuer !== "contributor") {
|
|
642
|
+
throw new ValidationError(`Provider "${config.id}" secret "${secret.name}" has invalid issuer "${String(secret.issuer)}"`, { fix: `Set issuer to "apifuse" or "contributor", or omit it.` });
|
|
643
|
+
}
|
|
644
|
+
const engineName = engineOwnedResolverCredentialTarget(secret.name);
|
|
645
|
+
if (engineName !== undefined) {
|
|
646
|
+
throw new ValidationError(`Provider "${config.id}" cannot declare engine-owned resolver credential "${secret.name}"`, {
|
|
647
|
+
fix: `Remove "${secret.name}" from provider secrets; configure the solver key only on the provider engine as ${engineName}.`,
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
if (isEngineOwnedTelemetryEnvName(secret.name)) {
|
|
651
|
+
throw new ValidationError(`Provider "${config.id}" cannot declare engine-owned telemetry variable "${secret.name}"`, {
|
|
652
|
+
fix: `Remove "${secret.name}" from provider secrets; trace export is configured only on the provider engine.`,
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
if (isEngineOwnedRuntimeEnvName(secret.name)) {
|
|
656
|
+
throw new ValidationError(`Provider "${config.id}" cannot declare engine-owned runtime variable "${secret.name}"`, {
|
|
657
|
+
fix: `Remove "${secret.name}" from provider secrets; the provider engine reads it from its own environment.`,
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
if (isEngineOwnedEnvName(secret.name) && !isEngineOwnedProxyCredentialName(secret.name)) {
|
|
661
|
+
throw new ValidationError(`Provider "${config.id}" cannot declare engine-owned control variable "${secret.name}"`, {
|
|
662
|
+
fix: `Remove "${secret.name}" from provider secrets; configure it only on the provider engine.`,
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
if (!isEngineOwnedProxyCredentialName(secret.name))
|
|
666
|
+
continue;
|
|
667
|
+
throw new ValidationError(`Provider "${config.id}" cannot declare engine-owned proxy credential "${secret.name}"`, {
|
|
668
|
+
fix: `Remove "${secret.name}" from provider secrets; configure it only on the provider engine.`,
|
|
669
|
+
});
|
|
670
|
+
}
|
|
131
671
|
const proxy = config.proxy;
|
|
132
672
|
if (proxy === undefined || typeof proxy === "boolean") {
|
|
133
673
|
return;
|
|
@@ -137,11 +677,21 @@ function validateProviderProxy(config) {
|
|
|
137
677
|
fix: `Use proxy: { mode: "required", provider: "smartproxy", geo: { country: "KR" }, session: { affinity: "connection", lifetimeMinutes: 30 } }`,
|
|
138
678
|
});
|
|
139
679
|
}
|
|
140
|
-
rejectUnknownFields(proxy, new Set(["mode", "provider", "geo", "session"]), "proxy");
|
|
680
|
+
rejectUnknownFields(proxy, new Set(["mode", "provider", "providers", "geo", "session"]), "proxy");
|
|
141
681
|
assertLiteralField(proxy.mode, "proxy.mode", VALID_PROVIDER_PROXY_MODES, config.id);
|
|
142
682
|
if (proxy.provider !== undefined) {
|
|
143
683
|
assertLiteralField(proxy.provider, "proxy.provider", VALID_PROVIDER_PROXY_PROVIDERS, config.id);
|
|
144
684
|
}
|
|
685
|
+
if (proxy.providers !== undefined) {
|
|
686
|
+
if (!Array.isArray(proxy.providers) || proxy.providers.length === 0) {
|
|
687
|
+
throw new ValidationError(`Provider "${config.id}" has invalid proxy.providers: must be a non-empty array of proxy vendors.`, {
|
|
688
|
+
fix: `Use proxy.providers: ["smartproxy", "nodemaven"] to declare an ordered fallback chain.`,
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
for (const vendor of proxy.providers) {
|
|
692
|
+
assertLiteralField(vendor, "proxy.providers[]", VALID_PROVIDER_PROXY_PROVIDERS, config.id);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
145
695
|
if (proxy.geo !== undefined) {
|
|
146
696
|
if (!proxy.geo || typeof proxy.geo !== "object" || Array.isArray(proxy.geo)) {
|
|
147
697
|
throw new ValidationError(`Provider "${config.id}" has invalid proxy.geo: must be an object.`, {
|
|
@@ -165,7 +715,7 @@ function validateProviderProxy(config) {
|
|
|
165
715
|
fix: `Use proxy.session: { affinity: "connection", lifetimeMinutes: 30 }.`,
|
|
166
716
|
});
|
|
167
717
|
}
|
|
168
|
-
rejectUnknownFields(proxy.session, new Set(["affinity", "lifetimeMinutes", "poolSize"]), "proxy.session");
|
|
718
|
+
rejectUnknownFields(proxy.session, new Set(["affinity", "lifetimeMinutes", "poolSize", "drainLeadSeconds"]), "proxy.session");
|
|
169
719
|
if (proxy.session.affinity !== undefined) {
|
|
170
720
|
assertLiteralField(proxy.session.affinity, "proxy.session.affinity", VALID_PROVIDER_PROXY_AFFINITIES, config.id);
|
|
171
721
|
}
|
|
@@ -177,15 +727,43 @@ function validateProviderProxy(config) {
|
|
|
177
727
|
if (poolSize !== undefined && (!Number.isInteger(poolSize) || poolSize <= 0)) {
|
|
178
728
|
throw new ValidationError(`Provider "${config.id}" has invalid proxy.session.poolSize: must be a positive integer.`);
|
|
179
729
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
730
|
+
const drainLeadSeconds = proxy.session.drainLeadSeconds;
|
|
731
|
+
if (drainLeadSeconds !== undefined &&
|
|
732
|
+
(!Number.isFinite(drainLeadSeconds) || drainLeadSeconds <= 0)) {
|
|
733
|
+
throw new ValidationError(`Provider "${config.id}" has invalid proxy.session.drainLeadSeconds: must be a positive number of seconds.`, {
|
|
734
|
+
fix: `Use proxy.session.drainLeadSeconds: 120 to receive the sticky-expiry drain event 120s before hard expiry.`,
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
// A drain lead longer than the sticky lifetime would fire the expiring
|
|
738
|
+
// event before the session is even established, so the provider would
|
|
739
|
+
// never get a usable window. Reject the contradiction at build time.
|
|
740
|
+
if (drainLeadSeconds !== undefined &&
|
|
741
|
+
lifetime !== undefined &&
|
|
742
|
+
Number.isFinite(lifetime) &&
|
|
743
|
+
drainLeadSeconds >= lifetime * 60) {
|
|
744
|
+
throw new ValidationError(`Provider "${config.id}" has proxy.session.drainLeadSeconds (${drainLeadSeconds}s) greater than or equal to proxy.session.lifetimeMinutes (${lifetime}m).`, {
|
|
745
|
+
fix: `Lower drainLeadSeconds below the sticky lifetime so the drain event leaves a usable session window.`,
|
|
186
746
|
});
|
|
187
747
|
}
|
|
188
748
|
}
|
|
749
|
+
const vendorChain = proxy.providers && proxy.providers.length > 0
|
|
750
|
+
? proxy.providers
|
|
751
|
+
: proxy.provider
|
|
752
|
+
? [proxy.provider]
|
|
753
|
+
: [];
|
|
754
|
+
// `decodo`/`custom` are deprecated vendor values (string-union members, so the
|
|
755
|
+
// @deprecated symbol gate can't catch them — warn at validation time instead).
|
|
756
|
+
const deprecatedVendors = vendorChain.filter((vendor) => vendor === "decodo" || vendor === "custom");
|
|
757
|
+
if (proxy.mode === "required" &&
|
|
758
|
+
vendorChain.length > 0 &&
|
|
759
|
+
deprecatedVendors.length === vendorChain.length) {
|
|
760
|
+
throw new ValidationError(`Provider "${config.id}" requires proxy egress but declares only deprecated proxy vendor(s): ${deprecatedVendors.join(", ")}.`, {
|
|
761
|
+
fix: `Use proxy.provider or proxy.providers with "smartproxy" and/or "nodemaven".`,
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
if (deprecatedVendors.length > 0) {
|
|
765
|
+
console.warn(`[provider-sdk] Provider "${config.id}" uses deprecated proxy vendor(s): ${deprecatedVendors.join(", ")}. Use "smartproxy"/"nodemaven".`);
|
|
766
|
+
}
|
|
189
767
|
}
|
|
190
768
|
function validateProviderStt(config) {
|
|
191
769
|
const stt = config.stt;
|
|
@@ -199,6 +777,59 @@ function validateProviderStt(config) {
|
|
|
199
777
|
rejectUnknownFields(stt, new Set(["mode"]), "stt");
|
|
200
778
|
assertLiteralField(stt.mode, "stt.mode", VALID_PROVIDER_STT_MODES, config.id);
|
|
201
779
|
}
|
|
780
|
+
function validateProviderOcr(config) {
|
|
781
|
+
const ocr = config.ocr;
|
|
782
|
+
if (ocr === undefined)
|
|
783
|
+
return;
|
|
784
|
+
if (!ocr || typeof ocr !== "object" || Array.isArray(ocr)) {
|
|
785
|
+
throw new ValidationError(`Provider "${config.id}" has invalid ocr: must be an object.`, {
|
|
786
|
+
fix: `Use ocr: { mode: "required" } or ocr: { mode: "optional" }.`,
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
rejectUnknownFields(ocr, new Set(["mode"]), "ocr");
|
|
790
|
+
assertLiteralField(ocr.mode, "ocr.mode", VALID_PROVIDER_OCR_MODES, config.id);
|
|
791
|
+
}
|
|
792
|
+
function validateProviderResolver(config) {
|
|
793
|
+
const resolver = config.resolver;
|
|
794
|
+
if (resolver === undefined)
|
|
795
|
+
return;
|
|
796
|
+
if (!resolver || typeof resolver !== "object" || Array.isArray(resolver)) {
|
|
797
|
+
throw new ValidationError(`Provider "${config.id}" has invalid resolver: must be an object.`, {
|
|
798
|
+
fix: `Set resolver for provider "${config.id}" to { vendors: ["2captcha"], kinds: ["turnstile"] }.`,
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
rejectUnknownFields(resolver, new Set(["vendors", "kinds", "clientProfile"]), "resolver", config.id);
|
|
802
|
+
if (resolver.vendors !== undefined) {
|
|
803
|
+
validateResolverLiteralArray(resolver.vendors, "resolver.vendors", VALID_PROVIDER_RESOLVER_VENDORS, config.id);
|
|
804
|
+
}
|
|
805
|
+
validateResolverLiteralArray(resolver.kinds, "resolver.kinds", VALID_PROVIDER_CHALLENGE_KINDS, config.id);
|
|
806
|
+
if (resolver.clientProfile !== undefined &&
|
|
807
|
+
(typeof resolver.clientProfile !== "string" || !resolver.clientProfile.trim())) {
|
|
808
|
+
throw new ValidationError(`Provider "${config.id}" has invalid resolver.clientProfile: must be a non-empty string.`, {
|
|
809
|
+
fix: `Set resolver.clientProfile for provider "${config.id}" to a transport-owned profile name.`,
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
if (resolver.kinds.some(kindRequiresClientProfile) && resolver.clientProfile === undefined) {
|
|
813
|
+
throw new ValidationError(`Provider "${config.id}" must declare resolver.clientProfile for akamai_sbsd.`, {
|
|
814
|
+
fix: `Set resolver.clientProfile for provider "${config.id}" to the transport-owned profile used by its Akamai session.`,
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
function validateResolverLiteralArray(value, field, validValues, providerId) {
|
|
819
|
+
if (!Array.isArray(value)) {
|
|
820
|
+
throw new ValidationError(`Provider "${providerId}" has invalid ${field}: must be an array.`, {
|
|
821
|
+
fix: `Set ${field} for provider "${providerId}" to an array containing only: ${validValues.join(", ")}.`,
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
for (const [index, item] of value.entries()) {
|
|
825
|
+
if (typeof item === "string" && validValues.some((validValue) => validValue === item)) {
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
throw new ValidationError(`Provider "${providerId}" has invalid ${field}[${index}]: ${JSON.stringify(item)}. Expected one of: ${validValues.join(", ")}`, {
|
|
829
|
+
fix: `Set ${field}[${index}] for provider "${providerId}" to one of ${validValues.map((validValue) => `"${validValue}"`).join(", ")}.`,
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
}
|
|
202
833
|
function validateOperationIds(providerId, operations) {
|
|
203
834
|
for (const operationName of Object.keys(operations)) {
|
|
204
835
|
if (!OPERATION_ID_REGEX.test(operationName))
|
|
@@ -219,31 +850,19 @@ function assertNonEmptyString(value, field, providerId, operationName) {
|
|
|
219
850
|
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" has invalid ${field}: must be a non-empty string.`, { fix: `Set ${field} to a non-empty customer-facing value.` });
|
|
220
851
|
}
|
|
221
852
|
}
|
|
222
|
-
function
|
|
853
|
+
function validateOperationMetadata(providerId, operations) {
|
|
223
854
|
for (const [operationName, operation] of Object.entries(operations)) {
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
if (!toolRouter || typeof toolRouter !== "object") {
|
|
228
|
-
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" has invalid operations.${operationName}.toolRouter: must be an object.`, {
|
|
229
|
-
fix: `Remove operations.${operationName}.toolRouter or provide MCP-safe metadata.`,
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
if (toolRouter.name !== undefined && !MCP_TOOL_NAME_REGEX.test(toolRouter.name)) {
|
|
233
|
-
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" has invalid operations.${operationName}.toolRouter.name: expected an MCP-safe name.`, {
|
|
234
|
-
fix: `Use letters, numbers, and underscores only, starting with a letter, for example "${providerId.replace(/[^A-Za-z0-9]+/g, "_")}__${operationName.replace(/[^A-Za-z0-9]+/g, "_")}".`,
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
if (toolRouter.riskClass !== undefined) {
|
|
238
|
-
assertLiteralField(toolRouter.riskClass, `operations.${operationName}.toolRouter.riskClass`, VALID_OPERATION_RISK_CLASSES, providerId);
|
|
855
|
+
assertLiteralField(operation.riskClass, `operations.${operationName}.riskClass`, VALID_OPERATION_RISK_CLASSES, providerId);
|
|
856
|
+
if (operation.approval !== undefined) {
|
|
857
|
+
assertLiteralField(operation.approval, `operations.${operationName}.approval`, VALID_OPERATION_APPROVAL_POLICIES, providerId);
|
|
239
858
|
}
|
|
240
|
-
if (
|
|
241
|
-
assertLiteralField(
|
|
859
|
+
if (operation.connectionMode !== undefined) {
|
|
860
|
+
assertLiteralField(operation.connectionMode, `operations.${operationName}.connectionMode`, VALID_OPERATION_CONNECTION_MODES, providerId);
|
|
242
861
|
}
|
|
243
|
-
if (
|
|
244
|
-
(typeof
|
|
245
|
-
|
|
246
|
-
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" has invalid operations.${operationName}.
|
|
862
|
+
if (operation.connectionExternalRefParam !== undefined &&
|
|
863
|
+
(typeof operation.connectionExternalRefParam !== "string" ||
|
|
864
|
+
operation.connectionExternalRefParam.trim().length === 0)) {
|
|
865
|
+
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" has invalid operations.${operationName}.connectionExternalRefParam: must be a non-empty string.`, {
|
|
247
866
|
fix: `Use "externalRef" unless the operation has a documented public alias.`,
|
|
248
867
|
});
|
|
249
868
|
}
|
|
@@ -279,15 +898,12 @@ function validateOperationContracts(providerId, operations) {
|
|
|
279
898
|
}
|
|
280
899
|
}
|
|
281
900
|
}
|
|
282
|
-
function
|
|
901
|
+
function validateOperationTimeouts(providerId, operations) {
|
|
283
902
|
for (const [operationName, operation] of Object.entries(operations)) {
|
|
284
|
-
const
|
|
285
|
-
if (!annotations)
|
|
286
|
-
continue;
|
|
287
|
-
const timeoutMs = annotations.timeoutMs;
|
|
903
|
+
const timeoutMs = operation.timeoutMs;
|
|
288
904
|
if (timeoutMs === undefined)
|
|
289
905
|
continue;
|
|
290
|
-
const field = `operations.${operationName}.
|
|
906
|
+
const field = `operations.${operationName}.timeoutMs`;
|
|
291
907
|
if (typeof timeoutMs !== "number" || !Number.isInteger(timeoutMs))
|
|
292
908
|
throw new ValidationError(`Provider "${providerId}" has invalid ${field}: must be an integer number of milliseconds.`, {
|
|
293
909
|
fix: `Set ${field} to an integer in [${OPERATION_TIMEOUT_MS_MIN}, ${OPERATION_TIMEOUT_MS_MAX}] (milliseconds).`,
|
|
@@ -335,6 +951,23 @@ function validateOperationObservability(providerId, operations) {
|
|
|
335
951
|
}
|
|
336
952
|
}
|
|
337
953
|
}
|
|
954
|
+
function validateOperationErrorCodes(providerId, operations) {
|
|
955
|
+
for (const [operationName, operation] of Object.entries(operations)) {
|
|
956
|
+
for (const [index, errorCode] of (operation.errorCodes ?? []).entries()) {
|
|
957
|
+
if (errorCode.status !== undefined &&
|
|
958
|
+
!VALID_OPERATION_ERROR_STATUSES.some((status) => status === errorCode.status)) {
|
|
959
|
+
const field = `operations.${operationName}.errorCodes[${index}].status`;
|
|
960
|
+
throw new ValidationError(`Provider "${providerId}" has invalid ${field}: ${String(errorCode.status)} is not an emittable provider error status.`, {
|
|
961
|
+
fix: `Set ${field} to one of ${VALID_OPERATION_ERROR_STATUSES.join(", ")}, or omit it.`,
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
if (errorCode.status !== undefined &&
|
|
965
|
+
SDK_RUNTIME_OWNED_ERROR_CODES.has(errorCode.code)) {
|
|
966
|
+
console.warn(`[provider-sdk] Provider "${providerId}" operation "${operationName}" declares status ${errorCode.status} for SDK-owned error code "${errorCode.code}"; the declared status is documentation-only and will be ignored at runtime.`);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
338
971
|
const JSON_TRANSPORT_FIELDS = new Set(["kind"]);
|
|
339
972
|
const SSE_TRANSPORT_FIELDS = new Set([
|
|
340
973
|
"kind",
|
|
@@ -500,6 +1133,7 @@ const HEALTH_CHECK_CASE_FIELDS = new Set([
|
|
|
500
1133
|
"input",
|
|
501
1134
|
"prepareInput",
|
|
502
1135
|
"assertions",
|
|
1136
|
+
"scenario",
|
|
503
1137
|
"degradedThresholdMs",
|
|
504
1138
|
"timeoutMs",
|
|
505
1139
|
"expectedStatus",
|
|
@@ -556,14 +1190,18 @@ function suggestField(unknown, candidates) {
|
|
|
556
1190
|
}
|
|
557
1191
|
return best;
|
|
558
1192
|
}
|
|
559
|
-
function rejectUnknownFields(value, allowed, fieldPath) {
|
|
1193
|
+
function rejectUnknownFields(value, allowed, fieldPath, providerId) {
|
|
560
1194
|
for (const key of Object.keys(value)) {
|
|
561
1195
|
if (allowed.has(key))
|
|
562
1196
|
continue;
|
|
563
1197
|
const hint = suggestField(key, allowed);
|
|
564
1198
|
throw new ValidationError(hint
|
|
565
1199
|
? `Unknown field "${key}" on ${fieldPath}. Did you mean "${hint}"?`
|
|
566
|
-
: `Unknown field "${key}" on ${fieldPath}.`, {
|
|
1200
|
+
: `Unknown field "${key}" on ${fieldPath}.`, {
|
|
1201
|
+
fix: providerId
|
|
1202
|
+
? `Remove ${fieldPath}.${key} from provider "${providerId}" or rename it.`
|
|
1203
|
+
: `Remove ${fieldPath}.${key} or rename it.`,
|
|
1204
|
+
});
|
|
567
1205
|
}
|
|
568
1206
|
}
|
|
569
1207
|
function assertBoundedIntegerMs(value, fieldPath, options) {
|
|
@@ -670,12 +1308,31 @@ function validateHealthCheckCase(providerId, operationName, caseValue, caseIndex
|
|
|
670
1308
|
const c = caseValue;
|
|
671
1309
|
if (typeof c.name !== "string" || c.name.length === 0)
|
|
672
1310
|
throw new ValidationError(`Provider "${providerId}" ${fieldPath}.name must be a non-empty string.`);
|
|
673
|
-
|
|
1311
|
+
const hasScenario = c.scenario !== undefined;
|
|
1312
|
+
const imperativeFields = [
|
|
1313
|
+
...(c.prepareInput === undefined ? [] : ["prepareInput"]),
|
|
1314
|
+
...(c.assertions === undefined ? [] : ["assertions"]),
|
|
1315
|
+
];
|
|
1316
|
+
if (hasScenario && imperativeFields.length > 0)
|
|
1317
|
+
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" health-check case "${c.name}" cannot declare scenario with ${imperativeFields.join(" and ")}.`, {
|
|
1318
|
+
fix: `Remove ${imperativeFields.map((field) => `${fieldPath}.${field}`).join(" and ")} and keep ${fieldPath}.scenario, or remove ${fieldPath}.scenario to keep the imperative hooks.`,
|
|
1319
|
+
});
|
|
1320
|
+
if (!hasScenario && typeof c.assertions !== "function")
|
|
674
1321
|
throw new ValidationError(`Provider "${providerId}" ${fieldPath}.assertions must be a function.`, {
|
|
675
1322
|
fix: `Set ${fieldPath}.assertions to (ctx) => { ... } that throws on failure.`,
|
|
676
1323
|
});
|
|
677
1324
|
if (c.prepareInput !== undefined && typeof c.prepareInput !== "function")
|
|
678
1325
|
throw new ValidationError(`Provider "${providerId}" ${fieldPath}.prepareInput must be a function.`);
|
|
1326
|
+
if (hasScenario) {
|
|
1327
|
+
const parsedScenario = HealthScenarioSchema.safeParse(c.scenario);
|
|
1328
|
+
if (!parsedScenario.success)
|
|
1329
|
+
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" health-check case "${c.name}" has an invalid scenario: it must conform to HealthScenario.`, { fix: `Build ${fieldPath}.scenario with defineHealthScenario().` });
|
|
1330
|
+
const unrelatedOperation = parsedScenario.data.coversOperations.find((operationId) => operationId !== operationName);
|
|
1331
|
+
if (unrelatedOperation !== undefined)
|
|
1332
|
+
throw new ValidationError(`Provider "${providerId}" operation "${operationName}" health-check case "${c.name}" scenario.coversOperations cannot claim unrelated operation "${unrelatedOperation}".`, {
|
|
1333
|
+
fix: `Set ${fieldPath}.scenario.coversOperations to ["${operationName}"].`,
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
679
1336
|
if (c.degradedThresholdMs !== undefined &&
|
|
680
1337
|
(typeof c.degradedThresholdMs !== "number" ||
|
|
681
1338
|
!Number.isInteger(c.degradedThresholdMs) ||
|
|
@@ -776,6 +1433,7 @@ const HEALTH_JOURNEY_FIELDS = new Set([
|
|
|
776
1433
|
"manualTrigger",
|
|
777
1434
|
"steps",
|
|
778
1435
|
"run",
|
|
1436
|
+
"scenario",
|
|
779
1437
|
]);
|
|
780
1438
|
const HEALTH_JOURNEY_SCHEDULE_FIELDS = new Set(["kind", "interval", "jitter", "randomize"]);
|
|
781
1439
|
const HEALTH_JOURNEY_STEP_FIELDS = new Set([
|
|
@@ -1198,6 +1856,10 @@ function validateHealthJourneys(providerId, operations, healthJourneys) {
|
|
|
1198
1856
|
}
|
|
1199
1857
|
if (journey.manualTrigger !== undefined)
|
|
1200
1858
|
validateHealthJourneyManualTrigger(providerId, journey.id, journey.manualTrigger);
|
|
1859
|
+
if (journey.scenario !== undefined && journey.smsMatchers !== undefined)
|
|
1860
|
+
throw new ValidationError(`Provider "${providerId}" healthJourneys.${journey.id}.smsMatchers is not allowed on declarative scenarios.`);
|
|
1861
|
+
if (journey.scenario !== undefined && journey.requiredSecrets !== undefined)
|
|
1862
|
+
throw new ValidationError(`Provider "${providerId}" healthJourneys.${journey.id}.requiredSecrets is not allowed on declarative scenarios.`);
|
|
1201
1863
|
if (journey.timeout !== undefined)
|
|
1202
1864
|
assertIsoDuration(journey.timeout, `Provider "${providerId}" healthJourneys.${journey.id}.timeout`);
|
|
1203
1865
|
if (journey.cooldown !== undefined)
|
|
@@ -1239,6 +1901,21 @@ function validateOperationFixtures(providerId, operations) {
|
|
|
1239
1901
|
throw new ValidationError(`Operation handler must be defined for provider "${providerId}" operation "${operationName}"`, {
|
|
1240
1902
|
fix: `Add operations.${operationName}.handler as an async function with signature (ctx, input) => Promise<output>`,
|
|
1241
1903
|
});
|
|
1904
|
+
if (operation.fixtures?.recordedAt !== undefined) {
|
|
1905
|
+
const recordedAt = operation.fixtures.recordedAt;
|
|
1906
|
+
const parsed = typeof recordedAt === "string"
|
|
1907
|
+
? new Date(`${recordedAt}T00:00:00.000Z`)
|
|
1908
|
+
: new Date(Number.NaN);
|
|
1909
|
+
const isCalendarDate = typeof recordedAt === "string" &&
|
|
1910
|
+
/^\d{4}-\d{2}-\d{2}$/.test(recordedAt) &&
|
|
1911
|
+
!Number.isNaN(parsed.getTime()) &&
|
|
1912
|
+
parsed.toISOString().slice(0, 10) === recordedAt;
|
|
1913
|
+
const kstToday = new Date(Date.now() + 9 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
|
1914
|
+
if (!isCalendarDate || recordedAt > kstToday)
|
|
1915
|
+
throw new ValidationError(`Fixture recordedAt must be a valid, non-future KST calendar date for provider "${providerId}" operation "${operationName}"`, {
|
|
1916
|
+
fix: `Set operations.${operationName}.fixtures.recordedAt to the KST capture date in YYYY-MM-DD format; it must not be in the future.`,
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1242
1919
|
if (operation.fixtures?.request !== undefined) {
|
|
1243
1920
|
const result = safeParseSchemaSync(operation.input, operation.fixtures.request, `operations.${operationName}.fixtures.request`);
|
|
1244
1921
|
if (!result.success)
|
|
@@ -1257,6 +1934,28 @@ function validateOperationFixtures(providerId, operations) {
|
|
|
1257
1934
|
}
|
|
1258
1935
|
}
|
|
1259
1936
|
}
|
|
1937
|
+
function resolveOperationFixtureRequests(operations) {
|
|
1938
|
+
let changed = false;
|
|
1939
|
+
const resolvedOperations = Object.fromEntries(Object.entries(operations).map(([operationName, operation]) => {
|
|
1940
|
+
if (operation.fixtures?.request === undefined)
|
|
1941
|
+
return [operationName, operation];
|
|
1942
|
+
const request = resolveHealthCheckInputDateTokens(operation.fixtures.request);
|
|
1943
|
+
if (request === operation.fixtures.request)
|
|
1944
|
+
return [operationName, operation];
|
|
1945
|
+
changed = true;
|
|
1946
|
+
return [
|
|
1947
|
+
operationName,
|
|
1948
|
+
{
|
|
1949
|
+
...operation,
|
|
1950
|
+
fixtures: {
|
|
1951
|
+
...operation.fixtures,
|
|
1952
|
+
request,
|
|
1953
|
+
},
|
|
1954
|
+
},
|
|
1955
|
+
];
|
|
1956
|
+
}));
|
|
1957
|
+
return changed ? resolvedOperations : operations;
|
|
1958
|
+
}
|
|
1260
1959
|
/**
|
|
1261
1960
|
* Shallow shape guard only: the `deployment` object is passed through
|
|
1262
1961
|
* verbatim and deliberately not deep-validated by the SDK — the APIFuse
|
|
@@ -1270,63 +1969,102 @@ function validateProviderDeployment(providerId, deployment) {
|
|
|
1270
1969
|
fix: 'Pass deployment: { runtime: "shared" | "dedicated" | "browser", ... } or remove the field',
|
|
1271
1970
|
});
|
|
1272
1971
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1972
|
+
/** Establish a provider declaration before its operations are contextually typed. */
|
|
1973
|
+
export function defineProvider(declaration) {
|
|
1974
|
+
validateProviderDeclaration(declaration);
|
|
1975
|
+
const buildProvider = (implementation) => finalizeProvider({
|
|
1976
|
+
...declaration,
|
|
1977
|
+
...implementation,
|
|
1978
|
+
});
|
|
1979
|
+
return buildProvider;
|
|
1980
|
+
}
|
|
1981
|
+
function validateProviderDeclaration(config) {
|
|
1982
|
+
validateProviderDeclarationShape(config);
|
|
1275
1983
|
if (!CONNECTOR_ID_REGEX.test(config.id))
|
|
1276
1984
|
throw new ProviderError(`Invalid provider id: "${config.id}"`, {
|
|
1277
1985
|
fix: 'Use lowercase alphanumeric with dashes, e.g., "korea-air-quality"',
|
|
1278
1986
|
});
|
|
1279
|
-
if (Object.keys(config.operations).length === 0)
|
|
1280
|
-
throw new ProviderError(`Provider "${config.id}" must define at least one operation`, {
|
|
1281
|
-
fix: "Add at least one operation to the operations object",
|
|
1282
|
-
});
|
|
1283
|
-
validateOperationIds(config.id, config.operations);
|
|
1284
|
-
validateOperationAnnotations(config.id, config.operations);
|
|
1285
|
-
validateOperationObservability(config.id, config.operations);
|
|
1286
|
-
validateOperationTransports(config.id, config.operations);
|
|
1287
|
-
validateOperationContracts(config.id, config.operations);
|
|
1288
|
-
validateToolRouterMetadata(config.id, config.operations);
|
|
1289
|
-
const journeyCoveredOperations = validateHealthJourneys(config.id, config.operations, config.healthJourneys);
|
|
1290
|
-
validateOperationHealthChecks(config.id, config.operations, journeyCoveredOperations);
|
|
1291
1987
|
if (config.healthMonitor !== undefined && config.healthProbe !== undefined)
|
|
1292
1988
|
throw new ValidationError(`Provider "${config.id}" declares both healthMonitor and healthProbe. They are aliases; declare exactly one.`, {
|
|
1293
1989
|
fix: "Keep healthProbe (the new name) and delete the healthMonitor block.",
|
|
1294
1990
|
});
|
|
1295
1991
|
validateProviderHealthMonitor(config.id, config.healthProbe ?? config.healthMonitor, config.healthProbe !== undefined ? "healthProbe" : "healthMonitor");
|
|
1296
|
-
validateOperationFixtures(config.id, config.operations);
|
|
1297
1992
|
validateProviderDeployment(config.id, config.deployment);
|
|
1993
|
+
try {
|
|
1994
|
+
validateNativeProviderConfig(config.native);
|
|
1995
|
+
}
|
|
1996
|
+
catch (error) {
|
|
1997
|
+
if (error instanceof NativeEgressPolicyValidationError)
|
|
1998
|
+
throw new ValidationError(error.message);
|
|
1999
|
+
throw error;
|
|
2000
|
+
}
|
|
1298
2001
|
validateProviderProxy(config);
|
|
2002
|
+
validateProviderOcr(config);
|
|
1299
2003
|
validateProviderStt(config);
|
|
2004
|
+
validateProviderResolver(config);
|
|
1300
2005
|
if (config.runtime === "browser" && !config.browser)
|
|
1301
2006
|
throw new ProviderError(`Provider "${config.id}" must define browser.engine when runtime is "browser"`, {
|
|
1302
2007
|
fix: 'Add browser: { engine: "playwright-stealth" } for TypeScript providers, or another supported engine for your runtime',
|
|
1303
2008
|
});
|
|
1304
2009
|
if (config.browser && config.runtime !== "browser")
|
|
1305
2010
|
throw new ProviderError(`Provider "${config.id}" cannot define browser config unless runtime is "browser"`, { fix: 'Set runtime: "browser" or remove the browser config' });
|
|
1306
|
-
|
|
2011
|
+
validateFailClosedProviderDeclaration(config);
|
|
2012
|
+
}
|
|
2013
|
+
function finalizeProvider(config) {
|
|
2014
|
+
validateProviderImplementationShape(config);
|
|
2015
|
+
const operations = resolveOperationFixtureRequests(config.operations);
|
|
2016
|
+
if (Object.keys(config.operations).length === 0)
|
|
2017
|
+
throw new ProviderError(`Provider "${config.id}" must define at least one operation`, {
|
|
2018
|
+
fix: "Add at least one operation to the operations object",
|
|
2019
|
+
});
|
|
2020
|
+
validateOperationIds(config.id, config.operations);
|
|
2021
|
+
validateOperationTimeouts(config.id, config.operations);
|
|
2022
|
+
validateOperationObservability(config.id, config.operations);
|
|
2023
|
+
validateOperationErrorCodes(config.id, config.operations);
|
|
2024
|
+
validateOperationTransports(config.id, config.operations);
|
|
2025
|
+
validateOperationContracts(config.id, config.operations);
|
|
2026
|
+
validateOperationMetadata(config.id, config.operations);
|
|
2027
|
+
const journeyCoveredOperations = validateHealthJourneys(config.id, config.operations, config.healthJourneys);
|
|
2028
|
+
validateOperationHealthChecks(config.id, config.operations, journeyCoveredOperations);
|
|
2029
|
+
validateOperationFixtures(config.id, operations);
|
|
2030
|
+
const provider = {
|
|
1307
2031
|
id: config.id,
|
|
1308
2032
|
version: config.version,
|
|
1309
2033
|
runtime: config.runtime,
|
|
2034
|
+
runtimeTarget: config.runtimeTarget,
|
|
1310
2035
|
// Verbatim passthrough: deployment validation and profile resolution
|
|
1311
2036
|
// are owned by the APIFuse registry builder, not the SDK.
|
|
1312
2037
|
deployment: config.deployment,
|
|
2038
|
+
http: config.http,
|
|
1313
2039
|
allowedHosts: config.allowedHosts,
|
|
2040
|
+
native: config.native,
|
|
1314
2041
|
stealth: config.stealth,
|
|
1315
2042
|
proxy: config.proxy,
|
|
2043
|
+
ocr: config.ocr,
|
|
1316
2044
|
stt: config.stt,
|
|
2045
|
+
resolver: config.resolver,
|
|
1317
2046
|
browser: config.browser,
|
|
1318
2047
|
auth: config.auth,
|
|
2048
|
+
handle: config.handle,
|
|
1319
2049
|
reviewed: config.reviewed,
|
|
1320
2050
|
access: config.access,
|
|
1321
2051
|
secrets: config.secrets,
|
|
2052
|
+
env: config.env,
|
|
1322
2053
|
credential: config.credential,
|
|
1323
2054
|
context: config.context,
|
|
2055
|
+
state: config.state,
|
|
2056
|
+
cache: config.cache,
|
|
2057
|
+
files: config.files,
|
|
1324
2058
|
meta: config.meta,
|
|
1325
|
-
operations
|
|
2059
|
+
operations,
|
|
1326
2060
|
// Transitional healthMonitor → healthProbe alias: mirror whichever field
|
|
1327
2061
|
// was declared onto both so old and new consumers keep working.
|
|
1328
2062
|
healthMonitor: config.healthMonitor ?? config.healthProbe,
|
|
1329
2063
|
healthProbe: config.healthProbe ?? config.healthMonitor,
|
|
1330
2064
|
healthJourneys: config.healthJourneys,
|
|
1331
2065
|
};
|
|
2066
|
+
// Declaration validation never invokes handlers, so their declaration-bound
|
|
2067
|
+
// context parameter is irrelevant to the runtime ProviderDefinition shape.
|
|
2068
|
+
validateFailClosedOperationDeclaration(provider);
|
|
2069
|
+
return provider;
|
|
1332
2070
|
}
|