@hkdigital/lib-core 0.4.15 → 0.4.17

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.
@@ -36,3 +36,9 @@ export function sign(claims: import("./typedef.js").JwtPayload, secretOrPrivateK
36
36
  * @returns {import('./typedef.js').JwtPayload} claims - The decoded JWT payload
37
37
  */
38
38
  export function verify(token: string, secretOrPrivateKey: import("./typedef.js").Secret, options?: import("./typedef.js").VerifyOptions): import("./typedef.js").JwtPayload;
39
+ /**
40
+ * Casts jsonwebtoken library errors to internal error types
41
+ * @param {Error} error - The original jsonwebtoken error
42
+ * @returns {Error} - The corresponding internal error
43
+ */
44
+ export function castJwtError(error: Error): Error;
@@ -131,7 +131,7 @@ export function verify( token, secretOrPrivateKey, options=VERIFY_OPTIONS )
131
131
  * @param {Error} error - The original jsonwebtoken error
132
132
  * @returns {Error} - The corresponding internal error
133
133
  */
134
- function castJwtError(error) {
134
+ export function castJwtError(error) {
135
135
  if (error instanceof JwtTokenExpiredError) {
136
136
  return new TokenExpiredError(error.message, error.expiredAt, error);
137
137
  }
@@ -6,15 +6,11 @@ export class InternalEventOrLogError extends Error {
6
6
  }
7
7
  export class DetailedError extends Error {
8
8
  /**
9
- * @param {string} message - Error message
10
- * @param {string|{[key: string]: any}|null} [details] - Additional details
11
- * @param {Error|string} [cause] - Original error
9
+ * @param {string} [message]
10
+ * @param {import('./typedef.js').ErrorDetails} [details] - Additional details
11
+ * @param {Error|null} [cause] - Original error
12
12
  */
13
- constructor(message: string, details?: string | {
14
- [key: string]: any;
15
- } | null, cause?: Error | string);
16
- details: string | {
17
- [key: string]: any;
18
- };
19
- cause: string | Error;
13
+ constructor(message?: string, details?: import("./typedef.js").ErrorDetails, cause?: Error | null);
14
+ details: import("./typedef.js").ErrorDetails;
15
+ cause: unknown;
20
16
  }
@@ -7,14 +7,24 @@ export class InternalEventOrLogError extends Error {}
7
7
  export class DetailedError extends Error
8
8
  {
9
9
  /**
10
- * @param {string} message - Error message
11
- * @param {string|{[key: string]: any}|null} [details] - Additional details
12
- * @param {Error|string} [cause] - Original error
10
+ * @param {string} [message]
11
+ * @param {import('./typedef.js').ErrorDetails} [details] - Additional details
12
+ * @param {Error|null} [cause] - Original error
13
13
  */
14
14
  constructor(message, details, cause ) {
15
15
  super(message);
16
16
  this.name = 'DetailedError';
17
17
  this.details = details ?? null;
18
- this.cause = cause;
18
+
19
+ if( cause )
20
+ {
21
+ if( cause instanceof Error )
22
+ {
23
+ this.cause = cause;
24
+ }
25
+ else {
26
+ throw new Error('Parameter [cause] should be an Error');
27
+ }
28
+ }
19
29
  }
20
30
  }
@@ -0,0 +1,5 @@
1
+ declare const _default: {};
2
+ export default _default;
3
+ export type ErrorDetails = string | {
4
+ [key: string]: any;
5
+ } | null;
@@ -0,0 +1,3 @@
1
+ /** @typedef {string|{[key: string]: any}|null} ErrorDetails */
2
+
3
+ export default {};
@@ -1,3 +1,4 @@
1
1
  export * from "./data/typedef.js";
2
+ export * from "./errors/typedef.js";
2
3
  declare const _default: {};
3
4
  export default _default;
@@ -1,3 +1,4 @@
1
1
  export * from './data/typedef.js';
2
+ export * from './errors/typedef.js';
2
3
 
3
4
  export default {};
@@ -109,11 +109,9 @@ const logger = createClientLogger('client');
109
109
 
110
110
  /** @type {import('@sveltejs/kit').HandleClientError} */
111
111
  export function handleError({ error, event }) {
112
- logger.error('Client error occurred', {
113
- message: error.message,
114
- stack: error.stack,
115
- url: event.url?.pathname,
116
- userAgent: navigator.userAgent
112
+ logger.error(error, {
113
+ url: event.url?.pathname,
114
+ userAgent: navigator.userAgent
117
115
  });
118
116
  }
119
117
 
@@ -126,19 +124,12 @@ export function init() {
126
124
 
127
125
  // Log unhandled errors
128
126
  window.addEventListener('error', (event) => {
129
- logger.error('Unhandled error', {
130
- message: event.error?.message || event.message,
131
- filename: event.filename,
132
- lineno: event.lineno,
133
- colno: event.colno
134
- });
127
+ logger.error(event, { url: window.location.pathname });
135
128
  });
136
129
 
137
130
  // Log unhandled promise rejections
138
131
  window.addEventListener('unhandledrejection', (event) => {
139
- logger.error('Unhandled promise rejection', {
140
- reason: event.reason
141
- });
132
+ logger.error(event, { url: window.location.pathname });
142
133
  });
143
134
  }
144
135
 
@@ -6,6 +6,13 @@ export class LoggerError extends Error
6
6
  constructor( originalError ) {
7
7
  super('LoggerError');
8
8
  this.name = 'LoggerError';
9
- this.cause = originalError;
9
+
10
+ if( originalError instanceof Error )
11
+ {
12
+ this.cause = originalError;
13
+ }
14
+ else {
15
+ throw new Error('Parameter [originalError] should be an Error');
16
+ }
10
17
  }
11
18
  }
@@ -360,8 +360,6 @@ export class ConsoleAdapter {
360
360
 
361
361
  let cleaned = trimmed;
362
362
 
363
- console.log(123, cleaned);
364
-
365
363
  // Convert Chrome format to Firefox format for consistency
366
364
  if (isChromeFormat) {
367
365
  // "at functionName (url:line:col)" -> "functionName@url:line:col"
@@ -49,12 +49,18 @@ export default class Logger extends EventEmitter {
49
49
  /**
50
50
  * Log an error message
51
51
  *
52
- * @param {Error|string} originalErrorOrMessage
53
- * @param {Error} [originalError]
52
+ * @param {Error|ErrorEvent|PromiseRejectionEvent|string}
53
+ * errorOrMessage
54
+ *
55
+ * @param {Error|ErrorDetails} [errorOrDetails]
56
+ * Error object (when first param is string) or details object
57
+ *
58
+ * @param {ErrorDetails} [details]
59
+ * Additional context details (when using string + error pattern)
54
60
  *
55
61
  * @returns {boolean} True if the log was emitted
56
62
  */
57
- error(originalErrorOrMessage: Error | string, originalError?: Error, ...args: any[]): boolean;
63
+ error(errorOrMessage: Error | ErrorEvent | PromiseRejectionEvent | string, errorOrDetails?: Error | ErrorDetails, details?: ErrorDetails, ...args: any[]): boolean;
58
64
  /**
59
65
  * Create a child logger with additional context
60
66
  *
@@ -77,4 +83,5 @@ export default class Logger extends EventEmitter {
77
83
  logFromEvent(eventName: string, eventData: import("../../typedef.js").LogEventData): boolean;
78
84
  #private;
79
85
  }
86
+ export type ErrorDetails = import("../../../generic/typedef.js").ErrorDetails;
80
87
  import { EventEmitter } from '../../../generic/events.js';
@@ -32,6 +32,8 @@
32
32
  * logger.setLevel(DEBUG); // Now debug messages will also be logged
33
33
  */
34
34
 
35
+ /** @typedef {import('../../../generic/typedef.js').ErrorDetails} ErrorDetails */
36
+
35
37
  import { EventEmitter } from '../../../generic/events.js';
36
38
 
37
39
  import {
@@ -44,9 +46,17 @@ import {
44
46
  } from '../../constants.js';
45
47
 
46
48
  import { DetailedError } from '../../../generic/errors.js';
47
- import { LoggerError } from '../../errors.js';
49
+ // import { LoggerError } from '../../errors.js';
50
+
51
+ import { toArray } from '../../../util/array.js';
52
+ import { exportNotNullish } from '../../../util/object.js';
53
+
54
+ // import {
55
+ // castErrorEventToDetailedError,
56
+ // castPromiseRejectionToDetailedError
57
+ // } from './util.js';
48
58
 
49
- import { toArray } from '../../../util/array/index.js';
59
+ import * as is from '../../../util/is.js';
50
60
 
51
61
  /**
52
62
  * Logger class for consistent logging
@@ -126,36 +136,73 @@ export default class Logger extends EventEmitter {
126
136
  /**
127
137
  * Log an error message
128
138
  *
129
- * @param {Error|string} originalErrorOrMessage
130
- * @param {Error} [originalError]
139
+ * @param {Error|ErrorEvent|PromiseRejectionEvent|string}
140
+ * errorOrMessage
141
+ *
142
+ * @param {Error|ErrorDetails} [errorOrDetails]
143
+ * Error object (when first param is string) or details object
144
+ *
145
+ * @param {ErrorDetails} [details]
146
+ * Additional context details (when using string + error pattern)
131
147
  *
132
148
  * @returns {boolean} True if the log was emitted
133
149
  */
134
- error(originalErrorOrMessage, originalError) {
150
+ error(errorOrMessage, errorOrDetails, details) {
151
+ let errorObject = null;
152
+
153
+ let message;
135
154
 
136
- if( originalErrorOrMessage instanceof Error )
155
+ if( typeof errorOrMessage === 'string' )
137
156
  {
138
- // params: {error} originalErrorOrMessage
139
- const loggerError = new LoggerError(originalErrorOrMessage);
157
+ message = errorOrMessage;
158
+ }
159
+
160
+ if (message) {
161
+
162
+ // First param is a string (message)
163
+ // => Second param might be the error (string + error pattern)
164
+
165
+ if (this.#isErrorLike(errorOrDetails)) {
166
+ let errorLike = errorOrDetails;
167
+ errorObject = this.#toError(errorLike);
168
+ }
169
+ } else {
170
+
171
+ // First param is not an (not empty) string
172
+ // => First param should be the error
140
173
 
141
- const message = originalErrorOrMessage.message;
174
+ if (this.#isErrorLike(errorOrMessage)) {
175
+ let errorLike = errorOrMessage;
176
+ errorObject = this.#toError(errorLike);
177
+ }
142
178
 
143
- return this.#log(ERROR, message, loggerError);
179
+ // Second parameter could be the details
180
+ // Third parameter will be ignored (overwritten)
181
+ details = errorOrDetails;
144
182
  }
145
- else if( typeof originalErrorOrMessage === 'string' && originalError instanceof Error ) {
146
- // params: {string} message, {error} originalError
147
- const detailedError = new DetailedError(
148
- originalErrorOrMessage,
149
- null,
150
- originalError
151
- );
152
183
 
153
- return this.#log(ERROR, detailedError.message, detailedError);
184
+ if( errorObject && details )
185
+ {
186
+ // Additional Details supplied
187
+ // => Prepend additional DetailedError to chain
188
+ errorObject = new DetailedError(message, details, errorObject );
189
+ }
190
+
191
+ if( message && errorObject )
192
+ {
193
+ // Log with message
194
+ return this.#log(ERROR, message, errorObject);
195
+ }
196
+ else if (errorObject) {
197
+ // Log without message
198
+ return this.#log(ERROR, errorObject.message, errorObject);
154
199
  }
155
200
  else {
156
- // wrong params
201
+ // Missing error like object
202
+ // => invalid parameters supplied to logger.error
203
+
157
204
  const detailedError = new DetailedError(
158
- 'Invalid parameters supplied to Logger.error',
205
+ 'Missing error like object in Logger.error parameters',
159
206
  toArray(arguments)
160
207
  );
161
208
 
@@ -249,4 +296,84 @@ export default class Logger extends EventEmitter {
249
296
 
250
297
  return true;
251
298
  }
299
+
300
+ /**
301
+ * Returns true is the supplied parameter is loggable as error
302
+ *
303
+ * @param {any} thing
304
+ *
305
+ * @returns {boolean}
306
+ */
307
+ #isErrorLike(thing) {
308
+ return (
309
+ thing instanceof Error ||
310
+ is.ErrorEvent(thing) ||
311
+ is.PromiseRejectionEvent(thing)
312
+ );
313
+ }
314
+
315
+ /**
316
+ * Convert an Error like object (Error, ErrorEvent, PromiseRejectionEvent)
317
+ * to a DetailedError
318
+ *
319
+ * @param {any} errorLike
320
+ *
321
+ * @returns {Error}
322
+ */
323
+ #toError( errorLike ) {
324
+ if (is.ErrorEvent(errorLike)) {
325
+ // errorLike is an ErrorEvent
326
+ // => convert to DetailedError
327
+ const errorEvent = /** @type {ErrorEvent} */ (errorLike);
328
+
329
+ let errorEventDetails = exportNotNullish( errorEvent, [
330
+ 'message',
331
+ 'filename',
332
+ 'lineno',
333
+ 'colno'
334
+ ]);
335
+
336
+ errorEventDetails.type = 'ErrorEvent';
337
+
338
+ let cause = errorEvent.error;
339
+
340
+ return new DetailedError(
341
+ errorEvent.message,
342
+ errorEventDetails,
343
+ cause
344
+ );
345
+
346
+ } else if (is.PromiseRejectionEvent(errorLike)) {
347
+ // errorLike is a PromiseRejectionEvent
348
+ // => convert to DetailedError
349
+ const rejectionEvent = /** @type {PromiseRejectionEvent} */ (errorLike);
350
+
351
+ const reason = rejectionEvent.reason;
352
+
353
+ if (reason instanceof Error) {
354
+ return reason;
355
+ }
356
+ else if ( is.object(reason) && reason?.message ) {
357
+ // reason is an object with message property
358
+ return new DetailedError(reason?.message, reason);
359
+ }
360
+ else if ( typeof reason === "string" ) {
361
+ // reason is a string
362
+ return new DetailedError(reason);
363
+ }
364
+ else {
365
+ // reason is not an Error or string
366
+ return new DetailedError('Promise rejected', reason);
367
+ }
368
+ } else if (errorLike instanceof Error) {
369
+ // errorLike is a plain Error
370
+ // => return it
371
+ return errorLike;
372
+ }
373
+
374
+ // errorLike cannot be converted to an Error
375
+ // => return logging error
376
+
377
+ return new DetailedError('Cannot convert to Error', errorLike);
378
+ }
252
379
  }
@@ -104,7 +104,7 @@ Manages multiple services with dependency resolution and coordinated lifecycle o
104
104
  ### Usage
105
105
 
106
106
  ```javascript
107
- import { ServiceManager } from '$lib/services/index.js';
107
+ import { ServiceManager } from '$hklib-core/services/index.js';
108
108
  import DatabaseService from './services/DatabaseService.js';
109
109
  import AuthService from './services/AuthService.js';
110
110
 
@@ -197,4 +197,4 @@ Services include comprehensive test suites demonstrating:
197
197
  - Health monitoring
198
198
  - Event emission
199
199
 
200
- Run tests with your project's test command to ensure service reliability.
200
+ Run tests with your project's test command to ensure service reliability.
@@ -4,13 +4,13 @@
4
4
  * - The originating Error is set as `cause` property
5
5
  *
6
6
  * @param {string} message - New error message
7
- * @param {Error|string} originalError
7
+ * @param {Error|string} originalErrorOrMessage
8
8
  * @param {string|Object.<string, any>|null} [details]
9
9
  * New error details (a DetailError will be thrown)
10
10
  *
11
11
  * @throws {DetailedError}
12
12
  * @returns {never} This function never returns
13
13
  */
14
- export function rethrow(message: string, originalError: Error | string, details?: string | {
14
+ export function rethrow(message: string, originalErrorOrMessage: Error | string, details?: string | {
15
15
  [x: string]: any;
16
16
  } | null): never;
@@ -7,20 +7,23 @@ import { DetailedError } from "../../generic/errors.js";
7
7
  * - The originating Error is set as `cause` property
8
8
  *
9
9
  * @param {string} message - New error message
10
- * @param {Error|string} originalError
10
+ * @param {Error|string} originalErrorOrMessage
11
11
  * @param {string|Object.<string, any>|null} [details]
12
12
  * New error details (a DetailError will be thrown)
13
13
  *
14
14
  * @throws {DetailedError}
15
15
  * @returns {never} This function never returns
16
16
  */
17
- export function rethrow(message, originalError, details ) {
17
+ export function rethrow(message, originalErrorOrMessage, details ) {
18
18
  let error;
19
19
 
20
- if (!(originalError instanceof Error)) {
20
+ if ( typeof originalErrorOrMessage === 'string' ) {
21
21
  // Convert non-Error values to Error objects
22
- error = new Error(String(originalError));
22
+ error = new Error( originalErrorOrMessage );
23
+ }
24
+ else {
25
+ error = originalErrorOrMessage;
23
26
  }
24
27
 
25
- throw new DetailedError(message, details, error ?? originalError );
28
+ throw new DetailedError(message, details, error );
26
29
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Check if object is an ErrorEvent
3
+ *
4
+ * @param {any} obj
5
+ *
6
+ * @returns {boolean}
7
+ */
8
+ export function ErrorEvent(obj: any): boolean;
9
+ /**
10
+ * Check if object is a PromiseRejectionEvent
11
+ *
12
+ * @param {any} obj
13
+ *
14
+ * @returns {boolean}
15
+ */
16
+ export function PromiseRejectionEvent(obj: any): boolean;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Check if object is an ErrorEvent
3
+ *
4
+ * @param {any} obj
5
+ *
6
+ * @returns {boolean}
7
+ */
8
+ export function ErrorEvent(obj) {
9
+ return Boolean(obj &&
10
+ typeof obj === 'object' &&
11
+ obj.constructor?.name === 'ErrorEvent');
12
+ }
13
+
14
+ /**
15
+ * Check if object is a PromiseRejectionEvent
16
+ *
17
+ * @param {any} obj
18
+ *
19
+ * @returns {boolean}
20
+ */
21
+ export function PromiseRejectionEvent(obj) {
22
+ return Boolean(obj &&
23
+ typeof obj === 'object' &&
24
+ obj.constructor?.name === 'PromiseRejectionEvent');
25
+ }
@@ -68,3 +68,4 @@ export { argumentsCheck as arguments };
68
68
  * @returns {boolean} true if the value is an Arguments object
69
69
  */
70
70
  declare function argumentsCheck(value: any): boolean;
71
+ export { ErrorEvent, PromiseRejectionEvent } from "./events.js";
@@ -146,3 +146,5 @@ export function object(value) {
146
146
 
147
147
  return true;
148
148
  }
149
+
150
+ export { ErrorEvent, PromiseRejectionEvent } from './events.js';
@@ -29,7 +29,7 @@ export function size(obj: object): number;
29
29
  *
30
30
  * @returns {object} new object without the null properties
31
31
  */
32
- export function exportNotNull(obj: object, onlyKeys?: string[]): object;
32
+ export function exportNotNullish(obj: object, onlyKeys?: string[]): object;
33
33
  /**
34
34
  * Create a shallow copy of the object's public properties. Properties that
35
35
  * start with an underscore are considered 'internal' properties and are not
@@ -90,7 +90,7 @@ export function size(obj) {
90
90
  *
91
91
  * @returns {object} new object without the null properties
92
92
  */
93
- export function exportNotNull(obj, onlyKeys) {
93
+ export function exportNotNullish(obj, onlyKeys) {
94
94
  expect.object(obj);
95
95
 
96
96
  const onlyKeysSet = onlyKeys ? new Set(onlyKeys) : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.4.15",
3
+ "version": "0.4.17",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"