cloud-dog-api-kit 0.13.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 (98) hide show
  1. cloud_dog_api_kit/__init__.py +170 -0
  2. cloud_dog_api_kit/a2a/__init__.py +53 -0
  3. cloud_dog_api_kit/a2a/card.py +138 -0
  4. cloud_dog_api_kit/a2a/events.py +1123 -0
  5. cloud_dog_api_kit/a2a/gateway.py +105 -0
  6. cloud_dog_api_kit/a2a/skill_audit.py +107 -0
  7. cloud_dog_api_kit/auth/__init__.py +35 -0
  8. cloud_dog_api_kit/auth/dependency.py +121 -0
  9. cloud_dog_api_kit/auth/rbac.py +107 -0
  10. cloud_dog_api_kit/auth/service_auth.py +54 -0
  11. cloud_dog_api_kit/clients/__init__.py +29 -0
  12. cloud_dog_api_kit/clients/circuit_breaker.py +39 -0
  13. cloud_dog_api_kit/clients/http_client.py +127 -0
  14. cloud_dog_api_kit/clients/retry.py +83 -0
  15. cloud_dog_api_kit/compat/__init__.py +37 -0
  16. cloud_dog_api_kit/compat/envelope.py +120 -0
  17. cloud_dog_api_kit/compat/profile.py +102 -0
  18. cloud_dog_api_kit/compat/routes.py +90 -0
  19. cloud_dog_api_kit/config.py +54 -0
  20. cloud_dog_api_kit/correlation/__init__.py +50 -0
  21. cloud_dog_api_kit/correlation/context.py +118 -0
  22. cloud_dog_api_kit/correlation/middleware.py +133 -0
  23. cloud_dog_api_kit/envelopes/__init__.py +37 -0
  24. cloud_dog_api_kit/envelopes/error.py +87 -0
  25. cloud_dog_api_kit/envelopes/success.py +84 -0
  26. cloud_dog_api_kit/errors/__init__.py +51 -0
  27. cloud_dog_api_kit/errors/exceptions.py +184 -0
  28. cloud_dog_api_kit/errors/handler.py +102 -0
  29. cloud_dog_api_kit/errors/taxonomy.py +62 -0
  30. cloud_dog_api_kit/factory.py +157 -0
  31. cloud_dog_api_kit/idempotency/__init__.py +28 -0
  32. cloud_dog_api_kit/idempotency/middleware.py +118 -0
  33. cloud_dog_api_kit/idempotency/store.py +100 -0
  34. cloud_dog_api_kit/lifecycle/__init__.py +39 -0
  35. cloud_dog_api_kit/lifecycle/hooks.py +75 -0
  36. cloud_dog_api_kit/lifecycle/shutdown.py +178 -0
  37. cloud_dog_api_kit/mcp/__init__.py +122 -0
  38. cloud_dog_api_kit/mcp/async_jobs.py +126 -0
  39. cloud_dog_api_kit/mcp/client_sdk.py +235 -0
  40. cloud_dog_api_kit/mcp/client_transport/__init__.py +47 -0
  41. cloud_dog_api_kit/mcp/client_transport/base.py +98 -0
  42. cloud_dog_api_kit/mcp/client_transport/exceptions.py +37 -0
  43. cloud_dog_api_kit/mcp/client_transport/http_jsonrpc.py +405 -0
  44. cloud_dog_api_kit/mcp/client_transport/legacy_sse.py +320 -0
  45. cloud_dog_api_kit/mcp/client_transport/stdio.py +322 -0
  46. cloud_dog_api_kit/mcp/client_transport/streamable_http.py +748 -0
  47. cloud_dog_api_kit/mcp/contract.py +113 -0
  48. cloud_dog_api_kit/mcp/error_mapper.py +84 -0
  49. cloud_dog_api_kit/mcp/gateway.py +117 -0
  50. cloud_dog_api_kit/mcp/legacy_sse.py +129 -0
  51. cloud_dog_api_kit/mcp/session.py +96 -0
  52. cloud_dog_api_kit/mcp/sync_handler.py +269 -0
  53. cloud_dog_api_kit/mcp/tool_audit.py +136 -0
  54. cloud_dog_api_kit/mcp/tool_router.py +180 -0
  55. cloud_dog_api_kit/mcp/transport.py +1041 -0
  56. cloud_dog_api_kit/middleware/__init__.py +39 -0
  57. cloud_dog_api_kit/middleware/cors.py +74 -0
  58. cloud_dog_api_kit/middleware/logging.py +98 -0
  59. cloud_dog_api_kit/middleware/request_size_limit.py +86 -0
  60. cloud_dog_api_kit/middleware/timeout.py +78 -0
  61. cloud_dog_api_kit/middleware/timing.py +52 -0
  62. cloud_dog_api_kit/openapi/__init__.py +30 -0
  63. cloud_dog_api_kit/openapi/customise.py +69 -0
  64. cloud_dog_api_kit/openapi/route.py +46 -0
  65. cloud_dog_api_kit/routers/__init__.py +41 -0
  66. cloud_dog_api_kit/routers/crud.py +173 -0
  67. cloud_dog_api_kit/routers/health.py +160 -0
  68. cloud_dog_api_kit/routers/jobs.py +69 -0
  69. cloud_dog_api_kit/routers/version.py +46 -0
  70. cloud_dog_api_kit/schemas/__init__.py +36 -0
  71. cloud_dog_api_kit/schemas/envelopes.py +37 -0
  72. cloud_dog_api_kit/schemas/filters.py +103 -0
  73. cloud_dog_api_kit/schemas/pagination.py +148 -0
  74. cloud_dog_api_kit/streaming/__init__.py +28 -0
  75. cloud_dog_api_kit/streaming/events.py +47 -0
  76. cloud_dog_api_kit/streaming/jsonl.py +68 -0
  77. cloud_dog_api_kit/streaming/sse.py +102 -0
  78. cloud_dog_api_kit/testing/__init__.py +46 -0
  79. cloud_dog_api_kit/testing/conformance.py +156 -0
  80. cloud_dog_api_kit/testing/fixtures.py +90 -0
  81. cloud_dog_api_kit/testing/flows/__init__.py +32 -0
  82. cloud_dog_api_kit/testing/flows/auth_flow.py +41 -0
  83. cloud_dog_api_kit/testing/flows/crud_flow.py +50 -0
  84. cloud_dog_api_kit/testing/flows/job_flow.py +42 -0
  85. cloud_dog_api_kit/testing/flows/streaming_flow.py +42 -0
  86. cloud_dog_api_kit/traceability_ids.py +84 -0
  87. cloud_dog_api_kit/versioning/__init__.py +30 -0
  88. cloud_dog_api_kit/versioning/header.py +52 -0
  89. cloud_dog_api_kit/web/__init__.py +7 -0
  90. cloud_dog_api_kit/web/proxy.py +222 -0
  91. cloud_dog_api_kit/webhook/__init__.py +29 -0
  92. cloud_dog_api_kit/webhook/signature.py +149 -0
  93. cloud_dog_api_kit-0.13.0.dist-info/METADATA +27 -0
  94. cloud_dog_api_kit-0.13.0.dist-info/RECORD +98 -0
  95. cloud_dog_api_kit-0.13.0.dist-info/WHEEL +4 -0
  96. cloud_dog_api_kit-0.13.0.dist-info/licenses/LICENCE +190 -0
  97. cloud_dog_api_kit-0.13.0.dist-info/licenses/LICENSE +176 -0
  98. cloud_dog_api_kit-0.13.0.dist-info/licenses/NOTICE +7 -0
@@ -0,0 +1,39 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — Middleware components
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Standard middleware components (logging, CORS, timing, timeout).
20
+ # Related requirements: FR11.1, FR12.1, FR13.1
21
+ # Related architecture: SA1
22
+
23
+ """Middleware components for cloud_dog_api_kit."""
24
+
25
+ from __future__ import annotations
26
+
27
+ from cloud_dog_api_kit.middleware.cors import configure_cors
28
+ from cloud_dog_api_kit.middleware.logging import RequestLoggingMiddleware
29
+ from cloud_dog_api_kit.middleware.request_size_limit import RequestSizeLimitMiddleware
30
+ from cloud_dog_api_kit.middleware.timing import TimingMiddleware
31
+ from cloud_dog_api_kit.middleware.timeout import TimeoutMiddleware
32
+
33
+ __all__ = [
34
+ "RequestLoggingMiddleware",
35
+ "RequestSizeLimitMiddleware",
36
+ "TimingMiddleware",
37
+ "TimeoutMiddleware",
38
+ "configure_cors",
39
+ ]
@@ -0,0 +1,74 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — CORS configuration helper
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: CORS middleware configuration with production-safe defaults.
20
+ # Does not use wildcard origins unless explicitly configured.
21
+ # Related requirements: FR11.1, CS1.4
22
+ # Related architecture: CC1.12
23
+
24
+ """CORS configuration helper for cloud_dog_api_kit."""
25
+
26
+ from __future__ import annotations
27
+
28
+
29
+ from fastapi import FastAPI
30
+ from starlette.middleware.cors import CORSMiddleware
31
+
32
+
33
+ def configure_cors(
34
+ app: FastAPI,
35
+ allowed_origins: list[str] | None = None,
36
+ allow_credentials: bool = True,
37
+ allow_methods: list[str] | None = None,
38
+ allow_headers: list[str] | None = None,
39
+ ) -> None:
40
+ """Configure CORS middleware on a FastAPI application.
41
+
42
+ Production-safe defaults: explicit origins only, not wildcard ``*``
43
+ unless explicitly provided.
44
+
45
+ Args:
46
+ app: The FastAPI application.
47
+ allowed_origins: List of allowed origins. Defaults to empty (no CORS).
48
+ allow_credentials: Whether to allow credentials. Defaults to True.
49
+ allow_methods: Allowed HTTP methods. Defaults to standard set.
50
+ allow_headers: Allowed headers. Defaults to standard set.
51
+
52
+ Related tests: UT1.25_CORSHelper
53
+ """
54
+ origins = allowed_origins or []
55
+ methods = allow_methods or ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
56
+ headers = allow_headers or [
57
+ "Authorization",
58
+ "X-API-Key",
59
+ "X-Request-Id",
60
+ "X-Correlation-Id",
61
+ "X-App-Id",
62
+ "X-Host-Id",
63
+ "Content-Type",
64
+ "Accept",
65
+ "Idempotency-Key",
66
+ ]
67
+
68
+ app.add_middleware(
69
+ CORSMiddleware,
70
+ allow_origins=origins,
71
+ allow_credentials=allow_credentials,
72
+ allow_methods=methods,
73
+ allow_headers=headers,
74
+ )
@@ -0,0 +1,98 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — Request/response logging middleware
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Middleware that logs request/response details with header
20
+ # redaction for sensitive values (Authorization, X-API-Key, Cookie).
21
+ # Related requirements: FR12.1, CS1.2, CS1.6
22
+ # Related architecture: CC1.13
23
+
24
+ """Request/response logging middleware for cloud_dog_api_kit."""
25
+
26
+ from __future__ import annotations
27
+
28
+ import logging
29
+ import time
30
+ from typing import Callable
31
+
32
+ from starlette.middleware.base import BaseHTTPMiddleware
33
+ from starlette.requests import Request
34
+ from starlette.responses import Response
35
+
36
+ REDACTED_HEADERS = frozenset({"authorization", "x-api-key", "cookie"})
37
+
38
+ logger = logging.getLogger("cloud_dog_api_kit.request_logging")
39
+
40
+
41
+ class RequestLoggingMiddleware(BaseHTTPMiddleware):
42
+ """Request/response logging middleware with header redaction.
43
+
44
+ Logs: request_id, correlation_id, user/system identity, method, path,
45
+ status code, duration (ms), client IP. Redacts sensitive headers.
46
+
47
+ Args:
48
+ app: The ASGI application.
49
+
50
+ Related tests: UT1.26_RequestLogging, SEC1.5_SecretRedaction
51
+ """
52
+
53
+ async def dispatch(self, request: Request, call_next: Callable) -> Response:
54
+ """Log request and response details.
55
+
56
+ Args:
57
+ request: The incoming HTTP request.
58
+ call_next: The next middleware or handler.
59
+
60
+ Returns:
61
+ The HTTP response.
62
+ """
63
+ request_id = getattr(request.state, "request_id", "")
64
+ correlation_id = getattr(request.state, "correlation_id", None)
65
+ user = getattr(request.state, "user", None)
66
+ client_ip = request.client.host if request.client else "unknown"
67
+
68
+ logger.info(
69
+ "Request started",
70
+ extra={
71
+ "request_id": request_id,
72
+ "correlation_id": correlation_id,
73
+ "user": user,
74
+ "method": request.method,
75
+ "path": request.url.path,
76
+ "client_ip": client_ip,
77
+ },
78
+ )
79
+
80
+ start_time = time.monotonic()
81
+ response = await call_next(request)
82
+ duration_ms = round((time.monotonic() - start_time) * 1000, 2)
83
+
84
+ logger.info(
85
+ "Request completed",
86
+ extra={
87
+ "request_id": request_id,
88
+ "correlation_id": correlation_id,
89
+ "user": user,
90
+ "method": request.method,
91
+ "path": request.url.path,
92
+ "status_code": response.status_code,
93
+ "duration_ms": duration_ms,
94
+ "client_ip": client_ip,
95
+ },
96
+ )
97
+
98
+ return response
@@ -0,0 +1,86 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — Request size limit middleware
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Middleware that enforces a maximum request body size and
20
+ # returns a standard envelope with HTTP 413 when exceeded.
21
+ # Related requirements: FR18.8
22
+ # Related architecture: SA1
23
+
24
+ """Request body size limit middleware for cloud_dog_api_kit."""
25
+
26
+ from __future__ import annotations
27
+
28
+ from typing import Any, Callable
29
+
30
+ from starlette.middleware.base import BaseHTTPMiddleware
31
+ from starlette.requests import Request
32
+ from starlette.responses import JSONResponse, Response
33
+
34
+ from cloud_dog_api_kit.envelopes.error import error_envelope
35
+
36
+
37
+ class RequestSizeLimitMiddleware(BaseHTTPMiddleware):
38
+ """Enforce a maximum request body size.
39
+
40
+ The middleware checks `Content-Length` when available and validates the
41
+ effective byte size by reading the request body when needed.
42
+
43
+ Args:
44
+ app: The ASGI application.
45
+ max_bytes: Maximum allowed body size in bytes.
46
+
47
+ Related tests: UT1.44_RequestSizeLimit
48
+ """
49
+
50
+ def __init__(self, app: Any, max_bytes: int) -> None:
51
+ if max_bytes < 1:
52
+ raise ValueError("max_bytes must be >= 1")
53
+ super().__init__(app)
54
+ self._max_bytes = max_bytes
55
+
56
+ async def dispatch(self, request: Request, call_next: Callable) -> Response:
57
+ """Reject requests larger than the configured threshold."""
58
+ content_length = request.headers.get("content-length")
59
+ if content_length:
60
+ try:
61
+ if int(content_length) > self._max_bytes:
62
+ return self._too_large_response(request)
63
+ except ValueError:
64
+ # Non-integer content length is treated as invalid request size.
65
+ return self._too_large_response(request)
66
+
67
+ body = await request.body()
68
+ if len(body) > self._max_bytes:
69
+ return self._too_large_response(request)
70
+ return await call_next(request)
71
+
72
+ def _too_large_response(self, request: Request) -> JSONResponse:
73
+ """Build a standard 413 error response."""
74
+ request_id = getattr(request.state, "request_id", "")
75
+ correlation_id = getattr(request.state, "correlation_id", None)
76
+ return JSONResponse(
77
+ status_code=413,
78
+ content=error_envelope(
79
+ code="INVALID_REQUEST",
80
+ message=f"Request body exceeds maximum size ({self._max_bytes} bytes)",
81
+ details={"max_bytes": self._max_bytes},
82
+ retryable=False,
83
+ request_id=request_id,
84
+ correlation_id=correlation_id,
85
+ ),
86
+ )
@@ -0,0 +1,78 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — Request timeout middleware
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Configurable request timeout middleware that returns a standard
20
+ # TIMEOUT error envelope when a request exceeds the configured duration.
21
+ # Related requirements: FR13.1
22
+ # Related architecture: CC1.13
23
+
24
+ """Request timeout middleware for cloud_dog_api_kit."""
25
+
26
+ from __future__ import annotations
27
+
28
+ import asyncio
29
+ from typing import Any, Callable
30
+
31
+ from starlette.middleware.base import BaseHTTPMiddleware
32
+ from starlette.requests import Request
33
+ from starlette.responses import JSONResponse, Response
34
+
35
+ from cloud_dog_api_kit.envelopes.error import error_envelope
36
+
37
+
38
+ class TimeoutMiddleware(BaseHTTPMiddleware):
39
+ """Request timeout middleware.
40
+
41
+ Returns a standard TIMEOUT error envelope when a request exceeds
42
+ the configured duration. Streaming endpoints should use jobs instead.
43
+
44
+ Args:
45
+ app: The ASGI application.
46
+ timeout_seconds: Default request timeout in seconds. Defaults to 30.
47
+
48
+ Related tests: UT1.27_TimeoutMiddleware
49
+ """
50
+
51
+ def __init__(self, app: Any, timeout_seconds: float = 30.0) -> None:
52
+ super().__init__(app)
53
+ self._timeout = timeout_seconds
54
+
55
+ async def dispatch(self, request: Request, call_next: Callable) -> Response:
56
+ """Process request with timeout enforcement.
57
+
58
+ Args:
59
+ request: The incoming HTTP request.
60
+ call_next: The next middleware or handler.
61
+
62
+ Returns:
63
+ The HTTP response or a TIMEOUT error envelope.
64
+ """
65
+ try:
66
+ return await asyncio.wait_for(
67
+ call_next(request),
68
+ timeout=self._timeout,
69
+ )
70
+ except asyncio.TimeoutError:
71
+ request_id = getattr(request.state, "request_id", "")
72
+ body = error_envelope(
73
+ code="TIMEOUT",
74
+ message=f"Request timed out after {self._timeout}s",
75
+ retryable=True,
76
+ request_id=request_id,
77
+ )
78
+ return JSONResponse(status_code=504, content=body)
@@ -0,0 +1,52 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — Timing middleware
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Measures request duration and exposes it via response header.
20
+ # Related requirements: FR12.1
21
+ # Related architecture: SA1
22
+
23
+ """Request timing middleware for cloud_dog_api_kit."""
24
+
25
+ from __future__ import annotations
26
+
27
+ import time
28
+ from typing import Any, Callable
29
+
30
+ from starlette.middleware.base import BaseHTTPMiddleware
31
+ from starlette.requests import Request
32
+ from starlette.responses import Response
33
+
34
+
35
+ class TimingMiddleware(BaseHTTPMiddleware):
36
+ """Measures request duration and sets response header.
37
+
38
+ Adds `X-Response-Time-Ms` header and stores `request.state.duration_ms`.
39
+ """
40
+
41
+ def __init__(self, app: Any, header_name: str = "X-Response-Time-Ms") -> None:
42
+ super().__init__(app)
43
+ self._header_name = header_name
44
+
45
+ async def dispatch(self, request: Request, call_next: Callable) -> Response:
46
+ """Handle dispatch."""
47
+ start = time.monotonic()
48
+ response = await call_next(request)
49
+ duration_ms = round((time.monotonic() - start) * 1000, 2)
50
+ setattr(request.state, "duration_ms", duration_ms)
51
+ response.headers[self._header_name] = str(duration_ms)
52
+ return response
@@ -0,0 +1,30 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — OpenAPI customisation helpers
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Helpers for OpenAPI schema customisation and versioning.
20
+ # Related requirements: FR10.1, FR10.2, FR10.4
21
+ # Related architecture: CC1.17
22
+
23
+ """OpenAPI customisation helpers for cloud_dog_api_kit."""
24
+
25
+ from __future__ import annotations
26
+
27
+ from cloud_dog_api_kit.openapi.customise import configure_openapi
28
+ from cloud_dog_api_kit.openapi.route import create_openapi_router
29
+
30
+ __all__ = ["configure_openapi", "create_openapi_router"]
@@ -0,0 +1,69 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — OpenAPI customisation
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Helpers for OpenAPI schema customisation, security schemes,
20
+ # and documentation behaviours.
21
+ # Related requirements: FR10.1, FR10.2
22
+ # Related architecture: SA1, CC1.17
23
+
24
+ """OpenAPI customisation helpers."""
25
+
26
+ from __future__ import annotations
27
+
28
+ from typing import Any
29
+
30
+ from fastapi import FastAPI
31
+
32
+
33
+ def configure_openapi(
34
+ app: FastAPI,
35
+ tags: list[dict] | None = None,
36
+ security_schemes: dict | None = None,
37
+ ) -> None:
38
+ """Configure OpenAPI schema customisation on a FastAPI application.
39
+
40
+ Args:
41
+ app: The FastAPI application.
42
+ tags: OpenAPI tag metadata for endpoint grouping.
43
+ security_schemes: Security scheme definitions.
44
+
45
+ Related tests: UT1.31_OpenAPICustomise
46
+ """
47
+ if tags:
48
+ app.openapi_tags = tags
49
+
50
+ if security_schemes:
51
+
52
+ def _custom_openapi() -> dict[str, Any]:
53
+ if app.openapi_schema:
54
+ return app.openapi_schema
55
+ from fastapi.openapi.utils import get_openapi
56
+
57
+ schema = get_openapi(
58
+ title=app.title,
59
+ version=app.version,
60
+ description=app.description,
61
+ routes=app.routes,
62
+ tags=app.openapi_tags,
63
+ )
64
+ schema.setdefault("components", {})
65
+ schema["components"]["securitySchemes"] = security_schemes
66
+ app.openapi_schema = schema
67
+ return schema
68
+
69
+ app.openapi = _custom_openapi # type: ignore[method-assign]
@@ -0,0 +1,46 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — OpenAPI spec route helper
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Provides a helper for serving an OpenAPI schema via a stable
20
+ # endpoint.
21
+ # Related requirements: FR10.1
22
+ # Related architecture: SA1
23
+
24
+ """OpenAPI spec route helper for cloud_dog_api_kit."""
25
+
26
+ from __future__ import annotations
27
+
28
+ from typing import Any
29
+
30
+ from fastapi import APIRouter, FastAPI
31
+
32
+
33
+ def create_openapi_router(
34
+ app: FastAPI,
35
+ path: str = "/openapi.json",
36
+ tags: list[str] | None = None,
37
+ ) -> APIRouter:
38
+ """Create a router that serves the OpenAPI schema for the given app."""
39
+ router = APIRouter(tags=tags or ["openapi"])
40
+
41
+ @router.get(path)
42
+ async def openapi_schema() -> dict[str, Any]:
43
+ """Return the OpenAPI schema."""
44
+ return app.openapi()
45
+
46
+ return router
@@ -0,0 +1,41 @@
1
+ # Copyright 2026 Cloud-Dog, Viewdeck Engineering Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # cloud_dog_api_kit — Router helpers
16
+ #
17
+ # Licence: Proprietary — Cloud-Dog AI Platform
18
+ # Owner: Cloud-Dog AI
19
+ # Description: Router factories (CRUD, health, jobs, version) for consistent
20
+ # API structure.
21
+ # Related requirements: FR4.1, FR4.2, FR6.1, FR7.1
22
+ # Related architecture: SA1
23
+
24
+ """Router helpers for cloud_dog_api_kit."""
25
+
26
+ from __future__ import annotations
27
+
28
+ from cloud_dog_api_kit.routers.crud import CRUDService, create_crud_router, create_versioned_router
29
+ from cloud_dog_api_kit.routers.health import HealthCheck, create_health_router
30
+ from cloud_dog_api_kit.routers.jobs import create_job_endpoint
31
+ from cloud_dog_api_kit.routers.version import create_version_router
32
+
33
+ __all__ = [
34
+ "CRUDService",
35
+ "create_crud_router",
36
+ "create_versioned_router",
37
+ "HealthCheck",
38
+ "create_health_router",
39
+ "create_job_endpoint",
40
+ "create_version_router",
41
+ ]