@object-ui/data-objectstack 0.3.1 → 0.5.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.
package/src/errors.ts ADDED
@@ -0,0 +1,275 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ /**
10
+ * Base error class for all ObjectStack adapter errors
11
+ */
12
+ export class ObjectStackError extends Error {
13
+ /**
14
+ * Create a new ObjectStackError
15
+ *
16
+ * @param message - Human-readable error message
17
+ * @param code - Unique error code for programmatic handling
18
+ * @param statusCode - Optional HTTP status code
19
+ * @param details - Optional additional error details for debugging
20
+ */
21
+ constructor(
22
+ message: string,
23
+ public code: string,
24
+ public statusCode?: number,
25
+ public details?: Record<string, unknown>
26
+ ) {
27
+ super(message);
28
+ this.name = 'ObjectStackError';
29
+
30
+ // Maintains proper stack trace for where error was thrown (only in V8)
31
+ if (Error.captureStackTrace) {
32
+ Error.captureStackTrace(this, this.constructor);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Convert error to JSON for logging/debugging
38
+ */
39
+ toJSON() {
40
+ return {
41
+ name: this.name,
42
+ message: this.message,
43
+ code: this.code,
44
+ statusCode: this.statusCode,
45
+ details: this.details,
46
+ stack: this.stack,
47
+ };
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Error thrown when requested metadata/schema is not found
53
+ */
54
+ export class MetadataNotFoundError extends ObjectStackError {
55
+ constructor(
56
+ objectName: string,
57
+ details?: Record<string, unknown>
58
+ ) {
59
+ super(
60
+ `Metadata not found for object: ${objectName}`,
61
+ 'METADATA_NOT_FOUND',
62
+ 404,
63
+ { objectName, ...details }
64
+ );
65
+ this.name = 'MetadataNotFoundError';
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Error thrown when a bulk operation fails
71
+ */
72
+ export class BulkOperationError extends ObjectStackError {
73
+ /**
74
+ * Create a new BulkOperationError
75
+ *
76
+ * @param operation - The bulk operation that failed (create, update, delete)
77
+ * @param successCount - Number of successful operations
78
+ * @param failureCount - Number of failed operations
79
+ * @param errors - Array of individual errors
80
+ * @param details - Additional error details
81
+ */
82
+ constructor(
83
+ operation: 'create' | 'update' | 'delete',
84
+ public successCount: number,
85
+ public failureCount: number,
86
+ public errors: Array<{ index: number; error: unknown }>,
87
+ details?: Record<string, unknown>
88
+ ) {
89
+ super(
90
+ `Bulk ${operation} operation failed: ${successCount} succeeded, ${failureCount} failed`,
91
+ 'BULK_OPERATION_ERROR',
92
+ 500,
93
+ {
94
+ operation,
95
+ successCount,
96
+ failureCount,
97
+ errors,
98
+ ...details,
99
+ }
100
+ );
101
+ this.name = 'BulkOperationError';
102
+ }
103
+
104
+ /**
105
+ * Get a summary of the bulk operation failure
106
+ */
107
+ getSummary() {
108
+ const total = this.successCount + this.failureCount;
109
+ const failureRate = total > 0 ? this.failureCount / total : 0;
110
+
111
+ return {
112
+ operation: this.details?.operation as string,
113
+ total: total,
114
+ successful: this.successCount,
115
+ failed: this.failureCount,
116
+ failureRate: failureRate,
117
+ errors: this.errors,
118
+ };
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Error thrown when connection to ObjectStack server fails
124
+ */
125
+ export class ConnectionError extends ObjectStackError {
126
+ constructor(
127
+ message: string,
128
+ public url?: string,
129
+ details?: Record<string, unknown>,
130
+ statusCode?: number
131
+ ) {
132
+ super(
133
+ `Connection error: ${message}`,
134
+ 'CONNECTION_ERROR',
135
+ statusCode || 503,
136
+ { url, ...details }
137
+ );
138
+ this.name = 'ConnectionError';
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Error thrown when authentication fails
144
+ */
145
+ export class AuthenticationError extends ObjectStackError {
146
+ constructor(
147
+ message: string = 'Authentication failed',
148
+ details?: Record<string, unknown>,
149
+ statusCode?: number
150
+ ) {
151
+ super(
152
+ message,
153
+ 'AUTHENTICATION_ERROR',
154
+ statusCode || 401,
155
+ details
156
+ );
157
+ this.name = 'AuthenticationError';
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Error thrown when data validation fails
163
+ */
164
+ export class ValidationError extends ObjectStackError {
165
+ /**
166
+ * Create a new ValidationError
167
+ *
168
+ * @param message - Human-readable error message
169
+ * @param field - The field that failed validation (optional)
170
+ * @param validationErrors - Array of validation error details
171
+ * @param details - Additional error details
172
+ */
173
+ constructor(
174
+ message: string,
175
+ public field?: string,
176
+ public validationErrors?: Array<{ field: string; message: string }>,
177
+ details?: Record<string, unknown>
178
+ ) {
179
+ super(
180
+ message,
181
+ 'VALIDATION_ERROR',
182
+ 400,
183
+ {
184
+ field,
185
+ validationErrors,
186
+ ...details,
187
+ }
188
+ );
189
+ this.name = 'ValidationError';
190
+ }
191
+
192
+ /**
193
+ * Get all validation errors as a formatted list
194
+ */
195
+ getValidationErrors() {
196
+ return this.validationErrors || [];
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Helper function to create an error from an HTTP response
202
+ *
203
+ * @param response - Response object or error from fetch/axios
204
+ * @param context - Additional context for debugging
205
+ * @returns Appropriate error instance
206
+ */
207
+ export function createErrorFromResponse(response: Record<string, unknown>, context?: string): ObjectStackError {
208
+ const status = (response?.status as number) || (response?.statusCode as number) || 500;
209
+ const message = (response?.message as string) || (response?.statusText as string) || 'Unknown error';
210
+ const details = {
211
+ context,
212
+ response: {
213
+ status,
214
+ data: response?.data,
215
+ headers: response?.headers,
216
+ },
217
+ };
218
+
219
+ switch (status) {
220
+ case 401:
221
+ return new AuthenticationError(message, details, 401);
222
+
223
+ case 403:
224
+ return new AuthenticationError(message, details, 403);
225
+
226
+ case 404:
227
+ // Check if it's a metadata request based on context
228
+ if (context?.includes('metadata') || context?.includes('schema') || context?.includes('getObjectSchema')) {
229
+ const objectName = extractObjectName(context);
230
+ return new MetadataNotFoundError(objectName, details);
231
+ }
232
+ return new ObjectStackError(message, 'NOT_FOUND', 404, details);
233
+
234
+ case 400:
235
+ return new ValidationError(message, undefined, (response?.data as Record<string, unknown>)?.errors as Array<{ field: string; message: string }>, details);
236
+
237
+ case 503:
238
+ return new ConnectionError(message, (response?.config as Record<string, unknown>)?.url as string, details, 503);
239
+
240
+ case 504:
241
+ return new ConnectionError(message, (response?.config as Record<string, unknown>)?.url as string, details, 504);
242
+
243
+ default:
244
+ return new ObjectStackError(message, 'UNKNOWN_ERROR', status, details);
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Helper to extract object name from context string
250
+ */
251
+ function extractObjectName(context?: string): string {
252
+ if (!context) return 'unknown';
253
+
254
+ // Try to extract object name from patterns like "getObjectSchema(users)"
255
+ const match = context.match(/\(([^)]+)\)/);
256
+ return match ? match[1] : 'unknown';
257
+ }
258
+
259
+ /**
260
+ * Type guard to check if an error is an ObjectStackError
261
+ */
262
+ export function isObjectStackError(error: unknown): error is ObjectStackError {
263
+ return error instanceof ObjectStackError;
264
+ }
265
+
266
+ /**
267
+ * Type guard to check if an error is a specific ObjectStack error type
268
+ */
269
+ export function isErrorType<T extends ObjectStackError>(
270
+ error: unknown,
271
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
272
+ errorClass: new (...args: any[]) => T
273
+ ): error is T {
274
+ return error instanceof errorClass;
275
+ }