django-cfg 1.4.10__py3-none-any.whl → 1.4.13__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 (225) hide show
  1. django_cfg/apps/agents/management/commands/create_agent.py +1 -1
  2. django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
  3. django_cfg/apps/newsletter/serializers.py +40 -3
  4. django_cfg/apps/newsletter/views/campaigns.py +12 -3
  5. django_cfg/apps/newsletter/views/emails.py +14 -3
  6. django_cfg/apps/newsletter/views/subscriptions.py +12 -2
  7. django_cfg/apps/payments/views/api/currencies.py +49 -6
  8. django_cfg/apps/payments/views/api/webhooks.py +72 -7
  9. django_cfg/apps/payments/views/overview/serializers.py +34 -1
  10. django_cfg/apps/payments/views/overview/views.py +2 -1
  11. django_cfg/apps/payments/views/serializers/payments.py +6 -6
  12. django_cfg/apps/urls.py +106 -45
  13. django_cfg/core/base/config_model.py +2 -2
  14. django_cfg/core/constants.py +1 -1
  15. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  16. django_cfg/core/generation/integration_generators/api.py +73 -49
  17. django_cfg/core/integration/display/startup.py +30 -22
  18. django_cfg/core/integration/url_integration.py +15 -16
  19. django_cfg/management/commands/check_endpoints.py +11 -160
  20. django_cfg/management/commands/check_settings.py +13 -348
  21. django_cfg/management/commands/clear_constance.py +13 -201
  22. django_cfg/management/commands/create_token.py +13 -321
  23. django_cfg/management/commands/generate_clients.py +23 -0
  24. django_cfg/management/commands/list_urls.py +13 -306
  25. django_cfg/management/commands/migrate_all.py +13 -126
  26. django_cfg/management/commands/migrator.py +13 -396
  27. django_cfg/management/commands/rundramatiq.py +15 -247
  28. django_cfg/management/commands/rundramatiq_simulator.py +12 -429
  29. django_cfg/management/commands/runserver_ngrok.py +15 -160
  30. django_cfg/management/commands/script.py +12 -488
  31. django_cfg/management/commands/show_config.py +12 -215
  32. django_cfg/management/commands/show_urls.py +12 -342
  33. django_cfg/management/commands/superuser.py +15 -295
  34. django_cfg/management/commands/task_clear.py +14 -217
  35. django_cfg/management/commands/task_status.py +13 -248
  36. django_cfg/management/commands/test_email.py +15 -86
  37. django_cfg/management/commands/test_telegram.py +14 -61
  38. django_cfg/management/commands/test_twilio.py +15 -105
  39. django_cfg/management/commands/tree.py +13 -383
  40. django_cfg/management/commands/validate_openapi.py +10 -0
  41. django_cfg/middleware/README.md +1 -1
  42. django_cfg/middleware/user_activity.py +3 -3
  43. django_cfg/models/__init__.py +2 -2
  44. django_cfg/models/api/drf/spectacular.py +6 -6
  45. django_cfg/models/django/__init__.py +2 -2
  46. django_cfg/models/django/openapi.py +162 -0
  47. django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
  48. django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
  49. django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
  50. django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
  51. django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
  52. django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
  53. django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
  54. django_cfg/modules/django_admin/management/commands/script.py +496 -0
  55. django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
  56. django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
  57. django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
  58. django_cfg/modules/django_admin/management/commands/tree.py +390 -0
  59. django_cfg/modules/django_client/__init__.py +20 -0
  60. django_cfg/modules/django_client/apps.py +35 -0
  61. django_cfg/modules/django_client/core/__init__.py +56 -0
  62. django_cfg/modules/django_client/core/archive/__init__.py +11 -0
  63. django_cfg/modules/django_client/core/archive/manager.py +134 -0
  64. django_cfg/modules/django_client/core/cli/__init__.py +12 -0
  65. django_cfg/modules/django_client/core/cli/main.py +235 -0
  66. django_cfg/modules/django_client/core/config/__init__.py +18 -0
  67. django_cfg/modules/django_client/core/config/config.py +208 -0
  68. django_cfg/modules/django_client/core/config/group.py +101 -0
  69. django_cfg/modules/django_client/core/config/service.py +209 -0
  70. django_cfg/modules/django_client/core/generator/__init__.py +115 -0
  71. django_cfg/modules/django_client/core/generator/base.py +838 -0
  72. django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
  73. django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
  74. django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
  75. django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
  76. django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
  77. django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
  78. django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
  79. django_cfg/modules/django_client/core/generator/python/templates/__init__.py.jinja +9 -0
  80. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +153 -0
  81. django_cfg/modules/django_client/core/generator/python/templates/app_init.py.jinja +6 -0
  82. django_cfg/modules/django_client/core/generator/python/templates/client/app_client.py.jinja +18 -0
  83. django_cfg/modules/django_client/core/generator/python/templates/client/flat_client.py.jinja +38 -0
  84. django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +68 -0
  85. django_cfg/modules/django_client/core/generator/python/templates/client/main_client_file.py.jinja +14 -0
  86. django_cfg/modules/django_client/core/generator/python/templates/client/operation_method.py.jinja +9 -0
  87. django_cfg/modules/django_client/core/generator/python/templates/client/sub_client.py.jinja +18 -0
  88. django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
  89. django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
  90. django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
  91. django_cfg/modules/django_client/core/generator/python/templates/client_file.py.jinja +13 -0
  92. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +52 -0
  93. django_cfg/modules/django_client/core/generator/python/templates/models/app_models.py.jinja +17 -0
  94. django_cfg/modules/django_client/core/generator/python/templates/models/enum_class.py.jinja +17 -0
  95. django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +8 -0
  96. django_cfg/modules/django_client/core/generator/python/templates/models/models.py.jinja +17 -0
  97. django_cfg/modules/django_client/core/generator/python/templates/models/schema_class.py.jinja +21 -0
  98. django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
  99. django_cfg/modules/django_client/core/generator/python/templates/utils/logger.py.jinja +255 -0
  100. django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
  101. django_cfg/modules/django_client/core/generator/python/templates/utils/schema.py.jinja +12 -0
  102. django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
  103. django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
  104. django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
  105. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
  106. django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
  107. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +536 -0
  108. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
  109. django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
  110. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
  111. django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
  112. django_cfg/modules/django_client/core/generator/typescript/templates/app_index.ts.jinja +2 -0
  113. django_cfg/modules/django_client/core/generator/typescript/templates/client/app_client.ts.jinja +18 -0
  114. django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +403 -0
  115. django_cfg/modules/django_client/core/generator/typescript/templates/client/flat_client.ts.jinja +109 -0
  116. django_cfg/modules/django_client/core/generator/typescript/templates/client/main_client_file.ts.jinja +10 -0
  117. django_cfg/modules/django_client/core/generator/typescript/templates/client/operation.ts.jinja +61 -0
  118. django_cfg/modules/django_client/core/generator/typescript/templates/client/sub_client.ts.jinja +15 -0
  119. django_cfg/modules/django_client/core/generator/typescript/templates/client_file.ts.jinja +9 -0
  120. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
  121. django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
  122. django_cfg/modules/django_client/core/generator/typescript/templates/index.ts.jinja +5 -0
  123. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +268 -0
  124. django_cfg/modules/django_client/core/generator/typescript/templates/models/app_models.ts.jinja +8 -0
  125. django_cfg/modules/django_client/core/generator/typescript/templates/models/enums.ts.jinja +4 -0
  126. django_cfg/modules/django_client/core/generator/typescript/templates/models/models.ts.jinja +8 -0
  127. django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
  128. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
  129. django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
  130. django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
  131. django_cfg/modules/django_client/core/generator/typescript/templates/utils/errors.ts.jinja +116 -0
  132. django_cfg/modules/django_client/core/generator/typescript/templates/utils/http.ts.jinja +98 -0
  133. django_cfg/modules/django_client/core/generator/typescript/templates/utils/logger.ts.jinja +259 -0
  134. django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
  135. django_cfg/modules/django_client/core/generator/typescript/templates/utils/schema.ts.jinja +7 -0
  136. django_cfg/modules/django_client/core/generator/typescript/templates/utils/storage.ts.jinja +158 -0
  137. django_cfg/modules/django_client/core/groups/__init__.py +13 -0
  138. django_cfg/modules/django_client/core/groups/detector.py +178 -0
  139. django_cfg/modules/django_client/core/groups/manager.py +314 -0
  140. django_cfg/modules/django_client/core/ir/__init__.py +57 -0
  141. django_cfg/modules/django_client/core/ir/context.py +387 -0
  142. django_cfg/modules/django_client/core/ir/operation.py +518 -0
  143. django_cfg/modules/django_client/core/ir/schema.py +353 -0
  144. django_cfg/modules/django_client/core/parser/__init__.py +74 -0
  145. django_cfg/modules/django_client/core/parser/base.py +648 -0
  146. django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
  147. django_cfg/modules/django_client/core/parser/models/base.py +212 -0
  148. django_cfg/modules/django_client/core/parser/models/components.py +160 -0
  149. django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
  150. django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
  151. django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
  152. django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
  153. django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
  154. django_cfg/modules/django_client/core/validation/__init__.py +22 -0
  155. django_cfg/modules/django_client/core/validation/checker.py +134 -0
  156. django_cfg/modules/django_client/core/validation/fixer.py +216 -0
  157. django_cfg/modules/django_client/core/validation/reporter.py +480 -0
  158. django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
  159. django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
  160. django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
  161. django_cfg/modules/django_client/core/validation/safety.py +266 -0
  162. django_cfg/modules/django_client/management/__init__.py +3 -0
  163. django_cfg/modules/django_client/management/commands/__init__.py +3 -0
  164. django_cfg/modules/django_client/management/commands/generate_client.py +427 -0
  165. django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
  166. django_cfg/modules/django_client/pytest.ini +30 -0
  167. django_cfg/modules/django_client/spectacular/__init__.py +10 -0
  168. django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
  169. django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
  170. django_cfg/modules/django_client/urls.py +72 -0
  171. django_cfg/{dashboard → modules/django_dashboard}/DEBUG_README.md +2 -2
  172. django_cfg/{dashboard → modules/django_dashboard}/REFACTORING_SUMMARY.md +1 -1
  173. django_cfg/modules/django_dashboard/management/__init__.py +0 -0
  174. django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
  175. django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
  176. django_cfg/modules/django_dashboard/sections/documentation.py +391 -0
  177. django_cfg/modules/django_email/management/__init__.py +0 -0
  178. django_cfg/modules/django_email/management/commands/__init__.py +0 -0
  179. django_cfg/modules/django_email/management/commands/test_email.py +93 -0
  180. django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
  181. django_cfg/modules/django_logging/django_logger.py +6 -6
  182. django_cfg/modules/django_ngrok/management/__init__.py +0 -0
  183. django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
  184. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
  185. django_cfg/modules/django_tasks/management/__init__.py +0 -0
  186. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  187. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
  188. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
  189. django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
  190. django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
  191. django_cfg/modules/django_telegram/management/__init__.py +0 -0
  192. django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
  193. django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
  194. django_cfg/modules/django_twilio/management/__init__.py +0 -0
  195. django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
  196. django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
  197. django_cfg/modules/django_unfold/callbacks/main.py +21 -10
  198. django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
  199. django_cfg/pyproject.toml +2 -6
  200. django_cfg/registry/third_party.py +5 -7
  201. django_cfg/routing/callbacks.py +1 -1
  202. django_cfg/static/admin/css/prose-unfold.css +666 -0
  203. django_cfg/templates/admin/index.html +8 -0
  204. django_cfg/templates/admin/index_new.html +13 -0
  205. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
  206. django_cfg/templates/admin/sections/documentation_section.html +172 -0
  207. django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
  208. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/METADATA +2 -2
  209. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/RECORD +224 -74
  210. django_cfg/management/commands/generate.py +0 -107
  211. /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
  212. /django_cfg/{dashboard → modules/django_admin}/management/__init__.py +0 -0
  213. /django_cfg/{dashboard → modules/django_admin}/management/commands/__init__.py +0 -0
  214. /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
  215. /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
  216. /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
  217. /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
  218. /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
  219. /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
  220. /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
  221. /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
  222. /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
  223. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/WHEEL +0 -0
  224. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/entry_points.txt +0 -0
  225. {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,268 @@
1
+ /**
2
+ * {{ api_title }} - API Client with JWT Management
3
+ *
4
+ * Usage:
5
+ * ```typescript
6
+ * import { API } from './api';
7
+ *
8
+ * const api = new API('https://api.example.com');
9
+ *
10
+ * // Set JWT token
11
+ * api.setToken('your-jwt-token', 'refresh-token');
12
+ *
13
+ * // Use API
14
+ * const posts = await api.posts.list();
15
+ * const user = await api.users.retrieve(1);
16
+ *
17
+ * // Check authentication
18
+ * if (api.isAuthenticated()) {
19
+ * // ...
20
+ * }
21
+ *
22
+ * // Custom storage with logging (for Electron/Node.js)
23
+ * import { MemoryStorageAdapter, APILogger } from './storage';
24
+ * const logger = new APILogger({ enabled: true, logLevel: 'debug' });
25
+ * const api = new API('https://api.example.com', {
26
+ * storage: new MemoryStorageAdapter(logger),
27
+ * loggerConfig: { enabled: true, logLevel: 'debug' }
28
+ * });
29
+ *
30
+ * // Get OpenAPI schema
31
+ * const schema = api.getSchema();
32
+ * ```
33
+ */
34
+
35
+ import { APIClient } from "./client";
36
+ import { OPENAPI_SCHEMA } from "./schema";
37
+ import {
38
+ StorageAdapter,
39
+ LocalStorageAdapter,
40
+ CookieStorageAdapter,
41
+ MemoryStorageAdapter
42
+ } from "./storage";
43
+ import type { RetryConfig } from "./retry";
44
+ import type { LoggerConfig } from "./logger";
45
+ import { APILogger } from "./logger";
46
+ {% for tag in tags %}
47
+ export * as {{ tag.class_name }}Types from "./{{ tag.slug }}/models";
48
+ {% endfor %}
49
+ {% if has_enums %}
50
+ export * as Enums from "./enums";
51
+ {% endif %}
52
+ {% if generate_zod_schemas %}
53
+
54
+ // Re-export Zod schemas for runtime validation
55
+ export * as Schemas from "./_utils/schemas";
56
+ {% endif %}
57
+ {% if generate_fetchers %}
58
+
59
+ // Re-export typed fetchers for universal usage
60
+ export * as Fetchers from "./_utils/fetchers";
61
+
62
+ // Re-export API instance configuration functions
63
+ export {
64
+ configureAPI,
65
+ getAPIInstance,
66
+ reconfigureAPI,
67
+ clearAPITokens,
68
+ resetAPI,
69
+ isAPIConfigured
70
+ } from "./api-instance";
71
+ {% endif %}
72
+ {% if generate_swr_hooks %}
73
+
74
+ // Re-export SWR hooks for React
75
+ export * as Hooks from "./_utils/hooks";
76
+ {% endif %}
77
+
78
+ // Re-export core client
79
+ export { APIClient };
80
+
81
+ // Re-export OpenAPI schema
82
+ export { OPENAPI_SCHEMA };
83
+
84
+ // Re-export storage adapters for convenience
85
+ export type { StorageAdapter };
86
+ export { LocalStorageAdapter, CookieStorageAdapter, MemoryStorageAdapter };
87
+
88
+ // Re-export error classes for convenience
89
+ export { APIError, NetworkError } from "./errors";
90
+
91
+ // Re-export HTTP adapters for custom implementations
92
+ export type { HttpClientAdapter, HttpRequest, HttpResponse } from "./http";
93
+ export { FetchAdapter } from "./http";
94
+
95
+ // Re-export logger types and classes
96
+ export type { LoggerConfig, RequestLog, ResponseLog, ErrorLog } from "./logger";
97
+ export { APILogger } from "./logger";
98
+
99
+ // Re-export retry configuration and utilities
100
+ export type { RetryConfig, FailedAttemptInfo } from "./retry";
101
+ export { withRetry, shouldRetry, DEFAULT_RETRY_CONFIG } from "./retry";
102
+
103
+ export const TOKEN_KEY = "auth_token";
104
+ export const REFRESH_TOKEN_KEY = "refresh_token";
105
+
106
+ export interface APIOptions {
107
+ /** Custom storage adapter (defaults to LocalStorageAdapter) */
108
+ storage?: StorageAdapter;
109
+ /** Retry configuration for failed requests */
110
+ retryConfig?: RetryConfig;
111
+ /** Logger configuration */
112
+ loggerConfig?: Partial<LoggerConfig>;
113
+ }
114
+
115
+ export class API {
116
+ private baseUrl: string;
117
+ private _client!: APIClient;
118
+ private _token: string | null = null;
119
+ private _refreshToken: string | null = null;
120
+ private storage: StorageAdapter;
121
+ private options?: APIOptions;
122
+
123
+ // Sub-clients
124
+ {% for tag in tags %}
125
+ public {{ tag.property }}!: APIClient['{{ tag.property }}'];
126
+ {% endfor %}
127
+
128
+ constructor(baseUrl: string, options?: APIOptions) {
129
+ this.baseUrl = baseUrl;
130
+ this.options = options;
131
+
132
+ // Create logger if config provided
133
+ const logger = options?.loggerConfig ? new APILogger(options.loggerConfig) : undefined;
134
+
135
+ // Initialize storage with logger
136
+ this.storage = options?.storage || new LocalStorageAdapter(logger);
137
+
138
+ this._loadTokensFromStorage();
139
+ this._initClients();
140
+ }
141
+
142
+ private _loadTokensFromStorage(): void {
143
+ this._token = this.storage.getItem(TOKEN_KEY);
144
+ this._refreshToken = this.storage.getItem(REFRESH_TOKEN_KEY);
145
+ }
146
+
147
+ private _initClients(): void {
148
+ this._client = new APIClient(this.baseUrl, {
149
+ retryConfig: (this as any).options?.retryConfig,
150
+ loggerConfig: (this as any).options?.loggerConfig,
151
+ });
152
+
153
+ // Inject Authorization header if token exists
154
+ if (this._token) {
155
+ this._injectAuthHeader();
156
+ }
157
+
158
+ // Proxy sub-clients
159
+ {% for tag in tags %}
160
+ this.{{ tag.property }} = this._client.{{ tag.property }};
161
+ {% endfor %}
162
+ }
163
+
164
+ private _injectAuthHeader(): void {
165
+ // Override request method to inject auth header
166
+ const originalRequest = this._client.request.bind(this._client);
167
+ this._client.request = async <T>(
168
+ method: string,
169
+ path: string,
170
+ options?: { params?: Record<string, any>; body?: any }
171
+ ): Promise<T> => {
172
+ const headers: Record<string, string> = {};
173
+
174
+ if (this._token) {
175
+ headers['Authorization'] = `Bearer ${this._token}`;
176
+ }
177
+
178
+ // Merge with existing options
179
+ const mergedOptions = {
180
+ ...options,
181
+ headers: {
182
+ ...(options as any)?.headers,
183
+ ...headers,
184
+ },
185
+ };
186
+
187
+ return originalRequest(method, path, mergedOptions);
188
+ };
189
+ }
190
+
191
+ /**
192
+ * Get current JWT token
193
+ */
194
+ getToken(): string | null {
195
+ return this.storage.getItem(TOKEN_KEY);
196
+ }
197
+
198
+ /**
199
+ * Get current refresh token
200
+ */
201
+ getRefreshToken(): string | null {
202
+ return this.storage.getItem(REFRESH_TOKEN_KEY);
203
+ }
204
+
205
+ /**
206
+ * Set JWT token and refresh token
207
+ * @param token - JWT access token
208
+ * @param refreshToken - JWT refresh token (optional)
209
+ */
210
+ setToken(token: string, refreshToken?: string): void {
211
+ this._token = token;
212
+ this.storage.setItem(TOKEN_KEY, token);
213
+
214
+ if (refreshToken) {
215
+ this._refreshToken = refreshToken;
216
+ this.storage.setItem(REFRESH_TOKEN_KEY, refreshToken);
217
+ }
218
+
219
+ // Reinitialize clients with new token
220
+ this._initClients();
221
+ }
222
+
223
+ /**
224
+ * Clear all tokens
225
+ */
226
+ clearTokens(): void {
227
+ this._token = null;
228
+ this._refreshToken = null;
229
+ this.storage.removeItem(TOKEN_KEY);
230
+ this.storage.removeItem(REFRESH_TOKEN_KEY);
231
+
232
+ // Reinitialize clients without token
233
+ this._initClients();
234
+ }
235
+
236
+ /**
237
+ * Check if user is authenticated
238
+ */
239
+ isAuthenticated(): boolean {
240
+ return !!this.getToken();
241
+ }
242
+
243
+ /**
244
+ * Update base URL and reinitialize clients
245
+ * @param url - New base URL
246
+ */
247
+ setBaseUrl(url: string): void {
248
+ this.baseUrl = url;
249
+ this._initClients();
250
+ }
251
+
252
+ /**
253
+ * Get current base URL
254
+ */
255
+ getBaseUrl(): string {
256
+ return this.baseUrl;
257
+ }
258
+
259
+ /**
260
+ * Get OpenAPI schema
261
+ * @returns Complete OpenAPI specification for this API
262
+ */
263
+ getSchema(): any {
264
+ return OPENAPI_SCHEMA;
265
+ }
266
+ }
267
+
268
+ export default API;
@@ -0,0 +1,8 @@
1
+ {% if has_enums %}
2
+ import * as Enums from "../enums";
3
+
4
+ {% endif %}
5
+ {% for schema in schemas %}
6
+ {{ schema }}
7
+
8
+ {% endfor %}
@@ -0,0 +1,4 @@
1
+ {% for enum in enums %}
2
+ {{ enum }}
3
+
4
+ {% endfor %}
@@ -0,0 +1,8 @@
1
+ {% if has_enums %}
2
+ import * as Enums from "./enums";
3
+
4
+ {% endif %}
5
+ {% for schema in schemas %}
6
+ {{ schema }}
7
+
8
+ {% endfor %}
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "{{ package_name }}",
3
+ "version": "{{ version }}",
4
+ "description": "{{ description }}",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "prepublishOnly": "npm run build",
21
+ "test": "vitest",
22
+ "lint": "eslint src/",
23
+ "format": "prettier --write src/"
24
+ },
25
+ "keywords": {{ keywords | tojson }},
26
+ {% if author %}"author": "{{ author }}",{% endif %}
27
+ "license": "{{ license }}",
28
+ {% if repository_url %}"repository": {
29
+ "type": "git",
30
+ "url": "{{ repository_url }}"
31
+ },{% endif %}
32
+ "dependencies": {
33
+ "p-retry": "^7.0.0",
34
+ "consola": "^3.4.2"{% if generate_zod_schemas %},
35
+ "zod": "^3.23.0"{% endif %}{% if generate_swr_hooks %},
36
+ "swr": "^2.2.0"{% endif %}
37
+ },{% if generate_swr_hooks %}
38
+ "peerDependencies": {
39
+ "react": "^18.0.0 || ^19.0.0"
40
+ },{% endif %}
41
+ "devDependencies": {
42
+ "@types/node": "^22.0.0",
43
+ "typescript": "^5.9.0",
44
+ "vitest": "^3.0.0",
45
+ "eslint": "^9.0.0",
46
+ "prettier": "^3.0.0"
47
+ },
48
+ "engines": {
49
+ "node": ">=18.0.0"
50
+ }{% if private %},
51
+ "private": true{% endif %}
52
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Zod Schemas - Runtime validation and type inference
3
+ *
4
+ * Auto-generated from OpenAPI specification.
5
+ * Provides runtime validation for API requests and responses.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * import { UserSchema } from './schemas'
10
+ *
11
+ * // Validate data
12
+ * const user = UserSchema.parse(data)
13
+ *
14
+ * // Type inference
15
+ * type User = z.infer<typeof UserSchema>
16
+ * ```
17
+ */
18
+
19
+ {% for schema_name in schema_names %}
20
+ export * from './{{ schema_name }}.schema'
21
+ {% endfor %}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Zod schema for {{ schema_name }}
3
+ *
4
+ * This schema provides runtime validation and type inference.
5
+ * {% if description %}
6
+ * {{ description }}
7
+ * {% endif %}
8
+ */
9
+ import { z } from 'zod'
10
+ {% if has_enums %}
11
+ import * as Enums from '../../enums'
12
+ {% endif %}
13
+ {% if has_refs %}
14
+ {% for ref_name in refs %}
15
+ import { {{ ref_name }}Schema } from './{{ ref_name }}.schema'
16
+ {% endfor %}
17
+ {% endif %}
18
+
19
+ {{ schema_code }}
20
+
21
+ /**
22
+ * Infer TypeScript type from Zod schema
23
+ */
24
+ export type {{ schema_name }} = z.infer<typeof {{ schema_name }}Schema>
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2022", "DOM"],
6
+ "moduleResolution": "bundler",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "sourceMap": true,
10
+ "outDir": "./dist",
11
+ "rootDir": ".",
12
+ "strict": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "forceConsistentCasingInFileNames": true,
16
+ "resolveJsonModule": true
17
+ },
18
+ "include": ["./**/*.ts"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * API Error Classes
3
+ *
4
+ * Typed error classes with Django REST Framework support.
5
+ */
6
+
7
+ /**
8
+ * HTTP API Error with DRF field-specific validation errors.
9
+ *
10
+ * Usage:
11
+ * ```typescript
12
+ * try {
13
+ * await api.users.create(userData);
14
+ * } catch (error) {
15
+ * if (error instanceof APIError) {
16
+ * if (error.isValidationError) {
17
+ * console.log('Field errors:', error.fieldErrors);
18
+ * // { "email": ["Email already exists"], "username": ["Required"] }
19
+ * }
20
+ * }
21
+ * }
22
+ * ```
23
+ */
24
+ export class APIError extends Error {
25
+ constructor(
26
+ public statusCode: number,
27
+ public statusText: string,
28
+ public response: any,
29
+ public url: string,
30
+ message?: string
31
+ ) {
32
+ super(message || `HTTP ${statusCode}: ${statusText}`);
33
+ this.name = 'APIError';
34
+ }
35
+
36
+ /**
37
+ * Get error details from response.
38
+ * DRF typically returns: { "detail": "Error message" } or { "field": ["error1", "error2"] }
39
+ */
40
+ get details(): Record<string, any> | null {
41
+ if (typeof this.response === 'object' && this.response !== null) {
42
+ return this.response;
43
+ }
44
+ return null;
45
+ }
46
+
47
+ /**
48
+ * Get field-specific validation errors from DRF.
49
+ * Returns: { "field_name": ["error1", "error2"], ... }
50
+ */
51
+ get fieldErrors(): Record<string, string[]> | null {
52
+ const details = this.details;
53
+ if (!details) return null;
54
+
55
+ // DRF typically returns: { "field": ["error1", "error2"] }
56
+ const fieldErrors: Record<string, string[]> = {};
57
+ for (const [key, value] of Object.entries(details)) {
58
+ if (Array.isArray(value)) {
59
+ fieldErrors[key] = value;
60
+ }
61
+ }
62
+
63
+ return Object.keys(fieldErrors).length > 0 ? fieldErrors : null;
64
+ }
65
+
66
+ /**
67
+ * Get single error message from DRF.
68
+ * Checks for "detail", "message", or first field error.
69
+ */
70
+ get errorMessage(): string {
71
+ const details = this.details;
72
+ if (!details) return this.message;
73
+
74
+ // Check for "detail" field (common in DRF)
75
+ if (details.detail) {
76
+ return Array.isArray(details.detail) ? details.detail.join(', ') : String(details.detail);
77
+ }
78
+
79
+ // Check for "message" field
80
+ if (details.message) {
81
+ return String(details.message);
82
+ }
83
+
84
+ // Return first field error
85
+ const fieldErrors = this.fieldErrors;
86
+ if (fieldErrors) {
87
+ const firstField = Object.keys(fieldErrors)[0];
88
+ if (firstField) {
89
+ return `${firstField}: ${fieldErrors[firstField]?.join(', ')}`;
90
+ }
91
+ }
92
+
93
+ return this.message;
94
+ }
95
+
96
+ // Helper methods for common HTTP status codes
97
+ get isValidationError(): boolean { return this.statusCode === 400; }
98
+ get isAuthError(): boolean { return this.statusCode === 401; }
99
+ get isPermissionError(): boolean { return this.statusCode === 403; }
100
+ get isNotFoundError(): boolean { return this.statusCode === 404; }
101
+ get isServerError(): boolean { return this.statusCode >= 500 && this.statusCode < 600; }
102
+ }
103
+
104
+ /**
105
+ * Network Error (connection failed, timeout, etc.)
106
+ */
107
+ export class NetworkError extends Error {
108
+ constructor(
109
+ message: string,
110
+ public url: string,
111
+ public originalError?: Error
112
+ ) {
113
+ super(message);
114
+ this.name = 'NetworkError';
115
+ }
116
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * HTTP Client Adapter Pattern
3
+ *
4
+ * Allows switching between fetch/axios/httpx without changing generated code.
5
+ * Provides unified interface for making HTTP requests.
6
+ */
7
+
8
+ export interface HttpRequest {
9
+ method: string;
10
+ url: string;
11
+ headers?: Record<string, string>;
12
+ body?: any;
13
+ params?: Record<string, any>;
14
+ /** FormData for file uploads (multipart/form-data) */
15
+ formData?: FormData;
16
+ }
17
+
18
+ export interface HttpResponse<T = any> {
19
+ data: T;
20
+ status: number;
21
+ statusText: string;
22
+ headers: Record<string, string>;
23
+ }
24
+
25
+ /**
26
+ * HTTP Client Adapter Interface.
27
+ * Implement this to use custom HTTP clients (axios, httpx, etc.)
28
+ */
29
+ export interface HttpClientAdapter {
30
+ request<T = any>(request: HttpRequest): Promise<HttpResponse<T>>;
31
+ }
32
+
33
+ /**
34
+ * Default Fetch API adapter.
35
+ * Uses native browser fetch() with proper error handling.
36
+ */
37
+ export class FetchAdapter implements HttpClientAdapter {
38
+ async request<T = any>(request: HttpRequest): Promise<HttpResponse<T>> {
39
+ const { method, url, headers, body, params, formData } = request;
40
+
41
+ // Build URL with query params
42
+ const finalUrl = new URL(url);
43
+ if (params) {
44
+ Object.entries(params).forEach(([key, value]) => {
45
+ if (value !== null && value !== undefined) {
46
+ finalUrl.searchParams.append(key, String(value));
47
+ }
48
+ });
49
+ }
50
+
51
+ // Build headers
52
+ const finalHeaders: Record<string, string> = { ...headers };
53
+
54
+ // Determine body and content-type
55
+ let requestBody: string | FormData | undefined;
56
+
57
+ if (formData) {
58
+ // For multipart/form-data, let browser set Content-Type with boundary
59
+ requestBody = formData;
60
+ // Don't set Content-Type - browser will set it with boundary
61
+ } else if (body) {
62
+ // JSON request
63
+ finalHeaders['Content-Type'] = 'application/json';
64
+ requestBody = JSON.stringify(body);
65
+ }
66
+
67
+ // Make request
68
+ const response = await fetch(finalUrl.toString(), {
69
+ method,
70
+ headers: finalHeaders,
71
+ body: requestBody,
72
+ credentials: 'include', // Include Django session cookies
73
+ });
74
+
75
+ // Parse response
76
+ let data: any = null;
77
+ const contentType = response.headers.get('content-type');
78
+
79
+ if (response.status !== 204 && contentType?.includes('application/json')) {
80
+ data = await response.json();
81
+ } else if (response.status !== 204) {
82
+ data = await response.text();
83
+ }
84
+
85
+ // Convert Headers to plain object
86
+ const responseHeaders: Record<string, string> = {};
87
+ response.headers.forEach((value, key) => {
88
+ responseHeaders[key] = value;
89
+ });
90
+
91
+ return {
92
+ data,
93
+ status: response.status,
94
+ statusText: response.statusText,
95
+ headers: responseHeaders,
96
+ };
97
+ }
98
+ }