@djangocfg/api 2.1.88 → 2.1.90
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.
- package/dist/auth-server.cjs +335 -320
- package/dist/auth-server.cjs.map +1 -1
- package/dist/auth-server.mjs +335 -320
- package/dist/auth-server.mjs.map +1 -1
- package/dist/auth.cjs +464 -394
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +464 -394
- package/dist/auth.mjs.map +1 -1
- package/dist/clients.cjs +460 -383
- package/dist/clients.cjs.map +1 -1
- package/dist/clients.d.cts +26 -6
- package/dist/clients.d.ts +26 -6
- package/dist/clients.mjs +460 -383
- package/dist/clients.mjs.map +1 -1
- package/dist/hooks.cjs +130 -105
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +24 -4
- package/dist/hooks.d.ts +24 -4
- package/dist/hooks.mjs +130 -105
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.cjs +373 -311
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -8
- package/dist/index.d.ts +54 -8
- package/dist/index.mjs +373 -311
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/auth/context/AccountsContext.tsx +3 -3
- package/src/auth/hooks/useTokenRefresh.ts +4 -10
- package/src/auth/middlewares/tokenRefresh.ts +4 -15
- package/src/generated/cfg_accounts/CLAUDE.md +2 -9
- package/src/generated/cfg_accounts/_utils/fetchers/accounts__user_profile.ts +2 -1
- package/src/generated/cfg_accounts/_utils/hooks/accounts__user_profile.ts +2 -1
- package/src/generated/cfg_accounts/_utils/schemas/CfgAccountsProfileAvatarCreateRequest.schema.ts +15 -0
- package/src/generated/cfg_accounts/_utils/schemas/index.ts +1 -0
- package/src/generated/cfg_accounts/accounts/models.ts +0 -1
- package/src/generated/cfg_accounts/accounts__user_profile/client.ts +4 -2
- package/src/generated/cfg_accounts/accounts__user_profile/models.ts +9 -1
- package/src/generated/cfg_accounts/client.ts +18 -0
- package/src/generated/cfg_accounts/index.ts +3 -1
- package/src/generated/cfg_accounts/schema.json +2 -2
- package/src/generated/cfg_centrifugo/CLAUDE.md +1 -8
- package/src/generated/cfg_centrifugo/client.ts +18 -0
- package/src/generated/cfg_centrifugo/index.ts +3 -1
- package/src/generated/cfg_totp/CLAUDE.md +1 -8
- package/src/generated/cfg_totp/client.ts +18 -0
- package/src/generated/cfg_totp/index.ts +3 -1
- package/src/generated/cfg_totp/totp/models.ts +2 -0
- package/src/generated/cfg_webpush/CLAUDE.md +1 -8
- package/src/generated/cfg_webpush/client.ts +18 -0
- package/src/generated/cfg_webpush/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/api",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.90",
|
|
4
4
|
"description": "Auto-generated TypeScript API client with React hooks, SWR integration, and Zod validation for Django REST Framework backends",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"check": "tsc --noEmit"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
77
|
+
"@djangocfg/ui-nextjs": "^2.1.90",
|
|
78
78
|
"consola": "^3.4.2",
|
|
79
79
|
"next": "^14 || ^15",
|
|
80
80
|
"p-retry": "^7.0.0",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@types/node": "^24.7.2",
|
|
87
87
|
"@types/react": "^19.0.0",
|
|
88
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
88
|
+
"@djangocfg/typescript-config": "^2.1.90",
|
|
89
89
|
"next": "^15.0.0",
|
|
90
90
|
"react": "^19.0.0",
|
|
91
91
|
"tsup": "^8.5.0",
|
|
@@ -59,7 +59,7 @@ export interface AccountsContextValue {
|
|
|
59
59
|
// Profile operations
|
|
60
60
|
updateProfile: (data: UserProfileUpdateRequest) => Promise<User>;
|
|
61
61
|
partialUpdateProfile: (data: PatchedUserProfileUpdateRequest) => Promise<User>;
|
|
62
|
-
uploadAvatar: (
|
|
62
|
+
uploadAvatar: (avatar: File | Blob) => Promise<User>;
|
|
63
63
|
refreshProfile: (callerId?: string) => Promise<User | undefined>;
|
|
64
64
|
|
|
65
65
|
// Authentication
|
|
@@ -165,8 +165,8 @@ export function AccountsProvider({ children }: AccountsProviderProps) {
|
|
|
165
165
|
};
|
|
166
166
|
|
|
167
167
|
// Upload avatar
|
|
168
|
-
const uploadAvatar = async (
|
|
169
|
-
const result = await avatarMutation(
|
|
168
|
+
const uploadAvatar = async (avatar: File | Blob): Promise<User> => {
|
|
169
|
+
const result = await avatarMutation({ avatar }, apiAccounts);
|
|
170
170
|
await refreshProfile('AccountsContext.uploadAvatar');
|
|
171
171
|
return result as User;
|
|
172
172
|
};
|
|
@@ -75,18 +75,12 @@ export function useTokenRefresh(options: UseTokenRefreshOptions = {}) {
|
|
|
75
75
|
authLogger.info('Refreshing token...');
|
|
76
76
|
|
|
77
77
|
try {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
body: JSON.stringify({ refresh: refreshTokenValue }),
|
|
78
|
+
// Use generated API client with correct URL (/cfg/accounts/token/refresh/)
|
|
79
|
+
const result = await apiAccounts.auth.accountsTokenRefreshCreate({
|
|
80
|
+
refresh: refreshTokenValue,
|
|
82
81
|
});
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
throw new Error(`Token refresh failed: ${response.status}`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const data = await response.json();
|
|
89
|
-
const newAccessToken = data.access;
|
|
83
|
+
const newAccessToken = result.access;
|
|
90
84
|
|
|
91
85
|
if (!newAccessToken) {
|
|
92
86
|
throw new Error('No access token in refresh response');
|
|
@@ -50,23 +50,12 @@ export async function refreshAccessToken(): Promise<string | null> {
|
|
|
50
50
|
return null;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
//
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
headers: {
|
|
57
|
-
'Content-Type': 'application/json',
|
|
58
|
-
},
|
|
59
|
-
body: JSON.stringify({ refresh: refreshToken }),
|
|
53
|
+
// Use generated API client with correct URL (/cfg/accounts/token/refresh/)
|
|
54
|
+
const result = await apiAccounts.auth.accountsTokenRefreshCreate({
|
|
55
|
+
refresh: refreshToken,
|
|
60
56
|
});
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
authLogger.error('Token refresh failed with status:', response.status);
|
|
64
|
-
onTokenRefreshed(null);
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const data = await response.json();
|
|
69
|
-
const newAccessToken = data.access;
|
|
58
|
+
const newAccessToken = result.access;
|
|
70
59
|
|
|
71
60
|
if (!newAccessToken) {
|
|
72
61
|
authLogger.error('Token refresh response missing access token');
|
|
@@ -12,7 +12,7 @@ python manage.py generate_client --groups cfg_accounts --typescript
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| Version | 3.0.3 |
|
|
14
14
|
| Operations | 14 |
|
|
15
|
-
| Schemas |
|
|
15
|
+
| Schemas | 20 |
|
|
16
16
|
|
|
17
17
|
## Resources
|
|
18
18
|
|
|
@@ -81,12 +81,5 @@ openapi_client = OpenAPIClientConfig(
|
|
|
81
81
|
)
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
**Copy to Next.js** (if `nextjs_admin` configured):
|
|
85
|
-
```python
|
|
86
|
-
nextjs_admin = NextJsAdminConfig(
|
|
87
|
-
project_path="../frontend/apps/...",
|
|
88
|
-
api_output_path="app/_lib/api/generated",
|
|
89
|
-
)
|
|
90
|
-
```
|
|
91
|
-
|
|
92
84
|
@see https://djangocfg.com/docs/features/api-generation
|
|
85
|
+
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
import { consola } from 'consola'
|
|
34
|
+
import { CfgAccountsProfileAvatarCreateRequestSchema, type CfgAccountsProfileAvatarCreateRequest } from '../schemas/CfgAccountsProfileAvatarCreateRequest.schema'
|
|
34
35
|
import { PatchedUserProfileUpdateRequestSchema, type PatchedUserProfileUpdateRequest } from '../schemas/PatchedUserProfileUpdateRequest.schema'
|
|
35
36
|
import { UserSchema, type User } from '../schemas/User.schema'
|
|
36
37
|
import { UserProfileUpdateRequestSchema, type UserProfileUpdateRequest } from '../schemas/UserProfileUpdateRequest.schema'
|
|
@@ -99,7 +100,7 @@ export async function getAccountsProfileRetrieve( client?: any
|
|
|
99
100
|
* @method POST
|
|
100
101
|
* @path /cfg/accounts/profile/avatar/
|
|
101
102
|
*/
|
|
102
|
-
export async function createAccountsProfileAvatarCreate( data:
|
|
103
|
+
export async function createAccountsProfileAvatarCreate( data: CfgAccountsProfileAvatarCreateRequest, client?: any
|
|
103
104
|
): Promise<User> {
|
|
104
105
|
const api = client || getAPIInstance()
|
|
105
106
|
const response = await api.user_profile.accountsProfileAvatarCreate(data)
|
|
@@ -21,6 +21,7 @@ import useSWR from 'swr'
|
|
|
21
21
|
import { useSWRConfig } from 'swr'
|
|
22
22
|
import * as Fetchers from '../fetchers/accounts__user_profile'
|
|
23
23
|
import type { API } from '../../index'
|
|
24
|
+
import type { CfgAccountsProfileAvatarCreateRequest } from '../schemas/CfgAccountsProfileAvatarCreateRequest.schema'
|
|
24
25
|
import type { PatchedUserProfileUpdateRequest } from '../schemas/PatchedUserProfileUpdateRequest.schema'
|
|
25
26
|
import type { User } from '../schemas/User.schema'
|
|
26
27
|
import type { UserProfileUpdateRequest } from '../schemas/UserProfileUpdateRequest.schema'
|
|
@@ -48,7 +49,7 @@ export function useAccountsProfileRetrieve(client?: API): ReturnType<typeof useS
|
|
|
48
49
|
export function useCreateAccountsProfileAvatarCreate() {
|
|
49
50
|
const { mutate } = useSWRConfig()
|
|
50
51
|
|
|
51
|
-
return async (data:
|
|
52
|
+
return async (data: CfgAccountsProfileAvatarCreateRequest, client?: API): Promise<User> => {
|
|
52
53
|
const result = await Fetchers.createAccountsProfileAvatarCreate(data, client)
|
|
53
54
|
// Revalidate related queries
|
|
54
55
|
mutate('cfg-accounts-profile-avatar')
|
package/src/generated/cfg_accounts/_utils/schemas/CfgAccountsProfileAvatarCreateRequest.schema.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema for CfgAccountsProfileAvatarCreateRequest
|
|
3
|
+
*
|
|
4
|
+
* This schema provides runtime validation and type inference.
|
|
5
|
+
* */
|
|
6
|
+
import { z } from 'zod'
|
|
7
|
+
|
|
8
|
+
export const CfgAccountsProfileAvatarCreateRequestSchema = z.object({
|
|
9
|
+
avatar: z.union([z.instanceof(File), z.instanceof(Blob)]),
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Infer TypeScript type from Zod schema
|
|
14
|
+
*/
|
|
15
|
+
export type CfgAccountsProfileAvatarCreateRequest = z.infer<typeof CfgAccountsProfileAvatarCreateRequestSchema>
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
export * from './CentrifugoToken.schema'
|
|
21
|
+
export * from './CfgAccountsProfileAvatarCreateRequest.schema'
|
|
21
22
|
export * from './OAuthAuthorizeRequestRequest.schema'
|
|
22
23
|
export * from './OAuthAuthorizeResponse.schema'
|
|
23
24
|
export * from './OAuthCallbackRequestRequest.schema'
|
|
@@ -27,8 +27,10 @@ export class UserProfile {
|
|
|
27
27
|
* Upload avatar image for the current authenticated user. Accepts
|
|
28
28
|
* multipart/form-data with 'avatar' field.
|
|
29
29
|
*/
|
|
30
|
-
async accountsProfileAvatarCreate(data:
|
|
31
|
-
const
|
|
30
|
+
async accountsProfileAvatarCreate(data: Models.CfgAccountsProfileAvatarCreateRequest): Promise<Models.User> {
|
|
31
|
+
const formData = new FormData();
|
|
32
|
+
formData.append('avatar', data.avatar);
|
|
33
|
+
const response = await this.client.request('POST', "/cfg/accounts/profile/avatar/", { formData });
|
|
32
34
|
return response;
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -25,11 +25,19 @@ export interface User {
|
|
|
25
25
|
is_superuser: boolean;
|
|
26
26
|
date_joined: string;
|
|
27
27
|
last_login?: string | null;
|
|
28
|
-
/** Get count of unanswered messages for the user. */
|
|
29
28
|
unanswered_messages_count: number;
|
|
30
29
|
centrifugo: CentrifugoToken | null;
|
|
31
30
|
}
|
|
32
31
|
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* Request model (no read-only fields).
|
|
35
|
+
*/
|
|
36
|
+
export interface CfgAccountsProfileAvatarCreateRequest {
|
|
37
|
+
/** Avatar image file (JPEG, PNG, GIF, WebP, max 5MB) */
|
|
38
|
+
avatar: File | Blob;
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
/**
|
|
34
42
|
* Serializer for updating user profile.
|
|
35
43
|
*
|
|
@@ -28,6 +28,7 @@ export class APIClient {
|
|
|
28
28
|
private httpClient: HttpClientAdapter;
|
|
29
29
|
private logger: APILogger | null = null;
|
|
30
30
|
private retryConfig: RetryConfig | null = null;
|
|
31
|
+
private tokenGetter: (() => string | null) | null = null;
|
|
31
32
|
|
|
32
33
|
// Sub-clients
|
|
33
34
|
public auth: Auth;
|
|
@@ -41,10 +42,12 @@ export class APIClient {
|
|
|
41
42
|
httpClient?: HttpClientAdapter;
|
|
42
43
|
loggerConfig?: Partial<LoggerConfig>;
|
|
43
44
|
retryConfig?: RetryConfig;
|
|
45
|
+
tokenGetter?: () => string | null;
|
|
44
46
|
}
|
|
45
47
|
) {
|
|
46
48
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
47
49
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
50
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
48
51
|
|
|
49
52
|
// Initialize logger if config provided
|
|
50
53
|
if (options?.loggerConfig !== undefined) {
|
|
@@ -78,6 +81,21 @@ export class APIClient {
|
|
|
78
81
|
return null;
|
|
79
82
|
}
|
|
80
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Get the base URL for building streaming/download URLs.
|
|
86
|
+
*/
|
|
87
|
+
getBaseUrl(): string {
|
|
88
|
+
return this.baseUrl;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
93
|
+
* Returns null if no token getter is configured or no token is available.
|
|
94
|
+
*/
|
|
95
|
+
getToken(): string | null {
|
|
96
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
/**
|
|
82
100
|
* Make HTTP request with Django CSRF and session handling.
|
|
83
101
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -148,10 +148,11 @@ export class API {
|
|
|
148
148
|
|
|
149
149
|
this._loadTokensFromStorage();
|
|
150
150
|
|
|
151
|
-
// Initialize APIClient
|
|
151
|
+
// Initialize APIClient with token getter for URL authentication
|
|
152
152
|
this._client = new APIClient(this.baseUrl, {
|
|
153
153
|
retryConfig: this.options?.retryConfig,
|
|
154
154
|
loggerConfig: this.options?.loggerConfig,
|
|
155
|
+
tokenGetter: () => this.getToken(),
|
|
155
156
|
});
|
|
156
157
|
|
|
157
158
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -173,6 +174,7 @@ export class API {
|
|
|
173
174
|
this._client = new APIClient(this.baseUrl, {
|
|
174
175
|
retryConfig: this.options?.retryConfig,
|
|
175
176
|
loggerConfig: this.options?.loggerConfig,
|
|
177
|
+
tokenGetter: () => this.getToken(),
|
|
176
178
|
});
|
|
177
179
|
|
|
178
180
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -1386,8 +1386,8 @@
|
|
|
1386
1386
|
},
|
|
1387
1387
|
"unanswered_messages_count": {
|
|
1388
1388
|
"type": "integer",
|
|
1389
|
-
"
|
|
1390
|
-
"
|
|
1389
|
+
"readOnly": true,
|
|
1390
|
+
"default": 0
|
|
1391
1391
|
},
|
|
1392
1392
|
"centrifugo": {
|
|
1393
1393
|
"allOf": [
|
|
@@ -81,12 +81,5 @@ openapi_client = OpenAPIClientConfig(
|
|
|
81
81
|
)
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
**Copy to Next.js** (if `nextjs_admin` configured):
|
|
85
|
-
```python
|
|
86
|
-
nextjs_admin = NextJsAdminConfig(
|
|
87
|
-
project_path="../frontend/apps/...",
|
|
88
|
-
api_output_path="app/_lib/api/generated",
|
|
89
|
-
)
|
|
90
|
-
```
|
|
91
|
-
|
|
92
84
|
@see https://djangocfg.com/docs/features/api-generation
|
|
85
|
+
|
|
@@ -28,6 +28,7 @@ export class APIClient {
|
|
|
28
28
|
private httpClient: HttpClientAdapter;
|
|
29
29
|
private logger: APILogger | null = null;
|
|
30
30
|
private retryConfig: RetryConfig | null = null;
|
|
31
|
+
private tokenGetter: (() => string | null) | null = null;
|
|
31
32
|
|
|
32
33
|
// Sub-clients
|
|
33
34
|
public centrifugo_admin_api: CentrifugoAdminApi;
|
|
@@ -41,10 +42,12 @@ export class APIClient {
|
|
|
41
42
|
httpClient?: HttpClientAdapter;
|
|
42
43
|
loggerConfig?: Partial<LoggerConfig>;
|
|
43
44
|
retryConfig?: RetryConfig;
|
|
45
|
+
tokenGetter?: () => string | null;
|
|
44
46
|
}
|
|
45
47
|
) {
|
|
46
48
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
47
49
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
50
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
48
51
|
|
|
49
52
|
// Initialize logger if config provided
|
|
50
53
|
if (options?.loggerConfig !== undefined) {
|
|
@@ -78,6 +81,21 @@ export class APIClient {
|
|
|
78
81
|
return null;
|
|
79
82
|
}
|
|
80
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Get the base URL for building streaming/download URLs.
|
|
86
|
+
*/
|
|
87
|
+
getBaseUrl(): string {
|
|
88
|
+
return this.baseUrl;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
93
|
+
* Returns null if no token getter is configured or no token is available.
|
|
94
|
+
*/
|
|
95
|
+
getToken(): string | null {
|
|
96
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
/**
|
|
82
100
|
* Make HTTP request with Django CSRF and session handling.
|
|
83
101
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -147,10 +147,11 @@ export class API {
|
|
|
147
147
|
|
|
148
148
|
this._loadTokensFromStorage();
|
|
149
149
|
|
|
150
|
-
// Initialize APIClient
|
|
150
|
+
// Initialize APIClient with token getter for URL authentication
|
|
151
151
|
this._client = new APIClient(this.baseUrl, {
|
|
152
152
|
retryConfig: this.options?.retryConfig,
|
|
153
153
|
loggerConfig: this.options?.loggerConfig,
|
|
154
|
+
tokenGetter: () => this.getToken(),
|
|
154
155
|
});
|
|
155
156
|
|
|
156
157
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -172,6 +173,7 @@ export class API {
|
|
|
172
173
|
this._client = new APIClient(this.baseUrl, {
|
|
173
174
|
retryConfig: this.options?.retryConfig,
|
|
174
175
|
loggerConfig: this.options?.loggerConfig,
|
|
176
|
+
tokenGetter: () => this.getToken(),
|
|
175
177
|
});
|
|
176
178
|
|
|
177
179
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -79,12 +79,5 @@ openapi_client = OpenAPIClientConfig(
|
|
|
79
79
|
)
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
**Copy to Next.js** (if `nextjs_admin` configured):
|
|
83
|
-
```python
|
|
84
|
-
nextjs_admin = NextJsAdminConfig(
|
|
85
|
-
project_path="../frontend/apps/...",
|
|
86
|
-
api_output_path="app/_lib/api/generated",
|
|
87
|
-
)
|
|
88
|
-
```
|
|
89
|
-
|
|
90
82
|
@see https://djangocfg.com/docs/features/api-generation
|
|
83
|
+
|
|
@@ -29,6 +29,7 @@ export class APIClient {
|
|
|
29
29
|
private httpClient: HttpClientAdapter;
|
|
30
30
|
private logger: APILogger | null = null;
|
|
31
31
|
private retryConfig: RetryConfig | null = null;
|
|
32
|
+
private tokenGetter: (() => string | null) | null = null;
|
|
32
33
|
|
|
33
34
|
// Sub-clients
|
|
34
35
|
public backup_codes: BackupCodes;
|
|
@@ -43,10 +44,12 @@ export class APIClient {
|
|
|
43
44
|
httpClient?: HttpClientAdapter;
|
|
44
45
|
loggerConfig?: Partial<LoggerConfig>;
|
|
45
46
|
retryConfig?: RetryConfig;
|
|
47
|
+
tokenGetter?: () => string | null;
|
|
46
48
|
}
|
|
47
49
|
) {
|
|
48
50
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
49
51
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
52
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
50
53
|
|
|
51
54
|
// Initialize logger if config provided
|
|
52
55
|
if (options?.loggerConfig !== undefined) {
|
|
@@ -81,6 +84,21 @@ export class APIClient {
|
|
|
81
84
|
return null;
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Get the base URL for building streaming/download URLs.
|
|
89
|
+
*/
|
|
90
|
+
getBaseUrl(): string {
|
|
91
|
+
return this.baseUrl;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
96
|
+
* Returns null if no token getter is configured or no token is available.
|
|
97
|
+
*/
|
|
98
|
+
getToken(): string | null {
|
|
99
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
84
102
|
/**
|
|
85
103
|
* Make HTTP request with Django CSRF and session handling.
|
|
86
104
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -153,10 +153,11 @@ export class API {
|
|
|
153
153
|
|
|
154
154
|
this._loadTokensFromStorage();
|
|
155
155
|
|
|
156
|
-
// Initialize APIClient
|
|
156
|
+
// Initialize APIClient with token getter for URL authentication
|
|
157
157
|
this._client = new APIClient(this.baseUrl, {
|
|
158
158
|
retryConfig: this.options?.retryConfig,
|
|
159
159
|
loggerConfig: this.options?.loggerConfig,
|
|
160
|
+
tokenGetter: () => this.getToken(),
|
|
160
161
|
});
|
|
161
162
|
|
|
162
163
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -179,6 +180,7 @@ export class API {
|
|
|
179
180
|
this._client = new APIClient(this.baseUrl, {
|
|
180
181
|
retryConfig: this.options?.retryConfig,
|
|
181
182
|
loggerConfig: this.options?.loggerConfig,
|
|
183
|
+
tokenGetter: () => this.getToken(),
|
|
182
184
|
});
|
|
183
185
|
|
|
184
186
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -59,12 +59,5 @@ openapi_client = OpenAPIClientConfig(
|
|
|
59
59
|
)
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
**Copy to Next.js** (if `nextjs_admin` configured):
|
|
63
|
-
```python
|
|
64
|
-
nextjs_admin = NextJsAdminConfig(
|
|
65
|
-
project_path="../frontend/apps/...",
|
|
66
|
-
api_output_path="app/_lib/api/generated",
|
|
67
|
-
)
|
|
68
|
-
```
|
|
69
|
-
|
|
70
62
|
@see https://djangocfg.com/docs/features/api-generation
|
|
63
|
+
|
|
@@ -25,6 +25,7 @@ export class APIClient {
|
|
|
25
25
|
private httpClient: HttpClientAdapter;
|
|
26
26
|
private logger: APILogger | null = null;
|
|
27
27
|
private retryConfig: RetryConfig | null = null;
|
|
28
|
+
private tokenGetter: (() => string | null) | null = null;
|
|
28
29
|
|
|
29
30
|
// Sub-clients
|
|
30
31
|
public web_push: WebPush;
|
|
@@ -35,10 +36,12 @@ export class APIClient {
|
|
|
35
36
|
httpClient?: HttpClientAdapter;
|
|
36
37
|
loggerConfig?: Partial<LoggerConfig>;
|
|
37
38
|
retryConfig?: RetryConfig;
|
|
39
|
+
tokenGetter?: () => string | null;
|
|
38
40
|
}
|
|
39
41
|
) {
|
|
40
42
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
41
43
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
44
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
42
45
|
|
|
43
46
|
// Initialize logger if config provided
|
|
44
47
|
if (options?.loggerConfig !== undefined) {
|
|
@@ -69,6 +72,21 @@ export class APIClient {
|
|
|
69
72
|
return null;
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Get the base URL for building streaming/download URLs.
|
|
77
|
+
*/
|
|
78
|
+
getBaseUrl(): string {
|
|
79
|
+
return this.baseUrl;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
84
|
+
* Returns null if no token getter is configured or no token is available.
|
|
85
|
+
*/
|
|
86
|
+
getToken(): string | null {
|
|
87
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
88
|
+
}
|
|
89
|
+
|
|
72
90
|
/**
|
|
73
91
|
* Make HTTP request with Django CSRF and session handling.
|
|
74
92
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -132,10 +132,11 @@ export class API {
|
|
|
132
132
|
|
|
133
133
|
this._loadTokensFromStorage();
|
|
134
134
|
|
|
135
|
-
// Initialize APIClient
|
|
135
|
+
// Initialize APIClient with token getter for URL authentication
|
|
136
136
|
this._client = new APIClient(this.baseUrl, {
|
|
137
137
|
retryConfig: this.options?.retryConfig,
|
|
138
138
|
loggerConfig: this.options?.loggerConfig,
|
|
139
|
+
tokenGetter: () => this.getToken(),
|
|
139
140
|
});
|
|
140
141
|
|
|
141
142
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -154,6 +155,7 @@ export class API {
|
|
|
154
155
|
this._client = new APIClient(this.baseUrl, {
|
|
155
156
|
retryConfig: this.options?.retryConfig,
|
|
156
157
|
loggerConfig: this.options?.loggerConfig,
|
|
158
|
+
tokenGetter: () => this.getToken(),
|
|
157
159
|
});
|
|
158
160
|
|
|
159
161
|
// Always inject auth header wrapper (reads token dynamically from storage)
|