ccproxy-api 0.1.7__py3-none-any.whl → 0.2.0a4__py3-none-any.whl
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.
- ccproxy/api/__init__.py +1 -15
- ccproxy/api/app.py +434 -219
- ccproxy/api/bootstrap.py +30 -0
- ccproxy/api/decorators.py +85 -0
- ccproxy/api/dependencies.py +144 -168
- ccproxy/api/format_validation.py +54 -0
- ccproxy/api/middleware/cors.py +6 -3
- ccproxy/api/middleware/errors.py +388 -524
- ccproxy/api/middleware/hooks.py +563 -0
- ccproxy/api/middleware/normalize_headers.py +59 -0
- ccproxy/api/middleware/request_id.py +35 -16
- ccproxy/api/middleware/streaming_hooks.py +292 -0
- ccproxy/api/routes/__init__.py +5 -14
- ccproxy/api/routes/health.py +39 -672
- ccproxy/api/routes/plugins.py +277 -0
- ccproxy/auth/__init__.py +2 -19
- ccproxy/auth/bearer.py +25 -15
- ccproxy/auth/dependencies.py +123 -157
- ccproxy/auth/exceptions.py +0 -12
- ccproxy/auth/manager.py +35 -49
- ccproxy/auth/managers/__init__.py +10 -0
- ccproxy/auth/managers/base.py +523 -0
- ccproxy/auth/managers/base_enhanced.py +63 -0
- ccproxy/auth/managers/token_snapshot.py +77 -0
- ccproxy/auth/models/base.py +65 -0
- ccproxy/auth/models/credentials.py +40 -0
- ccproxy/auth/oauth/__init__.py +4 -18
- ccproxy/auth/oauth/base.py +533 -0
- ccproxy/auth/oauth/cli_errors.py +37 -0
- ccproxy/auth/oauth/flows.py +430 -0
- ccproxy/auth/oauth/protocol.py +366 -0
- ccproxy/auth/oauth/registry.py +408 -0
- ccproxy/auth/oauth/router.py +396 -0
- ccproxy/auth/oauth/routes.py +186 -113
- ccproxy/auth/oauth/session.py +151 -0
- ccproxy/auth/oauth/templates.py +342 -0
- ccproxy/auth/storage/__init__.py +2 -5
- ccproxy/auth/storage/base.py +279 -5
- ccproxy/auth/storage/generic.py +134 -0
- ccproxy/cli/__init__.py +1 -2
- ccproxy/cli/_settings_help.py +351 -0
- ccproxy/cli/commands/auth.py +1519 -793
- ccproxy/cli/commands/config/commands.py +209 -276
- ccproxy/cli/commands/plugins.py +669 -0
- ccproxy/cli/commands/serve.py +75 -810
- ccproxy/cli/commands/status.py +254 -0
- ccproxy/cli/decorators.py +83 -0
- ccproxy/cli/helpers.py +22 -60
- ccproxy/cli/main.py +359 -10
- ccproxy/cli/options/claude_options.py +0 -25
- ccproxy/config/__init__.py +7 -11
- ccproxy/config/core.py +227 -0
- ccproxy/config/env_generator.py +232 -0
- ccproxy/config/runtime.py +67 -0
- ccproxy/config/security.py +36 -3
- ccproxy/config/settings.py +382 -441
- ccproxy/config/toml_generator.py +299 -0
- ccproxy/config/utils.py +452 -0
- ccproxy/core/__init__.py +7 -271
- ccproxy/{_version.py → core/_version.py} +16 -3
- ccproxy/core/async_task_manager.py +516 -0
- ccproxy/core/async_utils.py +47 -14
- ccproxy/core/auth/__init__.py +6 -0
- ccproxy/core/constants.py +16 -50
- ccproxy/core/errors.py +53 -0
- ccproxy/core/id_utils.py +20 -0
- ccproxy/core/interfaces.py +16 -123
- ccproxy/core/logging.py +473 -18
- ccproxy/core/plugins/__init__.py +77 -0
- ccproxy/core/plugins/cli_discovery.py +211 -0
- ccproxy/core/plugins/declaration.py +455 -0
- ccproxy/core/plugins/discovery.py +604 -0
- ccproxy/core/plugins/factories.py +967 -0
- ccproxy/core/plugins/hooks/__init__.py +30 -0
- ccproxy/core/plugins/hooks/base.py +58 -0
- ccproxy/core/plugins/hooks/events.py +46 -0
- ccproxy/core/plugins/hooks/implementations/__init__.py +16 -0
- ccproxy/core/plugins/hooks/implementations/formatters/__init__.py +11 -0
- ccproxy/core/plugins/hooks/implementations/formatters/json.py +552 -0
- ccproxy/core/plugins/hooks/implementations/formatters/raw.py +370 -0
- ccproxy/core/plugins/hooks/implementations/http_tracer.py +431 -0
- ccproxy/core/plugins/hooks/layers.py +44 -0
- ccproxy/core/plugins/hooks/manager.py +186 -0
- ccproxy/core/plugins/hooks/registry.py +139 -0
- ccproxy/core/plugins/hooks/thread_manager.py +203 -0
- ccproxy/core/plugins/hooks/types.py +22 -0
- ccproxy/core/plugins/interfaces.py +416 -0
- ccproxy/core/plugins/loader.py +166 -0
- ccproxy/core/plugins/middleware.py +233 -0
- ccproxy/core/plugins/models.py +59 -0
- ccproxy/core/plugins/protocol.py +180 -0
- ccproxy/core/plugins/runtime.py +519 -0
- ccproxy/{observability/context.py → core/request_context.py} +137 -94
- ccproxy/core/status_report.py +211 -0
- ccproxy/core/transformers.py +13 -8
- ccproxy/data/claude_headers_fallback.json +540 -19
- ccproxy/data/codex_headers_fallback.json +114 -7
- ccproxy/http/__init__.py +30 -0
- ccproxy/http/base.py +95 -0
- ccproxy/http/client.py +323 -0
- ccproxy/http/hooks.py +642 -0
- ccproxy/http/pool.py +279 -0
- ccproxy/llms/formatters/__init__.py +7 -0
- ccproxy/llms/formatters/anthropic_to_openai/__init__.py +55 -0
- ccproxy/llms/formatters/anthropic_to_openai/errors.py +65 -0
- ccproxy/llms/formatters/anthropic_to_openai/requests.py +356 -0
- ccproxy/llms/formatters/anthropic_to_openai/responses.py +153 -0
- ccproxy/llms/formatters/anthropic_to_openai/streams.py +1546 -0
- ccproxy/llms/formatters/base.py +140 -0
- ccproxy/llms/formatters/base_model.py +33 -0
- ccproxy/llms/formatters/common/__init__.py +51 -0
- ccproxy/llms/formatters/common/identifiers.py +48 -0
- ccproxy/llms/formatters/common/streams.py +254 -0
- ccproxy/llms/formatters/common/thinking.py +74 -0
- ccproxy/llms/formatters/common/usage.py +135 -0
- ccproxy/llms/formatters/constants.py +55 -0
- ccproxy/llms/formatters/context.py +116 -0
- ccproxy/llms/formatters/mapping.py +33 -0
- ccproxy/llms/formatters/openai_to_anthropic/__init__.py +55 -0
- ccproxy/llms/formatters/openai_to_anthropic/_helpers.py +141 -0
- ccproxy/llms/formatters/openai_to_anthropic/errors.py +53 -0
- ccproxy/llms/formatters/openai_to_anthropic/requests.py +674 -0
- ccproxy/llms/formatters/openai_to_anthropic/responses.py +285 -0
- ccproxy/llms/formatters/openai_to_anthropic/streams.py +530 -0
- ccproxy/llms/formatters/openai_to_openai/__init__.py +53 -0
- ccproxy/llms/formatters/openai_to_openai/_helpers.py +325 -0
- ccproxy/llms/formatters/openai_to_openai/errors.py +6 -0
- ccproxy/llms/formatters/openai_to_openai/requests.py +388 -0
- ccproxy/llms/formatters/openai_to_openai/responses.py +594 -0
- ccproxy/llms/formatters/openai_to_openai/streams.py +1832 -0
- ccproxy/llms/formatters/utils.py +306 -0
- ccproxy/llms/models/__init__.py +9 -0
- ccproxy/llms/models/anthropic.py +619 -0
- ccproxy/llms/models/openai.py +844 -0
- ccproxy/llms/streaming/__init__.py +26 -0
- ccproxy/llms/streaming/accumulators.py +1074 -0
- ccproxy/llms/streaming/formatters.py +251 -0
- ccproxy/{adapters/openai/streaming.py → llms/streaming/processors.py} +193 -240
- ccproxy/models/__init__.py +8 -159
- ccproxy/models/detection.py +92 -193
- ccproxy/models/provider.py +75 -0
- ccproxy/plugins/access_log/README.md +32 -0
- ccproxy/plugins/access_log/__init__.py +20 -0
- ccproxy/plugins/access_log/config.py +33 -0
- ccproxy/plugins/access_log/formatter.py +126 -0
- ccproxy/plugins/access_log/hook.py +763 -0
- ccproxy/plugins/access_log/logger.py +254 -0
- ccproxy/plugins/access_log/plugin.py +137 -0
- ccproxy/plugins/access_log/writer.py +109 -0
- ccproxy/plugins/analytics/README.md +24 -0
- ccproxy/plugins/analytics/__init__.py +1 -0
- ccproxy/plugins/analytics/config.py +5 -0
- ccproxy/plugins/analytics/ingest.py +85 -0
- ccproxy/plugins/analytics/models.py +97 -0
- ccproxy/plugins/analytics/plugin.py +121 -0
- ccproxy/plugins/analytics/routes.py +163 -0
- ccproxy/plugins/analytics/service.py +284 -0
- ccproxy/plugins/claude_api/README.md +29 -0
- ccproxy/plugins/claude_api/__init__.py +10 -0
- ccproxy/plugins/claude_api/adapter.py +829 -0
- ccproxy/plugins/claude_api/config.py +52 -0
- ccproxy/plugins/claude_api/detection_service.py +461 -0
- ccproxy/plugins/claude_api/health.py +175 -0
- ccproxy/plugins/claude_api/hooks.py +284 -0
- ccproxy/plugins/claude_api/models.py +256 -0
- ccproxy/plugins/claude_api/plugin.py +298 -0
- ccproxy/plugins/claude_api/routes.py +118 -0
- ccproxy/plugins/claude_api/streaming_metrics.py +68 -0
- ccproxy/plugins/claude_api/tasks.py +84 -0
- ccproxy/plugins/claude_sdk/README.md +35 -0
- ccproxy/plugins/claude_sdk/__init__.py +80 -0
- ccproxy/plugins/claude_sdk/adapter.py +749 -0
- ccproxy/plugins/claude_sdk/auth.py +57 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/client.py +63 -39
- ccproxy/plugins/claude_sdk/config.py +210 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/converter.py +6 -6
- ccproxy/plugins/claude_sdk/detection_service.py +163 -0
- ccproxy/{services/claude_sdk_service.py → plugins/claude_sdk/handler.py} +123 -304
- ccproxy/plugins/claude_sdk/health.py +113 -0
- ccproxy/plugins/claude_sdk/hooks.py +115 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/manager.py +42 -32
- ccproxy/{claude_sdk → plugins/claude_sdk}/message_queue.py +8 -8
- ccproxy/{models/claude_sdk.py → plugins/claude_sdk/models.py} +64 -16
- ccproxy/plugins/claude_sdk/options.py +154 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/parser.py +23 -5
- ccproxy/plugins/claude_sdk/plugin.py +269 -0
- ccproxy/plugins/claude_sdk/routes.py +104 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/session_client.py +124 -12
- ccproxy/plugins/claude_sdk/session_pool.py +700 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_handle.py +48 -43
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_worker.py +22 -18
- ccproxy/{claude_sdk → plugins/claude_sdk}/streaming.py +50 -16
- ccproxy/plugins/claude_sdk/tasks.py +97 -0
- ccproxy/plugins/claude_shared/README.md +18 -0
- ccproxy/plugins/claude_shared/__init__.py +12 -0
- ccproxy/plugins/claude_shared/model_defaults.py +171 -0
- ccproxy/plugins/codex/README.md +35 -0
- ccproxy/plugins/codex/__init__.py +6 -0
- ccproxy/plugins/codex/adapter.py +635 -0
- ccproxy/{config/codex.py → plugins/codex/config.py} +78 -12
- ccproxy/plugins/codex/detection_service.py +544 -0
- ccproxy/plugins/codex/health.py +162 -0
- ccproxy/plugins/codex/hooks.py +263 -0
- ccproxy/plugins/codex/model_defaults.py +39 -0
- ccproxy/plugins/codex/models.py +263 -0
- ccproxy/plugins/codex/plugin.py +275 -0
- ccproxy/plugins/codex/routes.py +129 -0
- ccproxy/plugins/codex/streaming_metrics.py +324 -0
- ccproxy/plugins/codex/tasks.py +106 -0
- ccproxy/plugins/codex/utils/__init__.py +1 -0
- ccproxy/plugins/codex/utils/sse_parser.py +106 -0
- ccproxy/plugins/command_replay/README.md +34 -0
- ccproxy/plugins/command_replay/__init__.py +17 -0
- ccproxy/plugins/command_replay/config.py +133 -0
- ccproxy/plugins/command_replay/formatter.py +432 -0
- ccproxy/plugins/command_replay/hook.py +294 -0
- ccproxy/plugins/command_replay/plugin.py +161 -0
- ccproxy/plugins/copilot/README.md +39 -0
- ccproxy/plugins/copilot/__init__.py +11 -0
- ccproxy/plugins/copilot/adapter.py +465 -0
- ccproxy/plugins/copilot/config.py +155 -0
- ccproxy/plugins/copilot/data/copilot_fallback.json +41 -0
- ccproxy/plugins/copilot/detection_service.py +255 -0
- ccproxy/plugins/copilot/manager.py +275 -0
- ccproxy/plugins/copilot/model_defaults.py +284 -0
- ccproxy/plugins/copilot/models.py +148 -0
- ccproxy/plugins/copilot/oauth/__init__.py +16 -0
- ccproxy/plugins/copilot/oauth/client.py +494 -0
- ccproxy/plugins/copilot/oauth/models.py +385 -0
- ccproxy/plugins/copilot/oauth/provider.py +602 -0
- ccproxy/plugins/copilot/oauth/storage.py +170 -0
- ccproxy/plugins/copilot/plugin.py +360 -0
- ccproxy/plugins/copilot/routes.py +294 -0
- ccproxy/plugins/credential_balancer/README.md +124 -0
- ccproxy/plugins/credential_balancer/__init__.py +6 -0
- ccproxy/plugins/credential_balancer/config.py +270 -0
- ccproxy/plugins/credential_balancer/factory.py +415 -0
- ccproxy/plugins/credential_balancer/hook.py +51 -0
- ccproxy/plugins/credential_balancer/manager.py +587 -0
- ccproxy/plugins/credential_balancer/plugin.py +146 -0
- ccproxy/plugins/dashboard/README.md +25 -0
- ccproxy/plugins/dashboard/__init__.py +1 -0
- ccproxy/plugins/dashboard/config.py +8 -0
- ccproxy/plugins/dashboard/plugin.py +71 -0
- ccproxy/plugins/dashboard/routes.py +67 -0
- ccproxy/plugins/docker/README.md +32 -0
- ccproxy/{docker → plugins/docker}/__init__.py +3 -0
- ccproxy/{docker → plugins/docker}/adapter.py +108 -10
- ccproxy/plugins/docker/config.py +82 -0
- ccproxy/{docker → plugins/docker}/docker_path.py +4 -3
- ccproxy/{docker → plugins/docker}/middleware.py +2 -2
- ccproxy/plugins/docker/plugin.py +198 -0
- ccproxy/{docker → plugins/docker}/stream_process.py +3 -3
- ccproxy/plugins/duckdb_storage/README.md +26 -0
- ccproxy/plugins/duckdb_storage/__init__.py +1 -0
- ccproxy/plugins/duckdb_storage/config.py +22 -0
- ccproxy/plugins/duckdb_storage/plugin.py +128 -0
- ccproxy/plugins/duckdb_storage/routes.py +51 -0
- ccproxy/plugins/duckdb_storage/storage.py +633 -0
- ccproxy/plugins/max_tokens/README.md +38 -0
- ccproxy/plugins/max_tokens/__init__.py +12 -0
- ccproxy/plugins/max_tokens/adapter.py +235 -0
- ccproxy/plugins/max_tokens/config.py +86 -0
- ccproxy/plugins/max_tokens/models.py +53 -0
- ccproxy/plugins/max_tokens/plugin.py +200 -0
- ccproxy/plugins/max_tokens/service.py +271 -0
- ccproxy/plugins/max_tokens/token_limits.json +54 -0
- ccproxy/plugins/metrics/README.md +35 -0
- ccproxy/plugins/metrics/__init__.py +10 -0
- ccproxy/{observability/metrics.py → plugins/metrics/collector.py} +20 -153
- ccproxy/plugins/metrics/config.py +85 -0
- ccproxy/plugins/metrics/grafana/dashboards/ccproxy-dashboard.json +1720 -0
- ccproxy/plugins/metrics/hook.py +403 -0
- ccproxy/plugins/metrics/plugin.py +268 -0
- ccproxy/{observability → plugins/metrics}/pushgateway.py +57 -59
- ccproxy/plugins/metrics/routes.py +107 -0
- ccproxy/plugins/metrics/tasks.py +117 -0
- ccproxy/plugins/oauth_claude/README.md +35 -0
- ccproxy/plugins/oauth_claude/__init__.py +14 -0
- ccproxy/plugins/oauth_claude/client.py +270 -0
- ccproxy/plugins/oauth_claude/config.py +84 -0
- ccproxy/plugins/oauth_claude/manager.py +482 -0
- ccproxy/plugins/oauth_claude/models.py +266 -0
- ccproxy/plugins/oauth_claude/plugin.py +149 -0
- ccproxy/plugins/oauth_claude/provider.py +571 -0
- ccproxy/plugins/oauth_claude/storage.py +212 -0
- ccproxy/plugins/oauth_codex/README.md +38 -0
- ccproxy/plugins/oauth_codex/__init__.py +14 -0
- ccproxy/plugins/oauth_codex/client.py +224 -0
- ccproxy/plugins/oauth_codex/config.py +95 -0
- ccproxy/plugins/oauth_codex/manager.py +256 -0
- ccproxy/plugins/oauth_codex/models.py +239 -0
- ccproxy/plugins/oauth_codex/plugin.py +146 -0
- ccproxy/plugins/oauth_codex/provider.py +574 -0
- ccproxy/plugins/oauth_codex/storage.py +92 -0
- ccproxy/plugins/permissions/README.md +28 -0
- ccproxy/plugins/permissions/__init__.py +22 -0
- ccproxy/plugins/permissions/config.py +28 -0
- ccproxy/{cli/commands/permission_handler.py → plugins/permissions/handlers/cli.py} +49 -25
- ccproxy/plugins/permissions/handlers/protocol.py +33 -0
- ccproxy/plugins/permissions/handlers/terminal.py +675 -0
- ccproxy/{api/routes → plugins/permissions}/mcp.py +34 -7
- ccproxy/{models/permissions.py → plugins/permissions/models.py} +65 -1
- ccproxy/plugins/permissions/plugin.py +153 -0
- ccproxy/{api/routes/permissions.py → plugins/permissions/routes.py} +20 -16
- ccproxy/{api/services/permission_service.py → plugins/permissions/service.py} +65 -11
- ccproxy/{api → plugins/permissions}/ui/permission_handler_protocol.py +1 -1
- ccproxy/{api → plugins/permissions}/ui/terminal_permission_handler.py +66 -10
- ccproxy/plugins/pricing/README.md +34 -0
- ccproxy/plugins/pricing/__init__.py +6 -0
- ccproxy/{pricing → plugins/pricing}/cache.py +7 -6
- ccproxy/{config/pricing.py → plugins/pricing/config.py} +32 -6
- ccproxy/plugins/pricing/exceptions.py +35 -0
- ccproxy/plugins/pricing/loader.py +440 -0
- ccproxy/{pricing → plugins/pricing}/models.py +13 -23
- ccproxy/plugins/pricing/plugin.py +169 -0
- ccproxy/plugins/pricing/service.py +191 -0
- ccproxy/plugins/pricing/tasks.py +300 -0
- ccproxy/{pricing → plugins/pricing}/updater.py +86 -72
- ccproxy/plugins/pricing/utils.py +99 -0
- ccproxy/plugins/request_tracer/README.md +40 -0
- ccproxy/plugins/request_tracer/__init__.py +7 -0
- ccproxy/plugins/request_tracer/config.py +120 -0
- ccproxy/plugins/request_tracer/hook.py +415 -0
- ccproxy/plugins/request_tracer/plugin.py +255 -0
- ccproxy/scheduler/__init__.py +2 -14
- ccproxy/scheduler/core.py +26 -41
- ccproxy/scheduler/manager.py +61 -105
- ccproxy/scheduler/registry.py +6 -32
- ccproxy/scheduler/tasks.py +268 -276
- ccproxy/services/__init__.py +0 -1
- ccproxy/services/adapters/__init__.py +11 -0
- ccproxy/services/adapters/base.py +123 -0
- ccproxy/services/adapters/chain_composer.py +88 -0
- ccproxy/services/adapters/chain_validation.py +44 -0
- ccproxy/services/adapters/chat_accumulator.py +200 -0
- ccproxy/services/adapters/delta_utils.py +142 -0
- ccproxy/services/adapters/format_adapter.py +136 -0
- ccproxy/services/adapters/format_context.py +11 -0
- ccproxy/services/adapters/format_registry.py +158 -0
- ccproxy/services/adapters/http_adapter.py +1045 -0
- ccproxy/services/adapters/mock_adapter.py +118 -0
- ccproxy/services/adapters/protocols.py +35 -0
- ccproxy/services/adapters/simple_converters.py +571 -0
- ccproxy/services/auth_registry.py +180 -0
- ccproxy/services/cache/__init__.py +6 -0
- ccproxy/services/cache/response_cache.py +261 -0
- ccproxy/services/cli_detection.py +437 -0
- ccproxy/services/config/__init__.py +6 -0
- ccproxy/services/config/proxy_configuration.py +111 -0
- ccproxy/services/container.py +256 -0
- ccproxy/services/factories.py +380 -0
- ccproxy/services/handler_config.py +76 -0
- ccproxy/services/interfaces.py +298 -0
- ccproxy/services/mocking/__init__.py +6 -0
- ccproxy/services/mocking/mock_handler.py +291 -0
- ccproxy/services/tracing/__init__.py +7 -0
- ccproxy/services/tracing/interfaces.py +61 -0
- ccproxy/services/tracing/null_tracer.py +57 -0
- ccproxy/streaming/__init__.py +23 -0
- ccproxy/streaming/buffer.py +1056 -0
- ccproxy/streaming/deferred.py +897 -0
- ccproxy/streaming/handler.py +117 -0
- ccproxy/streaming/interfaces.py +77 -0
- ccproxy/streaming/simple_adapter.py +39 -0
- ccproxy/streaming/sse.py +109 -0
- ccproxy/streaming/sse_parser.py +127 -0
- ccproxy/templates/__init__.py +6 -0
- ccproxy/templates/plugin_scaffold.py +695 -0
- ccproxy/testing/endpoints/__init__.py +33 -0
- ccproxy/testing/endpoints/cli.py +215 -0
- ccproxy/testing/endpoints/config.py +874 -0
- ccproxy/testing/endpoints/console.py +57 -0
- ccproxy/testing/endpoints/models.py +100 -0
- ccproxy/testing/endpoints/runner.py +1903 -0
- ccproxy/testing/endpoints/tools.py +308 -0
- ccproxy/testing/mock_responses.py +70 -1
- ccproxy/testing/response_handlers.py +20 -0
- ccproxy/utils/__init__.py +0 -6
- ccproxy/utils/binary_resolver.py +476 -0
- ccproxy/utils/caching.py +327 -0
- ccproxy/utils/cli_logging.py +101 -0
- ccproxy/utils/command_line.py +251 -0
- ccproxy/utils/headers.py +228 -0
- ccproxy/utils/model_mapper.py +120 -0
- ccproxy/utils/startup_helpers.py +68 -446
- ccproxy/utils/version_checker.py +273 -6
- ccproxy_api-0.2.0a4.dist-info/METADATA +212 -0
- ccproxy_api-0.2.0a4.dist-info/RECORD +417 -0
- {ccproxy_api-0.1.7.dist-info → ccproxy_api-0.2.0a4.dist-info}/WHEEL +1 -1
- ccproxy_api-0.2.0a4.dist-info/entry_points.txt +24 -0
- ccproxy/__init__.py +0 -4
- ccproxy/adapters/__init__.py +0 -11
- ccproxy/adapters/base.py +0 -80
- ccproxy/adapters/codex/__init__.py +0 -11
- ccproxy/adapters/openai/__init__.py +0 -42
- ccproxy/adapters/openai/adapter.py +0 -953
- ccproxy/adapters/openai/models.py +0 -412
- ccproxy/adapters/openai/response_adapter.py +0 -355
- ccproxy/adapters/openai/response_models.py +0 -178
- ccproxy/api/middleware/headers.py +0 -49
- ccproxy/api/middleware/logging.py +0 -180
- ccproxy/api/middleware/request_content_logging.py +0 -297
- ccproxy/api/middleware/server_header.py +0 -58
- ccproxy/api/responses.py +0 -89
- ccproxy/api/routes/claude.py +0 -371
- ccproxy/api/routes/codex.py +0 -1251
- ccproxy/api/routes/metrics.py +0 -1029
- ccproxy/api/routes/proxy.py +0 -211
- ccproxy/api/services/__init__.py +0 -6
- ccproxy/auth/conditional.py +0 -84
- ccproxy/auth/credentials_adapter.py +0 -93
- ccproxy/auth/models.py +0 -118
- ccproxy/auth/oauth/models.py +0 -48
- ccproxy/auth/openai/__init__.py +0 -13
- ccproxy/auth/openai/credentials.py +0 -166
- ccproxy/auth/openai/oauth_client.py +0 -334
- ccproxy/auth/openai/storage.py +0 -184
- ccproxy/auth/storage/json_file.py +0 -158
- ccproxy/auth/storage/keyring.py +0 -189
- ccproxy/claude_sdk/__init__.py +0 -18
- ccproxy/claude_sdk/options.py +0 -194
- ccproxy/claude_sdk/session_pool.py +0 -550
- ccproxy/cli/docker/__init__.py +0 -34
- ccproxy/cli/docker/adapter_factory.py +0 -157
- ccproxy/cli/docker/params.py +0 -274
- ccproxy/config/auth.py +0 -153
- ccproxy/config/claude.py +0 -348
- ccproxy/config/cors.py +0 -79
- ccproxy/config/discovery.py +0 -95
- ccproxy/config/docker_settings.py +0 -264
- ccproxy/config/observability.py +0 -158
- ccproxy/config/reverse_proxy.py +0 -31
- ccproxy/config/scheduler.py +0 -108
- ccproxy/config/server.py +0 -86
- ccproxy/config/validators.py +0 -231
- ccproxy/core/codex_transformers.py +0 -389
- ccproxy/core/http.py +0 -328
- ccproxy/core/http_transformers.py +0 -812
- ccproxy/core/proxy.py +0 -143
- ccproxy/core/validators.py +0 -288
- ccproxy/models/errors.py +0 -42
- ccproxy/models/messages.py +0 -269
- ccproxy/models/requests.py +0 -107
- ccproxy/models/responses.py +0 -270
- ccproxy/models/types.py +0 -102
- ccproxy/observability/__init__.py +0 -51
- ccproxy/observability/access_logger.py +0 -457
- ccproxy/observability/sse_events.py +0 -303
- ccproxy/observability/stats_printer.py +0 -753
- ccproxy/observability/storage/__init__.py +0 -1
- ccproxy/observability/storage/duckdb_simple.py +0 -677
- ccproxy/observability/storage/models.py +0 -70
- ccproxy/observability/streaming_response.py +0 -107
- ccproxy/pricing/__init__.py +0 -19
- ccproxy/pricing/loader.py +0 -251
- ccproxy/services/claude_detection_service.py +0 -243
- ccproxy/services/codex_detection_service.py +0 -252
- ccproxy/services/credentials/__init__.py +0 -55
- ccproxy/services/credentials/config.py +0 -105
- ccproxy/services/credentials/manager.py +0 -561
- ccproxy/services/credentials/oauth_client.py +0 -481
- ccproxy/services/proxy_service.py +0 -1827
- ccproxy/static/.keep +0 -0
- ccproxy/utils/cost_calculator.py +0 -210
- ccproxy/utils/disconnection_monitor.py +0 -83
- ccproxy/utils/model_mapping.py +0 -199
- ccproxy/utils/models_provider.py +0 -150
- ccproxy/utils/simple_request_logger.py +0 -284
- ccproxy/utils/streaming_metrics.py +0 -199
- ccproxy_api-0.1.7.dist-info/METADATA +0 -615
- ccproxy_api-0.1.7.dist-info/RECORD +0 -191
- ccproxy_api-0.1.7.dist-info/entry_points.txt +0 -4
- /ccproxy/{api/middleware/auth.py → auth/models/__init__.py} +0 -0
- /ccproxy/{claude_sdk → plugins/claude_sdk}/exceptions.py +0 -0
- /ccproxy/{docker → plugins/docker}/models.py +0 -0
- /ccproxy/{docker → plugins/docker}/protocol.py +0 -0
- /ccproxy/{docker → plugins/docker}/validators.py +0 -0
- /ccproxy/{auth/oauth/storage.py → plugins/permissions/handlers/__init__.py} +0 -0
- /ccproxy/{api → plugins/permissions}/ui/__init__.py +0 -0
- {ccproxy_api-0.1.7.dist-info → ccproxy_api-0.2.0a4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
"""Plugin runtime system for managing plugin instances.
|
|
2
|
+
|
|
3
|
+
This module defines runtime classes that manage plugin instances and lifecycle.
|
|
4
|
+
Factory/loader utilities remain in their respective modules to avoid import
|
|
5
|
+
cycles during consolidation. Import runtime classes from here, and import
|
|
6
|
+
factories/loaders from their modules for now.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from ccproxy.core.logging import TraceBoundLogger, get_logger
|
|
12
|
+
|
|
13
|
+
from .declaration import PluginContext, PluginManifest, PluginRuntimeProtocol
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"BasePluginRuntime",
|
|
18
|
+
"SystemPluginRuntime",
|
|
19
|
+
"AuthProviderPluginRuntime",
|
|
20
|
+
"ProviderPluginRuntime",
|
|
21
|
+
"PluginContext",
|
|
22
|
+
"PluginManifest",
|
|
23
|
+
"PluginRuntimeProtocol",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
logger: TraceBoundLogger = get_logger()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BasePluginRuntime(PluginRuntimeProtocol):
|
|
31
|
+
"""Base implementation of plugin runtime.
|
|
32
|
+
|
|
33
|
+
This class provides common functionality for all plugin runtimes.
|
|
34
|
+
Specific plugin types (system, provider) can extend this base class.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, manifest: PluginManifest):
|
|
38
|
+
"""Initialize runtime with manifest.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
manifest: Plugin manifest with static declarations
|
|
42
|
+
"""
|
|
43
|
+
self.manifest = manifest
|
|
44
|
+
self.context: PluginContext | None = None
|
|
45
|
+
self.initialized = False
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def name(self) -> str:
|
|
49
|
+
"""Plugin name from manifest."""
|
|
50
|
+
return self.manifest.name
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def version(self) -> str:
|
|
54
|
+
"""Plugin version from manifest."""
|
|
55
|
+
return self.manifest.version
|
|
56
|
+
|
|
57
|
+
async def initialize(self, context: PluginContext) -> None:
|
|
58
|
+
"""Initialize the plugin with runtime context.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
context: Runtime context with services and configuration
|
|
62
|
+
"""
|
|
63
|
+
if self.initialized:
|
|
64
|
+
logger.warning(
|
|
65
|
+
"plugin_already_initialized", plugin=self.name, category="plugin"
|
|
66
|
+
)
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
self.context = context
|
|
70
|
+
|
|
71
|
+
# Allow subclasses to perform custom initialization
|
|
72
|
+
await self._on_initialize()
|
|
73
|
+
|
|
74
|
+
self.initialized = True
|
|
75
|
+
logger.debug(
|
|
76
|
+
"plugin_initialized",
|
|
77
|
+
plugin=self.name,
|
|
78
|
+
version=self.version,
|
|
79
|
+
category="plugin",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
async def _on_initialize(self) -> None:
|
|
83
|
+
"""Hook for subclasses to perform custom initialization.
|
|
84
|
+
|
|
85
|
+
Override this method in subclasses to add custom initialization logic.
|
|
86
|
+
"""
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
async def shutdown(self) -> None:
|
|
90
|
+
"""Cleanup on shutdown."""
|
|
91
|
+
if not self.initialized:
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
# Allow subclasses to perform custom cleanup
|
|
95
|
+
await self._on_shutdown()
|
|
96
|
+
|
|
97
|
+
self.initialized = False
|
|
98
|
+
logger.info("plugin_shutdown", plugin=self.name, category="plugin")
|
|
99
|
+
|
|
100
|
+
async def _on_shutdown(self) -> None:
|
|
101
|
+
"""Hook for subclasses to perform custom cleanup.
|
|
102
|
+
|
|
103
|
+
Override this method in subclasses to add custom cleanup logic.
|
|
104
|
+
"""
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
async def validate(self) -> bool:
|
|
108
|
+
"""Validate plugin is ready.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
True if plugin is ready, False otherwise
|
|
112
|
+
"""
|
|
113
|
+
# Basic validation - plugin is initialized
|
|
114
|
+
if not self.initialized:
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
# Allow subclasses to add custom validation
|
|
118
|
+
return await self._on_validate()
|
|
119
|
+
|
|
120
|
+
async def _on_validate(self) -> bool:
|
|
121
|
+
"""Hook for subclasses to perform custom validation.
|
|
122
|
+
|
|
123
|
+
Override this method in subclasses to add custom validation logic.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
True if validation passes, False otherwise
|
|
127
|
+
"""
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
async def health_check(self) -> dict[str, Any]:
|
|
131
|
+
"""Perform health check.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Health check result following IETF format
|
|
135
|
+
"""
|
|
136
|
+
try:
|
|
137
|
+
# Start with basic health check
|
|
138
|
+
is_healthy = await self.validate()
|
|
139
|
+
|
|
140
|
+
# Allow subclasses to provide detailed health info
|
|
141
|
+
details = await self._get_health_details()
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
"status": "pass" if is_healthy else "fail",
|
|
145
|
+
"componentId": self.name,
|
|
146
|
+
"componentType": "provider_plugin"
|
|
147
|
+
if self.manifest.is_provider
|
|
148
|
+
else "system_plugin",
|
|
149
|
+
"version": self.version,
|
|
150
|
+
"details": details,
|
|
151
|
+
}
|
|
152
|
+
except Exception as e:
|
|
153
|
+
logger.error(
|
|
154
|
+
"plugin_health_check_failed",
|
|
155
|
+
plugin=self.name,
|
|
156
|
+
error=str(e),
|
|
157
|
+
exc_info=e,
|
|
158
|
+
category="plugin",
|
|
159
|
+
)
|
|
160
|
+
return {
|
|
161
|
+
"status": "fail",
|
|
162
|
+
"componentId": self.name,
|
|
163
|
+
"componentType": "provider_plugin"
|
|
164
|
+
if self.manifest.is_provider
|
|
165
|
+
else "system_plugin",
|
|
166
|
+
"version": self.version,
|
|
167
|
+
"output": str(e),
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async def _get_health_details(self) -> dict[str, Any]:
|
|
171
|
+
"""Hook for subclasses to provide health check details.
|
|
172
|
+
|
|
173
|
+
Override this method in subclasses to add custom health check details.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Dictionary with health check details
|
|
177
|
+
"""
|
|
178
|
+
return {}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class SystemPluginRuntime(BasePluginRuntime):
|
|
182
|
+
"""Runtime for system plugins (non-provider plugins).
|
|
183
|
+
|
|
184
|
+
System plugins provide functionality like logging, monitoring,
|
|
185
|
+
permissions, etc., but don't proxy to external providers.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
async def _on_initialize(self) -> None:
|
|
189
|
+
"""System plugin initialization."""
|
|
190
|
+
logger.debug("system_plugin_initializing", plugin=self.name, category="plugin")
|
|
191
|
+
# System plugins typically don't need special initialization
|
|
192
|
+
# but can override this method if needed
|
|
193
|
+
|
|
194
|
+
async def _get_health_details(self) -> dict[str, Any]:
|
|
195
|
+
"""System plugin health details."""
|
|
196
|
+
return {"type": "system", "initialized": self.initialized}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class AuthProviderPluginRuntime(BasePluginRuntime):
|
|
200
|
+
"""Runtime for authentication provider plugins.
|
|
201
|
+
|
|
202
|
+
Auth provider plugins provide OAuth authentication flows and token management
|
|
203
|
+
for various API providers without directly proxying requests.
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
def __init__(self, manifest: PluginManifest):
|
|
207
|
+
"""Initialize auth provider plugin runtime.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
manifest: Plugin manifest with static declarations
|
|
211
|
+
"""
|
|
212
|
+
super().__init__(manifest)
|
|
213
|
+
self.auth_provider: Any | None = None # OAuthProviderProtocol
|
|
214
|
+
self.token_manager: Any | None = None
|
|
215
|
+
self.storage: Any | None = None
|
|
216
|
+
|
|
217
|
+
async def _on_initialize(self) -> None:
|
|
218
|
+
"""Auth provider plugin initialization."""
|
|
219
|
+
logger.debug(
|
|
220
|
+
"auth_provider_plugin_initializing", plugin=self.name, category="plugin"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
if not self.context:
|
|
224
|
+
raise RuntimeError("Context not set")
|
|
225
|
+
|
|
226
|
+
# Extract auth-specific components from context
|
|
227
|
+
self.auth_provider = self.context.get("auth_provider")
|
|
228
|
+
self.token_manager = self.context.get("token_manager")
|
|
229
|
+
self.storage = self.context.get("storage")
|
|
230
|
+
|
|
231
|
+
# Register OAuth provider with app-scoped registry if present
|
|
232
|
+
if self.auth_provider:
|
|
233
|
+
await self._register_auth_provider()
|
|
234
|
+
|
|
235
|
+
async def _register_auth_provider(self) -> None:
|
|
236
|
+
"""Register OAuth provider with the app-scoped registry."""
|
|
237
|
+
if not self.auth_provider:
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
# Register with app-scoped registry from context
|
|
242
|
+
registry = None
|
|
243
|
+
if self.context and "oauth_registry" in self.context:
|
|
244
|
+
registry = self.context["oauth_registry"]
|
|
245
|
+
if registry is None:
|
|
246
|
+
logger.warning(
|
|
247
|
+
"oauth_registry_missing_in_context",
|
|
248
|
+
plugin=self.name,
|
|
249
|
+
category="plugin",
|
|
250
|
+
)
|
|
251
|
+
return
|
|
252
|
+
registry.register(self.auth_provider)
|
|
253
|
+
|
|
254
|
+
logger.debug(
|
|
255
|
+
"oauth_provider_registered",
|
|
256
|
+
plugin=self.name,
|
|
257
|
+
provider=self.auth_provider.provider_name,
|
|
258
|
+
category="plugin",
|
|
259
|
+
)
|
|
260
|
+
except Exception as e:
|
|
261
|
+
logger.error(
|
|
262
|
+
"oauth_provider_registration_failed",
|
|
263
|
+
plugin=self.name,
|
|
264
|
+
error=str(e),
|
|
265
|
+
exc_info=e,
|
|
266
|
+
category="plugin",
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
async def _on_shutdown(self) -> None:
|
|
270
|
+
"""Auth provider plugin shutdown."""
|
|
271
|
+
# Cleanup provider resources if it has a cleanup method
|
|
272
|
+
if self.auth_provider and hasattr(self.auth_provider, "cleanup"):
|
|
273
|
+
try:
|
|
274
|
+
await self.auth_provider.cleanup()
|
|
275
|
+
logger.debug(
|
|
276
|
+
"oauth_provider_cleaned_up",
|
|
277
|
+
plugin=self.name,
|
|
278
|
+
provider=self.auth_provider.provider_name,
|
|
279
|
+
category="plugin",
|
|
280
|
+
)
|
|
281
|
+
except Exception as e:
|
|
282
|
+
logger.error(
|
|
283
|
+
"oauth_provider_cleanup_failed",
|
|
284
|
+
plugin=self.name,
|
|
285
|
+
error=str(e),
|
|
286
|
+
exc_info=e,
|
|
287
|
+
category="plugin",
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# Unregister OAuth provider if present
|
|
291
|
+
if self.auth_provider:
|
|
292
|
+
await self._unregister_auth_provider()
|
|
293
|
+
|
|
294
|
+
async def _unregister_auth_provider(self) -> None:
|
|
295
|
+
"""Unregister OAuth provider from the app-scoped registry."""
|
|
296
|
+
if not self.auth_provider:
|
|
297
|
+
return
|
|
298
|
+
|
|
299
|
+
try:
|
|
300
|
+
# Unregister from app-scoped registry available in context
|
|
301
|
+
registry = None
|
|
302
|
+
if self.context and "oauth_registry" in self.context:
|
|
303
|
+
registry = self.context["oauth_registry"]
|
|
304
|
+
if registry is None:
|
|
305
|
+
logger.warning(
|
|
306
|
+
"oauth_registry_missing_in_context_on_shutdown",
|
|
307
|
+
plugin=self.name,
|
|
308
|
+
category="plugin",
|
|
309
|
+
)
|
|
310
|
+
return
|
|
311
|
+
registry.unregister(self.auth_provider.provider_name)
|
|
312
|
+
|
|
313
|
+
logger.debug(
|
|
314
|
+
"oauth_provider_unregistered",
|
|
315
|
+
plugin=self.name,
|
|
316
|
+
provider=self.auth_provider.provider_name,
|
|
317
|
+
category="plugin",
|
|
318
|
+
)
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(
|
|
321
|
+
"oauth_provider_unregistration_failed",
|
|
322
|
+
plugin=self.name,
|
|
323
|
+
error=str(e),
|
|
324
|
+
exc_info=e,
|
|
325
|
+
category="plugin",
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
async def _get_health_details(self) -> dict[str, Any]:
|
|
329
|
+
"""Auth provider plugin health details."""
|
|
330
|
+
details = {
|
|
331
|
+
"type": "auth_provider",
|
|
332
|
+
"initialized": self.initialized,
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if self.auth_provider:
|
|
336
|
+
# Check if provider is registered
|
|
337
|
+
try:
|
|
338
|
+
registry = None
|
|
339
|
+
if self.context and "oauth_registry" in self.context:
|
|
340
|
+
registry = self.context["oauth_registry"]
|
|
341
|
+
is_registered = (
|
|
342
|
+
registry.has(self.auth_provider.provider_name)
|
|
343
|
+
if registry is not None
|
|
344
|
+
else False
|
|
345
|
+
)
|
|
346
|
+
details.update(
|
|
347
|
+
{
|
|
348
|
+
"oauth_provider_registered": is_registered,
|
|
349
|
+
"oauth_provider_name": self.auth_provider.provider_name,
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
except Exception:
|
|
353
|
+
pass
|
|
354
|
+
|
|
355
|
+
return details
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class ProviderPluginRuntime(BasePluginRuntime):
|
|
359
|
+
"""Runtime for provider plugins.
|
|
360
|
+
|
|
361
|
+
Provider plugins proxy requests to external API providers and
|
|
362
|
+
require additional components like adapters and detection services.
|
|
363
|
+
"""
|
|
364
|
+
|
|
365
|
+
def __init__(self, manifest: PluginManifest):
|
|
366
|
+
"""Initialize provider plugin runtime.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
manifest: Plugin manifest with static declarations
|
|
370
|
+
"""
|
|
371
|
+
super().__init__(manifest)
|
|
372
|
+
self.adapter: Any | None = None # BaseAdapter
|
|
373
|
+
self.detection_service: Any | None = None
|
|
374
|
+
self.credentials_manager: Any | None = None
|
|
375
|
+
|
|
376
|
+
async def _on_initialize(self) -> None:
|
|
377
|
+
"""Provider plugin initialization."""
|
|
378
|
+
logger.debug(
|
|
379
|
+
"provider_plugin_initializing", plugin=self.name, category="plugin"
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
if not self.context:
|
|
383
|
+
raise RuntimeError("Context not set")
|
|
384
|
+
|
|
385
|
+
# Extract provider-specific components from context
|
|
386
|
+
self.adapter = self.context.get("adapter")
|
|
387
|
+
self.detection_service = self.context.get("detection_service")
|
|
388
|
+
self.credentials_manager = self.context.get("credentials_manager")
|
|
389
|
+
|
|
390
|
+
# Initialize detection service if present
|
|
391
|
+
if self.detection_service and hasattr(
|
|
392
|
+
self.detection_service, "initialize_detection"
|
|
393
|
+
):
|
|
394
|
+
await self.detection_service.initialize_detection()
|
|
395
|
+
logger.debug(
|
|
396
|
+
"detection_service_initialized", plugin=self.name, category="plugin"
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
# Register OAuth provider if factory is provided
|
|
400
|
+
if self.manifest.oauth_provider_factory:
|
|
401
|
+
await self._register_oauth_provider()
|
|
402
|
+
|
|
403
|
+
async def _register_oauth_provider(self) -> None:
|
|
404
|
+
"""Register OAuth provider with the app-scoped registry."""
|
|
405
|
+
if not self.manifest.oauth_provider_factory:
|
|
406
|
+
return
|
|
407
|
+
|
|
408
|
+
try:
|
|
409
|
+
# Create OAuth provider instance
|
|
410
|
+
oauth_provider = self.manifest.oauth_provider_factory()
|
|
411
|
+
|
|
412
|
+
# Use oauth_registry from context (injected via core services)
|
|
413
|
+
registry = None
|
|
414
|
+
if self.context and "oauth_registry" in self.context:
|
|
415
|
+
registry = self.context["oauth_registry"]
|
|
416
|
+
|
|
417
|
+
if registry is None:
|
|
418
|
+
logger.warning(
|
|
419
|
+
"oauth_registry_missing_in_context",
|
|
420
|
+
plugin=self.name,
|
|
421
|
+
category="plugin",
|
|
422
|
+
)
|
|
423
|
+
return
|
|
424
|
+
|
|
425
|
+
registry.register(oauth_provider)
|
|
426
|
+
|
|
427
|
+
logger.trace(
|
|
428
|
+
"oauth_provider_registered",
|
|
429
|
+
plugin=self.name,
|
|
430
|
+
provider=oauth_provider.provider_name,
|
|
431
|
+
category="plugin",
|
|
432
|
+
)
|
|
433
|
+
except Exception as e:
|
|
434
|
+
logger.error(
|
|
435
|
+
"oauth_provider_registration_failed",
|
|
436
|
+
plugin=self.name,
|
|
437
|
+
error=str(e),
|
|
438
|
+
exc_info=e,
|
|
439
|
+
category="plugin",
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
async def _unregister_oauth_provider(self) -> None:
|
|
443
|
+
"""Unregister OAuth provider from the app-scoped registry."""
|
|
444
|
+
if not self.manifest.oauth_provider_factory:
|
|
445
|
+
return
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
# Determine provider name
|
|
449
|
+
oauth_provider = self.manifest.oauth_provider_factory()
|
|
450
|
+
provider_name = oauth_provider.provider_name
|
|
451
|
+
|
|
452
|
+
# Use oauth_registry from context (injected via core services)
|
|
453
|
+
registry = None
|
|
454
|
+
if self.context and "oauth_registry" in self.context:
|
|
455
|
+
registry = self.context["oauth_registry"]
|
|
456
|
+
|
|
457
|
+
if registry is None:
|
|
458
|
+
logger.warning(
|
|
459
|
+
"oauth_registry_missing_in_context_on_shutdown",
|
|
460
|
+
plugin=self.name,
|
|
461
|
+
category="plugin",
|
|
462
|
+
)
|
|
463
|
+
return
|
|
464
|
+
|
|
465
|
+
registry.unregister(provider_name)
|
|
466
|
+
|
|
467
|
+
logger.trace(
|
|
468
|
+
"oauth_provider_unregistered",
|
|
469
|
+
plugin=self.name,
|
|
470
|
+
provider=provider_name,
|
|
471
|
+
category="plugin",
|
|
472
|
+
)
|
|
473
|
+
except Exception as e:
|
|
474
|
+
logger.error(
|
|
475
|
+
"oauth_provider_unregistration_failed",
|
|
476
|
+
plugin=self.name,
|
|
477
|
+
error=str(e),
|
|
478
|
+
exc_info=e,
|
|
479
|
+
category="plugin",
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
async def _on_shutdown(self) -> None:
|
|
483
|
+
"""Provider plugin cleanup."""
|
|
484
|
+
# Unregister OAuth provider if registered
|
|
485
|
+
await self._unregister_oauth_provider()
|
|
486
|
+
|
|
487
|
+
# Cleanup adapter if present
|
|
488
|
+
if self.adapter and hasattr(self.adapter, "cleanup"):
|
|
489
|
+
await self.adapter.cleanup()
|
|
490
|
+
logger.debug("adapter_cleaned_up", plugin=self.name, category="plugin")
|
|
491
|
+
|
|
492
|
+
async def _on_validate(self) -> bool:
|
|
493
|
+
"""Provider plugin validation."""
|
|
494
|
+
# Check that required components are present
|
|
495
|
+
if self.manifest.is_provider and not self.adapter:
|
|
496
|
+
logger.warning(
|
|
497
|
+
"provider_plugin_missing_adapter", plugin=self.name, category="plugin"
|
|
498
|
+
)
|
|
499
|
+
return False
|
|
500
|
+
return True
|
|
501
|
+
|
|
502
|
+
async def _get_health_details(self) -> dict[str, Any]:
|
|
503
|
+
"""Provider plugin health details."""
|
|
504
|
+
details: dict[str, Any] = {
|
|
505
|
+
"type": "provider",
|
|
506
|
+
"initialized": self.initialized,
|
|
507
|
+
"has_adapter": self.adapter is not None,
|
|
508
|
+
"has_detection": self.detection_service is not None,
|
|
509
|
+
"has_credentials": self.credentials_manager is not None,
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
# Add detection service info if available
|
|
513
|
+
if self.detection_service:
|
|
514
|
+
if hasattr(self.detection_service, "get_version"):
|
|
515
|
+
details["cli_version"] = self.detection_service.get_version()
|
|
516
|
+
if hasattr(self.detection_service, "get_cli_path"):
|
|
517
|
+
details["cli_path"] = self.detection_service.get_cli_path()
|
|
518
|
+
|
|
519
|
+
return details
|