ccproxy-api 0.1.7__py3-none-any.whl → 0.2.0__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.0.dist-info/METADATA +212 -0
- ccproxy_api-0.2.0.dist-info/RECORD +417 -0
- {ccproxy_api-0.1.7.dist-info → ccproxy_api-0.2.0.dist-info}/WHEEL +1 -1
- ccproxy_api-0.2.0.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.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
"""OAuth Provider Registry for dynamic provider management.
|
|
2
|
+
|
|
3
|
+
This module provides a central registry where plugins can register their OAuth
|
|
4
|
+
providers at runtime, enabling dynamic discovery and management of OAuth flows.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Any, Protocol
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
from ccproxy.core.logging import get_logger
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
logger = get_logger()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class FlowType(str, Enum):
|
|
20
|
+
"""OAuth flow types for CLI authentication."""
|
|
21
|
+
|
|
22
|
+
device = "device"
|
|
23
|
+
browser = "browser"
|
|
24
|
+
manual = "manual"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class CliAuthConfig:
|
|
29
|
+
"""CLI authentication configuration for OAuth providers."""
|
|
30
|
+
|
|
31
|
+
preferred_flow: FlowType = FlowType.browser
|
|
32
|
+
# RFC8252 loopback; use provider-specific fixed ports where required
|
|
33
|
+
callback_port: int = 8080
|
|
34
|
+
callback_path: str = "/callback"
|
|
35
|
+
# Some providers want an exact redirect_uri
|
|
36
|
+
fixed_redirect_uri: str | None = None
|
|
37
|
+
# Manual code flow redirect URI (defaults to OOB if not specified)
|
|
38
|
+
manual_redirect_uri: str | None = None
|
|
39
|
+
supports_manual_code: bool = True
|
|
40
|
+
supports_device_flow: bool = False
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class OAuthProviderInfo(BaseModel):
|
|
44
|
+
"""Information about a registered OAuth provider."""
|
|
45
|
+
|
|
46
|
+
name: str
|
|
47
|
+
display_name: str
|
|
48
|
+
description: str = ""
|
|
49
|
+
supports_pkce: bool = True
|
|
50
|
+
scopes: list[str] = []
|
|
51
|
+
is_available: bool = True
|
|
52
|
+
plugin_name: str = ""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class OAuthProviderProtocol(Protocol):
|
|
56
|
+
"""Protocol for OAuth provider implementations."""
|
|
57
|
+
|
|
58
|
+
# --- Existing web methods ---
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def provider_name(self) -> str:
|
|
62
|
+
"""Internal provider name (e.g., 'claude-api', 'codex')."""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def provider_display_name(self) -> str:
|
|
67
|
+
"""Display name for UI (e.g., 'Claude API', 'OpenAI Codex')."""
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def supports_pkce(self) -> bool:
|
|
72
|
+
"""Whether this provider supports PKCE flow."""
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
async def get_authorization_url(
|
|
76
|
+
self,
|
|
77
|
+
state: str,
|
|
78
|
+
code_verifier: str | None = None,
|
|
79
|
+
redirect_uri: str | None = None,
|
|
80
|
+
) -> str:
|
|
81
|
+
"""Get the authorization URL for OAuth flow.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
state: OAuth state parameter for CSRF protection
|
|
85
|
+
code_verifier: PKCE code verifier (if PKCE is supported)
|
|
86
|
+
redirect_uri: Redirect URI for OAuth callback
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Authorization URL to redirect user to
|
|
90
|
+
"""
|
|
91
|
+
...
|
|
92
|
+
|
|
93
|
+
async def handle_callback(
|
|
94
|
+
self,
|
|
95
|
+
code: str,
|
|
96
|
+
state: str,
|
|
97
|
+
code_verifier: str | None = None,
|
|
98
|
+
redirect_uri: str | None = None,
|
|
99
|
+
) -> Any:
|
|
100
|
+
"""Handle OAuth callback and exchange code for tokens.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
code: Authorization code from OAuth callback
|
|
104
|
+
state: State parameter for validation
|
|
105
|
+
code_verifier: PKCE code verifier (if PKCE is used)
|
|
106
|
+
redirect_uri: Redirect URI used in the authorization request
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Provider-specific credentials object
|
|
110
|
+
"""
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
async def refresh_access_token(self, refresh_token: str) -> Any:
|
|
114
|
+
"""Refresh access token using refresh token.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
refresh_token: Refresh token from previous auth
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
New token response
|
|
121
|
+
"""
|
|
122
|
+
...
|
|
123
|
+
|
|
124
|
+
async def revoke_token(self, token: str) -> None:
|
|
125
|
+
"""Revoke an access or refresh token.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
token: Token to revoke
|
|
129
|
+
"""
|
|
130
|
+
...
|
|
131
|
+
|
|
132
|
+
def get_provider_info(self) -> OAuthProviderInfo:
|
|
133
|
+
"""Get provider information for discovery.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Provider information
|
|
137
|
+
"""
|
|
138
|
+
...
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def supports_refresh(self) -> bool:
|
|
142
|
+
"""Whether this provider supports token refresh."""
|
|
143
|
+
...
|
|
144
|
+
|
|
145
|
+
def get_storage(self) -> Any:
|
|
146
|
+
"""Get storage implementation for this provider.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Storage implementation or None
|
|
150
|
+
"""
|
|
151
|
+
...
|
|
152
|
+
|
|
153
|
+
def get_credential_summary(self, credentials: Any) -> dict[str, Any]:
|
|
154
|
+
"""Get a summary of credentials for display.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
credentials: Provider-specific credentials
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Dictionary with display-friendly credential summary
|
|
161
|
+
"""
|
|
162
|
+
...
|
|
163
|
+
|
|
164
|
+
# --- CLI-capability surface (NEW) ---
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def cli(self) -> CliAuthConfig:
|
|
168
|
+
"""CLI authentication configuration for this provider.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Configuration object specifying CLI flow preferences and capabilities
|
|
172
|
+
"""
|
|
173
|
+
...
|
|
174
|
+
|
|
175
|
+
# Device flow (only if cli.supports_device_flow=True)
|
|
176
|
+
async def start_device_flow(self) -> tuple[str, str, str, int]:
|
|
177
|
+
"""Start OAuth device code flow.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Tuple of (device_code, user_code, verification_uri, expires_in)
|
|
181
|
+
|
|
182
|
+
Raises:
|
|
183
|
+
NotImplementedError: If device flow is not supported
|
|
184
|
+
"""
|
|
185
|
+
raise NotImplementedError("Device flow not supported by this provider")
|
|
186
|
+
|
|
187
|
+
async def complete_device_flow(
|
|
188
|
+
self, device_code: str, interval: int, expires_in: int
|
|
189
|
+
) -> Any:
|
|
190
|
+
"""Complete OAuth device code flow by polling for authorization.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
device_code: Device code from start_device_flow
|
|
194
|
+
interval: Polling interval in seconds
|
|
195
|
+
expires_in: Code expiration time in seconds
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
Provider-specific credentials object
|
|
199
|
+
|
|
200
|
+
Raises:
|
|
201
|
+
NotImplementedError: If device flow is not supported
|
|
202
|
+
"""
|
|
203
|
+
raise NotImplementedError("Device flow not supported by this provider")
|
|
204
|
+
|
|
205
|
+
# Manual code (only if cli.supports_manual_code=True)
|
|
206
|
+
async def exchange_manual_code(self, code: str) -> Any:
|
|
207
|
+
"""Exchange manually entered authorization code for tokens.
|
|
208
|
+
|
|
209
|
+
This method handles the case where users manually copy/paste
|
|
210
|
+
authorization codes in restricted environments.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
code: Authorization code entered manually by user
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Provider-specific credentials object
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
NotImplementedError: If manual code entry is not implemented
|
|
220
|
+
"""
|
|
221
|
+
raise NotImplementedError("Manual code entry not implemented by this provider")
|
|
222
|
+
|
|
223
|
+
# Common
|
|
224
|
+
async def save_credentials(
|
|
225
|
+
self, credentials: Any, custom_path: Any | None = None
|
|
226
|
+
) -> bool:
|
|
227
|
+
"""Save credentials using provider's storage mechanism.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
credentials: Provider-specific credentials object
|
|
231
|
+
custom_path: Optional custom storage path
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
True if saved successfully, False otherwise
|
|
235
|
+
"""
|
|
236
|
+
...
|
|
237
|
+
|
|
238
|
+
async def load_credentials(self, custom_path: Any | None = None) -> Any | None:
|
|
239
|
+
"""Load credentials from provider's storage.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
custom_path: Optional custom storage path
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Credentials if found, None otherwise
|
|
246
|
+
"""
|
|
247
|
+
...
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class OAuthRegistry:
|
|
251
|
+
"""Central registry for OAuth providers.
|
|
252
|
+
|
|
253
|
+
This registry allows plugins to register their OAuth providers at runtime,
|
|
254
|
+
enabling dynamic discovery and management of OAuth authentication flows.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
def __init__(self) -> None:
|
|
258
|
+
"""Initialize the OAuth registry."""
|
|
259
|
+
self._providers: dict[str, OAuthProviderProtocol] = {}
|
|
260
|
+
self._provider_info_cache: dict[str, OAuthProviderInfo] = {}
|
|
261
|
+
logger.debug("oauth_registry_initialized", category="auth")
|
|
262
|
+
|
|
263
|
+
def register(self, provider: OAuthProviderProtocol) -> None:
|
|
264
|
+
"""Register an OAuth provider from a plugin.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
provider: OAuth provider implementation
|
|
268
|
+
|
|
269
|
+
Raises:
|
|
270
|
+
ValueError: If provider with same name already registered
|
|
271
|
+
"""
|
|
272
|
+
provider_name = provider.provider_name
|
|
273
|
+
|
|
274
|
+
if provider_name in self._providers:
|
|
275
|
+
raise ValueError(f"OAuth provider '{provider_name}' is already registered")
|
|
276
|
+
|
|
277
|
+
self._providers[provider_name] = provider
|
|
278
|
+
|
|
279
|
+
# Cache provider info
|
|
280
|
+
try:
|
|
281
|
+
info = provider.get_provider_info()
|
|
282
|
+
self._provider_info_cache[provider_name] = info
|
|
283
|
+
logger.debug(
|
|
284
|
+
"oauth_provider_registered",
|
|
285
|
+
provider=provider_name,
|
|
286
|
+
display_name=info.display_name,
|
|
287
|
+
supports_pkce=info.supports_pkce,
|
|
288
|
+
plugin=info.plugin_name,
|
|
289
|
+
category="auth",
|
|
290
|
+
)
|
|
291
|
+
except Exception as e:
|
|
292
|
+
logger.error(
|
|
293
|
+
"oauth_provider_info_error",
|
|
294
|
+
provider=provider_name,
|
|
295
|
+
error=str(e),
|
|
296
|
+
exc_info=e,
|
|
297
|
+
category="auth",
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
def unregister(self, provider_name: str) -> None:
|
|
301
|
+
"""Unregister an OAuth provider.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
provider_name: Name of provider to unregister
|
|
305
|
+
"""
|
|
306
|
+
if provider_name in self._providers:
|
|
307
|
+
del self._providers[provider_name]
|
|
308
|
+
if provider_name in self._provider_info_cache:
|
|
309
|
+
del self._provider_info_cache[provider_name]
|
|
310
|
+
logger.debug(
|
|
311
|
+
"oauth_provider_unregistered", provider=provider_name, category="auth"
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
def get(self, provider_name: str) -> OAuthProviderProtocol | None:
|
|
315
|
+
"""Get a registered OAuth provider by name.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
provider_name: Name of the provider
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
OAuth provider instance or None if not found
|
|
322
|
+
"""
|
|
323
|
+
return self._providers.get(provider_name)
|
|
324
|
+
|
|
325
|
+
def list(self) -> dict[str, OAuthProviderInfo]:
|
|
326
|
+
"""List all registered OAuth providers.
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
Dictionary mapping provider names to their info
|
|
330
|
+
"""
|
|
331
|
+
result = {}
|
|
332
|
+
for name, provider in self._providers.items():
|
|
333
|
+
# Try to get fresh info, fall back to cache
|
|
334
|
+
try:
|
|
335
|
+
info = provider.get_provider_info()
|
|
336
|
+
self._provider_info_cache[name] = info
|
|
337
|
+
result[name] = info
|
|
338
|
+
except Exception as e:
|
|
339
|
+
logger.warning(
|
|
340
|
+
"oauth_provider_info_refresh_error",
|
|
341
|
+
provider=name,
|
|
342
|
+
error=str(e),
|
|
343
|
+
category="auth",
|
|
344
|
+
)
|
|
345
|
+
# Use cached info if available
|
|
346
|
+
if name in self._provider_info_cache:
|
|
347
|
+
result[name] = self._provider_info_cache[name]
|
|
348
|
+
|
|
349
|
+
return result
|
|
350
|
+
|
|
351
|
+
def has(self, provider_name: str) -> bool:
|
|
352
|
+
"""Check if a provider is registered.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
provider_name: Name of the provider
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
True if provider is registered
|
|
359
|
+
"""
|
|
360
|
+
return provider_name in self._providers
|
|
361
|
+
|
|
362
|
+
def get_info(self, provider_name: str) -> OAuthProviderInfo | None:
|
|
363
|
+
"""Get information about a specific provider.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
provider_name: Name of the provider
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
Provider information or None if not found
|
|
370
|
+
"""
|
|
371
|
+
provider = self.get(provider_name)
|
|
372
|
+
if not provider:
|
|
373
|
+
return None
|
|
374
|
+
|
|
375
|
+
try:
|
|
376
|
+
info = provider.get_provider_info()
|
|
377
|
+
self._provider_info_cache[provider_name] = info
|
|
378
|
+
return info
|
|
379
|
+
except Exception as e:
|
|
380
|
+
logger.error(
|
|
381
|
+
"oauth_provider_info_error",
|
|
382
|
+
provider=provider_name,
|
|
383
|
+
error=str(e),
|
|
384
|
+
exc_info=e,
|
|
385
|
+
category="auth",
|
|
386
|
+
)
|
|
387
|
+
# Return cached info if available
|
|
388
|
+
return self._provider_info_cache.get(provider_name)
|
|
389
|
+
|
|
390
|
+
def clear(self) -> None:
|
|
391
|
+
"""Clear all registered providers.
|
|
392
|
+
|
|
393
|
+
This is mainly useful for testing or shutdown scenarios.
|
|
394
|
+
"""
|
|
395
|
+
self._providers.clear()
|
|
396
|
+
self._provider_info_cache.clear()
|
|
397
|
+
logger.info("oauth_registry_cleared", category="auth")
|
|
398
|
+
|
|
399
|
+
# --- Backward-compatible method aliases ---
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
__all__ = [
|
|
403
|
+
"OAuthRegistry",
|
|
404
|
+
"OAuthProviderInfo",
|
|
405
|
+
"OAuthProviderProtocol",
|
|
406
|
+
"FlowType",
|
|
407
|
+
"CliAuthConfig",
|
|
408
|
+
]
|