@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/testing/run.js
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { ProviderError } from "../errors.js";
|
|
2
3
|
import { createProviderCache } from "../runtime/cache.js";
|
|
3
|
-
import {
|
|
4
|
+
import { createTestHandleContext } from "../runtime/handle.js";
|
|
5
|
+
/**
|
|
6
|
+
* Stable connection scope for the local test harness so bound handles (drafts,
|
|
7
|
+
* default cursors) can be exercised exactly as in a connected production call.
|
|
8
|
+
*/
|
|
9
|
+
const STANDARD_TEST_CONNECTION_ID = "standard-test-connection";
|
|
4
10
|
import { createMemoryProviderRuntimeState } from "../runtime/state.js";
|
|
11
|
+
import { assertCallerHeadersSupported } from "../runtime/stealth-owned-headers.js";
|
|
12
|
+
import { createUnsupportedOcrClient } from "../runtime/ocr.js";
|
|
5
13
|
import { createUnsupportedSttClient } from "../runtime/stt.js";
|
|
14
|
+
import { createNativeEgressAuthorization, NativeNetworkError, snapshotNativeConnectInput, snapshotNativeGrantInput, } from "../runtime/native-network.js";
|
|
6
15
|
import { safeParseSchemaSync } from "../schema.js";
|
|
16
|
+
import { requestPathForFixture } from "../fixture-sanitization.js";
|
|
17
|
+
import { findStreamCaptureGroup, replayStreamEvidence } from "../stream-evidence.js";
|
|
7
18
|
// Mirrors CONNECTOR_ID_REGEX in ../define.ts, which defineProvider() enforces.
|
|
8
19
|
// A single lowercase segment (no hyphen) is a valid id, so the trailing group
|
|
9
20
|
// is optional (`*`), matching providers like `kakaomap`, `kstartup`, `triple`.
|
|
10
21
|
const CONNECTOR_ID_REGEX = /^[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$/;
|
|
11
|
-
const VALID_AUTH_MODES = [
|
|
22
|
+
const VALID_AUTH_MODES = [
|
|
23
|
+
"none",
|
|
24
|
+
"platform-managed",
|
|
25
|
+
"credentials",
|
|
26
|
+
"oauth2",
|
|
27
|
+
"oauth2_proxied",
|
|
28
|
+
];
|
|
12
29
|
const UPDATE_SNAPSHOT_ARGS = new Set(["-u", "--update-snapshots"]);
|
|
30
|
+
const snapshotCaptureStates = new WeakMap();
|
|
13
31
|
function isFixtureEnvelope(value) {
|
|
14
32
|
return (value !== null &&
|
|
15
33
|
typeof value === "object" &&
|
|
@@ -74,10 +92,365 @@ function jsonResponse(data) {
|
|
|
74
92
|
bytes: async () => bodyBytes.slice(0),
|
|
75
93
|
};
|
|
76
94
|
}
|
|
95
|
+
function headersToRecord(headers) {
|
|
96
|
+
return Object.fromEntries(headers.entries());
|
|
97
|
+
}
|
|
98
|
+
async function normalizeUpstreamResponse(response) {
|
|
99
|
+
if (response instanceof Response) {
|
|
100
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
101
|
+
const text = new TextDecoder().decode(bytes);
|
|
102
|
+
const headers = headersToRecord(response.headers);
|
|
103
|
+
let data = text;
|
|
104
|
+
if (response.headers.get("content-type")?.includes("application/json")) {
|
|
105
|
+
data = text.length > 0 ? JSON.parse(text) : null;
|
|
106
|
+
}
|
|
107
|
+
return { status: response.status, headers, data, text, bytes };
|
|
108
|
+
}
|
|
109
|
+
const headers = { ...(response.headers ?? {}) };
|
|
110
|
+
const body = response.body ?? null;
|
|
111
|
+
let bytes;
|
|
112
|
+
let text;
|
|
113
|
+
let data;
|
|
114
|
+
if (body instanceof Uint8Array) {
|
|
115
|
+
bytes = body.slice(0);
|
|
116
|
+
text = new TextDecoder().decode(bytes);
|
|
117
|
+
data = text;
|
|
118
|
+
}
|
|
119
|
+
else if (body instanceof ArrayBuffer) {
|
|
120
|
+
bytes = new Uint8Array(body.slice(0));
|
|
121
|
+
text = new TextDecoder().decode(bytes);
|
|
122
|
+
data = text;
|
|
123
|
+
}
|
|
124
|
+
else if (typeof body === "string") {
|
|
125
|
+
text = body;
|
|
126
|
+
bytes = new TextEncoder().encode(text);
|
|
127
|
+
data = body;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
text = JSON.stringify(body);
|
|
131
|
+
bytes = new TextEncoder().encode(text);
|
|
132
|
+
data = body;
|
|
133
|
+
if (!Object.keys(headers).some((name) => name.toLowerCase() === "content-type")) {
|
|
134
|
+
headers["content-type"] = "application/json";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { status: response.status ?? 200, headers, data, text, bytes };
|
|
138
|
+
}
|
|
139
|
+
function toHttpResponse(response) {
|
|
140
|
+
return {
|
|
141
|
+
status: response.status,
|
|
142
|
+
ok: response.status >= 200 && response.status < 300,
|
|
143
|
+
headers: response.headers,
|
|
144
|
+
data: response.data,
|
|
145
|
+
json: async () => JSON.parse(response.text),
|
|
146
|
+
text: async () => response.text,
|
|
147
|
+
arrayBuffer: async () => response.bytes.slice(0).buffer,
|
|
148
|
+
bytes: async () => response.bytes.slice(0),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const emptyCookieJar = {
|
|
152
|
+
get: () => undefined,
|
|
153
|
+
getAll: () => ({}),
|
|
154
|
+
toString: () => "",
|
|
155
|
+
};
|
|
156
|
+
function emptyCookieStore() {
|
|
157
|
+
return {
|
|
158
|
+
version: 1,
|
|
159
|
+
jar: { cookies: [] },
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function toStealthResponse(response, url) {
|
|
163
|
+
return {
|
|
164
|
+
status: response.status,
|
|
165
|
+
ok: response.status >= 200 && response.status < 300,
|
|
166
|
+
url,
|
|
167
|
+
redirected: false,
|
|
168
|
+
headers: response.headers,
|
|
169
|
+
rawHeaders: Object.entries(response.headers),
|
|
170
|
+
body: response.text,
|
|
171
|
+
cookies: emptyCookieJar,
|
|
172
|
+
json: async () => JSON.parse(response.text),
|
|
173
|
+
arrayBuffer: async () => response.bytes.slice(0).buffer,
|
|
174
|
+
bytes: async () => response.bytes.slice(0),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function streamFromBytes(bytes) {
|
|
178
|
+
return new ReadableStream({
|
|
179
|
+
start(controller) {
|
|
180
|
+
controller.enqueue(bytes.slice(0));
|
|
181
|
+
controller.close();
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
async function* singleBytes(bytes) {
|
|
186
|
+
yield bytes.slice(0);
|
|
187
|
+
}
|
|
188
|
+
async function* singleText(textValue) {
|
|
189
|
+
yield textValue;
|
|
190
|
+
}
|
|
191
|
+
function createUpstreamContext(provider, operationName, upstreamStub) {
|
|
192
|
+
const credential = {
|
|
193
|
+
mode: "none",
|
|
194
|
+
get: () => undefined,
|
|
195
|
+
getAll: () => ({}),
|
|
196
|
+
getAccessToken: () => undefined,
|
|
197
|
+
getScopes: () => [],
|
|
198
|
+
};
|
|
199
|
+
const request = { headers: {}, connectionId: STANDARD_TEST_CONNECTION_ID };
|
|
200
|
+
const state = createMemoryProviderRuntimeState();
|
|
201
|
+
const nativeEgress = provider.native
|
|
202
|
+
? createNativeEgressAuthorization({ egress: provider.native.network })
|
|
203
|
+
: undefined;
|
|
204
|
+
const requireNativeEgress = () => {
|
|
205
|
+
if (!nativeEgress)
|
|
206
|
+
throw new NativeNetworkError("Native egress authorization is unavailable", "native_egress_policy_invalid");
|
|
207
|
+
return nativeEgress;
|
|
208
|
+
};
|
|
209
|
+
const dispatch = async (call) => {
|
|
210
|
+
const canned = await upstreamStub({ operationName, ...call });
|
|
211
|
+
if (canned === undefined) {
|
|
212
|
+
throw new Error(`Unmatched upstream call for operation "${operationName}": ${call.transport}.${call.method}${call.url ? ` ${call.url}` : ""}. Add a canned response to upstreamStub; live network passthrough is disabled.`);
|
|
213
|
+
}
|
|
214
|
+
return normalizeUpstreamResponse(canned);
|
|
215
|
+
};
|
|
216
|
+
const httpCall = async (method, url, body, options) => toHttpResponse(await dispatch({ transport: "http", method, url, body, options }));
|
|
217
|
+
// The production transport rejects owned headers (User-Agent, Sec-Fetch-*,
|
|
218
|
+
// sec-ch-ua*, ...) before any byte is sent; the fake applies the same
|
|
219
|
+
// function, so a provider test fails exactly where production would.
|
|
220
|
+
const stealthCall = async (url, options) => {
|
|
221
|
+
assertCallerHeadersSupported(options?.headers ?? {});
|
|
222
|
+
return toStealthResponse(await dispatch({
|
|
223
|
+
transport: "stealth",
|
|
224
|
+
method: options?.method?.toUpperCase() ?? "GET",
|
|
225
|
+
url,
|
|
226
|
+
body: options?.body,
|
|
227
|
+
options,
|
|
228
|
+
}), url);
|
|
229
|
+
};
|
|
230
|
+
const createBrowserPage = () => {
|
|
231
|
+
let currentUrl = "about:blank";
|
|
232
|
+
let currentResponse;
|
|
233
|
+
const browserAction = async (method, body) => {
|
|
234
|
+
currentResponse = await dispatch({
|
|
235
|
+
transport: "browser",
|
|
236
|
+
method,
|
|
237
|
+
url: currentUrl,
|
|
238
|
+
body,
|
|
239
|
+
});
|
|
240
|
+
return currentResponse;
|
|
241
|
+
};
|
|
242
|
+
const page = {
|
|
243
|
+
id: `standard-test-${operationName}`,
|
|
244
|
+
url: async () => currentUrl,
|
|
245
|
+
title: async () => currentResponse?.text.match(/<title[^>]*>([^<]*)<\/title>/i)?.[1] ?? "",
|
|
246
|
+
userAgent: async () => String((await browserAction("userAgent")).data),
|
|
247
|
+
content: async () => currentResponse?.text ?? "",
|
|
248
|
+
evaluate: async (fn) => (await browserAction("evaluate", typeof fn === "string" ? fn : String(fn))).data,
|
|
249
|
+
locator: (selector) => ({
|
|
250
|
+
click: async () => {
|
|
251
|
+
await browserAction("locator.click", { selector });
|
|
252
|
+
},
|
|
253
|
+
fill: async (textValue) => {
|
|
254
|
+
await browserAction("locator.fill", { selector, text: textValue });
|
|
255
|
+
},
|
|
256
|
+
textContent: async () => {
|
|
257
|
+
const value = (await browserAction("locator.textContent", { selector })).data;
|
|
258
|
+
return value === null || value === undefined ? null : String(value);
|
|
259
|
+
},
|
|
260
|
+
waitFor: async (options) => {
|
|
261
|
+
await browserAction("locator.waitFor", { selector, options });
|
|
262
|
+
},
|
|
263
|
+
}),
|
|
264
|
+
close: async () => { },
|
|
265
|
+
cookies: async () => (await browserAction("cookies")).data,
|
|
266
|
+
fill: async (selector, textValue) => {
|
|
267
|
+
await browserAction("fill", { selector, text: textValue });
|
|
268
|
+
},
|
|
269
|
+
goto: async (url) => {
|
|
270
|
+
currentUrl = url;
|
|
271
|
+
await browserAction("goto");
|
|
272
|
+
},
|
|
273
|
+
screenshot: async (options) => Buffer.from((await browserAction("screenshot", options)).bytes),
|
|
274
|
+
click: async (selector) => {
|
|
275
|
+
await browserAction("click", { selector });
|
|
276
|
+
},
|
|
277
|
+
type: async (selector, textValue) => {
|
|
278
|
+
await browserAction("type", { selector, text: textValue });
|
|
279
|
+
},
|
|
280
|
+
waitForSelector: async (selector, options) => {
|
|
281
|
+
await browserAction("waitForSelector", { selector, options });
|
|
282
|
+
},
|
|
283
|
+
frames: async () => [page],
|
|
284
|
+
withResourcePolicy: async (_policy, run) => run(),
|
|
285
|
+
};
|
|
286
|
+
return page;
|
|
287
|
+
};
|
|
288
|
+
const createStealthSession = () => ({
|
|
289
|
+
fetch: stealthCall,
|
|
290
|
+
async replayChallenged() {
|
|
291
|
+
throw new ProviderError("Recorded transports cannot replay an engine-owned challenge", {
|
|
292
|
+
code: "REPLAY_SESSION_MISMATCH",
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
cookies: {
|
|
296
|
+
...emptyCookieJar,
|
|
297
|
+
has: () => false,
|
|
298
|
+
setFromCookieStrings: () => { },
|
|
299
|
+
toHeader: () => "",
|
|
300
|
+
snapshot: () => ({}),
|
|
301
|
+
restore: () => { },
|
|
302
|
+
serialize: emptyCookieStore,
|
|
303
|
+
deserialize: () => { },
|
|
304
|
+
clear: () => { },
|
|
305
|
+
},
|
|
306
|
+
redirects: {
|
|
307
|
+
run: async (options) => {
|
|
308
|
+
const final = await stealthCall(options.url, options);
|
|
309
|
+
return {
|
|
310
|
+
final,
|
|
311
|
+
hops: [],
|
|
312
|
+
reason: "completed",
|
|
313
|
+
cookies: {},
|
|
314
|
+
cookieStore: emptyCookieStore(),
|
|
315
|
+
};
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
close: () => { },
|
|
319
|
+
});
|
|
320
|
+
return {
|
|
321
|
+
env: { get: () => undefined },
|
|
322
|
+
credential,
|
|
323
|
+
request,
|
|
324
|
+
http: {
|
|
325
|
+
request: (url, options) => httpCall(options?.method?.toUpperCase() ?? "GET", url, options?.body, options),
|
|
326
|
+
get: (url, options) => httpCall("GET", url, undefined, options),
|
|
327
|
+
post: (url, body, options) => httpCall("POST", url, body, options),
|
|
328
|
+
put: (url, body, options) => httpCall("PUT", url, body, options),
|
|
329
|
+
delete: (url, options) => httpCall("DELETE", url, undefined, options),
|
|
330
|
+
stream: async (url, options) => {
|
|
331
|
+
const response = await dispatch({
|
|
332
|
+
transport: "http",
|
|
333
|
+
method: options?.method?.toUpperCase() ?? "GET",
|
|
334
|
+
url,
|
|
335
|
+
body: options?.body,
|
|
336
|
+
options,
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
status: response.status,
|
|
340
|
+
ok: response.status >= 200 && response.status < 300,
|
|
341
|
+
headers: response.headers,
|
|
342
|
+
body: streamFromBytes(response.bytes),
|
|
343
|
+
bytes: () => singleBytes(response.bytes),
|
|
344
|
+
textChunks: () => singleText(response.text),
|
|
345
|
+
lines: () => singleText(response.text),
|
|
346
|
+
};
|
|
347
|
+
},
|
|
348
|
+
sse: async (url, options) => {
|
|
349
|
+
const response = await dispatch({
|
|
350
|
+
transport: "http",
|
|
351
|
+
method: options?.method?.toUpperCase() ?? "GET",
|
|
352
|
+
url,
|
|
353
|
+
body: options?.body,
|
|
354
|
+
options,
|
|
355
|
+
});
|
|
356
|
+
async function* messages() {
|
|
357
|
+
for (const block of response.text.split(/\r?\n\r?\n/)) {
|
|
358
|
+
const data = block
|
|
359
|
+
.split(/\r?\n/)
|
|
360
|
+
.filter((line) => line.startsWith("data:"))
|
|
361
|
+
.map((line) => line.slice(5).trimStart())
|
|
362
|
+
.join("\n");
|
|
363
|
+
if (!data)
|
|
364
|
+
continue;
|
|
365
|
+
yield { event: "message", data, json: () => JSON.parse(data) };
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return messages();
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
cache: createProviderCache({ providerId: `standard-test-${operationName}` }),
|
|
372
|
+
state,
|
|
373
|
+
stealth: {
|
|
374
|
+
fetch: stealthCall,
|
|
375
|
+
createSession: createStealthSession,
|
|
376
|
+
},
|
|
377
|
+
browser: {
|
|
378
|
+
engine: "playwright-stealth",
|
|
379
|
+
newPage: async () => createBrowserPage(),
|
|
380
|
+
rawPage: async () => createBrowserPage(),
|
|
381
|
+
withIsolatedContext: async (handler) => handler(createBrowserPage()),
|
|
382
|
+
solveChallenge: async (challenge) => (await dispatch({
|
|
383
|
+
transport: "browser",
|
|
384
|
+
method: "solveChallenge",
|
|
385
|
+
body: challenge,
|
|
386
|
+
})).data,
|
|
387
|
+
},
|
|
388
|
+
...(provider.native
|
|
389
|
+
? {
|
|
390
|
+
native: {
|
|
391
|
+
network: {
|
|
392
|
+
connectTcp: async (options) => {
|
|
393
|
+
const request = snapshotNativeConnectInput(options);
|
|
394
|
+
requireNativeEgress().assertConnect(request, "disabled");
|
|
395
|
+
return createNativeConnection(await dispatch({
|
|
396
|
+
transport: "native",
|
|
397
|
+
method: "connectTcp",
|
|
398
|
+
url: `tcp://${request.host}:${request.port}`,
|
|
399
|
+
options: request,
|
|
400
|
+
}), dispatch, `tcp://${request.host}:${request.port}`);
|
|
401
|
+
},
|
|
402
|
+
connectTls: async (options) => {
|
|
403
|
+
const request = snapshotNativeConnectInput(options);
|
|
404
|
+
requireNativeEgress().assertConnect(request, "required");
|
|
405
|
+
return createNativeConnection(await dispatch({
|
|
406
|
+
transport: "native",
|
|
407
|
+
method: "connectTls",
|
|
408
|
+
url: `tls://${request.host}:${request.port}`,
|
|
409
|
+
options: request,
|
|
410
|
+
}), dispatch, `tls://${request.host}:${request.port}`);
|
|
411
|
+
},
|
|
412
|
+
grantTcpEgress: (input) => {
|
|
413
|
+
return requireNativeEgress().grant(snapshotNativeGrantInput(input));
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
}
|
|
418
|
+
: {}),
|
|
419
|
+
trace: { span: async (_name, fn) => fn() },
|
|
420
|
+
auth: { requestField: async (name) => unsupported(`ctx.auth.requestField(${name})`) },
|
|
421
|
+
ocr: createUnsupportedOcrClient("Standard test upstream context does not support ctx.ocr.recognize"),
|
|
422
|
+
stt: createUnsupportedSttClient("Standard test upstream context does not support ctx.stt.transcribe"),
|
|
423
|
+
resolver: {
|
|
424
|
+
solve: async () => unsupported("ctx.resolver.solve"),
|
|
425
|
+
},
|
|
426
|
+
handle: createTestHandleContext({
|
|
427
|
+
providerId: `standard-test-${operationName}`,
|
|
428
|
+
request,
|
|
429
|
+
state,
|
|
430
|
+
}),
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
function createNativeConnection(initialResponse, dispatch, url) {
|
|
434
|
+
let unread = initialResponse.bytes.slice(0);
|
|
435
|
+
return {
|
|
436
|
+
read: async () => {
|
|
437
|
+
if (unread.byteLength === 0)
|
|
438
|
+
return null;
|
|
439
|
+
const bytes = unread;
|
|
440
|
+
unread = new Uint8Array();
|
|
441
|
+
return bytes;
|
|
442
|
+
},
|
|
443
|
+
write: async (body) => {
|
|
444
|
+
const response = await dispatch({ transport: "native", method: "write", url, body });
|
|
445
|
+
unread = response.bytes.slice(0);
|
|
446
|
+
},
|
|
447
|
+
close: async () => { },
|
|
448
|
+
};
|
|
449
|
+
}
|
|
77
450
|
function unsupported(name) {
|
|
78
451
|
throw new Error(`Standard test snapshot context does not support ${name}`);
|
|
79
452
|
}
|
|
80
|
-
function createSnapshotContext(rawFixture) {
|
|
453
|
+
export function createSnapshotContext(rawFixture) {
|
|
81
454
|
const credential = {
|
|
82
455
|
mode: "none",
|
|
83
456
|
get: () => undefined,
|
|
@@ -85,19 +458,54 @@ function createSnapshotContext(rawFixture) {
|
|
|
85
458
|
getAccessToken: () => undefined,
|
|
86
459
|
getScopes: () => [],
|
|
87
460
|
};
|
|
88
|
-
const request = { headers: {} };
|
|
461
|
+
const request = { headers: {}, connectionId: STANDARD_TEST_CONNECTION_ID };
|
|
89
462
|
const state = createMemoryProviderRuntimeState();
|
|
90
|
-
|
|
463
|
+
const streamCaptureGroup = findStreamCaptureGroup(rawFixture);
|
|
464
|
+
let nextCaptureItem = 0;
|
|
465
|
+
const replayJsonResponse = () => {
|
|
466
|
+
if (!streamCaptureGroup)
|
|
467
|
+
return jsonResponse(rawFixture);
|
|
468
|
+
const item = streamCaptureGroup.items[nextCaptureItem];
|
|
469
|
+
if (!item) {
|
|
470
|
+
throw new Error(`Stream fixture exhausted: no recorded response exists for ordinary HTTP call ${nextCaptureItem + 1}.`);
|
|
471
|
+
}
|
|
472
|
+
if (item.kind !== "response") {
|
|
473
|
+
throw new Error(`Stream fixture call-order mismatch: expected a stream call at position ${nextCaptureItem + 1}, received an ordinary HTTP call.`);
|
|
474
|
+
}
|
|
475
|
+
nextCaptureItem += 1;
|
|
476
|
+
return jsonResponse(item.value);
|
|
477
|
+
};
|
|
478
|
+
const context = {
|
|
91
479
|
env: { get: () => undefined },
|
|
92
480
|
credential,
|
|
93
481
|
request,
|
|
94
482
|
http: {
|
|
95
|
-
request: async () =>
|
|
96
|
-
get: async () =>
|
|
97
|
-
post: async () =>
|
|
98
|
-
put: async () =>
|
|
99
|
-
delete: async () =>
|
|
100
|
-
stream: async () =>
|
|
483
|
+
request: async () => replayJsonResponse(),
|
|
484
|
+
get: async () => replayJsonResponse(),
|
|
485
|
+
post: async () => replayJsonResponse(),
|
|
486
|
+
put: async () => replayJsonResponse(),
|
|
487
|
+
delete: async () => replayJsonResponse(),
|
|
488
|
+
stream: async (...args) => {
|
|
489
|
+
if (!streamCaptureGroup)
|
|
490
|
+
return unsupported("ctx.http.stream");
|
|
491
|
+
const item = streamCaptureGroup.items[nextCaptureItem];
|
|
492
|
+
if (!item) {
|
|
493
|
+
throw new Error(`Stream fixture exhausted: no recorded evidence exists for stream call ${nextCaptureItem + 1}.`);
|
|
494
|
+
}
|
|
495
|
+
if (item.kind !== "stream") {
|
|
496
|
+
throw new Error(`Stream fixture call-order mismatch: expected an ordinary HTTP call at position ${nextCaptureItem + 1}, received a stream call.`);
|
|
497
|
+
}
|
|
498
|
+
if (item.evidence.request) {
|
|
499
|
+
const expected = item.evidence.request;
|
|
500
|
+
const actualMethod = (args[1]?.method ?? "GET").toUpperCase();
|
|
501
|
+
const actualPath = replayRequestPath(args[0], expected.path);
|
|
502
|
+
if (actualMethod !== expected.method || actualPath !== expected.path) {
|
|
503
|
+
throw new Error(`Stream fixture request mismatch: expected ${expected.method} ${expected.path}, received ${actualMethod} ${actualPath}.`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
nextCaptureItem += 1;
|
|
507
|
+
return replayStreamEvidence(item.evidence);
|
|
508
|
+
},
|
|
101
509
|
sse: async () => unsupported("ctx.http.sse"),
|
|
102
510
|
},
|
|
103
511
|
cache: createProviderCache({ providerId: "standard-test" }),
|
|
@@ -119,23 +527,50 @@ function createSnapshotContext(rawFixture) {
|
|
|
119
527
|
auth: {
|
|
120
528
|
requestField: async (name) => unsupported(`ctx.auth.requestField(${name})`),
|
|
121
529
|
},
|
|
530
|
+
ocr: createUnsupportedOcrClient("Standard test snapshot context does not support ctx.ocr.recognize"),
|
|
122
531
|
stt: createUnsupportedSttClient("Standard test snapshot context does not support ctx.stt.transcribe"),
|
|
123
|
-
|
|
532
|
+
resolver: {
|
|
533
|
+
solve: async () => unsupported("ctx.resolver.solve"),
|
|
534
|
+
},
|
|
535
|
+
handle: createTestHandleContext({
|
|
124
536
|
providerId: "standard-test",
|
|
125
537
|
request,
|
|
126
|
-
credential,
|
|
127
538
|
state,
|
|
128
539
|
}),
|
|
129
540
|
};
|
|
541
|
+
snapshotCaptureStates.set(context, {
|
|
542
|
+
assertConsumed() {
|
|
543
|
+
if (streamCaptureGroup && nextCaptureItem !== streamCaptureGroup.items.length) {
|
|
544
|
+
throw new Error(`Stream fixture has ${streamCaptureGroup.items.length - nextCaptureItem} unconsumed capture item${streamCaptureGroup.items.length - nextCaptureItem === 1 ? "" : "s"} after handler completion.`);
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
consumed: () => nextCaptureItem,
|
|
548
|
+
});
|
|
549
|
+
return context;
|
|
550
|
+
}
|
|
551
|
+
function replayRequestPath(requestUrl, expectedPath) {
|
|
552
|
+
if (/^[a-z][a-z\d+.-]*:\/\//i.test(requestUrl) || requestUrl.startsWith("/")) {
|
|
553
|
+
return requestPathForFixture(requestUrl);
|
|
554
|
+
}
|
|
555
|
+
return requestPathForFixture(new URL(requestUrl, `https://fixture.invalid${expectedPath}`).toString());
|
|
130
556
|
}
|
|
131
557
|
async function transformSnapshotOutput(provider, rawFixture) {
|
|
132
558
|
const entries = Object.entries(provider.operations);
|
|
133
|
-
const
|
|
559
|
+
const captureStates = [];
|
|
134
560
|
const outputs = await Promise.all(entries.map(async ([operationName, operation]) => {
|
|
561
|
+
const context = createSnapshotContext(rawFixture);
|
|
135
562
|
const request = operation.fixtures?.request ?? {};
|
|
136
563
|
const output = await operation.handler(context, request);
|
|
564
|
+
const captureState = snapshotCaptureStates.get(context);
|
|
565
|
+
if (captureState)
|
|
566
|
+
captureStates.push(captureState);
|
|
567
|
+
if (captureState?.consumed())
|
|
568
|
+
captureState.assertConsumed();
|
|
137
569
|
return [operationName, output];
|
|
138
570
|
}));
|
|
571
|
+
if (findStreamCaptureGroup(rawFixture) && !captureStates.some((state) => state.consumed() > 0)) {
|
|
572
|
+
captureStates[0]?.assertConsumed();
|
|
573
|
+
}
|
|
139
574
|
if (outputs.length === 1) {
|
|
140
575
|
return outputs[0]?.[1];
|
|
141
576
|
}
|
|
@@ -154,7 +589,7 @@ function formatJsonDiff(current, expected) {
|
|
|
154
589
|
const expectedLine = expectedLines[index];
|
|
155
590
|
if (currentLine === expectedLine) {
|
|
156
591
|
if (currentLine !== undefined) {
|
|
157
|
-
lines.push(`
|
|
592
|
+
lines.push(` ${currentLine}`);
|
|
158
593
|
}
|
|
159
594
|
continue;
|
|
160
595
|
}
|
|
@@ -180,16 +615,51 @@ function expectSchemaFixture(operationName, fieldName, fixture, result) {
|
|
|
180
615
|
function parseSchemaFixture(operationName, fieldName, schema, fixture) {
|
|
181
616
|
expectSchemaFixture(operationName, fieldName, fixture, safeParseSchemaSync(schema, fixture, `operations.${operationName}.fixtures.${fieldName}`));
|
|
182
617
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
618
|
+
async function materializeHandlerOutput(output) {
|
|
619
|
+
if (!(output instanceof Response))
|
|
620
|
+
return output;
|
|
621
|
+
const contentType = output.headers.get("content-type") ?? "";
|
|
622
|
+
if (contentType.includes("application/json"))
|
|
623
|
+
return output.json();
|
|
624
|
+
return output.text();
|
|
625
|
+
}
|
|
626
|
+
/** Internal execution seam exported for focused SDK tests; use runStandardTests as public API. */
|
|
627
|
+
export async function executeStandardTestHandler(provider, operationName, upstreamStub) {
|
|
628
|
+
const operation = provider.operations[operationName];
|
|
629
|
+
if (!operation)
|
|
630
|
+
throw new Error(`Unknown operation "${operationName}".`);
|
|
631
|
+
if (operation.fixtures?.request === undefined) {
|
|
632
|
+
throw new Error(`Operation "${operationName}" has no fixtures.request for handler E2E execution.`);
|
|
633
|
+
}
|
|
634
|
+
const context = createUpstreamContext(provider, operationName, upstreamStub);
|
|
635
|
+
const output = await materializeHandlerOutput(await operation.handler(context, operation.fixtures.request));
|
|
636
|
+
const result = safeParseSchemaSync(operation.output, output, `operations.${operationName}.handler.output`);
|
|
637
|
+
if (!result.success) {
|
|
638
|
+
throw new Error([
|
|
639
|
+
`Handler output for operation "${operationName}" failed schema validation.`,
|
|
640
|
+
formatJsonDiff({ valid: false, value: output, error: result.error }, { valid: true, value: output }),
|
|
641
|
+
].join("\n"));
|
|
642
|
+
}
|
|
643
|
+
return output;
|
|
644
|
+
}
|
|
645
|
+
function isOptionsShortcut(value) {
|
|
646
|
+
return (value !== null &&
|
|
647
|
+
typeof value === "object" &&
|
|
648
|
+
!Array.isArray(value) &&
|
|
649
|
+
Object.hasOwn(value, "upstreamStub"));
|
|
650
|
+
}
|
|
651
|
+
export function runStandardTests(provider, rawFixtureOrOptions, manifest, legacyOptions) {
|
|
652
|
+
const shortcut = manifest === undefined && legacyOptions === undefined && isOptionsShortcut(rawFixtureOrOptions);
|
|
653
|
+
const rawFixture = shortcut ? undefined : rawFixtureOrOptions;
|
|
654
|
+
const options = shortcut ? rawFixtureOrOptions : (legacyOptions ?? {});
|
|
192
655
|
const operations = Object.entries(provider.operations);
|
|
656
|
+
const warnings = options.upstreamStub
|
|
657
|
+
? operations
|
|
658
|
+
.filter(([, operation]) => operation.fixtures?.request === undefined)
|
|
659
|
+
.map(([operationName]) => `[provider-sdk] Operation "${provider.id}.${operationName}" has no fixtures.request, so runStandardTests cannot invoke its handler E2E.`)
|
|
660
|
+
: operations.map(([operationName]) => `[provider-sdk] Operation "${provider.id}.${operationName}" has no handler E2E coverage in runStandardTests; configure upstreamStub to invoke the real handler.`);
|
|
661
|
+
for (const warning of warnings)
|
|
662
|
+
console.warn(warning);
|
|
193
663
|
const assertFixtureValidation = () => {
|
|
194
664
|
expect(rawFixture).toBeDefined();
|
|
195
665
|
expect(isJsonCompatible(rawFixture)).toBe(true);
|
|
@@ -289,12 +759,26 @@ export function runStandardTests(provider, rawFixture, manifest, options = {}) {
|
|
|
289
759
|
const actual = await transformSnapshotOutput(provider, rawFixture);
|
|
290
760
|
const serialized = stableStringify(actual);
|
|
291
761
|
const snapshotFile = Bun.file(snapshotPath);
|
|
292
|
-
|
|
762
|
+
const snapshotExists = await snapshotFile.exists();
|
|
763
|
+
if (!snapshotExists && options.requireSnapshot && !shouldUpdateSnapshots()) {
|
|
764
|
+
throw new Error(`Required golden snapshot is missing: ${snapshotPath}. Regenerate it with bun test --update-snapshots.`);
|
|
765
|
+
}
|
|
766
|
+
if (shouldUpdateSnapshots() || !snapshotExists) {
|
|
293
767
|
await Bun.write(snapshotPath, serialized);
|
|
294
768
|
}
|
|
295
769
|
const expected = JSON.parse(await Bun.file(snapshotPath).text());
|
|
296
770
|
expect(actual).toEqual(expected);
|
|
297
771
|
});
|
|
298
772
|
}
|
|
773
|
+
if (options.upstreamStub) {
|
|
774
|
+
for (const [operationName, operation] of operations) {
|
|
775
|
+
if (operation.fixtures?.request === undefined)
|
|
776
|
+
continue;
|
|
777
|
+
it(`invokes the real ${operationName} handler with canned upstream responses`, async () => {
|
|
778
|
+
await executeStandardTestHandler(provider, operationName, options.upstreamStub);
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
}
|
|
299
782
|
});
|
|
783
|
+
return { warnings };
|
|
300
784
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type DiagnosticRedactor } from "./runtime/diagnostic-redactor.js";
|
|
2
|
+
import type { TraceSpan } from "./types.js";
|
|
3
|
+
/** Span names are SDK-authored identifiers; retain them while preventing log injection. */
|
|
4
|
+
export declare function sanitizeSpanNameForOutput(value: string, redact?: DiagnosticRedactor): string;
|
|
5
|
+
export declare function sanitizeTraceAttributes(attributes: Record<string, unknown>, redact?: DiagnosticRedactor, reservedKeys?: Iterable<string>): Record<string, string | number | boolean>;
|
|
6
|
+
export declare function sanitizeSpanForOutput(span: TraceSpan, additionalAttributes?: Record<string, string>, redact?: DiagnosticRedactor): TraceSpan;
|