ccproxy-api 0.1.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.
Files changed (148) hide show
  1. ccproxy/__init__.py +4 -0
  2. ccproxy/__main__.py +7 -0
  3. ccproxy/_version.py +21 -0
  4. ccproxy/adapters/__init__.py +11 -0
  5. ccproxy/adapters/base.py +80 -0
  6. ccproxy/adapters/openai/__init__.py +43 -0
  7. ccproxy/adapters/openai/adapter.py +915 -0
  8. ccproxy/adapters/openai/models.py +412 -0
  9. ccproxy/adapters/openai/streaming.py +449 -0
  10. ccproxy/api/__init__.py +28 -0
  11. ccproxy/api/app.py +225 -0
  12. ccproxy/api/dependencies.py +140 -0
  13. ccproxy/api/middleware/__init__.py +11 -0
  14. ccproxy/api/middleware/auth.py +0 -0
  15. ccproxy/api/middleware/cors.py +55 -0
  16. ccproxy/api/middleware/errors.py +703 -0
  17. ccproxy/api/middleware/headers.py +51 -0
  18. ccproxy/api/middleware/logging.py +175 -0
  19. ccproxy/api/middleware/request_id.py +69 -0
  20. ccproxy/api/middleware/server_header.py +62 -0
  21. ccproxy/api/responses.py +84 -0
  22. ccproxy/api/routes/__init__.py +16 -0
  23. ccproxy/api/routes/claude.py +181 -0
  24. ccproxy/api/routes/health.py +489 -0
  25. ccproxy/api/routes/metrics.py +1033 -0
  26. ccproxy/api/routes/proxy.py +238 -0
  27. ccproxy/auth/__init__.py +75 -0
  28. ccproxy/auth/bearer.py +68 -0
  29. ccproxy/auth/credentials_adapter.py +93 -0
  30. ccproxy/auth/dependencies.py +229 -0
  31. ccproxy/auth/exceptions.py +79 -0
  32. ccproxy/auth/manager.py +102 -0
  33. ccproxy/auth/models.py +118 -0
  34. ccproxy/auth/oauth/__init__.py +26 -0
  35. ccproxy/auth/oauth/models.py +49 -0
  36. ccproxy/auth/oauth/routes.py +396 -0
  37. ccproxy/auth/oauth/storage.py +0 -0
  38. ccproxy/auth/storage/__init__.py +12 -0
  39. ccproxy/auth/storage/base.py +57 -0
  40. ccproxy/auth/storage/json_file.py +159 -0
  41. ccproxy/auth/storage/keyring.py +192 -0
  42. ccproxy/claude_sdk/__init__.py +20 -0
  43. ccproxy/claude_sdk/client.py +169 -0
  44. ccproxy/claude_sdk/converter.py +331 -0
  45. ccproxy/claude_sdk/options.py +120 -0
  46. ccproxy/cli/__init__.py +14 -0
  47. ccproxy/cli/commands/__init__.py +8 -0
  48. ccproxy/cli/commands/auth.py +553 -0
  49. ccproxy/cli/commands/config/__init__.py +14 -0
  50. ccproxy/cli/commands/config/commands.py +766 -0
  51. ccproxy/cli/commands/config/schema_commands.py +119 -0
  52. ccproxy/cli/commands/serve.py +630 -0
  53. ccproxy/cli/docker/__init__.py +34 -0
  54. ccproxy/cli/docker/adapter_factory.py +157 -0
  55. ccproxy/cli/docker/params.py +278 -0
  56. ccproxy/cli/helpers.py +144 -0
  57. ccproxy/cli/main.py +193 -0
  58. ccproxy/cli/options/__init__.py +14 -0
  59. ccproxy/cli/options/claude_options.py +216 -0
  60. ccproxy/cli/options/core_options.py +40 -0
  61. ccproxy/cli/options/security_options.py +48 -0
  62. ccproxy/cli/options/server_options.py +117 -0
  63. ccproxy/config/__init__.py +40 -0
  64. ccproxy/config/auth.py +154 -0
  65. ccproxy/config/claude.py +124 -0
  66. ccproxy/config/cors.py +79 -0
  67. ccproxy/config/discovery.py +87 -0
  68. ccproxy/config/docker_settings.py +265 -0
  69. ccproxy/config/loader.py +108 -0
  70. ccproxy/config/observability.py +158 -0
  71. ccproxy/config/pricing.py +88 -0
  72. ccproxy/config/reverse_proxy.py +31 -0
  73. ccproxy/config/scheduler.py +89 -0
  74. ccproxy/config/security.py +14 -0
  75. ccproxy/config/server.py +81 -0
  76. ccproxy/config/settings.py +534 -0
  77. ccproxy/config/validators.py +231 -0
  78. ccproxy/core/__init__.py +274 -0
  79. ccproxy/core/async_utils.py +675 -0
  80. ccproxy/core/constants.py +97 -0
  81. ccproxy/core/errors.py +256 -0
  82. ccproxy/core/http.py +328 -0
  83. ccproxy/core/http_transformers.py +428 -0
  84. ccproxy/core/interfaces.py +247 -0
  85. ccproxy/core/logging.py +189 -0
  86. ccproxy/core/middleware.py +114 -0
  87. ccproxy/core/proxy.py +143 -0
  88. ccproxy/core/system.py +38 -0
  89. ccproxy/core/transformers.py +259 -0
  90. ccproxy/core/types.py +129 -0
  91. ccproxy/core/validators.py +288 -0
  92. ccproxy/docker/__init__.py +67 -0
  93. ccproxy/docker/adapter.py +588 -0
  94. ccproxy/docker/docker_path.py +207 -0
  95. ccproxy/docker/middleware.py +103 -0
  96. ccproxy/docker/models.py +228 -0
  97. ccproxy/docker/protocol.py +192 -0
  98. ccproxy/docker/stream_process.py +264 -0
  99. ccproxy/docker/validators.py +173 -0
  100. ccproxy/models/__init__.py +123 -0
  101. ccproxy/models/errors.py +42 -0
  102. ccproxy/models/messages.py +243 -0
  103. ccproxy/models/requests.py +85 -0
  104. ccproxy/models/responses.py +227 -0
  105. ccproxy/models/types.py +102 -0
  106. ccproxy/observability/__init__.py +51 -0
  107. ccproxy/observability/access_logger.py +400 -0
  108. ccproxy/observability/context.py +447 -0
  109. ccproxy/observability/metrics.py +539 -0
  110. ccproxy/observability/pushgateway.py +366 -0
  111. ccproxy/observability/sse_events.py +303 -0
  112. ccproxy/observability/stats_printer.py +755 -0
  113. ccproxy/observability/storage/__init__.py +1 -0
  114. ccproxy/observability/storage/duckdb_simple.py +665 -0
  115. ccproxy/observability/storage/models.py +55 -0
  116. ccproxy/pricing/__init__.py +19 -0
  117. ccproxy/pricing/cache.py +212 -0
  118. ccproxy/pricing/loader.py +267 -0
  119. ccproxy/pricing/models.py +106 -0
  120. ccproxy/pricing/updater.py +309 -0
  121. ccproxy/scheduler/__init__.py +39 -0
  122. ccproxy/scheduler/core.py +335 -0
  123. ccproxy/scheduler/exceptions.py +34 -0
  124. ccproxy/scheduler/manager.py +186 -0
  125. ccproxy/scheduler/registry.py +150 -0
  126. ccproxy/scheduler/tasks.py +484 -0
  127. ccproxy/services/__init__.py +10 -0
  128. ccproxy/services/claude_sdk_service.py +614 -0
  129. ccproxy/services/credentials/__init__.py +55 -0
  130. ccproxy/services/credentials/config.py +105 -0
  131. ccproxy/services/credentials/manager.py +562 -0
  132. ccproxy/services/credentials/oauth_client.py +482 -0
  133. ccproxy/services/proxy_service.py +1536 -0
  134. ccproxy/static/.keep +0 -0
  135. ccproxy/testing/__init__.py +34 -0
  136. ccproxy/testing/config.py +148 -0
  137. ccproxy/testing/content_generation.py +197 -0
  138. ccproxy/testing/mock_responses.py +262 -0
  139. ccproxy/testing/response_handlers.py +161 -0
  140. ccproxy/testing/scenarios.py +241 -0
  141. ccproxy/utils/__init__.py +6 -0
  142. ccproxy/utils/cost_calculator.py +210 -0
  143. ccproxy/utils/streaming_metrics.py +199 -0
  144. ccproxy_api-0.1.0.dist-info/METADATA +253 -0
  145. ccproxy_api-0.1.0.dist-info/RECORD +148 -0
  146. ccproxy_api-0.1.0.dist-info/WHEEL +4 -0
  147. ccproxy_api-0.1.0.dist-info/entry_points.txt +2 -0
  148. ccproxy_api-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,140 @@
1
+ """Shared dependencies for CCProxy API Server."""
2
+
3
+ from typing import Annotated
4
+
5
+ from fastapi import Depends, Request
6
+ from structlog import get_logger
7
+
8
+ from ccproxy.auth.dependencies import AuthManagerDep, get_auth_manager
9
+ from ccproxy.config.settings import Settings, get_settings
10
+ from ccproxy.core.http import BaseProxyClient
11
+ from ccproxy.observability import PrometheusMetrics, get_metrics
12
+ from ccproxy.observability.storage.duckdb_simple import SimpleDuckDBStorage
13
+ from ccproxy.services.claude_sdk_service import ClaudeSDKService
14
+ from ccproxy.services.credentials.manager import CredentialsManager
15
+ from ccproxy.services.proxy_service import ProxyService
16
+
17
+
18
+ logger = get_logger(__name__)
19
+
20
+ # Type aliases for dependency injection
21
+ SettingsDep = Annotated[Settings, Depends(get_settings)]
22
+
23
+
24
+ def get_claude_service(
25
+ auth_manager: AuthManagerDep,
26
+ ) -> ClaudeSDKService:
27
+ """Get Claude SDK service instance.
28
+
29
+ Args:
30
+ auth_manager: Authentication manager dependency
31
+
32
+ Returns:
33
+ Claude SDK service instance
34
+ """
35
+ logger.debug("Creating Claude SDK service instance")
36
+ # Get global metrics instance
37
+ metrics = get_metrics()
38
+
39
+ return ClaudeSDKService(
40
+ auth_manager=auth_manager,
41
+ metrics=metrics,
42
+ )
43
+
44
+
45
+ def get_credentials_manager(
46
+ settings: SettingsDep,
47
+ ) -> CredentialsManager:
48
+ """Get credentials manager instance.
49
+
50
+ Args:
51
+ settings: Application settings dependency
52
+
53
+ Returns:
54
+ Credentials manager instance
55
+ """
56
+ logger.debug("Creating credentials manager instance")
57
+ return CredentialsManager(config=settings.auth)
58
+
59
+
60
+ def get_proxy_service(
61
+ settings: SettingsDep,
62
+ credentials_manager: Annotated[
63
+ CredentialsManager, Depends(get_credentials_manager)
64
+ ],
65
+ ) -> ProxyService:
66
+ """Get proxy service instance.
67
+
68
+ Args:
69
+ settings: Application settings dependency
70
+ credentials_manager: Credentials manager dependency
71
+
72
+ Returns:
73
+ Proxy service instance
74
+ """
75
+ logger.debug("Creating proxy service instance")
76
+ # Create HTTP client for proxy
77
+ from ccproxy.core.http import HTTPXClient
78
+
79
+ http_client = HTTPXClient()
80
+ proxy_client = BaseProxyClient(http_client)
81
+
82
+ # Get global metrics instance
83
+ metrics = get_metrics()
84
+
85
+ return ProxyService(
86
+ proxy_client=proxy_client,
87
+ credentials_manager=credentials_manager,
88
+ settings=settings,
89
+ proxy_mode="full",
90
+ target_base_url=settings.reverse_proxy.target_url,
91
+ metrics=metrics,
92
+ )
93
+
94
+
95
+ def get_observability_metrics() -> PrometheusMetrics:
96
+ """Get observability metrics instance.
97
+
98
+ Returns:
99
+ PrometheusMetrics instance
100
+ """
101
+ logger.debug("Getting observability metrics instance")
102
+ return get_metrics()
103
+
104
+
105
+ async def get_log_storage(request: Request) -> SimpleDuckDBStorage | None:
106
+ """Get log storage from app state.
107
+
108
+ Args:
109
+ request: FastAPI request object
110
+
111
+ Returns:
112
+ SimpleDuckDBStorage instance if available, None otherwise
113
+ """
114
+ return getattr(request.app.state, "log_storage", None)
115
+
116
+
117
+ async def get_duckdb_storage(request: Request) -> SimpleDuckDBStorage | None:
118
+ """Get DuckDB storage from app state (backward compatibility).
119
+
120
+ Args:
121
+ request: FastAPI request object
122
+
123
+ Returns:
124
+ SimpleDuckDBStorage instance if available, None otherwise
125
+ """
126
+ # Try new name first, then fall back to old name for backward compatibility
127
+ storage = getattr(request.app.state, "log_storage", None)
128
+ if storage is None:
129
+ storage = getattr(request.app.state, "duckdb_storage", None)
130
+ return storage
131
+
132
+
133
+ # Type aliases for service dependencies
134
+ ClaudeServiceDep = Annotated[ClaudeSDKService, Depends(get_claude_service)]
135
+ ProxyServiceDep = Annotated[ProxyService, Depends(get_proxy_service)]
136
+ ObservabilityMetricsDep = Annotated[
137
+ PrometheusMetrics, Depends(get_observability_metrics)
138
+ ]
139
+ LogStorageDep = Annotated[SimpleDuckDBStorage | None, Depends(get_log_storage)]
140
+ DuckDBStorageDep = Annotated[SimpleDuckDBStorage | None, Depends(get_duckdb_storage)]
@@ -0,0 +1,11 @@
1
+ """API middleware for CCProxy API Server."""
2
+
3
+ from ccproxy.api.middleware.cors import get_cors_config, setup_cors_middleware
4
+ from ccproxy.api.middleware.errors import setup_error_handlers
5
+
6
+
7
+ __all__ = [
8
+ "setup_cors_middleware",
9
+ "get_cors_config",
10
+ "setup_error_handlers",
11
+ ]
File without changes
@@ -0,0 +1,55 @@
1
+ """CORS middleware for CCProxy API Server."""
2
+
3
+ from typing import Any
4
+
5
+ from fastapi import FastAPI
6
+ from fastapi.middleware.cors import CORSMiddleware
7
+ from structlog import get_logger
8
+
9
+ from ccproxy.config.settings import Settings
10
+
11
+
12
+ logger = get_logger(__name__)
13
+
14
+
15
+ def setup_cors_middleware(app: FastAPI, settings: Settings) -> None:
16
+ """Setup CORS middleware for the FastAPI application.
17
+
18
+ Args:
19
+ app: FastAPI application instance
20
+ settings: Application settings containing CORS configuration
21
+ """
22
+ logger.debug("cors_middleware_setup_start")
23
+
24
+ app.add_middleware(
25
+ CORSMiddleware,
26
+ allow_origins=settings.cors.origins,
27
+ allow_credentials=settings.cors.credentials,
28
+ allow_methods=settings.cors.methods,
29
+ allow_headers=settings.cors.headers,
30
+ allow_origin_regex=settings.cors.origin_regex,
31
+ expose_headers=settings.cors.expose_headers,
32
+ max_age=settings.cors.max_age,
33
+ )
34
+
35
+ logger.debug("cors_middleware_configured", origins=settings.cors.origins)
36
+
37
+
38
+ def get_cors_config(settings: Settings) -> dict[str, Any]:
39
+ """Get CORS configuration dictionary.
40
+
41
+ Args:
42
+ settings: Application settings containing CORS configuration
43
+
44
+ Returns:
45
+ Dictionary containing CORS configuration
46
+ """
47
+ return {
48
+ "allow_origins": settings.cors.origins,
49
+ "allow_credentials": settings.cors.credentials,
50
+ "allow_methods": settings.cors.methods,
51
+ "allow_headers": settings.cors.headers,
52
+ "allow_origin_regex": settings.cors.origin_regex,
53
+ "expose_headers": settings.cors.expose_headers,
54
+ "max_age": settings.cors.max_age,
55
+ }