@djangocfg/ext-support 1.0.0

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 (65) hide show
  1. package/README.md +233 -0
  2. package/dist/chunk-AZ4LWZB7.js +2630 -0
  3. package/dist/hooks.cjs +2716 -0
  4. package/dist/hooks.d.cts +255 -0
  5. package/dist/hooks.d.ts +255 -0
  6. package/dist/hooks.js +1 -0
  7. package/dist/index.cjs +2693 -0
  8. package/dist/index.d.cts +1392 -0
  9. package/dist/index.d.ts +1392 -0
  10. package/dist/index.js +1 -0
  11. package/package.json +80 -0
  12. package/src/api/generated/ext_support/_utils/fetchers/ext_support__support.ts +642 -0
  13. package/src/api/generated/ext_support/_utils/fetchers/index.ts +28 -0
  14. package/src/api/generated/ext_support/_utils/hooks/ext_support__support.ts +237 -0
  15. package/src/api/generated/ext_support/_utils/hooks/index.ts +28 -0
  16. package/src/api/generated/ext_support/_utils/schemas/Message.schema.ts +21 -0
  17. package/src/api/generated/ext_support/_utils/schemas/MessageCreate.schema.ts +15 -0
  18. package/src/api/generated/ext_support/_utils/schemas/MessageCreateRequest.schema.ts +15 -0
  19. package/src/api/generated/ext_support/_utils/schemas/MessageRequest.schema.ts +15 -0
  20. package/src/api/generated/ext_support/_utils/schemas/PaginatedMessageList.schema.ts +24 -0
  21. package/src/api/generated/ext_support/_utils/schemas/PaginatedTicketList.schema.ts +24 -0
  22. package/src/api/generated/ext_support/_utils/schemas/PatchedMessageRequest.schema.ts +15 -0
  23. package/src/api/generated/ext_support/_utils/schemas/PatchedTicketRequest.schema.ts +18 -0
  24. package/src/api/generated/ext_support/_utils/schemas/Sender.schema.ts +21 -0
  25. package/src/api/generated/ext_support/_utils/schemas/Ticket.schema.ts +21 -0
  26. package/src/api/generated/ext_support/_utils/schemas/TicketRequest.schema.ts +18 -0
  27. package/src/api/generated/ext_support/_utils/schemas/index.ts +29 -0
  28. package/src/api/generated/ext_support/api-instance.ts +131 -0
  29. package/src/api/generated/ext_support/client.ts +301 -0
  30. package/src/api/generated/ext_support/enums.ts +45 -0
  31. package/src/api/generated/ext_support/errors.ts +116 -0
  32. package/src/api/generated/ext_support/ext_support__support/client.ts +151 -0
  33. package/src/api/generated/ext_support/ext_support__support/index.ts +2 -0
  34. package/src/api/generated/ext_support/ext_support__support/models.ts +165 -0
  35. package/src/api/generated/ext_support/http.ts +103 -0
  36. package/src/api/generated/ext_support/index.ts +273 -0
  37. package/src/api/generated/ext_support/logger.ts +259 -0
  38. package/src/api/generated/ext_support/retry.ts +175 -0
  39. package/src/api/generated/ext_support/schema.json +1049 -0
  40. package/src/api/generated/ext_support/storage.ts +161 -0
  41. package/src/api/generated/ext_support/validation-events.ts +133 -0
  42. package/src/api/index.ts +9 -0
  43. package/src/config.ts +20 -0
  44. package/src/contexts/SupportContext.tsx +250 -0
  45. package/src/contexts/SupportExtensionProvider.tsx +38 -0
  46. package/src/contexts/types.ts +26 -0
  47. package/src/hooks/index.ts +33 -0
  48. package/src/index.ts +39 -0
  49. package/src/layouts/SupportLayout/README.md +91 -0
  50. package/src/layouts/SupportLayout/SupportLayout.tsx +179 -0
  51. package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +155 -0
  52. package/src/layouts/SupportLayout/components/MessageInput.tsx +92 -0
  53. package/src/layouts/SupportLayout/components/MessageList.tsx +312 -0
  54. package/src/layouts/SupportLayout/components/TicketCard.tsx +96 -0
  55. package/src/layouts/SupportLayout/components/TicketList.tsx +153 -0
  56. package/src/layouts/SupportLayout/components/index.ts +6 -0
  57. package/src/layouts/SupportLayout/context/SupportLayoutContext.tsx +258 -0
  58. package/src/layouts/SupportLayout/context/index.ts +2 -0
  59. package/src/layouts/SupportLayout/events.ts +33 -0
  60. package/src/layouts/SupportLayout/hooks/index.ts +2 -0
  61. package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +115 -0
  62. package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +88 -0
  63. package/src/layouts/SupportLayout/index.ts +6 -0
  64. package/src/layouts/SupportLayout/types.ts +21 -0
  65. package/src/utils/logger.ts +14 -0
@@ -0,0 +1,301 @@
1
+ import { ExtSupportSupport } from "./ext_support__support";
2
+ import { HttpClientAdapter, FetchAdapter } from "./http";
3
+ import { APIError, NetworkError } from "./errors";
4
+ import { APILogger, type LoggerConfig } from "./logger";
5
+ import { withRetry, type RetryConfig } from "./retry";
6
+
7
+
8
+ /**
9
+ * Async API client for Django CFG API.
10
+ *
11
+ * Usage:
12
+ * ```typescript
13
+ * const client = new APIClient('https://api.example.com');
14
+ * const users = await client.users.list();
15
+ * const post = await client.posts.create(newPost);
16
+ *
17
+ * // Custom HTTP adapter (e.g., Axios)
18
+ * const client = new APIClient('https://api.example.com', {
19
+ * httpClient: new AxiosAdapter()
20
+ * });
21
+ * ```
22
+ */
23
+ export class APIClient {
24
+ private baseUrl: string;
25
+ private httpClient: HttpClientAdapter;
26
+ private logger: APILogger | null = null;
27
+ private retryConfig: RetryConfig | null = null;
28
+
29
+ // Sub-clients
30
+ public ext_support_support: ExtSupportSupport;
31
+
32
+ constructor(
33
+ baseUrl: string,
34
+ options?: {
35
+ httpClient?: HttpClientAdapter;
36
+ loggerConfig?: Partial<LoggerConfig>;
37
+ retryConfig?: RetryConfig;
38
+ }
39
+ ) {
40
+ this.baseUrl = baseUrl.replace(/\/$/, '');
41
+ this.httpClient = options?.httpClient || new FetchAdapter();
42
+
43
+ // Initialize logger if config provided
44
+ if (options?.loggerConfig !== undefined) {
45
+ this.logger = new APILogger(options.loggerConfig);
46
+ }
47
+
48
+ // Store retry configuration
49
+ if (options?.retryConfig !== undefined) {
50
+ this.retryConfig = options.retryConfig;
51
+ }
52
+
53
+ // Initialize sub-clients
54
+ this.ext_support_support = new ExtSupportSupport(this);
55
+ }
56
+
57
+ /**
58
+ * Get CSRF token from cookies (for SessionAuthentication).
59
+ *
60
+ * Returns null if cookie doesn't exist (JWT-only auth).
61
+ */
62
+ getCsrfToken(): string | null {
63
+ const name = 'csrftoken';
64
+ const value = `; ${document.cookie}`;
65
+ const parts = value.split(`; ${name}=`);
66
+ if (parts.length === 2) {
67
+ return parts.pop()?.split(';').shift() || null;
68
+ }
69
+ return null;
70
+ }
71
+
72
+ /**
73
+ * Make HTTP request with Django CSRF and session handling.
74
+ * Automatically retries on network errors and 5xx server errors.
75
+ */
76
+ async request<T>(
77
+ method: string,
78
+ path: string,
79
+ options?: {
80
+ params?: Record<string, any>;
81
+ body?: any;
82
+ formData?: FormData;
83
+ headers?: Record<string, string>;
84
+ }
85
+ ): Promise<T> {
86
+ // Wrap request in retry logic if configured
87
+ if (this.retryConfig) {
88
+ return withRetry(() => this._makeRequest<T>(method, path, options), {
89
+ ...this.retryConfig,
90
+ onFailedAttempt: (info) => {
91
+ // Log retry attempts
92
+ if (this.logger) {
93
+ this.logger.warn(
94
+ `Retry attempt ${info.attemptNumber}/${info.retriesLeft + info.attemptNumber} ` +
95
+ `for ${method} ${path}: ${info.error.message}`
96
+ );
97
+ }
98
+ // Call user's onFailedAttempt if provided
99
+ this.retryConfig?.onFailedAttempt?.(info);
100
+ },
101
+ });
102
+ }
103
+
104
+ // No retry configured, make request directly
105
+ return this._makeRequest<T>(method, path, options);
106
+ }
107
+
108
+ /**
109
+ * Internal request method (without retry wrapper).
110
+ * Used by request() method with optional retry logic.
111
+ */
112
+ private async _makeRequest<T>(
113
+ method: string,
114
+ path: string,
115
+ options?: {
116
+ params?: Record<string, any>;
117
+ body?: any;
118
+ formData?: FormData;
119
+ headers?: Record<string, string>;
120
+ }
121
+ ): Promise<T> {
122
+ // Build URL - handle both absolute and relative paths
123
+ // When baseUrl is empty (static builds), path is used as-is (relative to current origin)
124
+ const url = this.baseUrl ? `${this.baseUrl}${path}` : path;
125
+ const startTime = Date.now();
126
+
127
+ // Build headers - start with custom headers from options
128
+ const headers: Record<string, string> = {
129
+ ...(options?.headers || {})
130
+ };
131
+
132
+ // Don't set Content-Type for FormData (browser will set it with boundary)
133
+ if (!options?.formData && !headers['Content-Type']) {
134
+ headers['Content-Type'] = 'application/json';
135
+ }
136
+
137
+ // CSRF not needed - SessionAuthentication not enabled in DRF config
138
+ // Your API uses JWT/Token authentication (no CSRF required)
139
+
140
+ // Log request
141
+ if (this.logger) {
142
+ this.logger.logRequest({
143
+ method,
144
+ url: url,
145
+ headers,
146
+ body: options?.formData || options?.body,
147
+ timestamp: startTime,
148
+ });
149
+ }
150
+
151
+ try {
152
+ // Make request via HTTP adapter
153
+ const response = await this.httpClient.request<T>({
154
+ method,
155
+ url: url,
156
+ headers,
157
+ params: options?.params,
158
+ body: options?.body,
159
+ formData: options?.formData,
160
+ });
161
+
162
+ const duration = Date.now() - startTime;
163
+
164
+ // Check for HTTP errors
165
+ if (response.status >= 400) {
166
+ const error = new APIError(
167
+ response.status,
168
+ response.statusText,
169
+ response.data,
170
+ url
171
+ );
172
+
173
+ // Log error
174
+ if (this.logger) {
175
+ this.logger.logError(
176
+ {
177
+ method,
178
+ url: url,
179
+ headers,
180
+ body: options?.formData || options?.body,
181
+ timestamp: startTime,
182
+ },
183
+ {
184
+ message: error.message,
185
+ statusCode: response.status,
186
+ duration,
187
+ timestamp: Date.now(),
188
+ }
189
+ );
190
+ }
191
+
192
+ throw error;
193
+ }
194
+
195
+ // Log successful response
196
+ if (this.logger) {
197
+ this.logger.logResponse(
198
+ {
199
+ method,
200
+ url: url,
201
+ headers,
202
+ body: options?.formData || options?.body,
203
+ timestamp: startTime,
204
+ },
205
+ {
206
+ status: response.status,
207
+ statusText: response.statusText,
208
+ data: response.data,
209
+ duration,
210
+ timestamp: Date.now(),
211
+ }
212
+ );
213
+ }
214
+
215
+ return response.data as T;
216
+ } catch (error) {
217
+ const duration = Date.now() - startTime;
218
+
219
+ // Re-throw APIError as-is
220
+ if (error instanceof APIError) {
221
+ throw error;
222
+ }
223
+
224
+ // Detect CORS errors and dispatch event
225
+ const isCORSError = error instanceof TypeError &&
226
+ (error.message.toLowerCase().includes('cors') ||
227
+ error.message.toLowerCase().includes('failed to fetch') ||
228
+ error.message.toLowerCase().includes('network request failed'));
229
+
230
+ // Log specific error type first
231
+ if (this.logger) {
232
+ if (isCORSError) {
233
+ this.logger.error(`🚫 CORS Error: ${method} ${url}`);
234
+ this.logger.error(` → ${error instanceof Error ? error.message : String(error)}`);
235
+ this.logger.error(` → Configure security_domains parameter on the server`);
236
+ } else {
237
+ this.logger.error(`⚠️ Network Error: ${method} ${url}`);
238
+ this.logger.error(` → ${error instanceof Error ? error.message : String(error)}`);
239
+ }
240
+ }
241
+
242
+ // Dispatch browser events
243
+ if (typeof window !== 'undefined') {
244
+ try {
245
+ if (isCORSError) {
246
+ // Dispatch CORS-specific error event
247
+ window.dispatchEvent(new CustomEvent('cors-error', {
248
+ detail: {
249
+ url: url,
250
+ method: method,
251
+ error: error instanceof Error ? error.message : String(error),
252
+ timestamp: new Date(),
253
+ },
254
+ bubbles: true,
255
+ cancelable: false,
256
+ }));
257
+ } else {
258
+ // Dispatch generic network error event
259
+ window.dispatchEvent(new CustomEvent('network-error', {
260
+ detail: {
261
+ url: url,
262
+ method: method,
263
+ error: error instanceof Error ? error.message : String(error),
264
+ timestamp: new Date(),
265
+ },
266
+ bubbles: true,
267
+ cancelable: false,
268
+ }));
269
+ }
270
+ } catch (eventError) {
271
+ // Silently fail - event dispatch should never crash the app
272
+ }
273
+ }
274
+
275
+ // Wrap other errors as NetworkError
276
+ const networkError = error instanceof Error
277
+ ? new NetworkError(error.message, url, error)
278
+ : new NetworkError('Unknown error', url);
279
+
280
+ // Detailed logging via logger.logError
281
+ if (this.logger) {
282
+ this.logger.logError(
283
+ {
284
+ method,
285
+ url: url,
286
+ headers,
287
+ body: options?.formData || options?.body,
288
+ timestamp: startTime,
289
+ },
290
+ {
291
+ message: networkError.message,
292
+ duration,
293
+ timestamp: Date.now(),
294
+ }
295
+ );
296
+ }
297
+
298
+ throw networkError;
299
+ }
300
+ }
301
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * * `open` - Open
3
+ * * `waiting_for_user` - Waiting for User
4
+ * * `waiting_for_admin` - Waiting for Admin
5
+ * * `resolved` - Resolved
6
+ * * `closed` - Closed
7
+ */
8
+ export enum PatchedTicketRequestStatus {
9
+ OPEN = "open",
10
+ WAITING_FOR_USER = "waiting_for_user",
11
+ WAITING_FOR_ADMIN = "waiting_for_admin",
12
+ RESOLVED = "resolved",
13
+ CLOSED = "closed",
14
+ }
15
+
16
+ /**
17
+ * * `open` - Open
18
+ * * `waiting_for_user` - Waiting for User
19
+ * * `waiting_for_admin` - Waiting for Admin
20
+ * * `resolved` - Resolved
21
+ * * `closed` - Closed
22
+ */
23
+ export enum TicketStatus {
24
+ OPEN = "open",
25
+ WAITING_FOR_USER = "waiting_for_user",
26
+ WAITING_FOR_ADMIN = "waiting_for_admin",
27
+ RESOLVED = "resolved",
28
+ CLOSED = "closed",
29
+ }
30
+
31
+ /**
32
+ * * `open` - Open
33
+ * * `waiting_for_user` - Waiting for User
34
+ * * `waiting_for_admin` - Waiting for Admin
35
+ * * `resolved` - Resolved
36
+ * * `closed` - Closed
37
+ */
38
+ export enum TicketRequestStatus {
39
+ OPEN = "open",
40
+ WAITING_FOR_USER = "waiting_for_user",
41
+ WAITING_FOR_ADMIN = "waiting_for_admin",
42
+ RESOLVED = "resolved",
43
+ CLOSED = "closed",
44
+ }
45
+
@@ -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,151 @@
1
+ import * as Models from "./models";
2
+
3
+
4
+ /**
5
+ * API endpoints for Support.
6
+ */
7
+ export class ExtSupportSupport {
8
+ private client: any;
9
+
10
+ constructor(client: any) {
11
+ this.client = client;
12
+ }
13
+
14
+ async ticketsList(page?: number, page_size?: number): Promise<Models.PaginatedTicketList>;
15
+ async ticketsList(params?: { page?: number; page_size?: number }): Promise<Models.PaginatedTicketList>;
16
+
17
+ /**
18
+ * ViewSet for managing support tickets. Requires authenticated user (JWT
19
+ * or Session). Staff users can see all tickets, regular users see only
20
+ * their own.
21
+ */
22
+ async ticketsList(...args: any[]): Promise<Models.PaginatedTicketList> {
23
+ const isParamsObject = args.length === 1 && typeof args[0] === 'object' && args[0] !== null && !Array.isArray(args[0]);
24
+
25
+ let params;
26
+ if (isParamsObject) {
27
+ params = args[0];
28
+ } else {
29
+ params = { page: args[0], page_size: args[1] };
30
+ }
31
+ const response = await this.client.request('GET', "/cfg/support/tickets/", { params });
32
+ return response;
33
+ }
34
+
35
+ /**
36
+ * ViewSet for managing support tickets. Requires authenticated user (JWT
37
+ * or Session). Staff users can see all tickets, regular users see only
38
+ * their own.
39
+ */
40
+ async ticketsCreate(data: Models.TicketRequest): Promise<Models.Ticket> {
41
+ const response = await this.client.request('POST', "/cfg/support/tickets/", { body: data });
42
+ return response;
43
+ }
44
+
45
+ async ticketsMessagesList(ticket_uuid: string, page?: number, page_size?: number): Promise<Models.PaginatedMessageList>;
46
+ async ticketsMessagesList(ticket_uuid: string, params?: { page?: number; page_size?: number }): Promise<Models.PaginatedMessageList>;
47
+
48
+ /**
49
+ * ViewSet for managing support messages. Requires authenticated user (JWT
50
+ * or Session). Users can only access messages for their own tickets.
51
+ */
52
+ async ticketsMessagesList(...args: any[]): Promise<Models.PaginatedMessageList> {
53
+ const ticket_uuid = args[0];
54
+ const isParamsObject = args.length === 2 && typeof args[1] === 'object' && args[1] !== null && !Array.isArray(args[1]);
55
+
56
+ let params;
57
+ if (isParamsObject) {
58
+ params = args[1];
59
+ } else {
60
+ params = { page: args[1], page_size: args[2] };
61
+ }
62
+ const response = await this.client.request('GET', `/cfg/support/tickets/${ticket_uuid}/messages/`, { params });
63
+ return response;
64
+ }
65
+
66
+ /**
67
+ * ViewSet for managing support messages. Requires authenticated user (JWT
68
+ * or Session). Users can only access messages for their own tickets.
69
+ */
70
+ async ticketsMessagesCreate(ticket_uuid: string, data: Models.MessageCreateRequest): Promise<Models.MessageCreate> {
71
+ const response = await this.client.request('POST', `/cfg/support/tickets/${ticket_uuid}/messages/`, { body: data });
72
+ return response;
73
+ }
74
+
75
+ /**
76
+ * ViewSet for managing support messages. Requires authenticated user (JWT
77
+ * or Session). Users can only access messages for their own tickets.
78
+ */
79
+ async ticketsMessagesRetrieve(ticket_uuid: string, uuid: string): Promise<Models.Message> {
80
+ const response = await this.client.request('GET', `/cfg/support/tickets/${ticket_uuid}/messages/${uuid}/`);
81
+ return response;
82
+ }
83
+
84
+ /**
85
+ * ViewSet for managing support messages. Requires authenticated user (JWT
86
+ * or Session). Users can only access messages for their own tickets.
87
+ */
88
+ async ticketsMessagesUpdate(ticket_uuid: string, uuid: string, data: Models.MessageRequest): Promise<Models.Message> {
89
+ const response = await this.client.request('PUT', `/cfg/support/tickets/${ticket_uuid}/messages/${uuid}/`, { body: data });
90
+ return response;
91
+ }
92
+
93
+ /**
94
+ * ViewSet for managing support messages. Requires authenticated user (JWT
95
+ * or Session). Users can only access messages for their own tickets.
96
+ */
97
+ async ticketsMessagesPartialUpdate(ticket_uuid: string, uuid: string, data?: Models.PatchedMessageRequest): Promise<Models.Message> {
98
+ const response = await this.client.request('PATCH', `/cfg/support/tickets/${ticket_uuid}/messages/${uuid}/`, { body: data });
99
+ return response;
100
+ }
101
+
102
+ /**
103
+ * ViewSet for managing support messages. Requires authenticated user (JWT
104
+ * or Session). Users can only access messages for their own tickets.
105
+ */
106
+ async ticketsMessagesDestroy(ticket_uuid: string, uuid: string): Promise<void> {
107
+ const response = await this.client.request('DELETE', `/cfg/support/tickets/${ticket_uuid}/messages/${uuid}/`);
108
+ return;
109
+ }
110
+
111
+ /**
112
+ * ViewSet for managing support tickets. Requires authenticated user (JWT
113
+ * or Session). Staff users can see all tickets, regular users see only
114
+ * their own.
115
+ */
116
+ async ticketsRetrieve(uuid: string): Promise<Models.Ticket> {
117
+ const response = await this.client.request('GET', `/cfg/support/tickets/${uuid}/`);
118
+ return response;
119
+ }
120
+
121
+ /**
122
+ * ViewSet for managing support tickets. Requires authenticated user (JWT
123
+ * or Session). Staff users can see all tickets, regular users see only
124
+ * their own.
125
+ */
126
+ async ticketsUpdate(uuid: string, data: Models.TicketRequest): Promise<Models.Ticket> {
127
+ const response = await this.client.request('PUT', `/cfg/support/tickets/${uuid}/`, { body: data });
128
+ return response;
129
+ }
130
+
131
+ /**
132
+ * ViewSet for managing support tickets. Requires authenticated user (JWT
133
+ * or Session). Staff users can see all tickets, regular users see only
134
+ * their own.
135
+ */
136
+ async ticketsPartialUpdate(uuid: string, data?: Models.PatchedTicketRequest): Promise<Models.Ticket> {
137
+ const response = await this.client.request('PATCH', `/cfg/support/tickets/${uuid}/`, { body: data });
138
+ return response;
139
+ }
140
+
141
+ /**
142
+ * ViewSet for managing support tickets. Requires authenticated user (JWT
143
+ * or Session). Staff users can see all tickets, regular users see only
144
+ * their own.
145
+ */
146
+ async ticketsDestroy(uuid: string): Promise<void> {
147
+ const response = await this.client.request('DELETE', `/cfg/support/tickets/${uuid}/`);
148
+ return;
149
+ }
150
+
151
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./client";
2
+ export * as Models from "./models";