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,366 @@
|
|
|
1
|
+
"""OAuth protocol definitions for plugin OAuth implementations.
|
|
2
|
+
|
|
3
|
+
This module defines the protocols and interfaces that plugins must implement
|
|
4
|
+
to provide OAuth authentication capabilities.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import abstractmethod
|
|
8
|
+
from collections.abc import Awaitable, Callable
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import Any, Protocol, cast
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, Field
|
|
13
|
+
|
|
14
|
+
from ccproxy.core.logging import get_logger
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Import CLI types from registry to avoid duplication
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class StandardProfileFields(BaseModel):
|
|
24
|
+
"""Standardized profile fields for consistent UI display across OAuth providers."""
|
|
25
|
+
|
|
26
|
+
# Core Identity
|
|
27
|
+
account_id: str
|
|
28
|
+
provider_type: str # 'claude', 'codex', etc.
|
|
29
|
+
email: str | None = None
|
|
30
|
+
display_name: str | None = None
|
|
31
|
+
|
|
32
|
+
# Account Status
|
|
33
|
+
authenticated: bool = True
|
|
34
|
+
active: bool = True
|
|
35
|
+
expired: bool = False
|
|
36
|
+
|
|
37
|
+
# Subscription/Plan Information
|
|
38
|
+
subscription_type: str | None = None # 'plus', 'pro', 'max', 'free'
|
|
39
|
+
subscription_status: str | None = None # 'active', 'expired', 'cancelled'
|
|
40
|
+
subscription_expires_at: datetime | None = None
|
|
41
|
+
|
|
42
|
+
# Token Information
|
|
43
|
+
has_refresh_token: bool = False
|
|
44
|
+
has_id_token: bool = False
|
|
45
|
+
token_expires_at: datetime | None = None
|
|
46
|
+
|
|
47
|
+
# Organization/Team
|
|
48
|
+
organization_name: str | None = None
|
|
49
|
+
organization_role: str | None = None # 'owner', 'admin', 'member'
|
|
50
|
+
|
|
51
|
+
# Verification Status
|
|
52
|
+
email_verified: bool | None = None
|
|
53
|
+
|
|
54
|
+
# Additional Features (provider-specific)
|
|
55
|
+
features: dict[str, Any] = Field(
|
|
56
|
+
default_factory=dict
|
|
57
|
+
) # For provider-specific features like 'has_claude_max'
|
|
58
|
+
|
|
59
|
+
# Raw data (for debugging, not UI display)
|
|
60
|
+
raw_profile_data: dict[str, Any] = Field(
|
|
61
|
+
default_factory=dict,
|
|
62
|
+
exclude=True, # Exclude raw data from normal serialization
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ProfileLoggingMixin:
|
|
67
|
+
"""Mixin to provide standardized profile dump logging for OAuth providers."""
|
|
68
|
+
|
|
69
|
+
def _log_profile_dump(
|
|
70
|
+
self, provider_name: str, profile: StandardProfileFields, category: str = "auth"
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Log standardized profile data in UI-friendly format.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
provider_name: Name of the OAuth provider (e.g., 'claude', 'codex')
|
|
76
|
+
profile: Standardized profile fields for UI display
|
|
77
|
+
category: Log category (defaults to 'auth')
|
|
78
|
+
"""
|
|
79
|
+
# Log clean UI-friendly profile data
|
|
80
|
+
profile_data = profile.model_dump(exclude={"raw_profile_data"})
|
|
81
|
+
logger.debug(
|
|
82
|
+
f"{provider_name}_profile_full_dump",
|
|
83
|
+
profile_data=profile_data,
|
|
84
|
+
category=category,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Optionally log raw data separately for debugging (only if needed)
|
|
88
|
+
if profile.raw_profile_data:
|
|
89
|
+
logger.debug(
|
|
90
|
+
f"{provider_name}_profile_raw_data",
|
|
91
|
+
raw_data=profile.raw_profile_data,
|
|
92
|
+
category="auth_debug",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
@abstractmethod
|
|
96
|
+
def _extract_standard_profile(self, credentials: Any) -> StandardProfileFields:
|
|
97
|
+
"""Extract standardized profile fields from provider-specific credentials.
|
|
98
|
+
|
|
99
|
+
This method should be implemented by each OAuth provider to map their
|
|
100
|
+
credential format to the standardized profile fields for UI display.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
credentials: Provider-specific credentials object
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
StandardProfileFields with clean, UI-friendly data
|
|
107
|
+
"""
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
async def get_standard_profile(
|
|
111
|
+
self, credentials: Any | None = None
|
|
112
|
+
) -> StandardProfileFields | None:
|
|
113
|
+
"""Return standardized profile fields for UI display.
|
|
114
|
+
|
|
115
|
+
If credentials are not provided, attempts to load them via a
|
|
116
|
+
provider's `load_credentials()` method when available. This method
|
|
117
|
+
intentionally avoids network calls and relies on locally available
|
|
118
|
+
information or cached profile data inside provider implementations.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
credentials: Optional provider-specific credentials
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
StandardProfileFields or None if unavailable
|
|
125
|
+
"""
|
|
126
|
+
try:
|
|
127
|
+
creds = credentials
|
|
128
|
+
if creds is None and hasattr(self, "load_credentials"):
|
|
129
|
+
# Best-effort local load (provider-specific, may use storage)
|
|
130
|
+
load_fn = self.load_credentials
|
|
131
|
+
if callable(load_fn):
|
|
132
|
+
creds = await cast(Callable[[], Awaitable[Any]], load_fn)()
|
|
133
|
+
|
|
134
|
+
if not creds:
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
return self._extract_standard_profile(creds)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
logger.debug(
|
|
140
|
+
"standard_profile_generation_failed",
|
|
141
|
+
provider=getattr(self, "provider_name", type(self).__name__),
|
|
142
|
+
error=str(e),
|
|
143
|
+
)
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
def _log_credentials_loaded(
|
|
147
|
+
self, provider_name: str, credentials: Any, category: str = "auth"
|
|
148
|
+
) -> None:
|
|
149
|
+
"""Log credentials loaded with standardized profile data.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
provider_name: Name of the OAuth provider
|
|
153
|
+
credentials: Loaded credentials object
|
|
154
|
+
category: Log category
|
|
155
|
+
"""
|
|
156
|
+
if credentials:
|
|
157
|
+
try:
|
|
158
|
+
profile = self._extract_standard_profile(credentials)
|
|
159
|
+
self._log_profile_dump(provider_name, profile, category)
|
|
160
|
+
except Exception as e:
|
|
161
|
+
logger.debug(
|
|
162
|
+
f"{provider_name}_profile_extraction_failed",
|
|
163
|
+
error=str(e),
|
|
164
|
+
category=category,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class OAuthConfig(BaseModel):
|
|
169
|
+
"""Base configuration for OAuth providers."""
|
|
170
|
+
|
|
171
|
+
client_id: str
|
|
172
|
+
client_secret: str | None = None # Not needed for PKCE flows
|
|
173
|
+
redirect_uri: str
|
|
174
|
+
authorize_url: str
|
|
175
|
+
token_url: str
|
|
176
|
+
scopes: list[str] = []
|
|
177
|
+
use_pkce: bool = True
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class OAuthStorageProtocol(Protocol):
|
|
181
|
+
"""Protocol for OAuth token storage implementations."""
|
|
182
|
+
|
|
183
|
+
async def save_tokens(
|
|
184
|
+
self,
|
|
185
|
+
provider: str,
|
|
186
|
+
access_token: str,
|
|
187
|
+
refresh_token: str | None = None,
|
|
188
|
+
expires_in: int | None = None,
|
|
189
|
+
**kwargs: Any,
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Save OAuth tokens.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
provider: Provider name
|
|
195
|
+
access_token: Access token
|
|
196
|
+
refresh_token: Optional refresh token
|
|
197
|
+
expires_in: Token expiration in seconds
|
|
198
|
+
**kwargs: Additional provider-specific data
|
|
199
|
+
"""
|
|
200
|
+
...
|
|
201
|
+
|
|
202
|
+
async def get_tokens(self, provider: str) -> dict[str, Any] | None:
|
|
203
|
+
"""Retrieve stored tokens for a provider.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
provider: Provider name
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Token data or None if not found
|
|
210
|
+
"""
|
|
211
|
+
...
|
|
212
|
+
|
|
213
|
+
async def delete_tokens(self, provider: str) -> None:
|
|
214
|
+
"""Delete stored tokens for a provider.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
provider: Provider name
|
|
218
|
+
"""
|
|
219
|
+
...
|
|
220
|
+
|
|
221
|
+
async def has_valid_tokens(self, provider: str) -> bool:
|
|
222
|
+
"""Check if valid tokens exist for a provider.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
provider: Provider name
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
True if valid tokens exist
|
|
229
|
+
"""
|
|
230
|
+
...
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class OAuthConfigProtocol(Protocol):
|
|
234
|
+
"""Protocol for OAuth configuration providers."""
|
|
235
|
+
|
|
236
|
+
def get_client_id(self) -> str:
|
|
237
|
+
"""Get OAuth client ID."""
|
|
238
|
+
...
|
|
239
|
+
|
|
240
|
+
def get_client_secret(self) -> str | None:
|
|
241
|
+
"""Get OAuth client secret (if applicable)."""
|
|
242
|
+
...
|
|
243
|
+
|
|
244
|
+
def get_redirect_uri(self) -> str:
|
|
245
|
+
"""Get OAuth redirect URI."""
|
|
246
|
+
...
|
|
247
|
+
|
|
248
|
+
def get_authorize_url(self) -> str:
|
|
249
|
+
"""Get authorization endpoint URL."""
|
|
250
|
+
...
|
|
251
|
+
|
|
252
|
+
def get_token_url(self) -> str:
|
|
253
|
+
"""Get token endpoint URL."""
|
|
254
|
+
...
|
|
255
|
+
|
|
256
|
+
def get_scopes(self) -> list[str]:
|
|
257
|
+
"""Get requested OAuth scopes."""
|
|
258
|
+
...
|
|
259
|
+
|
|
260
|
+
def uses_pkce(self) -> bool:
|
|
261
|
+
"""Check if PKCE should be used."""
|
|
262
|
+
...
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class TokenResponse(BaseModel):
|
|
266
|
+
"""Standard OAuth token response."""
|
|
267
|
+
|
|
268
|
+
access_token: str
|
|
269
|
+
token_type: str = "Bearer"
|
|
270
|
+
expires_in: int | None = None
|
|
271
|
+
refresh_token: str | None = None
|
|
272
|
+
scope: str | None = None
|
|
273
|
+
|
|
274
|
+
# Additional fields that providers might include
|
|
275
|
+
id_token: str | None = None # For OpenID Connect
|
|
276
|
+
account_id: str | None = None # Provider-specific user ID
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
# Import the full protocol from registry
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class OAuthProviderBase(Protocol):
|
|
283
|
+
"""Extended protocol for OAuth providers with additional capabilities."""
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def provider_name(self) -> str:
|
|
287
|
+
"""Internal provider name."""
|
|
288
|
+
...
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
def provider_display_name(self) -> str:
|
|
292
|
+
"""Display name for UI."""
|
|
293
|
+
...
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def supports_pkce(self) -> bool:
|
|
297
|
+
"""Whether this provider supports PKCE."""
|
|
298
|
+
...
|
|
299
|
+
|
|
300
|
+
@property
|
|
301
|
+
def supports_refresh(self) -> bool:
|
|
302
|
+
"""Whether this provider supports token refresh."""
|
|
303
|
+
...
|
|
304
|
+
|
|
305
|
+
@property
|
|
306
|
+
def requires_client_secret(self) -> bool:
|
|
307
|
+
"""Whether this provider requires a client secret."""
|
|
308
|
+
...
|
|
309
|
+
|
|
310
|
+
async def get_authorization_url(
|
|
311
|
+
self, state: str, code_verifier: str | None = None
|
|
312
|
+
) -> str:
|
|
313
|
+
"""Get authorization URL."""
|
|
314
|
+
...
|
|
315
|
+
|
|
316
|
+
async def handle_callback(
|
|
317
|
+
self, code: str, state: str, code_verifier: str | None = None
|
|
318
|
+
) -> Any:
|
|
319
|
+
"""Handle OAuth callback."""
|
|
320
|
+
...
|
|
321
|
+
|
|
322
|
+
async def refresh_access_token(self, refresh_token: str) -> Any:
|
|
323
|
+
"""Refresh access token."""
|
|
324
|
+
...
|
|
325
|
+
|
|
326
|
+
async def revoke_token(self, token: str) -> None:
|
|
327
|
+
"""Revoke a token."""
|
|
328
|
+
...
|
|
329
|
+
|
|
330
|
+
async def validate_token(self, access_token: str) -> bool:
|
|
331
|
+
"""Validate an access token.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
access_token: Token to validate
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
True if token is valid
|
|
338
|
+
"""
|
|
339
|
+
...
|
|
340
|
+
|
|
341
|
+
async def get_user_info(self, access_token: str) -> dict[str, Any] | None:
|
|
342
|
+
"""Get user information using access token.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
access_token: Valid access token
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
User information or None
|
|
349
|
+
"""
|
|
350
|
+
...
|
|
351
|
+
|
|
352
|
+
def get_storage(self) -> OAuthStorageProtocol | None:
|
|
353
|
+
"""Get storage implementation for this provider.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
Storage implementation or None if provider handles storage
|
|
357
|
+
"""
|
|
358
|
+
...
|
|
359
|
+
|
|
360
|
+
def get_config(self) -> OAuthConfigProtocol | None:
|
|
361
|
+
"""Get configuration for this provider.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
Configuration implementation or None
|
|
365
|
+
"""
|
|
366
|
+
...
|