@ooneex/exception 0.0.1
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/LICENSE +21 -0
- package/README.md +481 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +14 -0
- package/dist/ooneex-exception-0.0.1.tgz +0 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ooneex
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
# @ooneex/exception
|
|
2
|
+
|
|
3
|
+
A comprehensive TypeScript/JavaScript library for creating structured, HTTP status-aware exceptions. This package provides a robust foundation for error handling in web applications with built-in support for HTTP status codes, structured data, and stack trace parsing.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
✅ **HTTP Status Integration** - Built-in support for HTTP status codes via @ooneex/http-status
|
|
15
|
+
|
|
16
|
+
✅ **Type-Safe** - Full TypeScript support with generic data types
|
|
17
|
+
|
|
18
|
+
✅ **Structured Data** - Attach custom data objects to exceptions
|
|
19
|
+
|
|
20
|
+
✅ **Stack Trace Parsing** - Parse stack traces into structured JSON format
|
|
21
|
+
|
|
22
|
+
✅ **Predefined Exceptions** - Common HTTP exceptions (400, 401, 404, 405)
|
|
23
|
+
|
|
24
|
+
✅ **Cross-Platform** - Works in Browser, Node.js, Bun, and Deno
|
|
25
|
+
|
|
26
|
+
✅ **Immutable Data** - Exception data is automatically frozen
|
|
27
|
+
|
|
28
|
+
✅ **Error Wrapping** - Wrap native Error objects with additional context
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### Bun
|
|
33
|
+
```bash
|
|
34
|
+
bun add @ooneex/exception
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### pnpm
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add @ooneex/exception
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Yarn
|
|
43
|
+
```bash
|
|
44
|
+
yarn add @ooneex/exception
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### npm
|
|
48
|
+
```bash
|
|
49
|
+
npm install @ooneex/exception
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
### Basic Usage
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { Exception } from '@ooneex/exception';
|
|
58
|
+
|
|
59
|
+
// Simple exception with message
|
|
60
|
+
const exception = new Exception('Something went wrong');
|
|
61
|
+
|
|
62
|
+
console.log(exception.message); // "Something went wrong"
|
|
63
|
+
console.log(exception.name); // "Exception"
|
|
64
|
+
console.log(exception.date); // Date object
|
|
65
|
+
|
|
66
|
+
// Exception with HTTP status and data
|
|
67
|
+
const detailedException = new Exception('User not found', {
|
|
68
|
+
status: 404,
|
|
69
|
+
data: {
|
|
70
|
+
userId: 123,
|
|
71
|
+
searchCriteria: { email: 'user@example.com' }
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
console.log(detailedException.status); // 404
|
|
76
|
+
console.log(detailedException.data); // { userId: 123, searchCriteria: {...} }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Using Predefined Exceptions
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import {
|
|
83
|
+
BadRequestException,
|
|
84
|
+
UnauthorizedException,
|
|
85
|
+
NotFoundException,
|
|
86
|
+
MethodNotAllowedException
|
|
87
|
+
} from '@ooneex/exception';
|
|
88
|
+
|
|
89
|
+
// 400 Bad Request
|
|
90
|
+
throw new BadRequestException('Invalid input data', {
|
|
91
|
+
field: 'email',
|
|
92
|
+
value: 'invalid-email',
|
|
93
|
+
rule: 'Must be a valid email address'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// 401 Unauthorized
|
|
97
|
+
throw new UnauthorizedException('Token expired', {
|
|
98
|
+
token: 'eyJ...',
|
|
99
|
+
expiredAt: new Date()
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// 404 Not Found
|
|
103
|
+
throw new NotFoundException('Resource not found', {
|
|
104
|
+
resourceType: 'User',
|
|
105
|
+
id: 123
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// 405 Method Not Allowed
|
|
109
|
+
throw new MethodNotAllowedException('POST not allowed on this endpoint', {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
allowedMethods: ['GET', 'PUT']
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Error Wrapping
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { Exception } from '@ooneex/exception';
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
// Some operation that might fail
|
|
122
|
+
JSON.parse('invalid json');
|
|
123
|
+
} catch (error) {
|
|
124
|
+
// Wrap the native error with additional context
|
|
125
|
+
throw new Exception(error as Error, {
|
|
126
|
+
status: 400,
|
|
127
|
+
data: {
|
|
128
|
+
operation: 'JSON parsing',
|
|
129
|
+
input: 'invalid json'
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Stack Trace Parsing
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { Exception } from '@ooneex/exception';
|
|
139
|
+
|
|
140
|
+
const exception = new Exception('Parsing failed');
|
|
141
|
+
const stackFrames = exception.stackToJson();
|
|
142
|
+
|
|
143
|
+
console.log(stackFrames);
|
|
144
|
+
// [
|
|
145
|
+
// {
|
|
146
|
+
// functionName: 'parseData',
|
|
147
|
+
// fileName: '/path/to/file.ts',
|
|
148
|
+
// lineNumber: 42,
|
|
149
|
+
// columnNumber: 15,
|
|
150
|
+
// source: ' at parseData (/path/to/file.ts:42:15)'
|
|
151
|
+
// },
|
|
152
|
+
// ...
|
|
153
|
+
// ]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Generic Data Types
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { Exception } from '@ooneex/exception';
|
|
160
|
+
|
|
161
|
+
// Define custom data interface
|
|
162
|
+
interface ValidationError {
|
|
163
|
+
field: string;
|
|
164
|
+
value: unknown;
|
|
165
|
+
rule: string;
|
|
166
|
+
message: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Create typed exception
|
|
170
|
+
const validationException = new Exception<ValidationError>('Validation failed', {
|
|
171
|
+
status: 400,
|
|
172
|
+
data: {
|
|
173
|
+
field: 'email',
|
|
174
|
+
value: 'not-an-email',
|
|
175
|
+
rule: 'email',
|
|
176
|
+
message: 'Must be a valid email address'
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// TypeScript ensures type safety
|
|
181
|
+
console.log(validationException.data?.field); // string
|
|
182
|
+
console.log(validationException.data?.rule); // string
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## API Reference
|
|
186
|
+
|
|
187
|
+
### `Exception<T>` Class
|
|
188
|
+
|
|
189
|
+
The main exception class providing structured error handling with optional HTTP status and custom data.
|
|
190
|
+
|
|
191
|
+
#### Constructor
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
new Exception<T>(message: string | Error, options?: {
|
|
195
|
+
status?: StatusCodeType;
|
|
196
|
+
data?: T;
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Parameters:**
|
|
201
|
+
- `message` - Error message string or native Error object to wrap
|
|
202
|
+
- `options.status` - HTTP status code (from @ooneex/http-status)
|
|
203
|
+
- `options.data` - Custom data object (automatically frozen)
|
|
204
|
+
|
|
205
|
+
#### Properties
|
|
206
|
+
|
|
207
|
+
##### `date: Date` (readonly)
|
|
208
|
+
Timestamp when the exception was created.
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const exception = new Exception('Error occurred');
|
|
212
|
+
console.log(exception.date); // 2024-01-15T10:30:00.000Z
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
##### `status?: StatusCodeType` (readonly)
|
|
216
|
+
HTTP status code associated with the exception.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const exception = new Exception('Not found', { status: 404 });
|
|
220
|
+
console.log(exception.status); // 404
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
##### `data?: T` (readonly)
|
|
224
|
+
Custom data object associated with the exception. Automatically frozen to prevent mutations.
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
const exception = new Exception('Error', {
|
|
228
|
+
data: { userId: 123, action: 'delete' }
|
|
229
|
+
});
|
|
230
|
+
console.log(exception.data); // { userId: 123, action: 'delete' }
|
|
231
|
+
// exception.data.userId = 456; // TypeError: Cannot assign to read only property
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
##### `native?: Error` (readonly)
|
|
235
|
+
Original native Error object when wrapping existing errors.
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
const originalError = new Error('Original message');
|
|
239
|
+
const exception = new Exception(originalError);
|
|
240
|
+
console.log(exception.native); // Original Error object
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
##### `message: string`
|
|
244
|
+
Error message (inherited from Error).
|
|
245
|
+
|
|
246
|
+
##### `name: string`
|
|
247
|
+
Exception name (inherited from Error).
|
|
248
|
+
|
|
249
|
+
##### `stack?: string`
|
|
250
|
+
Stack trace string (inherited from Error).
|
|
251
|
+
|
|
252
|
+
#### Methods
|
|
253
|
+
|
|
254
|
+
##### `stackToJson(): ExceptionStackFrameType[] | null`
|
|
255
|
+
Parses the stack trace into a structured JSON format.
|
|
256
|
+
|
|
257
|
+
**Returns:** Array of stack frame objects or `null` if no stack trace available.
|
|
258
|
+
|
|
259
|
+
**Example:**
|
|
260
|
+
```typescript
|
|
261
|
+
const exception = new Exception('Error occurred');
|
|
262
|
+
const frames = exception.stackToJson();
|
|
263
|
+
|
|
264
|
+
if (frames) {
|
|
265
|
+
frames.forEach(frame => {
|
|
266
|
+
console.log(`Function: ${frame.functionName}`);
|
|
267
|
+
console.log(`File: ${frame.fileName}:${frame.lineNumber}:${frame.columnNumber}`);
|
|
268
|
+
console.log(`Source: ${frame.source}`);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Predefined Exception Classes
|
|
274
|
+
|
|
275
|
+
#### `BadRequestException<T>`
|
|
276
|
+
HTTP 400 Bad Request exception.
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
new BadRequestException<T>(message: string, data?: T)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Example:**
|
|
283
|
+
```typescript
|
|
284
|
+
throw new BadRequestException('Invalid request data', {
|
|
285
|
+
validationErrors: ['email is required', 'age must be a number']
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
#### `UnauthorizedException<T>`
|
|
290
|
+
HTTP 401 Unauthorized exception.
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
new UnauthorizedException<T>(message: string, data?: T)
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Example:**
|
|
297
|
+
```typescript
|
|
298
|
+
throw new UnauthorizedException('Access token expired', {
|
|
299
|
+
tokenType: 'Bearer',
|
|
300
|
+
expiredAt: new Date()
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### `NotFoundException<T>`
|
|
305
|
+
HTTP 404 Not Found exception.
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
new NotFoundException<T>(message: string, data?: T)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Example:**
|
|
312
|
+
```typescript
|
|
313
|
+
throw new NotFoundException('User not found', {
|
|
314
|
+
userId: 123,
|
|
315
|
+
searchedBy: 'email'
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### `MethodNotAllowedException<T>`
|
|
320
|
+
HTTP 405 Method Not Allowed exception.
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
new MethodNotAllowedException<T>(message: string, data?: T)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Example:**
|
|
327
|
+
```typescript
|
|
328
|
+
throw new MethodNotAllowedException('DELETE method not allowed', {
|
|
329
|
+
requestedMethod: 'DELETE',
|
|
330
|
+
allowedMethods: ['GET', 'POST', 'PUT']
|
|
331
|
+
});
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Types and Interfaces
|
|
335
|
+
|
|
336
|
+
#### `ExceptionStackFrameType`
|
|
337
|
+
Represents a single frame in a parsed stack trace.
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
type ExceptionStackFrameType = {
|
|
341
|
+
functionName?: string;
|
|
342
|
+
fileName?: string;
|
|
343
|
+
lineNumber?: number;
|
|
344
|
+
columnNumber?: number;
|
|
345
|
+
source: string;
|
|
346
|
+
};
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### `IException<T>`
|
|
350
|
+
Interface defining the exception contract.
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
interface IException<T = unknown> {
|
|
354
|
+
readonly date: Date;
|
|
355
|
+
readonly status?: StatusCodeType;
|
|
356
|
+
readonly data?: Readonly<Record<string, T>>;
|
|
357
|
+
readonly native?: Error;
|
|
358
|
+
readonly message: string;
|
|
359
|
+
readonly name: string;
|
|
360
|
+
readonly stack?: string;
|
|
361
|
+
stackToJson(): ExceptionStackFrameType[] | null;
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## Advanced Usage
|
|
366
|
+
|
|
367
|
+
### Custom Exception Classes
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
import { Exception } from '@ooneex/exception';
|
|
371
|
+
import { HttpStatus } from '@ooneex/http-status';
|
|
372
|
+
|
|
373
|
+
class PaymentException extends Exception {
|
|
374
|
+
constructor(message: string, data: Record<string, unknown> = {}) {
|
|
375
|
+
super(message, {
|
|
376
|
+
status: HttpStatus.Code.PaymentRequired, // 402
|
|
377
|
+
data
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Usage
|
|
383
|
+
throw new PaymentException('Insufficient funds', {
|
|
384
|
+
accountBalance: 50.00,
|
|
385
|
+
requiredAmount: 100.00,
|
|
386
|
+
currency: 'USD'
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Error Serialization
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import { Exception } from '@ooneex/exception';
|
|
394
|
+
|
|
395
|
+
const exception = new Exception('Process failed', {
|
|
396
|
+
status: 500,
|
|
397
|
+
data: {
|
|
398
|
+
processId: 'proc-123',
|
|
399
|
+
step: 'validation',
|
|
400
|
+
retryCount: 3
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Serialize for logging or API responses
|
|
405
|
+
const serialized = JSON.stringify({
|
|
406
|
+
message: exception.message,
|
|
407
|
+
name: exception.name,
|
|
408
|
+
status: exception.status,
|
|
409
|
+
data: exception.data,
|
|
410
|
+
date: exception.date,
|
|
411
|
+
stackFrames: exception.stackToJson()
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
console.log(serialized);
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Integration with Express.js
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
import express from 'express';
|
|
421
|
+
import { Exception, NotFoundException } from '@ooneex/exception';
|
|
422
|
+
|
|
423
|
+
const app = express();
|
|
424
|
+
|
|
425
|
+
app.get('/users/:id', (req, res, next) => {
|
|
426
|
+
const userId = req.params.id;
|
|
427
|
+
|
|
428
|
+
// Simulate user lookup
|
|
429
|
+
const user = findUser(userId);
|
|
430
|
+
if (!user) {
|
|
431
|
+
throw new NotFoundException('User not found', {
|
|
432
|
+
userId,
|
|
433
|
+
searchedBy: 'id'
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
res.json(user);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// Error handler
|
|
441
|
+
app.use((error: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
442
|
+
if (error instanceof Exception) {
|
|
443
|
+
res.status(error.status || 500).json({
|
|
444
|
+
error: {
|
|
445
|
+
message: error.message,
|
|
446
|
+
status: error.status,
|
|
447
|
+
data: error.data,
|
|
448
|
+
timestamp: error.date
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
next(error);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## License
|
|
458
|
+
|
|
459
|
+
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
|
|
460
|
+
|
|
461
|
+
## Contributing
|
|
462
|
+
|
|
463
|
+
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
464
|
+
|
|
465
|
+
### Development Setup
|
|
466
|
+
|
|
467
|
+
1. Clone the repository
|
|
468
|
+
2. Install dependencies: `bun install`
|
|
469
|
+
3. Run tests: `bun run test`
|
|
470
|
+
4. Build the project: `bun run build`
|
|
471
|
+
|
|
472
|
+
### Guidelines
|
|
473
|
+
|
|
474
|
+
- Write tests for new features
|
|
475
|
+
- Follow the existing code style
|
|
476
|
+
- Update documentation for API changes
|
|
477
|
+
- Ensure all tests pass before submitting PR
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
Made with ❤️ by the Ooneex team
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { StatusCodeType as StatusCodeType2 } from "@ooneex/http-status";
|
|
2
|
+
import { StatusCodeType } from "@ooneex/http-status";
|
|
3
|
+
type ExceptionStackFrameType = {
|
|
4
|
+
functionName?: string;
|
|
5
|
+
fileName?: string;
|
|
6
|
+
lineNumber?: number;
|
|
7
|
+
columnNumber?: number;
|
|
8
|
+
source: string;
|
|
9
|
+
};
|
|
10
|
+
interface IException {
|
|
11
|
+
readonly date: Date;
|
|
12
|
+
readonly status: StatusCodeType;
|
|
13
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
14
|
+
readonly native?: Error;
|
|
15
|
+
readonly message: string;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly stack?: string;
|
|
18
|
+
stackToJson: () => ExceptionStackFrameType[] | null;
|
|
19
|
+
}
|
|
20
|
+
declare class Exception extends Error implements IException {
|
|
21
|
+
readonly date: Date;
|
|
22
|
+
readonly status: StatusCodeType2;
|
|
23
|
+
readonly data: Record<string, unknown>;
|
|
24
|
+
readonly native?: Error;
|
|
25
|
+
constructor(message: string | Error, options?: {
|
|
26
|
+
status?: StatusCodeType2;
|
|
27
|
+
data?: Record<string, unknown>;
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Converts the stack trace into a structured JSON object
|
|
31
|
+
* @returns Array of stack frames or null if no stack trace is available
|
|
32
|
+
*/
|
|
33
|
+
stackToJson(): ExceptionStackFrameType[] | null;
|
|
34
|
+
}
|
|
35
|
+
declare class BadRequestException extends Exception {
|
|
36
|
+
constructor(message: string, data?: Record<string, unknown>);
|
|
37
|
+
}
|
|
38
|
+
declare class MethodNotAllowedException extends Exception {
|
|
39
|
+
constructor(message: string, data?: Record<string, unknown>);
|
|
40
|
+
}
|
|
41
|
+
declare class NotFoundException extends Exception {
|
|
42
|
+
constructor(message: string, data?: Record<string, unknown>);
|
|
43
|
+
}
|
|
44
|
+
declare class UnauthorizedException extends Exception {
|
|
45
|
+
constructor(message: string, data?: Record<string, unknown>);
|
|
46
|
+
}
|
|
47
|
+
export { UnauthorizedException, NotFoundException, MethodNotAllowedException, IException, ExceptionStackFrameType, Exception, BadRequestException };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{HttpStatus as w}from"@ooneex/http-status";class p extends Error{date=new Date;status;data;native;constructor(r,t){super(r instanceof Error?r.message:r);if(this.status=t?.status||500,this.data=t?.data||{},r instanceof Error)this.native=r;this.name=this.constructor.name,this.data=Object.freeze(this.data)}stackToJson(){if(!this.stack)return null;let r=this.stack.split(`
|
|
2
|
+
`),t=[];for(let u=1;u<r.length;u++){let E=r[u]?.trim();if(!E)continue;let o={source:E},R=E.match(/^\s*at\s+(.+)$/);if(R){let x=R[1],y=x?.match(/^(.+?)\s+\((.+)\)$/);if(y){let e=y[1],n=y[2];if(e)o.functionName=e;let d=n?.match(/^(.+):(\d+):(\d+)$/);if(d){let s=d[1],S=d[2],k=d[3];if(s)o.fileName=s;if(S)o.lineNumber=Number.parseInt(S,10);if(k)o.columnNumber=Number.parseInt(k,10)}else if(n)o.fileName=n}else{let e=x?.match(/^(.+):(\d+):(\d+)$/);if(e){let n=e[1],d=e[2],s=e[3];if(n)o.fileName=n;if(d)o.lineNumber=Number.parseInt(d,10);if(s)o.columnNumber=Number.parseInt(s,10)}else if(x)o.functionName=x}}t.push(o)}return t}}class g extends p{constructor(r,t={}){super(r,{status:w.Code.BadRequest,data:t});this.name="BadRequestException"}}import{HttpStatus as C}from"@ooneex/http-status";class F extends p{constructor(r,t={}){super(r,{status:C.Code.MethodNotAllowed,data:t});this.name="MethodNotAllowedException"}}import{HttpStatus as T}from"@ooneex/http-status";class H extends p{constructor(r,t={}){super(r,{status:T.Code.NotFound,data:t});this.name="NotFoundException"}}import{HttpStatus as b}from"@ooneex/http-status";class i extends p{constructor(r,t={}){super(r,{status:b.Code.Unauthorized,data:t});this.name="UnauthorizedException"}}export{i as UnauthorizedException,H as NotFoundException,F as MethodNotAllowedException,p as Exception,g as BadRequestException};
|
|
3
|
+
|
|
4
|
+
//# debugId=C86D27C94A89C34764756E2164756E21
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["src/BadRequestException.ts", "src/Exception.ts", "src/MethodNotAllowedException.ts", "src/NotFoundException.ts", "src/UnauthorizedException.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { HttpStatus } from \"@ooneex/http-status\";\nimport { Exception } from \"./Exception\";\n\nexport class BadRequestException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.BadRequest,\n data,\n });\n this.name = \"BadRequestException\";\n }\n}\n",
|
|
6
|
+
"import type { StatusCodeType } from \"@ooneex/http-status\";\nimport type { ExceptionStackFrameType, IException } from \"./types\";\n\nexport class Exception extends Error implements IException {\n public readonly date: Date = new Date();\n public readonly status: StatusCodeType;\n public readonly data: Record<string, unknown>;\n public readonly native?: Error;\n\n constructor(message: string | Error, options?: { status?: StatusCodeType; data?: Record<string, unknown> }) {\n super(message instanceof Error ? (message as Error).message : message);\n\n this.status = options?.status || 500;\n this.data = options?.data || {};\n\n if (message instanceof Error) {\n this.native = message as Error;\n }\n this.name = this.constructor.name;\n this.data = Object.freeze(this.data);\n }\n\n /**\n * Converts the stack trace into a structured JSON object\n * @returns Array of stack frames or null if no stack trace is available\n */\n public stackToJson(): ExceptionStackFrameType[] | null {\n if (!this.stack) {\n return null;\n }\n\n const stackLines = this.stack.split(\"\\n\");\n const frames: ExceptionStackFrameType[] = [];\n\n // Skip the first line (error message) and process stack frames\n for (let i = 1; i < stackLines.length; i++) {\n const line = stackLines[i]?.trim();\n if (!line) continue;\n\n const frame: ExceptionStackFrameType = {\n source: line,\n };\n\n // Parse common stack trace formats\n // Format: \" at functionName (file:line:column)\"\n // Format: \" at file:line:column\"\n // Format: \" at functionName (file)\"\n\n const atMatch = line.match(/^\\s*at\\s+(.+)$/);\n if (atMatch) {\n const content = atMatch[1];\n\n // Check if it has parentheses (function name with location)\n const funcWithLocationMatch = content?.match(/^(.+?)\\s+\\((.+)\\)$/);\n if (funcWithLocationMatch) {\n const functionName = funcWithLocationMatch[1];\n const location = funcWithLocationMatch[2];\n\n if (functionName) {\n frame.functionName = functionName;\n }\n\n // Parse file:line:column\n const locationMatch = location?.match(/^(.+):(\\d+):(\\d+)$/);\n if (locationMatch) {\n const fileName = locationMatch[1];\n const lineNum = locationMatch[2];\n const colNum = locationMatch[3];\n\n if (fileName) {\n frame.fileName = fileName;\n }\n if (lineNum) {\n frame.lineNumber = Number.parseInt(lineNum, 10);\n }\n if (colNum) {\n frame.columnNumber = Number.parseInt(colNum, 10);\n }\n } else if (location) {\n frame.fileName = location;\n }\n } else {\n // Direct file:line:column format\n const directLocationMatch = content?.match(/^(.+):(\\d+):(\\d+)$/);\n if (directLocationMatch) {\n const fileName = directLocationMatch[1];\n const lineNum = directLocationMatch[2];\n const colNum = directLocationMatch[3];\n\n if (fileName) {\n frame.fileName = fileName;\n }\n if (lineNum) {\n frame.lineNumber = Number.parseInt(lineNum, 10);\n }\n if (colNum) {\n frame.columnNumber = Number.parseInt(colNum, 10);\n }\n } else if (content) {\n // Assume it's a function name or location without line numbers\n frame.functionName = content;\n }\n }\n }\n\n frames.push(frame);\n }\n\n return frames;\n }\n}\n",
|
|
7
|
+
"import { HttpStatus } from \"@ooneex/http-status\";\nimport { Exception } from \"./Exception\";\n\nexport class MethodNotAllowedException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.MethodNotAllowed,\n data,\n });\n this.name = \"MethodNotAllowedException\";\n }\n}\n",
|
|
8
|
+
"import { HttpStatus } from \"@ooneex/http-status\";\nimport { Exception } from \"./Exception\";\n\nexport class NotFoundException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.NotFound,\n data,\n });\n this.name = \"NotFoundException\";\n }\n}\n",
|
|
9
|
+
"import { HttpStatus } from \"@ooneex/http-status\";\nimport { Exception } from \"./Exception\";\n\nexport class UnauthorizedException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.Unauthorized,\n data,\n });\n this.name = \"UnauthorizedException\";\n }\n}\n"
|
|
10
|
+
],
|
|
11
|
+
"mappings": "AAAA,qBAAS,4BCGF,MAAM,UAAkB,KAA4B,CACzC,KAAa,IAAI,KACjB,OACA,KACA,OAEhB,WAAW,CAAC,EAAyB,EAAuE,CAC1G,MAAM,aAAmB,MAAS,EAAkB,QAAU,CAAO,EAKrE,GAHA,KAAK,OAAS,GAAS,QAAU,IACjC,KAAK,KAAO,GAAS,MAAQ,CAAC,EAE1B,aAAmB,MACrB,KAAK,OAAS,EAEhB,KAAK,KAAO,KAAK,YAAY,KAC7B,KAAK,KAAO,OAAO,OAAO,KAAK,IAAI,EAO9B,WAAW,EAAqC,CACrD,GAAI,CAAC,KAAK,MACR,OAAO,KAGT,IAAM,EAAa,KAAK,MAAM,MAAM;AAAA,CAAI,EAClC,EAAoC,CAAC,EAG3C,QAAS,EAAI,EAAG,EAAI,EAAW,OAAQ,IAAK,CAC1C,IAAM,EAAO,EAAW,IAAI,KAAK,EACjC,GAAI,CAAC,EAAM,SAEX,IAAM,EAAiC,CACrC,OAAQ,CACV,EAOM,EAAU,EAAK,MAAM,gBAAgB,EAC3C,GAAI,EAAS,CACX,IAAM,EAAU,EAAQ,GAGlB,EAAwB,GAAS,MAAM,oBAAoB,EACjE,GAAI,EAAuB,CACzB,IAAM,EAAe,EAAsB,GACrC,EAAW,EAAsB,GAEvC,GAAI,EACF,EAAM,aAAe,EAIvB,IAAM,EAAgB,GAAU,MAAM,oBAAoB,EAC1D,GAAI,EAAe,CACjB,IAAM,EAAW,EAAc,GACzB,EAAU,EAAc,GACxB,EAAS,EAAc,GAE7B,GAAI,EACF,EAAM,SAAW,EAEnB,GAAI,EACF,EAAM,WAAa,OAAO,SAAS,EAAS,EAAE,EAEhD,GAAI,EACF,EAAM,aAAe,OAAO,SAAS,EAAQ,EAAE,EAE5C,QAAI,EACT,EAAM,SAAW,EAEd,KAEL,IAAM,EAAsB,GAAS,MAAM,oBAAoB,EAC/D,GAAI,EAAqB,CACvB,IAAM,EAAW,EAAoB,GAC/B,EAAU,EAAoB,GAC9B,EAAS,EAAoB,GAEnC,GAAI,EACF,EAAM,SAAW,EAEnB,GAAI,EACF,EAAM,WAAa,OAAO,SAAS,EAAS,EAAE,EAEhD,GAAI,EACF,EAAM,aAAe,OAAO,SAAS,EAAQ,EAAE,EAE5C,QAAI,EAET,EAAM,aAAe,GAK3B,EAAO,KAAK,CAAK,EAGnB,OAAO,EAEX,CD3GO,MAAM,UAA4B,CAAU,CACjD,WAAW,CAAC,EAAiB,EAAgC,CAAC,EAAG,CAC/D,MAAM,EAAS,CACb,OAAQ,EAAW,KAAK,WACxB,MACF,CAAC,EACD,KAAK,KAAO,sBAEhB,CEXA,qBAAS,4BAGF,MAAM,UAAkC,CAAU,CACvD,WAAW,CAAC,EAAiB,EAAgC,CAAC,EAAG,CAC/D,MAAM,EAAS,CACb,OAAQ,EAAW,KAAK,iBACxB,MACF,CAAC,EACD,KAAK,KAAO,4BAEhB,CCXA,qBAAS,4BAGF,MAAM,UAA0B,CAAU,CAC/C,WAAW,CAAC,EAAiB,EAAgC,CAAC,EAAG,CAC/D,MAAM,EAAS,CACb,OAAQ,EAAW,KAAK,SACxB,MACF,CAAC,EACD,KAAK,KAAO,oBAEhB,CCXA,qBAAS,4BAGF,MAAM,UAA8B,CAAU,CACnD,WAAW,CAAC,EAAiB,EAAgC,CAAC,EAAG,CAC/D,MAAM,EAAS,CACb,OAAQ,EAAW,KAAK,aACxB,MACF,CAAC,EACD,KAAK,KAAO,wBAEhB",
|
|
12
|
+
"debugId": "C86D27C94A89C34764756E2164756E21",
|
|
13
|
+
"names": []
|
|
14
|
+
}
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ooneex/exception",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"LICENSE",
|
|
9
|
+
"README.md",
|
|
10
|
+
"package.json"
|
|
11
|
+
],
|
|
12
|
+
"module": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "bun test tests",
|
|
26
|
+
"build": "bunup",
|
|
27
|
+
"lint": "tsgo --noEmit && bunx biome lint",
|
|
28
|
+
"publish:prod": "bun publish --tolerate-republish --access public",
|
|
29
|
+
"publish:pack": "bun pm pack --destination ./dist",
|
|
30
|
+
"publish:dry": "bun publish --dry-run"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@ooneex/http-status": "0.0.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {},
|
|
36
|
+
"peerDependencies": {}
|
|
37
|
+
}
|