@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
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
providerCacheRedisResolutionFromEnv,
|
|
3
|
+
type ProviderRedisUrlResolution,
|
|
4
|
+
providerStateRedisResolutionFromEnv,
|
|
5
|
+
} from "../config/loader.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* What a provider store resolved to at boot.
|
|
9
|
+
*
|
|
10
|
+
* `endpoint` is deliberately host and port only: the URL can carry a password
|
|
11
|
+
* (`redis://:secret@host:6379`), and the diagnostic inventory already treats
|
|
12
|
+
* those credential components — and only those — as sensitive
|
|
13
|
+
* (`collectDiagnosticSensitiveValues`, `urlCredentialComponents(url, {
|
|
14
|
+
* includePathAndQuery: false })`). A URL that does not parse contributes no
|
|
15
|
+
* endpoint at all rather than a redacted-looking fragment of itself.
|
|
16
|
+
*/
|
|
17
|
+
export type ProviderStoreBackendReport = {
|
|
18
|
+
/**
|
|
19
|
+
* `redis` when a URL resolved, `memory` for the in-process fallback,
|
|
20
|
+
* `unsupported` when state has no backend and every call fails closed,
|
|
21
|
+
* `injected` when the host handed the server a store object.
|
|
22
|
+
*/
|
|
23
|
+
readonly backend: "redis" | "memory" | "unsupported" | "injected";
|
|
24
|
+
/** Env name that supplied the Redis URL. Present only for `redis`. */
|
|
25
|
+
readonly envName?: string;
|
|
26
|
+
/**
|
|
27
|
+
* `host:port` of the resolved Redis. Never includes credentials, path or
|
|
28
|
+
* query. Absent when the URL does not parse, or when its query carries an
|
|
29
|
+
* ioredis option that moves the endpoint (`path`, `port`, `host`, `family`)
|
|
30
|
+
* so the authority is not where the client connects — see
|
|
31
|
+
* `state_redis_url_ambiguous_endpoint`.
|
|
32
|
+
*/
|
|
33
|
+
readonly endpoint?: string;
|
|
34
|
+
/** URL scheme, e.g. `redis` or `rediss`. Present only for `redis`. */
|
|
35
|
+
readonly scheme?: string;
|
|
36
|
+
/** True when the URL came from a shared fallback env rather than the store's own. */
|
|
37
|
+
readonly fallback?: boolean;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* One line per process boot naming the stores the provider resolved. Without
|
|
42
|
+
* it, a provider silently riding the cache Redis for its state is
|
|
43
|
+
* indistinguishable from one on a durable instance, from outside the pod and
|
|
44
|
+
* from the pod's own logs (apifuse#2302, the reason apifuse#2144 could only be
|
|
45
|
+
* verified by inference from the Deployment spec).
|
|
46
|
+
*/
|
|
47
|
+
export type ProviderStateBackendLogEvent = {
|
|
48
|
+
/** `warn` when a warning was raised, otherwise `info`. */
|
|
49
|
+
readonly level: "info" | "warn";
|
|
50
|
+
readonly event: "provider_state_backend";
|
|
51
|
+
readonly providerId: string;
|
|
52
|
+
readonly state: ProviderStoreBackendReport;
|
|
53
|
+
readonly cache: ProviderStoreBackendReport;
|
|
54
|
+
readonly sdkVersion: string;
|
|
55
|
+
/**
|
|
56
|
+
* Non-fatal findings, e.g. `state_redis_url_fallback` (the state store is
|
|
57
|
+
* sharing an instance provisioned for something else),
|
|
58
|
+
* `state_redis_url_unparsed`, or `state_redis_url_ambiguous_endpoint` (the
|
|
59
|
+
* URL's query carries an ioredis option that moves the endpoint, so the
|
|
60
|
+
* authority is not reported as the endpoint). Absent when the resolution
|
|
61
|
+
* was unambiguous.
|
|
62
|
+
*/
|
|
63
|
+
readonly warnings?: readonly string[];
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Whether ioredis' own URL parsing would move the endpoint away from the
|
|
68
|
+
* authority this function can see. `createProviderRedisClient` hands the raw
|
|
69
|
+
* URL to `new Redis(url, …)`, and `parseURL` ends with
|
|
70
|
+
* `defaults(result, queryOptions)` — lodash `defaults`, so a query key only
|
|
71
|
+
* applies where the authority supplied nothing:
|
|
72
|
+
*
|
|
73
|
+
* - `path` is never derived from the authority of a `redis://` URL (that
|
|
74
|
+
* pathname is the db index), so `?path=` always applies — and
|
|
75
|
+
* `StandaloneConnector` connects to `options.path` INSTEAD of host/port.
|
|
76
|
+
* The client is then on a Unix socket the authority says nothing about.
|
|
77
|
+
* - `port` applies only when the URL carries no explicit port.
|
|
78
|
+
* - `host` never applies here: we return early unless `parsed.hostname` is
|
|
79
|
+
* set, so `result.host` is always already populated.
|
|
80
|
+
* - `family` selects an address family; it does not move `host:port`.
|
|
81
|
+
*
|
|
82
|
+
* Verified against the pinned ioredis 5.11.1. In those cases the endpoint is
|
|
83
|
+
* WITHHELD and the ambiguity named, rather than reported as the authority — a
|
|
84
|
+
* diagnostic whose whole job is to answer "which Redis is this provider on"
|
|
85
|
+
* must not answer it wrongly. The query is never echoed: it can carry a
|
|
86
|
+
* password, which is why `endpoint` is host-and-port only to begin with.
|
|
87
|
+
*/
|
|
88
|
+
function queryMovesEndpoint(parsed: URL): boolean {
|
|
89
|
+
if (parsed.searchParams.has("path")) return true;
|
|
90
|
+
return parsed.searchParams.has("port") && parsed.port === "";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function redisEndpoint(url: string): {
|
|
94
|
+
endpoint?: string;
|
|
95
|
+
scheme?: string;
|
|
96
|
+
ambiguous?: boolean;
|
|
97
|
+
} {
|
|
98
|
+
let parsed: URL;
|
|
99
|
+
try {
|
|
100
|
+
parsed = new URL(url);
|
|
101
|
+
} catch {
|
|
102
|
+
return {};
|
|
103
|
+
}
|
|
104
|
+
// No authority means this is not the `redis://host:port` shape at all (e.g.
|
|
105
|
+
// a bare `host:port`, which parses as a scheme). Report nothing rather than
|
|
106
|
+
// a fragment of a string whose parts we have not identified.
|
|
107
|
+
if (!parsed.hostname) return {};
|
|
108
|
+
const scheme = parsed.protocol.replace(/:$/, "");
|
|
109
|
+
if (queryMovesEndpoint(parsed)) return { scheme, ambiguous: true };
|
|
110
|
+
return {
|
|
111
|
+
scheme,
|
|
112
|
+
endpoint: parsed.port ? `${parsed.hostname}:${parsed.port}` : parsed.hostname,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function redisReport(resolution: ProviderRedisUrlResolution): {
|
|
117
|
+
report: ProviderStoreBackendReport;
|
|
118
|
+
parsed: boolean;
|
|
119
|
+
ambiguous: boolean;
|
|
120
|
+
} {
|
|
121
|
+
const { endpoint, scheme, ambiguous } = redisEndpoint(resolution.url);
|
|
122
|
+
return {
|
|
123
|
+
parsed: endpoint !== undefined || ambiguous === true,
|
|
124
|
+
ambiguous: ambiguous === true,
|
|
125
|
+
report: {
|
|
126
|
+
backend: "redis",
|
|
127
|
+
envName: resolution.envName,
|
|
128
|
+
...(endpoint === undefined ? {} : { endpoint }),
|
|
129
|
+
...(scheme === undefined ? {} : { scheme }),
|
|
130
|
+
...(resolution.fallback ? { fallback: true } : {}),
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Build the boot event from the same env precedence the stores themselves use
|
|
137
|
+
* (`providerStateRedisResolutionFromEnv` / `providerCacheRedisResolutionFromEnv`),
|
|
138
|
+
* so the line can never describe a backend other than the one in use.
|
|
139
|
+
*/
|
|
140
|
+
export function providerStateBackendLogEvent(input: {
|
|
141
|
+
readonly providerId: string;
|
|
142
|
+
readonly sdkVersion: string;
|
|
143
|
+
/** The host passed an explicit state store, so no env resolution happened. */
|
|
144
|
+
readonly injectedState: boolean;
|
|
145
|
+
/** Mirrors `createProviderRuntimeStateFromEnv({ allowMemoryFallback })`. */
|
|
146
|
+
readonly allowMemoryFallback: boolean;
|
|
147
|
+
}): ProviderStateBackendLogEvent {
|
|
148
|
+
const warnings: string[] = [];
|
|
149
|
+
let state: ProviderStoreBackendReport;
|
|
150
|
+
if (input.injectedState) {
|
|
151
|
+
state = { backend: "injected" };
|
|
152
|
+
} else {
|
|
153
|
+
const resolution = providerStateRedisResolutionFromEnv();
|
|
154
|
+
if (resolution) {
|
|
155
|
+
const { report, parsed, ambiguous } = redisReport(resolution);
|
|
156
|
+
state = report;
|
|
157
|
+
if (!parsed) warnings.push("state_redis_url_unparsed");
|
|
158
|
+
if (ambiguous) warnings.push("state_redis_url_ambiguous_endpoint");
|
|
159
|
+
if (resolution.fallback) warnings.push("state_redis_url_fallback");
|
|
160
|
+
} else {
|
|
161
|
+
state = { backend: input.allowMemoryFallback ? "memory" : "unsupported" };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const cacheResolution = providerCacheRedisResolutionFromEnv();
|
|
166
|
+
let cache: ProviderStoreBackendReport;
|
|
167
|
+
if (cacheResolution) {
|
|
168
|
+
const { report, parsed, ambiguous } = redisReport(cacheResolution);
|
|
169
|
+
cache = report;
|
|
170
|
+
if (!parsed) warnings.push("cache_redis_url_unparsed");
|
|
171
|
+
if (ambiguous) warnings.push("cache_redis_url_ambiguous_endpoint");
|
|
172
|
+
} else {
|
|
173
|
+
cache = { backend: "memory" };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
level: warnings.length > 0 ? "warn" : "info",
|
|
178
|
+
event: "provider_state_backend",
|
|
179
|
+
providerId: input.providerId,
|
|
180
|
+
state,
|
|
181
|
+
cache,
|
|
182
|
+
sdkVersion: input.sdkVersion,
|
|
183
|
+
...(warnings.length === 0 ? {} : { warnings }),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { isSensitiveFixtureKey, REDACTED_FIXTURE_VALUE } from "../fixture-sanitization.js";
|
|
2
|
+
import {
|
|
3
|
+
type DiagnosticRedactor,
|
|
4
|
+
redactedKeyAllocator,
|
|
5
|
+
isRedactedKey,
|
|
6
|
+
REDACTION_FAILED,
|
|
7
|
+
redactDiagnosticText,
|
|
8
|
+
} from "../runtime/diagnostic-redactor.js";
|
|
9
|
+
import {
|
|
10
|
+
OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
11
|
+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
|
|
12
|
+
type OTLPExportOptions,
|
|
13
|
+
type OTLPExportResolution,
|
|
14
|
+
type OTLPResourceResolution,
|
|
15
|
+
resolveOTLPExportOptions,
|
|
16
|
+
resolveOTLPResourceAttributes,
|
|
17
|
+
} from "../runtime/otlp.js";
|
|
18
|
+
import {
|
|
19
|
+
type CreateTraceContextOptions,
|
|
20
|
+
resolveTraceContextOptions,
|
|
21
|
+
type Span,
|
|
22
|
+
} from "../runtime/trace.js";
|
|
23
|
+
import {
|
|
24
|
+
sanitizeSpanForOutput,
|
|
25
|
+
sanitizeSpanNameForOutput,
|
|
26
|
+
sanitizeTraceAttributes,
|
|
27
|
+
} from "../trace-sanitization.js";
|
|
28
|
+
import type { TraceConfig } from "../types.js";
|
|
29
|
+
|
|
30
|
+
type EnvLike = Record<string, string | undefined>;
|
|
31
|
+
|
|
32
|
+
const TRACE_RESOURCE_ATTRIBUTE_SANITIZER = Symbol.for(
|
|
33
|
+
"@apifuse/provider-sdk/runtime/trace-resource-attribute-sanitizer",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
type ResourceAttributesWithSanitizer = Record<string, string> & {
|
|
37
|
+
[TRACE_RESOURCE_ATTRIBUTE_SANITIZER]?: (
|
|
38
|
+
attributes: Record<string, string>,
|
|
39
|
+
) => Record<string, string>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Warn once per environment object: process.env in production, each injected env in tests.
|
|
43
|
+
const warnedEnvironments = new WeakSet<EnvLike>();
|
|
44
|
+
const warnedResourceEnvironments = new WeakSet<EnvLike>();
|
|
45
|
+
|
|
46
|
+
function warnDiscardedResourceAttributes(env: EnvLike, resolution: OTLPResourceResolution): void {
|
|
47
|
+
if (resolution.discarded.length === 0 || warnedResourceEnvironments.has(env)) return;
|
|
48
|
+
warnedResourceEnvironments.add(env);
|
|
49
|
+
console.warn(
|
|
50
|
+
`[apifuse] ${resolution.discarded.join(", ")} could not be parsed as an OTel key=value list and was ignored.`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function warnExportDisabled(
|
|
55
|
+
env: EnvLike,
|
|
56
|
+
resolution: Exclude<OTLPExportResolution, { status: "resolved" }>,
|
|
57
|
+
): void {
|
|
58
|
+
if (warnedEnvironments.has(env)) return;
|
|
59
|
+
warnedEnvironments.add(env);
|
|
60
|
+
console.warn(
|
|
61
|
+
resolution.status === "unconfigured"
|
|
62
|
+
? `[apifuse] OTLP trace export is enabled but no endpoint is configured; set ${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT} or ${OTEL_EXPORTER_OTLP_ENDPOINT}. Trace export is disabled.`
|
|
63
|
+
: `[apifuse] OTLP trace export is enabled but ${resolution.source} ${resolution.reason}. Trace export is disabled.`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function resolveServerOTLPExportOptions(
|
|
68
|
+
config: TraceConfig,
|
|
69
|
+
env: EnvLike,
|
|
70
|
+
): OTLPExportOptions | undefined {
|
|
71
|
+
const resolution = resolveOTLPExportOptions(
|
|
72
|
+
{
|
|
73
|
+
endpoint: config.otlp?.endpoint ?? config.endpoint,
|
|
74
|
+
headers: config.otlp?.headers,
|
|
75
|
+
timeout: config.otlp?.timeout,
|
|
76
|
+
},
|
|
77
|
+
env,
|
|
78
|
+
);
|
|
79
|
+
if (resolution.status === "resolved") return resolution.options;
|
|
80
|
+
warnExportDisabled(env, resolution);
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Per-request attributes carry client-supplied values (request_id) and get the full attribute
|
|
86
|
+
* sanitizer, exactly as on the console path. Operator-configured attributes from the process
|
|
87
|
+
* environment are identifiers rather than request data: their values are kept, with control
|
|
88
|
+
* characters neutralized, length bounded, and secret-named keys redacted.
|
|
89
|
+
*/
|
|
90
|
+
function resolveExportResourceAttributes(
|
|
91
|
+
requestAttributes: Record<string, string>,
|
|
92
|
+
env: EnvLike,
|
|
93
|
+
redact?: DiagnosticRedactor,
|
|
94
|
+
): {
|
|
95
|
+
attributes: Record<string, string>;
|
|
96
|
+
sanitize: (attributes: Record<string, string>) => Record<string, string>;
|
|
97
|
+
} {
|
|
98
|
+
const resolution = resolveOTLPResourceAttributes({}, env);
|
|
99
|
+
warnDiscardedResourceAttributes(env, resolution);
|
|
100
|
+
const operatorAttributes = resolution.attributes;
|
|
101
|
+
const requestKeys = new Set(Object.keys(requestAttributes));
|
|
102
|
+
return {
|
|
103
|
+
// Keep the raw snapshot private until export. A credential registered after
|
|
104
|
+
// trace creation must be matched before any key or value is bounded.
|
|
105
|
+
attributes: { ...operatorAttributes, ...requestAttributes },
|
|
106
|
+
sanitize(attributes) {
|
|
107
|
+
const nextKey = redactedKeyAllocator(Object.keys(attributes));
|
|
108
|
+
const sanitizedOperatorAttributes: Record<string, string> = {};
|
|
109
|
+
const rawRequestAttributes: Record<string, string> = {};
|
|
110
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
111
|
+
const unchangedOperatorValue = !requestKeys.has(key) && operatorAttributes[key] === value;
|
|
112
|
+
if (unchangedOperatorValue) {
|
|
113
|
+
const redactedKey = isRedactedKey(key) ? key : redactDiagnosticText(key, redact);
|
|
114
|
+
const keyChanged = redactedKey !== key;
|
|
115
|
+
const sanitizedKey = keyChanged ? nextKey() : sanitizeSpanNameForOutput(key);
|
|
116
|
+
sanitizedOperatorAttributes[sanitizedKey] = keyChanged
|
|
117
|
+
? redactedKey === REDACTION_FAILED
|
|
118
|
+
? REDACTION_FAILED
|
|
119
|
+
: REDACTED_FIXTURE_VALUE
|
|
120
|
+
: isSensitiveFixtureKey(key)
|
|
121
|
+
? REDACTED_FIXTURE_VALUE
|
|
122
|
+
: sanitizeSpanNameForOutput(value, redact);
|
|
123
|
+
} else {
|
|
124
|
+
rawRequestAttributes[key] = value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const sanitizedRequestAttributes = Object.fromEntries(
|
|
128
|
+
Object.entries(
|
|
129
|
+
sanitizeTraceAttributes(
|
|
130
|
+
rawRequestAttributes,
|
|
131
|
+
redact,
|
|
132
|
+
Object.keys(sanitizedOperatorAttributes),
|
|
133
|
+
),
|
|
134
|
+
).map(([key, value]) => [key, String(value)]),
|
|
135
|
+
);
|
|
136
|
+
return { ...sanitizedOperatorAttributes, ...sanitizedRequestAttributes };
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Server-only trace output policy. Shared programmatic trace callers stay in-memory. */
|
|
142
|
+
export function resolveServerTraceContextOptions(
|
|
143
|
+
config: TraceConfig,
|
|
144
|
+
resourceAttributes: Record<string, string>,
|
|
145
|
+
env: EnvLike = process.env,
|
|
146
|
+
redact?: DiagnosticRedactor,
|
|
147
|
+
): CreateTraceContextOptions {
|
|
148
|
+
const resolved = resolveTraceContextOptions(config);
|
|
149
|
+
const outputEnabled = config.enabled !== false && config.exporter !== "none";
|
|
150
|
+
const consoleHook =
|
|
151
|
+
outputEnabled && (config.exporter === "console" || config.exporter === "json")
|
|
152
|
+
? (span: Span) =>
|
|
153
|
+
console.log(JSON.stringify(sanitizeSpanForOutput(span, resourceAttributes, redact)))
|
|
154
|
+
: undefined;
|
|
155
|
+
const onSpan =
|
|
156
|
+
consoleHook && resolved.onSpan
|
|
157
|
+
? (span: Span) => {
|
|
158
|
+
consoleHook(span);
|
|
159
|
+
resolved.onSpan?.(span);
|
|
160
|
+
}
|
|
161
|
+
: (consoleHook ?? resolved.onSpan);
|
|
162
|
+
const exportOptions =
|
|
163
|
+
outputEnabled && config.exporter === "otlp"
|
|
164
|
+
? resolveServerOTLPExportOptions(config, env)
|
|
165
|
+
: undefined;
|
|
166
|
+
const exportResources = exportOptions
|
|
167
|
+
? resolveExportResourceAttributes(resourceAttributes, env, redact)
|
|
168
|
+
: undefined;
|
|
169
|
+
if (exportResources) {
|
|
170
|
+
Object.defineProperty(
|
|
171
|
+
exportResources.attributes as ResourceAttributesWithSanitizer,
|
|
172
|
+
TRACE_RESOURCE_ATTRIBUTE_SANITIZER,
|
|
173
|
+
{ value: exportResources.sanitize },
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
maxSpans: resolved.maxSpans,
|
|
179
|
+
onSpan,
|
|
180
|
+
...(redact ? { redact } : {}),
|
|
181
|
+
...(exportOptions
|
|
182
|
+
? {
|
|
183
|
+
exportOptions,
|
|
184
|
+
resourceAttributes: exportResources?.attributes,
|
|
185
|
+
sanitizeSpanForExport: (span: Span) => sanitizeSpanForOutput(span, undefined, redact),
|
|
186
|
+
}
|
|
187
|
+
: {}),
|
|
188
|
+
};
|
|
189
|
+
}
|
package/src/server/types.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { PROVIDER_ERROR_SOURCES } from "../observability.js";
|
|
2
3
|
|
|
3
4
|
import { HttpRetryPreset } from "../types.js";
|
|
4
5
|
|
|
5
|
-
export const ConnectionModeSchema = z.enum([
|
|
6
|
+
export const ConnectionModeSchema = z.enum([
|
|
7
|
+
"oauth2",
|
|
8
|
+
"oauth2_proxied",
|
|
9
|
+
"credentials",
|
|
10
|
+
"platform-managed",
|
|
11
|
+
"none",
|
|
12
|
+
]);
|
|
6
13
|
|
|
7
14
|
export const OperationConnectionSchema = z.object({
|
|
8
15
|
id: z.string(),
|
|
@@ -18,6 +25,13 @@ export const OperationRequestSchema = z.object({
|
|
|
18
25
|
input: z.record(z.string(), z.unknown()),
|
|
19
26
|
connectionId: z.string().optional(),
|
|
20
27
|
connection: OperationConnectionSchema.optional(),
|
|
28
|
+
/**
|
|
29
|
+
* Gateway-asserted principal scope: the organization id for customer
|
|
30
|
+
* subjects, the service-account id for platform service accounts. Absent
|
|
31
|
+
* on direct calls and self-test. Trusted exactly like `connectionId`; it is
|
|
32
|
+
* never derived from caller headers or `input`.
|
|
33
|
+
*/
|
|
34
|
+
tenantId: z.string().optional(),
|
|
21
35
|
headers: z.record(z.string(), z.string()).optional(),
|
|
22
36
|
trace: z.record(z.string(), z.string()).optional(),
|
|
23
37
|
});
|
|
@@ -26,6 +40,11 @@ export const ErrorEnvelopeSchema = z.object({
|
|
|
26
40
|
code: z.string(),
|
|
27
41
|
message: z.string(),
|
|
28
42
|
requestId: z.string().optional(),
|
|
43
|
+
retryable: z.boolean(),
|
|
44
|
+
// Who stopped the request (honest-provider-error-contract); optional so
|
|
45
|
+
// older peers (stateful forwarding owners) remain parseable. Derived from
|
|
46
|
+
// the PROVIDER_ERROR_SOURCES registry so the enum cannot drift.
|
|
47
|
+
source: z.enum(PROVIDER_ERROR_SOURCES).optional(),
|
|
29
48
|
fix: z.string().optional(),
|
|
30
49
|
details: z.unknown().optional(),
|
|
31
50
|
});
|
|
@@ -81,12 +100,26 @@ export const AuthFlowRequestSchema = z.object({
|
|
|
81
100
|
headers: z.record(z.string(), z.string()).optional(),
|
|
82
101
|
input: z.record(z.string(), z.unknown()).optional(),
|
|
83
102
|
context: z.record(z.string(), z.unknown()).optional(),
|
|
103
|
+
/** Opaque engine state. This is never projected into FlowContext or provider contextPatch. */
|
|
104
|
+
engine: z
|
|
105
|
+
.object({
|
|
106
|
+
egressLease: z.string().min(1).max(16_384).optional(),
|
|
107
|
+
})
|
|
108
|
+
.strict()
|
|
109
|
+
.optional(),
|
|
84
110
|
connection: OperationConnectionSchema.optional(),
|
|
85
111
|
});
|
|
86
112
|
|
|
87
113
|
export const AuthFlowSuccessResponseSchema = z.object({
|
|
88
114
|
data: z.unknown(),
|
|
89
115
|
contextPatch: z.record(z.string(), z.unknown().nullable()).optional(),
|
|
116
|
+
/** Opaque engine state to carry verbatim to the next auth turn. */
|
|
117
|
+
engine: z
|
|
118
|
+
.object({
|
|
119
|
+
egressLease: z.string().min(1).max(16_384).optional(),
|
|
120
|
+
})
|
|
121
|
+
.strict()
|
|
122
|
+
.optional(),
|
|
90
123
|
});
|
|
91
124
|
|
|
92
125
|
export const AuthFlowErrorResponseSchema = OperationErrorResponseSchema;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Stateful module compatibility note
|
|
2
|
+
|
|
3
|
+
The `@apifuse/provider-sdk/stateful` entry point is new and unreleased. Its initial contract includes
|
|
4
|
+
the following compatibility-sensitive behavior:
|
|
5
|
+
|
|
6
|
+
- Session identifiers use the branded `SessionKey` returned by `buildSessionKey`.
|
|
7
|
+
`parseSessionKey` returns `SessionKeyParts`; validate and brand an external string with
|
|
8
|
+
`buildSessionKey(parseSessionKey(value))`. Registry inputs, routing requests, event owner fences,
|
|
9
|
+
and release APIs no longer accept arbitrary strings. A decoded `SessionOwnerRecord.sessionKey`
|
|
10
|
+
remains a string and must be checked where external data enters trusted SDK code (a trust
|
|
11
|
+
boundary).
|
|
12
|
+
- Adapters declare `policy.concurrency` (`serialize` or bounded/unbounded `parallel`) and
|
|
13
|
+
`policy.reconnect` (`resume`, `recreate`, or `unsupported`). `restore`, `snapshot`, and `health`
|
|
14
|
+
are optional; a declared `snapshot` must be paired with the manager's `checkpointStore`.
|
|
15
|
+
- Code in the process hosting the adapter (the provider pod) publishes through
|
|
16
|
+
`ProviderEventPublisher`; persistent services that survive provider-pod restarts (durable
|
|
17
|
+
platform code) implement `ProviderEventPipeline`. An adapter's
|
|
18
|
+
`subscribe(ctx, session, publish)` callback accepts only an event. The session manager, not the
|
|
19
|
+
adapter, binds the registry's current write authorization (the authoritative
|
|
20
|
+
`{ sessionKey, generation, ownerPodId, ownerEndpoint }` fence) before calling the publisher.
|
|
21
|
+
Adapters must not construct or cache owner fences themselves.
|
|
22
|
+
- `subscribe` must return a disposer. The manager runs it before checkpointing and closing a
|
|
23
|
+
session. `health()` and `reconcileWrite()` use the same per-session concurrency scheduler and
|
|
24
|
+
optional ownership validation semantics as invocation.
|
|
25
|
+
- `HttpProviderEventEmitter.flush(timeoutMs)` resolves to
|
|
26
|
+
`{ delivered: number, failed: number, pending: number }`. Counts are cumulative for the emitter's
|
|
27
|
+
lifetime; `pending` is the buffer remaining when the flush returns.
|
|
28
|
+
- `serve()` resolves to a `ProviderServerHandle` with `port` and idempotent `close({ timeoutMs? })`.
|
|
29
|
+
Close stops listeners, runs shutdown hooks in declaration order, and enforces the configured
|
|
30
|
+
timeout. Signal-enabled handles share one process handler per signal; a signal closes every
|
|
31
|
+
registered server before it is re-raised. Closing the last handle removes the shared handlers.
|
|
32
|
+
- `ProviderServerStatefulForwardEnvelope` is strict. Its owner fence is flattened into
|
|
33
|
+
`sessionKey`, `ownerPodId`, and `generation`; a nested `owner` object is not accepted. The
|
|
34
|
+
envelope also carries operation/session identity, `sourcePodId`, `forwardedAt`, optional
|
|
35
|
+
`idempotencyKey`, optional ISO `deadlineAt`, and the nested `operationRequest`. Unknown or
|
|
36
|
+
malformed fields fail closed, and the owner-side executor receives `deadlineAt` on its request.
|
|
37
|
+
- Stateful forwarding is configured as a pair: `internalOperationExecutor` requires
|
|
38
|
+
`statefulForwarding`, and `statefulForwarding` requires an `internalOperationExecutor`.
|
|
39
|
+
`statefulForwarding` supplies the signing secret and `validateOwnerFence`; it may also set
|
|
40
|
+
`maxSkewMs` and `replayCacheMaxEntries`. Replay-cache capacity returns HTTP 503 with
|
|
41
|
+
`Retry-After`; fail-closed nonce handling means invalid, replayed, or untrackable nonces are
|
|
42
|
+
rejected instead of allowing an unverifiable request.
|
|
43
|
+
- Stateful signatures bind the method, route, timestamp, nonce, and exact body. Forwarding also
|
|
44
|
+
rejects provider/source mismatches, stale owner fences, nonce replay, and request-scoped files.
|
|
45
|
+
|
|
46
|
+
## Minimal composition
|
|
47
|
+
|
|
48
|
+
Inside the module that defines your `provider`, the following wires an adapter, session manager,
|
|
49
|
+
router, signed owner forwarding, and graceful shutdown. Replace the environment variable names and
|
|
50
|
+
the service-account mapping with your deployment's values.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import {
|
|
54
|
+
buildSessionKey,
|
|
55
|
+
createStatefulOwnerFenceValidator,
|
|
56
|
+
HttpSessionOwnerRegistry,
|
|
57
|
+
HttpStatefulOwnerForwarder,
|
|
58
|
+
parseSessionKey,
|
|
59
|
+
statefulForwardingContextFromProviderRequest,
|
|
60
|
+
StatefulProviderSessionManager,
|
|
61
|
+
StatefulSessionRouter,
|
|
62
|
+
type StatefulProviderAdapter,
|
|
63
|
+
withStatefulLocalProviderContext,
|
|
64
|
+
} from "@apifuse/provider-sdk/stateful";
|
|
65
|
+
import { serve, type ProviderServerOperationExecutor } from "@apifuse/provider-sdk/server";
|
|
66
|
+
|
|
67
|
+
type Session = { closed: boolean };
|
|
68
|
+
|
|
69
|
+
const adapter = {
|
|
70
|
+
providerId: provider.id,
|
|
71
|
+
policy: { concurrency: { mode: "serialize" }, reconnect: "recreate" },
|
|
72
|
+
connect: async () => ({ closed: false }),
|
|
73
|
+
invoke: async (_ctx, _session, request) => ({ output: request.input }),
|
|
74
|
+
close: async (_ctx, session) => {
|
|
75
|
+
session.closed = true;
|
|
76
|
+
},
|
|
77
|
+
} satisfies StatefulProviderAdapter<Session>;
|
|
78
|
+
|
|
79
|
+
const registry = new HttpSessionOwnerRegistry({
|
|
80
|
+
baseUrl: process.env.STATEFUL_CONTROL_PLANE_URL as string,
|
|
81
|
+
secret: process.env.STATEFUL_CONTROL_PLANE_SECRET as string,
|
|
82
|
+
});
|
|
83
|
+
const manager = new StatefulProviderSessionManager({
|
|
84
|
+
adapter,
|
|
85
|
+
poolPolicy: { maxSessions: 100, idleTimeoutMs: "unlimited", maxLifetimeMs: "unlimited" },
|
|
86
|
+
});
|
|
87
|
+
const currentPod = {
|
|
88
|
+
podId: process.env.POD_ID as string,
|
|
89
|
+
endpoint: process.env.POD_ENDPOINT as string,
|
|
90
|
+
};
|
|
91
|
+
const router = new StatefulSessionRouter({
|
|
92
|
+
currentPod,
|
|
93
|
+
registry,
|
|
94
|
+
forwarder: new HttpStatefulOwnerForwarder({
|
|
95
|
+
currentPodId: currentPod.podId,
|
|
96
|
+
secret: process.env.STATEFUL_FORWARDING_SECRET as string,
|
|
97
|
+
}),
|
|
98
|
+
executor: manager,
|
|
99
|
+
leaseDurationMs: 30_000,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const executeStateful: ProviderServerOperationExecutor = async ({
|
|
103
|
+
ctx,
|
|
104
|
+
request,
|
|
105
|
+
operationId,
|
|
106
|
+
internalStatefulForward,
|
|
107
|
+
}) => {
|
|
108
|
+
const keyParts = internalStatefulForward
|
|
109
|
+
? parseSessionKey(internalStatefulForward.sessionKey)
|
|
110
|
+
: {
|
|
111
|
+
providerId: provider.id,
|
|
112
|
+
serviceAccountId: request.connection?.externalRef as string,
|
|
113
|
+
connectionId: (request.connection?.id ?? request.connectionId) as string,
|
|
114
|
+
};
|
|
115
|
+
const result = await router.route({
|
|
116
|
+
requestId: request.requestId,
|
|
117
|
+
sessionKey: buildSessionKey(keyParts),
|
|
118
|
+
providerId: provider.id,
|
|
119
|
+
operationId,
|
|
120
|
+
connectionId: keyParts.connectionId,
|
|
121
|
+
serviceAccountId: keyParts.serviceAccountId,
|
|
122
|
+
input: request.input,
|
|
123
|
+
...(request.deadlineAt ? { deadlineAt: request.deadlineAt } : {}),
|
|
124
|
+
runtimeContext: withStatefulLocalProviderContext(
|
|
125
|
+
ctx,
|
|
126
|
+
statefulForwardingContextFromProviderRequest(request),
|
|
127
|
+
),
|
|
128
|
+
});
|
|
129
|
+
return result.output;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
await serve(provider, {
|
|
133
|
+
operationExecutor: executeStateful,
|
|
134
|
+
internalOperationExecutor: executeStateful,
|
|
135
|
+
statefulForwarding: {
|
|
136
|
+
secret: process.env.STATEFUL_FORWARDING_SECRET as string,
|
|
137
|
+
validateOwnerFence: createStatefulOwnerFenceValidator(registry),
|
|
138
|
+
},
|
|
139
|
+
shutdown: {
|
|
140
|
+
hooks: [
|
|
141
|
+
() => manager.closeAll("server-shutdown"),
|
|
142
|
+
() => router.release(),
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type StatefulControlPlaneOperation = "resolve" | "acquire" | "renew" | "release";
|
|
2
|
+
|
|
3
|
+
export class StatefulRoutingDeadlineError extends Error {
|
|
4
|
+
readonly requestId: string;
|
|
5
|
+
readonly deadlineAt: string;
|
|
6
|
+
|
|
7
|
+
constructor(requestId: string, deadlineAt: string) {
|
|
8
|
+
super(`Stateful operation request ${requestId} deadline has expired.`);
|
|
9
|
+
this.name = "StatefulRoutingDeadlineError";
|
|
10
|
+
this.requestId = requestId;
|
|
11
|
+
this.deadlineAt = deadlineAt;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class StatefulControlPlaneError extends Error {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
readonly operation: StatefulControlPlaneOperation;
|
|
18
|
+
readonly status?: number;
|
|
19
|
+
readonly cause?: unknown;
|
|
20
|
+
|
|
21
|
+
constructor(input: {
|
|
22
|
+
readonly code: string;
|
|
23
|
+
readonly message: string;
|
|
24
|
+
readonly operation: StatefulControlPlaneOperation;
|
|
25
|
+
readonly status?: number;
|
|
26
|
+
readonly cause?: unknown;
|
|
27
|
+
}) {
|
|
28
|
+
super(input.message);
|
|
29
|
+
this.name = "StatefulControlPlaneError";
|
|
30
|
+
this.code = input.code;
|
|
31
|
+
this.operation = input.operation;
|
|
32
|
+
this.status = input.status;
|
|
33
|
+
this.cause = input.cause;
|
|
34
|
+
}
|
|
35
|
+
}
|