sdkrouter 0.1.1__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 (96) hide show
  1. sdkrouter/__init__.py +110 -0
  2. sdkrouter/_api/__init__.py +28 -0
  3. sdkrouter/_api/client.py +204 -0
  4. sdkrouter/_api/generated/__init__.py +21 -0
  5. sdkrouter/_api/generated/cdn/__init__.py +209 -0
  6. sdkrouter/_api/generated/cdn/cdn__api__cdn/__init__.py +7 -0
  7. sdkrouter/_api/generated/cdn/cdn__api__cdn/client.py +133 -0
  8. sdkrouter/_api/generated/cdn/cdn__api__cdn/models.py +163 -0
  9. sdkrouter/_api/generated/cdn/cdn__api__cdn/sync_client.py +132 -0
  10. sdkrouter/_api/generated/cdn/client.py +75 -0
  11. sdkrouter/_api/generated/cdn/logger.py +256 -0
  12. sdkrouter/_api/generated/cdn/pyproject.toml +55 -0
  13. sdkrouter/_api/generated/cdn/retry.py +272 -0
  14. sdkrouter/_api/generated/cdn/sync_client.py +58 -0
  15. sdkrouter/_api/generated/cleaner/__init__.py +212 -0
  16. sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/__init__.py +7 -0
  17. sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/client.py +83 -0
  18. sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/models.py +117 -0
  19. sdkrouter/_api/generated/cleaner/cleaner__api__cleaner/sync_client.py +82 -0
  20. sdkrouter/_api/generated/cleaner/client.py +75 -0
  21. sdkrouter/_api/generated/cleaner/enums.py +55 -0
  22. sdkrouter/_api/generated/cleaner/logger.py +256 -0
  23. sdkrouter/_api/generated/cleaner/pyproject.toml +55 -0
  24. sdkrouter/_api/generated/cleaner/retry.py +272 -0
  25. sdkrouter/_api/generated/cleaner/sync_client.py +58 -0
  26. sdkrouter/_api/generated/keys/__init__.py +212 -0
  27. sdkrouter/_api/generated/keys/client.py +75 -0
  28. sdkrouter/_api/generated/keys/enums.py +64 -0
  29. sdkrouter/_api/generated/keys/keys__api__keys/__init__.py +7 -0
  30. sdkrouter/_api/generated/keys/keys__api__keys/client.py +150 -0
  31. sdkrouter/_api/generated/keys/keys__api__keys/models.py +152 -0
  32. sdkrouter/_api/generated/keys/keys__api__keys/sync_client.py +149 -0
  33. sdkrouter/_api/generated/keys/logger.py +256 -0
  34. sdkrouter/_api/generated/keys/pyproject.toml +55 -0
  35. sdkrouter/_api/generated/keys/retry.py +272 -0
  36. sdkrouter/_api/generated/keys/sync_client.py +58 -0
  37. sdkrouter/_api/generated/models/__init__.py +209 -0
  38. sdkrouter/_api/generated/models/client.py +75 -0
  39. sdkrouter/_api/generated/models/logger.py +256 -0
  40. sdkrouter/_api/generated/models/models__api__llm_models/__init__.py +7 -0
  41. sdkrouter/_api/generated/models/models__api__llm_models/client.py +99 -0
  42. sdkrouter/_api/generated/models/models__api__llm_models/models.py +206 -0
  43. sdkrouter/_api/generated/models/models__api__llm_models/sync_client.py +99 -0
  44. sdkrouter/_api/generated/models/pyproject.toml +55 -0
  45. sdkrouter/_api/generated/models/retry.py +272 -0
  46. sdkrouter/_api/generated/models/sync_client.py +58 -0
  47. sdkrouter/_api/generated/shortlinks/__init__.py +209 -0
  48. sdkrouter/_api/generated/shortlinks/client.py +75 -0
  49. sdkrouter/_api/generated/shortlinks/logger.py +256 -0
  50. sdkrouter/_api/generated/shortlinks/pyproject.toml +55 -0
  51. sdkrouter/_api/generated/shortlinks/retry.py +272 -0
  52. sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/__init__.py +7 -0
  53. sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/client.py +137 -0
  54. sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/models.py +153 -0
  55. sdkrouter/_api/generated/shortlinks/shortlinks__api__shortlinks/sync_client.py +136 -0
  56. sdkrouter/_api/generated/shortlinks/sync_client.py +58 -0
  57. sdkrouter/_api/generated/vision/__init__.py +212 -0
  58. sdkrouter/_api/generated/vision/client.py +75 -0
  59. sdkrouter/_api/generated/vision/enums.py +40 -0
  60. sdkrouter/_api/generated/vision/logger.py +256 -0
  61. sdkrouter/_api/generated/vision/pyproject.toml +55 -0
  62. sdkrouter/_api/generated/vision/retry.py +272 -0
  63. sdkrouter/_api/generated/vision/sync_client.py +58 -0
  64. sdkrouter/_api/generated/vision/vision__api__vision/__init__.py +7 -0
  65. sdkrouter/_api/generated/vision/vision__api__vision/client.py +65 -0
  66. sdkrouter/_api/generated/vision/vision__api__vision/models.py +138 -0
  67. sdkrouter/_api/generated/vision/vision__api__vision/sync_client.py +65 -0
  68. sdkrouter/_client.py +432 -0
  69. sdkrouter/_config.py +74 -0
  70. sdkrouter/_constants.py +21 -0
  71. sdkrouter/_internal/__init__.py +1 -0
  72. sdkrouter/_types/__init__.py +30 -0
  73. sdkrouter/_types/cdn.py +27 -0
  74. sdkrouter/_types/models.py +26 -0
  75. sdkrouter/_types/ocr.py +24 -0
  76. sdkrouter/_types/parsed.py +101 -0
  77. sdkrouter/_types/shortlinks.py +27 -0
  78. sdkrouter/_types/vision.py +29 -0
  79. sdkrouter/_version.py +3 -0
  80. sdkrouter/helpers/__init__.py +13 -0
  81. sdkrouter/helpers/formatting.py +15 -0
  82. sdkrouter/helpers/html.py +100 -0
  83. sdkrouter/helpers/json_cleaner.py +53 -0
  84. sdkrouter/tools/__init__.py +129 -0
  85. sdkrouter/tools/cdn.py +285 -0
  86. sdkrouter/tools/cleaner.py +186 -0
  87. sdkrouter/tools/keys.py +215 -0
  88. sdkrouter/tools/models.py +196 -0
  89. sdkrouter/tools/shortlinks.py +165 -0
  90. sdkrouter/tools/vision.py +173 -0
  91. sdkrouter/utils/__init__.py +27 -0
  92. sdkrouter/utils/parsing.py +109 -0
  93. sdkrouter/utils/tokens.py +375 -0
  94. sdkrouter-0.1.1.dist-info/METADATA +411 -0
  95. sdkrouter-0.1.1.dist-info/RECORD +96 -0
  96. sdkrouter-0.1.1.dist-info/WHEEL +4 -0
@@ -0,0 +1,137 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+
5
+ from .models import *
6
+
7
+
8
+ class ShortlinksShortlinksAPI:
9
+ """API endpoints for Shortlinks."""
10
+
11
+ def __init__(self, client: httpx.AsyncClient):
12
+ """Initialize sub-client with shared httpx client."""
13
+ self._client = client
14
+
15
+ async def list(self, page: int | None = None, page_size: int | None = None) -> list[PaginatedShortLinkListList]:
16
+ """
17
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
18
+ List user's short links - POST /api/shortlinks/ - Create a new short
19
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
20
+ /api/shortlinks/{code}/ - Deactivate short link - GET
21
+ /api/shortlinks/stats/ - Get link statistics
22
+ """
23
+ url = "/api/shortlinks/"
24
+ response = await self._client.get(url, params={"page": page if page is not None else None, "page_size": page_size if page_size is not None else None})
25
+ if not response.is_success:
26
+ try:
27
+ error_body = response.json()
28
+ except Exception:
29
+ error_body = response.text
30
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
31
+ return PaginatedShortLinkListList.model_validate(response.json())
32
+
33
+
34
+ async def create(self, data: ShortLinkCreateRequest) -> ShortLinkCreate:
35
+ """
36
+ Create a new short link.
37
+ """
38
+ url = "/api/shortlinks/"
39
+ response = await self._client.post(url, json=data.model_dump(exclude_unset=True))
40
+ if not response.is_success:
41
+ try:
42
+ error_body = response.json()
43
+ except Exception:
44
+ error_body = response.text
45
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
46
+ return ShortLinkCreate.model_validate(response.json())
47
+
48
+
49
+ async def retrieve(self, code: str) -> ShortLinkDetail:
50
+ """
51
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
52
+ List user's short links - POST /api/shortlinks/ - Create a new short
53
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
54
+ /api/shortlinks/{code}/ - Deactivate short link - GET
55
+ /api/shortlinks/stats/ - Get link statistics
56
+ """
57
+ url = f"/api/shortlinks/{code}/"
58
+ response = await self._client.get(url)
59
+ if not response.is_success:
60
+ try:
61
+ error_body = response.json()
62
+ except Exception:
63
+ error_body = response.text
64
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
65
+ return ShortLinkDetail.model_validate(response.json())
66
+
67
+
68
+ async def update(self, code: str) -> ShortLinkList:
69
+ """
70
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
71
+ List user's short links - POST /api/shortlinks/ - Create a new short
72
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
73
+ /api/shortlinks/{code}/ - Deactivate short link - GET
74
+ /api/shortlinks/stats/ - Get link statistics
75
+ """
76
+ url = f"/api/shortlinks/{code}/"
77
+ response = await self._client.put(url)
78
+ if not response.is_success:
79
+ try:
80
+ error_body = response.json()
81
+ except Exception:
82
+ error_body = response.text
83
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
84
+ return ShortLinkList.model_validate(response.json())
85
+
86
+
87
+ async def partial_update(self, code: str) -> ShortLinkList:
88
+ """
89
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
90
+ List user's short links - POST /api/shortlinks/ - Create a new short
91
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
92
+ /api/shortlinks/{code}/ - Deactivate short link - GET
93
+ /api/shortlinks/stats/ - Get link statistics
94
+ """
95
+ url = f"/api/shortlinks/{code}/"
96
+ response = await self._client.patch(url)
97
+ if not response.is_success:
98
+ try:
99
+ error_body = response.json()
100
+ except Exception:
101
+ error_body = response.text
102
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
103
+ return ShortLinkList.model_validate(response.json())
104
+
105
+
106
+ async def destroy(self, code: str) -> None:
107
+ """
108
+ Deactivate a short link.
109
+ """
110
+ url = f"/api/shortlinks/{code}/"
111
+ response = await self._client.delete(url)
112
+ if not response.is_success:
113
+ try:
114
+ error_body = response.json()
115
+ except Exception:
116
+ error_body = response.text
117
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
118
+ return None
119
+
120
+
121
+ async def stats_retrieve(self) -> ShortLinkStats:
122
+ """
123
+ Get shortlink statistics
124
+
125
+ Get shortlink statistics for the current user.
126
+ """
127
+ url = "/api/shortlinks/stats/"
128
+ response = await self._client.get(url)
129
+ if not response.is_success:
130
+ try:
131
+ error_body = response.json()
132
+ except Exception:
133
+ error_body = response.text
134
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
135
+ return ShortLinkStats.model_validate(response.json())
136
+
137
+
@@ -0,0 +1,153 @@
1
+ # Auto-generated by DjangoCFG - see CLAUDE.md
2
+ from __future__ import annotations
3
+
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+
10
+ class ShortLinkList(BaseModel):
11
+ """
12
+ Serializer for listing short links.
13
+
14
+ Response model (includes read-only fields).
15
+ """
16
+
17
+ model_config = ConfigDict(
18
+ validate_assignment=True,
19
+ extra="allow",
20
+ frozen=False,
21
+ )
22
+
23
+ id: Any = ...
24
+ code: Any = Field(description='Short code for the URL')
25
+ custom_slug: Any | None = Field(None, description='Custom slug (optional)')
26
+ target_url: Any = Field(description='Target URL to redirect to')
27
+ short_url: Any = ...
28
+ is_active: bool = Field(description='Whether the link is active')
29
+ is_expired: bool = ...
30
+ is_valid: bool = ...
31
+ hit_count: int = Field(description='Number of times the link was accessed')
32
+ max_hits: int | None = Field(None, description='Maximum number of redirects (null = unlimited)')
33
+ expires_at: Any | None = Field(None, description='When the link expires (null = never)')
34
+ created_at: Any = ...
35
+
36
+
37
+
38
+ class PaginatedShortLinkListList(BaseModel):
39
+ """
40
+
41
+ Response model (includes read-only fields).
42
+ """
43
+
44
+ model_config = ConfigDict(
45
+ validate_assignment=True,
46
+ extra="allow",
47
+ frozen=False,
48
+ )
49
+
50
+ count: int = Field(description='Total number of items across all pages')
51
+ page: int = Field(description='Current page number (1-based)')
52
+ pages: int = Field(description='Total number of pages')
53
+ page_size: int = Field(description='Number of items per page')
54
+ has_next: bool = Field(description='Whether there is a next page')
55
+ has_previous: bool = Field(description='Whether there is a previous page')
56
+ next_page: int | None = Field(None, description='Next page number (null if no next page)')
57
+ previous_page: int | None = Field(None, description='Previous page number (null if no previous page)')
58
+ results: list[ShortLinkList] = Field(description='Array of items for current page')
59
+
60
+
61
+
62
+ class ShortLinkCreateRequest(BaseModel):
63
+ """
64
+ Serializer for creating short links.
65
+
66
+ Request model (no read-only fields).
67
+ """
68
+
69
+ model_config = ConfigDict(
70
+ validate_assignment=True,
71
+ extra="allow",
72
+ frozen=False,
73
+ )
74
+
75
+ target_url: str = Field(min_length=1, max_length=2000)
76
+ custom_slug: str | None = Field(None, min_length=1, max_length=50)
77
+ expires_at: str | None = None
78
+ max_hits: int | None = Field(None, ge=1)
79
+ metadata: dict[str, Any] | None = None
80
+
81
+
82
+
83
+ class ShortLinkCreate(BaseModel):
84
+ """
85
+ Serializer for creating short links.
86
+
87
+ Response model (includes read-only fields).
88
+ """
89
+
90
+ model_config = ConfigDict(
91
+ validate_assignment=True,
92
+ extra="allow",
93
+ frozen=False,
94
+ )
95
+
96
+ target_url: str = Field(max_length=2000)
97
+ custom_slug: str | None = Field(None, max_length=50)
98
+ expires_at: str | None = None
99
+ max_hits: int | None = Field(None, ge=1)
100
+ metadata: dict[str, Any] | None = None
101
+
102
+
103
+
104
+ class ShortLinkDetail(BaseModel):
105
+ """
106
+ Serializer for short link details.
107
+
108
+ Response model (includes read-only fields).
109
+ """
110
+
111
+ model_config = ConfigDict(
112
+ validate_assignment=True,
113
+ extra="allow",
114
+ frozen=False,
115
+ )
116
+
117
+ id: Any = ...
118
+ code: Any = Field(description='Short code for the URL')
119
+ custom_slug: Any | None = Field(None, description='Custom slug (optional)')
120
+ target_url: Any = Field(description='Target URL to redirect to')
121
+ short_url: Any = ...
122
+ is_active: bool = Field(description='Whether the link is active')
123
+ is_expired: bool = ...
124
+ is_valid: bool = ...
125
+ hit_count: int = Field(description='Number of times the link was accessed')
126
+ max_hits: int | None = Field(None, description='Maximum number of redirects (null = unlimited)')
127
+ expires_at: Any | None = Field(None, description='When the link expires (null = never)')
128
+ created_at: Any = ...
129
+ last_hit_at: str | None = Field(None, description='Last time the link was accessed')
130
+ metadata: dict[str, Any] | None = Field(None, description='Additional metadata (e.g., title, description)')
131
+ updated_at: Any = ...
132
+
133
+
134
+
135
+ class ShortLinkStats(BaseModel):
136
+ """
137
+ Serializer for shortlink statistics.
138
+
139
+ Response model (includes read-only fields).
140
+ """
141
+
142
+ model_config = ConfigDict(
143
+ validate_assignment=True,
144
+ extra="allow",
145
+ frozen=False,
146
+ )
147
+
148
+ total_links: int = Field(description='Total number of short links')
149
+ active_links: int = Field(description='Number of active links')
150
+ total_hits: int = Field(description='Total hit count across all links')
151
+
152
+
153
+
@@ -0,0 +1,136 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+
5
+ from .models import *
6
+
7
+
8
+ class SyncShortlinksShortlinksAPI:
9
+ """Synchronous API endpoints for Shortlinks."""
10
+
11
+ def __init__(self, client: httpx.Client):
12
+ """Initialize sync sub-client with shared httpx client."""
13
+ self._client = client
14
+
15
+ def list(self, page: int | None = None, page_size: int | None = None) -> list[PaginatedShortLinkListList]:
16
+ """
17
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
18
+ List user's short links - POST /api/shortlinks/ - Create a new short
19
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
20
+ /api/shortlinks/{code}/ - Deactivate short link - GET
21
+ /api/shortlinks/stats/ - Get link statistics
22
+ """
23
+ url = "/api/shortlinks/"
24
+ response = self._client.get(url, params={"page": page if page is not None else None, "page_size": page_size if page_size is not None else None})
25
+ if not response.is_success:
26
+ try:
27
+ error_body = response.json()
28
+ except Exception:
29
+ error_body = response.text
30
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
31
+ return PaginatedShortLinkListList.model_validate(response.json())
32
+
33
+
34
+ def create(self, data: ShortLinkCreateRequest) -> ShortLinkCreate:
35
+ """
36
+ Create a new short link.
37
+ """
38
+ url = "/api/shortlinks/"
39
+ response = self._client.post(url, json=data.model_dump(exclude_unset=True))
40
+ if not response.is_success:
41
+ try:
42
+ error_body = response.json()
43
+ except Exception:
44
+ error_body = response.text
45
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
46
+ return ShortLinkCreate.model_validate(response.json())
47
+
48
+
49
+ def retrieve(self, code: str) -> ShortLinkDetail:
50
+ """
51
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
52
+ List user's short links - POST /api/shortlinks/ - Create a new short
53
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
54
+ /api/shortlinks/{code}/ - Deactivate short link - GET
55
+ /api/shortlinks/stats/ - Get link statistics
56
+ """
57
+ url = f"/api/shortlinks/{code}/"
58
+ response = self._client.get(url)
59
+ if not response.is_success:
60
+ try:
61
+ error_body = response.json()
62
+ except Exception:
63
+ error_body = response.text
64
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
65
+ return ShortLinkDetail.model_validate(response.json())
66
+
67
+
68
+ def update(self, code: str) -> ShortLinkList:
69
+ """
70
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
71
+ List user's short links - POST /api/shortlinks/ - Create a new short
72
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
73
+ /api/shortlinks/{code}/ - Deactivate short link - GET
74
+ /api/shortlinks/stats/ - Get link statistics
75
+ """
76
+ url = f"/api/shortlinks/{code}/"
77
+ response = self._client.put(url)
78
+ if not response.is_success:
79
+ try:
80
+ error_body = response.json()
81
+ except Exception:
82
+ error_body = response.text
83
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
84
+ return ShortLinkList.model_validate(response.json())
85
+
86
+
87
+ def partial_update(self, code: str) -> ShortLinkList:
88
+ """
89
+ ViewSet for short link management. Endpoints: - GET /api/shortlinks/ -
90
+ List user's short links - POST /api/shortlinks/ - Create a new short
91
+ link - GET /api/shortlinks/{code}/ - Get short link details - DELETE
92
+ /api/shortlinks/{code}/ - Deactivate short link - GET
93
+ /api/shortlinks/stats/ - Get link statistics
94
+ """
95
+ url = f"/api/shortlinks/{code}/"
96
+ response = self._client.patch(url)
97
+ if not response.is_success:
98
+ try:
99
+ error_body = response.json()
100
+ except Exception:
101
+ error_body = response.text
102
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
103
+ return ShortLinkList.model_validate(response.json())
104
+
105
+
106
+ def destroy(self, code: str) -> None:
107
+ """
108
+ Deactivate a short link.
109
+ """
110
+ url = f"/api/shortlinks/{code}/"
111
+ response = self._client.delete(url)
112
+ if not response.is_success:
113
+ try:
114
+ error_body = response.json()
115
+ except Exception:
116
+ error_body = response.text
117
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
118
+
119
+
120
+ def stats_retrieve(self) -> ShortLinkStats:
121
+ """
122
+ Get shortlink statistics
123
+
124
+ Get shortlink statistics for the current user.
125
+ """
126
+ url = "/api/shortlinks/stats/"
127
+ response = self._client.get(url)
128
+ if not response.is_success:
129
+ try:
130
+ error_body = response.json()
131
+ except Exception:
132
+ error_body = response.text
133
+ raise httpx.HTTPStatusError(f"{response.status_code}: {error_body}", request=response.request, response=response)
134
+ return ShortLinkStats.model_validate(response.json())
135
+
136
+
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Optional
4
+
5
+ import httpx
6
+
7
+ from .shortlinks__api__shortlinks.sync_client import SyncShortlinksShortlinksAPI
8
+ from .logger import APILogger, LoggerConfig
9
+ from .retry import RetryConfig, RetryAsyncClient
10
+
11
+
12
+ class SyncAPIClient:
13
+ """
14
+ Synchronous API client for SDKRouter API.
15
+
16
+ Usage:
17
+ >>> with SyncAPIClient(base_url='https://api.example.com') as client:
18
+ ... users = client.users.list()
19
+ ... post = client.posts.create(data=new_post)
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ base_url: str,
25
+ logger_config: Optional[LoggerConfig] = None,
26
+ **kwargs: Any,
27
+ ):
28
+ """
29
+ Initialize sync API client.
30
+
31
+ Args:
32
+ base_url: Base API URL (e.g., 'https://api.example.com')
33
+ logger_config: Logger configuration (None to disable logging)
34
+ **kwargs: Additional httpx.Client kwargs
35
+ """
36
+ self.base_url = base_url.rstrip('/')
37
+ self._client = httpx.Client(
38
+ base_url=self.base_url,
39
+ **kwargs,
40
+ )
41
+
42
+ # Initialize logger
43
+ self.logger: Optional[APILogger] = None
44
+ if logger_config is not None:
45
+ self.logger = APILogger(logger_config)
46
+
47
+ # Initialize sub-clients
48
+ self.shortlinks_shortlinks = SyncShortlinksShortlinksAPI(self._client)
49
+
50
+ def __enter__(self) -> 'SyncAPIClient':
51
+ return self
52
+
53
+ def __exit__(self, *args: Any) -> None:
54
+ self._client.close()
55
+
56
+ def close(self) -> None:
57
+ """Close HTTP client."""
58
+ self._client.close()
@@ -0,0 +1,212 @@
1
+ # Auto-generated by DjangoCFG - see CLAUDE.md
2
+ """
3
+ SDKRouter API - API Client with JWT Management
4
+
5
+ Usage:
6
+ >>> from api import API
7
+ >>>
8
+ >>> api = API('https://api.example.com')
9
+ >>>
10
+ >>> # Set JWT token
11
+ >>> api.set_token('your-jwt-token', 'refresh-token')
12
+ >>>
13
+ >>> # Use API
14
+ >>> async with api:
15
+ ... posts = await api.posts.list()
16
+ ... user = await api.users.retrieve(1)
17
+ >>>
18
+ >>> # Check authentication
19
+ >>> if api.is_authenticated():
20
+ ... # ...
21
+ >>>
22
+ >>> # Get OpenAPI schema path
23
+ >>> schema_path = api.get_schema_path()
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import threading
29
+ from typing import Any
30
+
31
+ import httpx
32
+
33
+ from .client import APIClient
34
+ from .logger import LoggerConfig
35
+ from .retry import RetryConfig
36
+ from .vision__api__vision import VisionVisionAPI
37
+ from . import enums
38
+ # NOTE: Individual enum imports commented out due to invalid Python syntax with dotted names
39
+ # from .enums import OCRRequestRequest.mode, VisionAnalyzeRequestRequest.model_quality
40
+
41
+ TOKEN_KEY = "auth_token"
42
+ REFRESH_TOKEN_KEY = "refresh_token"
43
+
44
+ # Auto-generated by DjangoCFG - see CLAUDE.md
45
+ class API:
46
+ """
47
+ API Client wrapper with JWT token management.
48
+
49
+ This class provides:
50
+ - Thread-safe JWT token storage
51
+ - Automatic Authorization header injection
52
+ - Context manager support for async operations
53
+ - Optional retry and logging configuration
54
+
55
+ Example:
56
+ >>> api = API('https://api.example.com')
57
+ >>> api.set_token('jwt-token')
58
+ >>> async with api:
59
+ ... users = await api.users.list()
60
+ >>>
61
+ >>> # With retry and logging
62
+ >>> api = API(
63
+ ... 'https://api.example.com',
64
+ ... retry_config=RetryConfig(max_attempts=5),
65
+ ... logger_config=LoggerConfig(enabled=True)
66
+ ... )
67
+ """
68
+
69
+ def __init__(
70
+ self,
71
+ base_url: str,
72
+ logger_config: LoggerConfig | None = None,
73
+ retry_config: RetryConfig | None = None,
74
+ **kwargs: Any
75
+ ):
76
+ """
77
+ Initialize API client.
78
+
79
+ Args:
80
+ base_url: Base API URL (e.g., 'https://api.example.com')
81
+ logger_config: Logger configuration (None to disable logging)
82
+ retry_config: Retry configuration (None to disable retry)
83
+ **kwargs: Additional httpx.AsyncClient kwargs
84
+ """
85
+ self.base_url = base_url.rstrip('/')
86
+ self._kwargs = kwargs
87
+ self._logger_config = logger_config
88
+ self._retry_config = retry_config
89
+ self._token: str | None = None
90
+ self._refresh_token: str | None = None
91
+ self._lock = threading.Lock()
92
+ self._client: APIClient | None = None
93
+ self._init_clients()
94
+
95
+ def _init_clients(self) -> None:
96
+ """Initialize API client with current token."""
97
+ # Create httpx client with auth header if token exists
98
+ headers = {}
99
+ if self._token:
100
+ headers['Authorization'] = f'Bearer {self._token}'
101
+
102
+ kwargs = {**self._kwargs}
103
+ if headers:
104
+ kwargs['headers'] = headers
105
+
106
+ # Create new APIClient
107
+ self._client = APIClient(
108
+ self.base_url,
109
+ logger_config=self._logger_config,
110
+ retry_config=self._retry_config,
111
+ **kwargs
112
+ )
113
+
114
+ @property
115
+ def vision_vision(self) -> VisionVisionAPI:
116
+ """Access vision endpoints."""
117
+ return self._client.vision_vision
118
+
119
+ def get_token(self) -> str | None:
120
+ """Get current JWT token."""
121
+ with self._lock:
122
+ return self._token
123
+
124
+ def get_refresh_token(self) -> str | None:
125
+ """Get current refresh token."""
126
+ with self._lock:
127
+ return self._refresh_token
128
+
129
+ def set_token(self, token: str, refresh_token: str | None = None) -> None:
130
+ """
131
+ Set JWT token and refresh token.
132
+
133
+ Args:
134
+ token: JWT access token
135
+ refresh_token: JWT refresh token (optional)
136
+ """
137
+ with self._lock:
138
+ self._token = token
139
+ if refresh_token:
140
+ self._refresh_token = refresh_token
141
+
142
+ # Reinitialize clients with new token
143
+ self._init_clients()
144
+
145
+ def clear_tokens(self) -> None:
146
+ """Clear all tokens."""
147
+ with self._lock:
148
+ self._token = None
149
+ self._refresh_token = None
150
+
151
+ # Reinitialize clients without token
152
+ self._init_clients()
153
+
154
+ def is_authenticated(self) -> bool:
155
+ """Check if user is authenticated."""
156
+ return self.get_token() is not None
157
+
158
+ def set_base_url(self, url: str) -> None:
159
+ """
160
+ Update base URL and reinitialize clients.
161
+
162
+ Args:
163
+ url: New base URL
164
+ """
165
+ self.base_url = url.rstrip('/')
166
+ self._init_clients()
167
+
168
+ def get_base_url(self) -> str:
169
+ """Get current base URL."""
170
+ return self.base_url
171
+
172
+ def get_schema_path(self) -> str:
173
+ """
174
+ Get OpenAPI schema path.
175
+
176
+ Returns:
177
+ Path to the OpenAPI schema JSON file
178
+
179
+ Note:
180
+ The OpenAPI schema is available in the schema.json file.
181
+ You can load it dynamically using:
182
+ ```python
183
+ import json
184
+ from pathlib import Path
185
+
186
+ schema_path = Path(__file__).parent / 'schema.json'
187
+ with open(schema_path) as f:
188
+ schema = json.load(f)
189
+ ```
190
+ """
191
+ return './schema.json'
192
+
193
+ async def __aenter__(self) -> 'API':
194
+ """Async context manager entry."""
195
+ if self._client:
196
+ await self._client.__aenter__()
197
+ return self
198
+
199
+ async def __aexit__(self, *args: Any) -> None:
200
+ """Async context manager exit."""
201
+ if self._client:
202
+ await self._client.__aexit__(*args)
203
+
204
+ async def close(self) -> None:
205
+ """Close HTTP client."""
206
+ if self._client:
207
+ await self._client.close()
208
+
209
+ __all__ = [
210
+ "API",
211
+ "APIClient",
212
+ ]