@djangocfg/layouts 2.1.49 → 2.1.51
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/package.json +5 -5
- package/src/components/errors/ErrorsTracker/components/ErrorButtons.tsx +10 -5
- package/src/components/errors/ErrorsTracker/components/ErrorToast.tsx +40 -2
- package/src/components/errors/ErrorsTracker/index.ts +4 -1
- package/src/components/errors/ErrorsTracker/providers/ErrorTrackingProvider.tsx +33 -3
- package/src/components/errors/ErrorsTracker/types.ts +51 -2
- package/src/components/errors/ErrorsTracker/utils/formatters.ts +22 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/layouts",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.51",
|
|
4
4
|
"description": "Simple, straightforward layout components for Next.js - import and use with props",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"layouts",
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"check": "tsc --noEmit"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
|
-
"@djangocfg/api": "^2.1.
|
|
96
|
-
"@djangocfg/centrifugo": "^2.1.
|
|
97
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
95
|
+
"@djangocfg/api": "^2.1.51",
|
|
96
|
+
"@djangocfg/centrifugo": "^2.1.51",
|
|
97
|
+
"@djangocfg/ui-nextjs": "^2.1.51",
|
|
98
98
|
"@hookform/resolvers": "^5.2.0",
|
|
99
99
|
"consola": "^3.4.2",
|
|
100
100
|
"lucide-react": "^0.545.0",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"uuid": "^11.1.0"
|
|
117
117
|
},
|
|
118
118
|
"devDependencies": {
|
|
119
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
119
|
+
"@djangocfg/typescript-config": "^2.1.51",
|
|
120
120
|
"@types/node": "^24.7.2",
|
|
121
121
|
"@types/react": "^19.1.0",
|
|
122
122
|
"@types/react-dom": "^19.1.0",
|
|
@@ -13,18 +13,21 @@ import { Button, useCopy } from '@djangocfg/ui-nextjs';
|
|
|
13
13
|
|
|
14
14
|
import { generateCurlFromError } from '../utils/curl-generator';
|
|
15
15
|
import {
|
|
16
|
-
|
|
16
|
+
formatCentrifugoErrorForClipboard,
|
|
17
|
+
formatCORSErrorForClipboard,
|
|
18
|
+
formatNetworkErrorForClipboard,
|
|
19
|
+
formatValidationErrorForClipboard
|
|
17
20
|
} from '../utils/formatters';
|
|
18
21
|
|
|
19
|
-
import type { ValidationErrorDetail, CORSErrorDetail, NetworkErrorDetail } from '../types';
|
|
22
|
+
import type { ValidationErrorDetail, CORSErrorDetail, NetworkErrorDetail, CentrifugoErrorDetail } from '../types';
|
|
20
23
|
export interface ErrorButtonsProps {
|
|
21
|
-
detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail;
|
|
24
|
+
detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail | CentrifugoErrorDetail;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* Format error for clipboard based on type
|
|
26
29
|
*/
|
|
27
|
-
function formatErrorForClipboard(detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail): string {
|
|
30
|
+
function formatErrorForClipboard(detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail | CentrifugoErrorDetail): string {
|
|
28
31
|
switch (detail.type) {
|
|
29
32
|
case 'validation':
|
|
30
33
|
return formatValidationErrorForClipboard(detail);
|
|
@@ -32,6 +35,8 @@ function formatErrorForClipboard(detail: ValidationErrorDetail | CORSErrorDetail
|
|
|
32
35
|
return formatCORSErrorForClipboard(detail);
|
|
33
36
|
case 'network':
|
|
34
37
|
return formatNetworkErrorForClipboard(detail);
|
|
38
|
+
case 'centrifugo':
|
|
39
|
+
return formatCentrifugoErrorForClipboard(detail);
|
|
35
40
|
default:
|
|
36
41
|
return JSON.stringify(detail, null, 2);
|
|
37
42
|
}
|
|
@@ -40,7 +45,7 @@ function formatErrorForClipboard(detail: ValidationErrorDetail | CORSErrorDetail
|
|
|
40
45
|
/**
|
|
41
46
|
* Check if error supports cURL generation
|
|
42
47
|
*/
|
|
43
|
-
function supportsCurl(detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail): boolean {
|
|
48
|
+
function supportsCurl(detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail | CentrifugoErrorDetail): boolean {
|
|
44
49
|
return detail.type === 'validation';
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -15,9 +15,11 @@ import type {
|
|
|
15
15
|
ValidationErrorDetail,
|
|
16
16
|
CORSErrorDetail,
|
|
17
17
|
NetworkErrorDetail,
|
|
18
|
+
CentrifugoErrorDetail,
|
|
18
19
|
ValidationErrorConfig,
|
|
19
20
|
CORSErrorConfig,
|
|
20
21
|
NetworkErrorConfig,
|
|
22
|
+
CentrifugoErrorConfig,
|
|
21
23
|
} from '../types';
|
|
22
24
|
/**
|
|
23
25
|
* Build validation error description
|
|
@@ -133,12 +135,46 @@ function buildNetworkDescription(
|
|
|
133
135
|
);
|
|
134
136
|
}
|
|
135
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Build centrifugo error description
|
|
140
|
+
*/
|
|
141
|
+
function buildCentrifugoDescription(
|
|
142
|
+
detail: CentrifugoErrorDetail,
|
|
143
|
+
config: Required<CentrifugoErrorConfig>
|
|
144
|
+
): React.ReactNode {
|
|
145
|
+
const parts: string[] = [];
|
|
146
|
+
|
|
147
|
+
// Add method info
|
|
148
|
+
if (config.showMethod) {
|
|
149
|
+
parts.push(`RPC: ${detail.method}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Add error code
|
|
153
|
+
if (config.showCode && detail.code !== undefined) {
|
|
154
|
+
parts.push(`Code: ${detail.code}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<div className="flex flex-col gap-2 text-sm">
|
|
159
|
+
{parts.length > 0 && (
|
|
160
|
+
<div className="font-mono text-xs opacity-90">
|
|
161
|
+
{parts.join(' • ')}
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
164
|
+
|
|
165
|
+
<div className="opacity-90">{detail.error}</div>
|
|
166
|
+
|
|
167
|
+
<ErrorButtons detail={detail} />
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
136
172
|
/**
|
|
137
173
|
* Create toast options for any error type
|
|
138
174
|
*/
|
|
139
175
|
export function createErrorToast(
|
|
140
|
-
detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail,
|
|
141
|
-
config: Required<ValidationErrorConfig | CORSErrorConfig | NetworkErrorConfig>
|
|
176
|
+
detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail | CentrifugoErrorDetail,
|
|
177
|
+
config: Required<ValidationErrorConfig | CORSErrorConfig | NetworkErrorConfig | CentrifugoErrorConfig>
|
|
142
178
|
) {
|
|
143
179
|
let description: React.ReactNode;
|
|
144
180
|
|
|
@@ -147,6 +183,8 @@ export function createErrorToast(
|
|
|
147
183
|
description = buildValidationDescription(detail, config as Required<ValidationErrorConfig>);
|
|
148
184
|
} else if (detail.type === 'cors') {
|
|
149
185
|
description = buildCORSDescription(detail, config as Required<CORSErrorConfig>);
|
|
186
|
+
} else if (detail.type === 'centrifugo') {
|
|
187
|
+
description = buildCentrifugoDescription(detail, config as Required<CentrifugoErrorConfig>);
|
|
150
188
|
} else {
|
|
151
189
|
description = buildNetworkDescription(detail, config as Required<NetworkErrorConfig>);
|
|
152
190
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Error Tracking - Unified error tracking for all error types
|
|
3
3
|
*
|
|
4
|
-
* Single provider and hook for validation, CORS, and
|
|
4
|
+
* Single provider and hook for validation, CORS, network, and Centrifugo errors
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
// Main provider and hook
|
|
@@ -14,11 +14,13 @@ export type {
|
|
|
14
14
|
ValidationErrorDetail,
|
|
15
15
|
CORSErrorDetail,
|
|
16
16
|
NetworkErrorDetail,
|
|
17
|
+
CentrifugoErrorDetail,
|
|
17
18
|
StoredError,
|
|
18
19
|
ErrorTrackingConfig,
|
|
19
20
|
ValidationErrorConfig,
|
|
20
21
|
CORSErrorConfig,
|
|
21
22
|
NetworkErrorConfig,
|
|
23
|
+
CentrifugoErrorConfig,
|
|
22
24
|
ErrorTrackingContextValue,
|
|
23
25
|
} from './types';
|
|
24
26
|
|
|
@@ -32,6 +34,7 @@ export {
|
|
|
32
34
|
formatValidationErrorForClipboard,
|
|
33
35
|
formatCORSErrorForClipboard,
|
|
34
36
|
formatNetworkErrorForClipboard,
|
|
37
|
+
formatCentrifugoErrorForClipboard,
|
|
35
38
|
formatErrorTitle,
|
|
36
39
|
extractDomain,
|
|
37
40
|
} from './utils/formatters';
|
|
@@ -34,7 +34,11 @@ import { toast } from 'sonner';
|
|
|
34
34
|
|
|
35
35
|
import { createErrorToast } from '../components/ErrorToast';
|
|
36
36
|
import {
|
|
37
|
-
|
|
37
|
+
DEFAULT_CENTRIFUGO_CONFIG,
|
|
38
|
+
DEFAULT_CORS_CONFIG,
|
|
39
|
+
DEFAULT_NETWORK_CONFIG,
|
|
40
|
+
DEFAULT_VALIDATION_CONFIG,
|
|
41
|
+
ERROR_EVENTS
|
|
38
42
|
} from '../types';
|
|
39
43
|
|
|
40
44
|
import type {
|
|
@@ -44,9 +48,11 @@ import type {
|
|
|
44
48
|
ValidationErrorConfig,
|
|
45
49
|
CORSErrorConfig,
|
|
46
50
|
NetworkErrorConfig,
|
|
51
|
+
CentrifugoErrorConfig,
|
|
47
52
|
ValidationErrorDetail,
|
|
48
53
|
CORSErrorDetail,
|
|
49
54
|
NetworkErrorDetail,
|
|
55
|
+
CentrifugoErrorDetail,
|
|
50
56
|
ErrorTrackingContextValue,
|
|
51
57
|
} from '../types';
|
|
52
58
|
const ErrorTrackingContext = createContext<ErrorTrackingContextValue | undefined>(undefined);
|
|
@@ -64,6 +70,7 @@ export interface ErrorTrackingProviderProps {
|
|
|
64
70
|
validation?: Partial<ValidationErrorConfig>;
|
|
65
71
|
cors?: Partial<CORSErrorConfig>;
|
|
66
72
|
network?: Partial<NetworkErrorConfig>;
|
|
73
|
+
centrifugo?: Partial<CentrifugoErrorConfig>;
|
|
67
74
|
onError?: (error: ErrorDetail) => boolean | void;
|
|
68
75
|
}
|
|
69
76
|
|
|
@@ -77,6 +84,7 @@ export function ErrorTrackingProvider({
|
|
|
77
84
|
validation: userValidationConfig,
|
|
78
85
|
cors: userCorsConfig,
|
|
79
86
|
network: userNetworkConfig,
|
|
87
|
+
centrifugo: userCentrifugoConfig,
|
|
80
88
|
onError,
|
|
81
89
|
}: ErrorTrackingProviderProps) {
|
|
82
90
|
const [errors, setErrors] = useState<StoredError[]>([]);
|
|
@@ -97,6 +105,11 @@ export function ErrorTrackingProvider({
|
|
|
97
105
|
...userNetworkConfig,
|
|
98
106
|
};
|
|
99
107
|
|
|
108
|
+
const centrifugoConfig: Required<CentrifugoErrorConfig> = {
|
|
109
|
+
...DEFAULT_CENTRIFUGO_CONFIG,
|
|
110
|
+
...userCentrifugoConfig,
|
|
111
|
+
};
|
|
112
|
+
|
|
100
113
|
/**
|
|
101
114
|
* Clear all errors
|
|
102
115
|
*/
|
|
@@ -122,7 +135,7 @@ export function ErrorTrackingProvider({
|
|
|
122
135
|
* Handle any error event
|
|
123
136
|
*/
|
|
124
137
|
const handleError = useCallback(
|
|
125
|
-
(detail: ErrorDetail, config: Required<ValidationErrorConfig | CORSErrorConfig | NetworkErrorConfig>) => {
|
|
138
|
+
(detail: ErrorDetail, config: Required<ValidationErrorConfig | CORSErrorConfig | NetworkErrorConfig | CentrifugoErrorConfig>) => {
|
|
126
139
|
// Create stored error with ID
|
|
127
140
|
const storedError: StoredError = {
|
|
128
141
|
...detail,
|
|
@@ -201,24 +214,40 @@ export function ErrorTrackingProvider({
|
|
|
201
214
|
handlers.push({ event: ERROR_EVENTS.NETWORK, handler });
|
|
202
215
|
}
|
|
203
216
|
|
|
217
|
+
// Centrifugo errors
|
|
218
|
+
if (centrifugoConfig.enabled) {
|
|
219
|
+
const handler = (event: Event) => {
|
|
220
|
+
if (!(event instanceof CustomEvent)) return;
|
|
221
|
+
const detail: CentrifugoErrorDetail = {
|
|
222
|
+
...event.detail,
|
|
223
|
+
type: 'centrifugo' as const,
|
|
224
|
+
};
|
|
225
|
+
handleError(detail, centrifugoConfig);
|
|
226
|
+
};
|
|
227
|
+
window.addEventListener(ERROR_EVENTS.CENTRIFUGO, handler);
|
|
228
|
+
handlers.push({ event: ERROR_EVENTS.CENTRIFUGO, handler });
|
|
229
|
+
}
|
|
230
|
+
|
|
204
231
|
// Cleanup
|
|
205
232
|
return () => {
|
|
206
233
|
handlers.forEach(({ event, handler }) => {
|
|
207
234
|
window.removeEventListener(event, handler);
|
|
208
235
|
});
|
|
209
236
|
};
|
|
210
|
-
}, [handleError, validationConfig, corsConfig, networkConfig]);
|
|
237
|
+
}, [handleError, validationConfig, corsConfig, networkConfig, centrifugoConfig]);
|
|
211
238
|
|
|
212
239
|
// Filter errors by type
|
|
213
240
|
const validationErrors = errors.filter((e) => e.type === 'validation') as StoredError<ValidationErrorDetail>[];
|
|
214
241
|
const corsErrors = errors.filter((e) => e.type === 'cors') as StoredError<CORSErrorDetail>[];
|
|
215
242
|
const networkErrors = errors.filter((e) => e.type === 'network') as StoredError<NetworkErrorDetail>[];
|
|
243
|
+
const centrifugoErrors = errors.filter((e) => e.type === 'centrifugo') as StoredError<CentrifugoErrorDetail>[];
|
|
216
244
|
|
|
217
245
|
const value: ErrorTrackingContextValue = {
|
|
218
246
|
errors,
|
|
219
247
|
validationErrors,
|
|
220
248
|
corsErrors,
|
|
221
249
|
networkErrors,
|
|
250
|
+
centrifugoErrors,
|
|
222
251
|
clearErrors,
|
|
223
252
|
clearErrorsByType,
|
|
224
253
|
clearError,
|
|
@@ -228,6 +257,7 @@ export function ErrorTrackingProvider({
|
|
|
228
257
|
validation: validationConfig,
|
|
229
258
|
cors: corsConfig,
|
|
230
259
|
network: networkConfig,
|
|
260
|
+
centrifugo: centrifugoConfig,
|
|
231
261
|
},
|
|
232
262
|
};
|
|
233
263
|
|
|
@@ -59,10 +59,25 @@ export interface NetworkErrorDetail extends BaseErrorDetail {
|
|
|
59
59
|
statusCode?: number;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Centrifugo error detail (from centrifugo-error event)
|
|
64
|
+
*/
|
|
65
|
+
export interface CentrifugoErrorDetail extends BaseErrorDetail {
|
|
66
|
+
type: 'centrifugo';
|
|
67
|
+
/** RPC method that failed */
|
|
68
|
+
method: string;
|
|
69
|
+
/** Error message */
|
|
70
|
+
error: string;
|
|
71
|
+
/** Error code from Centrifugo */
|
|
72
|
+
code?: number;
|
|
73
|
+
/** Additional data sent with the request */
|
|
74
|
+
data?: any;
|
|
75
|
+
}
|
|
76
|
+
|
|
62
77
|
/**
|
|
63
78
|
* Union type of all error details
|
|
64
79
|
*/
|
|
65
|
-
export type ErrorDetail = ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail;
|
|
80
|
+
export type ErrorDetail = ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail | CentrifugoErrorDetail;
|
|
66
81
|
|
|
67
82
|
/**
|
|
68
83
|
* Stored error with unique ID
|
|
@@ -170,6 +185,23 @@ export interface NetworkErrorConfig extends ErrorTypeConfig {
|
|
|
170
185
|
showStatusCode?: boolean;
|
|
171
186
|
}
|
|
172
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Centrifugo error specific config
|
|
190
|
+
*/
|
|
191
|
+
export interface CentrifugoErrorConfig extends ErrorTypeConfig {
|
|
192
|
+
/**
|
|
193
|
+
* Show RPC method in toast
|
|
194
|
+
* @default true
|
|
195
|
+
*/
|
|
196
|
+
showMethod?: boolean;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Show error code in toast
|
|
200
|
+
* @default true
|
|
201
|
+
*/
|
|
202
|
+
showCode?: boolean;
|
|
203
|
+
}
|
|
204
|
+
|
|
173
205
|
/**
|
|
174
206
|
* Complete error tracking configuration
|
|
175
207
|
*/
|
|
@@ -189,6 +221,11 @@ export interface ErrorTrackingConfig {
|
|
|
189
221
|
*/
|
|
190
222
|
network?: NetworkErrorConfig;
|
|
191
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Centrifugo error tracking configuration
|
|
226
|
+
*/
|
|
227
|
+
centrifugo?: CentrifugoErrorConfig;
|
|
228
|
+
|
|
192
229
|
/**
|
|
193
230
|
* Custom error handler (called before toast for all errors)
|
|
194
231
|
* Return false to prevent default toast notification
|
|
@@ -212,11 +249,14 @@ export interface ErrorTrackingContextValue {
|
|
|
212
249
|
/** Network errors only */
|
|
213
250
|
networkErrors: StoredError<NetworkErrorDetail>[];
|
|
214
251
|
|
|
252
|
+
/** Centrifugo errors only */
|
|
253
|
+
centrifugoErrors: StoredError<CentrifugoErrorDetail>[];
|
|
254
|
+
|
|
215
255
|
/** Clear all errors */
|
|
216
256
|
clearErrors: () => void;
|
|
217
257
|
|
|
218
258
|
/** Clear errors by type */
|
|
219
|
-
clearErrorsByType: (type: 'validation' | 'cors' | 'network') => void;
|
|
259
|
+
clearErrorsByType: (type: 'validation' | 'cors' | 'network' | 'centrifugo') => void;
|
|
220
260
|
|
|
221
261
|
/** Clear specific error by ID */
|
|
222
262
|
clearError: (id: string) => void;
|
|
@@ -232,6 +272,7 @@ export interface ErrorTrackingContextValue {
|
|
|
232
272
|
validation: Required<ValidationErrorConfig>;
|
|
233
273
|
cors: Required<CORSErrorConfig>;
|
|
234
274
|
network: Required<NetworkErrorConfig>;
|
|
275
|
+
centrifugo: Required<CentrifugoErrorConfig>;
|
|
235
276
|
};
|
|
236
277
|
}
|
|
237
278
|
|
|
@@ -242,6 +283,7 @@ export const ERROR_EVENTS = {
|
|
|
242
283
|
VALIDATION: 'zod-validation-error',
|
|
243
284
|
CORS: 'cors-error',
|
|
244
285
|
NETWORK: 'network-error',
|
|
286
|
+
CENTRIFUGO: 'centrifugo-error',
|
|
245
287
|
} as const;
|
|
246
288
|
|
|
247
289
|
/**
|
|
@@ -276,3 +318,10 @@ export const DEFAULT_NETWORK_CONFIG: Required<NetworkErrorConfig> = {
|
|
|
276
318
|
showMethod: true,
|
|
277
319
|
showStatusCode: true,
|
|
278
320
|
};
|
|
321
|
+
|
|
322
|
+
export const DEFAULT_CENTRIFUGO_CONFIG: Required<CentrifugoErrorConfig> = {
|
|
323
|
+
...DEFAULT_ERROR_CONFIG,
|
|
324
|
+
duration: 0, // Don't auto-dismiss centrifugo errors
|
|
325
|
+
showMethod: true,
|
|
326
|
+
showCode: true,
|
|
327
|
+
};
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ZodError } from 'zod';
|
|
8
|
-
import type { ValidationErrorDetail, CORSErrorDetail, NetworkErrorDetail } from '../types';
|
|
8
|
+
import type { ValidationErrorDetail, CORSErrorDetail, NetworkErrorDetail, CentrifugoErrorDetail } from '../types';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Format Zod error issues for display
|
|
@@ -83,6 +83,22 @@ export function formatNetworkErrorForClipboard(detail: NetworkErrorDetail): stri
|
|
|
83
83
|
return JSON.stringify(errorData, null, 2);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Format centrifugo error for clipboard
|
|
88
|
+
*/
|
|
89
|
+
export function formatCentrifugoErrorForClipboard(detail: CentrifugoErrorDetail): string {
|
|
90
|
+
const errorData = {
|
|
91
|
+
type: 'centrifugo',
|
|
92
|
+
timestamp: detail.timestamp.toISOString(),
|
|
93
|
+
method: detail.method,
|
|
94
|
+
error: detail.error,
|
|
95
|
+
...(detail.code !== undefined && { code: detail.code }),
|
|
96
|
+
...(detail.data && { data: detail.data }),
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return JSON.stringify(errorData, null, 2);
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
/**
|
|
87
103
|
* Extract domain from URL
|
|
88
104
|
*/
|
|
@@ -98,7 +114,7 @@ export function extractDomain(url: string): string {
|
|
|
98
114
|
/**
|
|
99
115
|
* Format error title based on type
|
|
100
116
|
*/
|
|
101
|
-
export function formatErrorTitle(detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail): string {
|
|
117
|
+
export function formatErrorTitle(detail: ValidationErrorDetail | CORSErrorDetail | NetworkErrorDetail | CentrifugoErrorDetail): string {
|
|
102
118
|
switch (detail.type) {
|
|
103
119
|
case 'validation':
|
|
104
120
|
return `❌ Validation Error in ${detail.operation}`;
|
|
@@ -108,6 +124,10 @@ export function formatErrorTitle(detail: ValidationErrorDetail | CORSErrorDetail
|
|
|
108
124
|
return detail.statusCode
|
|
109
125
|
? `⚠️ Network Error (${detail.statusCode})`
|
|
110
126
|
: '⚠️ Network Error';
|
|
127
|
+
case 'centrifugo':
|
|
128
|
+
return detail.code !== undefined
|
|
129
|
+
? `🔌 Centrifugo Error (${detail.code})`
|
|
130
|
+
: '🔌 Centrifugo Error';
|
|
111
131
|
default:
|
|
112
132
|
return '❌ Error';
|
|
113
133
|
}
|