@hkdigital/lib-core 0.4.21 → 0.4.23
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/dist/auth/jwt/util.js +35 -41
- package/dist/logging/internal/adapters/console.js +7 -1
- package/dist/logging/internal/adapters/formatting.d.ts +2 -7
- package/dist/logging/internal/adapters/formatting.js +135 -85
- package/dist/logging/internal/adapters/pino.js +5 -2
- package/dist/logging/internal/logger/Logger.js +15 -1
- package/dist/logging/internal/test-errors.d.ts +4 -0
- package/dist/logging/internal/test-errors.js +8 -0
- package/dist/util/is/sveltekit.d.ts +8 -0
- package/dist/util/is/sveltekit.js +14 -0
- package/dist/util/is.d.ts +2 -0
- package/dist/util/is.js +3 -1
- package/package.json +1 -1
package/dist/auth/jwt/util.js
CHANGED
|
@@ -2,24 +2,32 @@
|
|
|
2
2
|
* JWT utility functions
|
|
3
3
|
*
|
|
4
4
|
* @description
|
|
5
|
-
* This module provides utility functions for JWT operations including
|
|
5
|
+
* This module provides utility functions for JWT operations including
|
|
6
6
|
* sign, verify and error casting.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
// import jwt from 'jsonwebtoken';
|
|
10
|
+
|
|
11
|
+
// import {
|
|
12
|
+
// TokenExpiredError as JwtTokenExpiredError,
|
|
13
|
+
// JsonWebTokenError as JwtJsonWebTokenError,
|
|
14
|
+
// NotBeforeError as JwtNotBeforeError
|
|
15
|
+
// } from 'jsonwebtoken';
|
|
16
|
+
|
|
9
17
|
import jwt from 'jsonwebtoken';
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
TokenExpiredError
|
|
13
|
-
JsonWebTokenError
|
|
14
|
-
NotBeforeError
|
|
15
|
-
}
|
|
19
|
+
const {
|
|
20
|
+
TokenExpiredError: JwtTokenExpiredError,
|
|
21
|
+
JsonWebTokenError: JwtJsonWebTokenError,
|
|
22
|
+
NotBeforeError: JwtNotBeforeError
|
|
23
|
+
} = jwt;
|
|
16
24
|
|
|
17
25
|
import * as expect from '../../util/expect.js';
|
|
18
26
|
|
|
19
27
|
import {
|
|
20
28
|
JWT_DEFAULT_EXPIRES_IN,
|
|
21
29
|
DEFAULT_ALGORITHM,
|
|
22
|
-
VERIFY_OPTIONS
|
|
30
|
+
VERIFY_OPTIONS
|
|
23
31
|
} from './constants.js';
|
|
24
32
|
|
|
25
33
|
import {
|
|
@@ -54,38 +62,28 @@ import {
|
|
|
54
62
|
*
|
|
55
63
|
* @returns {string} JsonWebToken
|
|
56
64
|
*/
|
|
57
|
-
export function sign(
|
|
58
|
-
claims
|
|
59
|
-
secretOrPrivateKey
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if( options )
|
|
66
|
-
{
|
|
67
|
-
expect.object( options );
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
65
|
+
export function sign(claims, secretOrPrivateKey, options = {}) {
|
|
66
|
+
expect.object(claims);
|
|
67
|
+
expect.defined(secretOrPrivateKey);
|
|
68
|
+
|
|
69
|
+
if (options) {
|
|
70
|
+
expect.object(options);
|
|
71
|
+
} else {
|
|
70
72
|
options = {};
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
if(
|
|
74
|
-
{
|
|
75
|
+
if (!('algorithm' in options)) {
|
|
75
76
|
options.algorithm = DEFAULT_ALGORITHM;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
if(
|
|
79
|
-
{
|
|
79
|
+
if (!('expiresIn' in options)) {
|
|
80
80
|
options.expiresIn = JWT_DEFAULT_EXPIRES_IN;
|
|
81
|
-
}
|
|
82
|
-
else if( !options.expiresIn )
|
|
83
|
-
{
|
|
81
|
+
} else if (!options.expiresIn) {
|
|
84
82
|
delete options.expiresIn;
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
// @ts-ignore
|
|
88
|
-
return jwt.sign(
|
|
86
|
+
return jwt.sign(claims, secretOrPrivateKey, options);
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
/**
|
|
@@ -99,24 +97,20 @@ export function sign(
|
|
|
99
97
|
*
|
|
100
98
|
* @returns {import('./typedef.js').JwtPayload} claims - The decoded JWT payload
|
|
101
99
|
*/
|
|
102
|
-
export function verify(
|
|
103
|
-
|
|
104
|
-
expect.
|
|
105
|
-
expect.defined( secretOrPrivateKey );
|
|
100
|
+
export function verify(token, secretOrPrivateKey, options = VERIFY_OPTIONS) {
|
|
101
|
+
expect.notEmptyString(token);
|
|
102
|
+
expect.defined(secretOrPrivateKey);
|
|
106
103
|
|
|
107
|
-
if(
|
|
108
|
-
{
|
|
104
|
+
if (!('algorithms' in options)) {
|
|
109
105
|
options.algorithms = VERIFY_OPTIONS.algorithms;
|
|
110
106
|
}
|
|
111
107
|
|
|
112
108
|
try {
|
|
113
109
|
// @ts-ignore
|
|
114
|
-
const decoded = jwt.verify(
|
|
110
|
+
const decoded = jwt.verify(token, secretOrPrivateKey, options);
|
|
115
111
|
|
|
116
112
|
return decoded;
|
|
117
|
-
}
|
|
118
|
-
catch( e )
|
|
119
|
-
{
|
|
113
|
+
} catch (e) {
|
|
120
114
|
//
|
|
121
115
|
// Cast internal jsonwebtoken errors to Error types defined in this lib
|
|
122
116
|
//
|
|
@@ -135,18 +129,18 @@ export function castJwtError(error) {
|
|
|
135
129
|
if (error instanceof JwtTokenExpiredError) {
|
|
136
130
|
return new TokenExpiredError(error.message, error.expiredAt, error);
|
|
137
131
|
}
|
|
138
|
-
|
|
132
|
+
|
|
139
133
|
if (error instanceof JwtNotBeforeError) {
|
|
140
134
|
return new NotBeforeError(error.message, error.date, error);
|
|
141
135
|
}
|
|
142
|
-
|
|
136
|
+
|
|
143
137
|
if (error instanceof JwtJsonWebTokenError) {
|
|
144
138
|
if (error.message === 'invalid signature') {
|
|
145
139
|
return new InvalidSignatureError(error.message, error, error);
|
|
146
140
|
}
|
|
147
141
|
return new JsonWebTokenError(error.message, error, error);
|
|
148
142
|
}
|
|
149
|
-
|
|
143
|
+
|
|
150
144
|
// Return original error if not a known JWT error
|
|
151
145
|
return error;
|
|
152
146
|
}
|
|
@@ -262,7 +262,7 @@ export class ConsoleAdapter {
|
|
|
262
262
|
let current = err;
|
|
263
263
|
let isFirst = true;
|
|
264
264
|
|
|
265
|
-
while (current) {
|
|
265
|
+
while (current && current instanceof Error) {
|
|
266
266
|
// Check if this is the first error and it's a LoggerError - extract logging context
|
|
267
267
|
if (isFirst && current.name === 'LoggerError') {
|
|
268
268
|
if (current.stack) {
|
|
@@ -393,6 +393,12 @@ export class ConsoleAdapter {
|
|
|
393
393
|
continue;
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
+
// Skip internal logger methods
|
|
397
|
+
if (cleaned.includes('#toError@') ||
|
|
398
|
+
(cleaned.includes('logger/Logger.js') && cleaned.includes('#toError'))) {
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
|
|
396
402
|
relevantFrames.push(cleaned);
|
|
397
403
|
|
|
398
404
|
// Limit to first 15 relevant frames to see more
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared error formatting logic for logging adapters
|
|
3
|
-
*
|
|
4
|
-
* This module contains reusable functions for analyzing and formatting
|
|
5
|
-
* errors with enhanced stack trace detection and error type identification.
|
|
6
|
-
*/
|
|
7
1
|
/**
|
|
8
2
|
* Find the most relevant frame index for highlighting in stack traces
|
|
9
3
|
*
|
|
@@ -50,9 +44,10 @@ export function getHttpMethod(cleanedStack: string[]): string | null;
|
|
|
50
44
|
*
|
|
51
45
|
* @param {Error} error - The error object
|
|
52
46
|
* @param {string[]} cleanedStack - Array of cleaned stack trace frames
|
|
47
|
+
* @param {number} [relevantFrameIndex] - Pre-computed relevant frame index to use
|
|
53
48
|
* @returns {string|null} User function name or null
|
|
54
49
|
*/
|
|
55
|
-
export function extractUserFunctionName(error: Error, cleanedStack: string[]): string | null;
|
|
50
|
+
export function extractUserFunctionName(error: Error, cleanedStack: string[], relevantFrameIndex?: number): string | null;
|
|
56
51
|
/**
|
|
57
52
|
* Check if function name is meaningful (not anonymous or framework code)
|
|
58
53
|
*
|
|
@@ -1,22 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared error formatting logic for logging adapters
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* This module contains reusable functions for analyzing and formatting
|
|
5
5
|
* errors with enhanced stack trace detection and error type identification.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import * as is from '../../../util/is.js';
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Find the most relevant frame index for highlighting in stack traces
|
|
10
|
-
*
|
|
12
|
+
*
|
|
11
13
|
* @param {Error} error - The error object
|
|
12
14
|
* @param {string[]} cleanedStack - Array of cleaned stack trace frames
|
|
13
15
|
* @returns {number} Index of the most relevant frame to highlight
|
|
14
16
|
*/
|
|
15
17
|
export function findRelevantFrameIndex(error, cleanedStack) {
|
|
18
|
+
// Check for SvelteKit HttpError - look for action pattern
|
|
19
|
+
if (
|
|
20
|
+
error.name === 'HttpError' &&
|
|
21
|
+
error.cause &&
|
|
22
|
+
is.SveltekitHttpError(error.cause)
|
|
23
|
+
) {
|
|
24
|
+
const svelteKitActionsIndex = cleanedStack.findIndex((frame) =>
|
|
25
|
+
frame.includes(
|
|
26
|
+
'node_modules/@sveltejs/kit/src/runtime/server/page/actions.js'
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
if (svelteKitActionsIndex >= 1) {
|
|
30
|
+
// Return the frame before the SvelteKit actions.js frame
|
|
31
|
+
// This should be the actual server action function where throw error() was called
|
|
32
|
+
return svelteKitActionsIndex - 1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
16
36
|
// Check if this is a LoggerError - look for Logger.error call
|
|
17
37
|
if (error.name === 'LoggerError') {
|
|
18
|
-
const loggerErrorIndex = cleanedStack.findIndex(
|
|
19
|
-
frame
|
|
38
|
+
const loggerErrorIndex = cleanedStack.findIndex(
|
|
39
|
+
(frame) =>
|
|
40
|
+
frame.includes('Logger.error') && frame.includes('logger/Logger.js')
|
|
20
41
|
);
|
|
21
42
|
if (loggerErrorIndex >= 0 && loggerErrorIndex + 1 < cleanedStack.length) {
|
|
22
43
|
return loggerErrorIndex + 1;
|
|
@@ -25,15 +46,17 @@ export function findRelevantFrameIndex(error, cleanedStack) {
|
|
|
25
46
|
|
|
26
47
|
if (error.name === 'ValiError') {
|
|
27
48
|
// Look for expect_ function first, user code is right after (handle Node.js format)
|
|
28
|
-
const expectIndex = cleanedStack.findIndex(
|
|
29
|
-
frame.includes('expect_') || frame.includes('Module.expect_')
|
|
49
|
+
const expectIndex = cleanedStack.findIndex(
|
|
50
|
+
(frame) => frame.includes('expect_') || frame.includes('Module.expect_')
|
|
30
51
|
);
|
|
31
52
|
if (expectIndex >= 0 && expectIndex + 1 < cleanedStack.length) {
|
|
32
53
|
return expectIndex + 1;
|
|
33
54
|
}
|
|
34
|
-
|
|
55
|
+
|
|
35
56
|
// If no expect_ function, look for valibotParser, user code is right after
|
|
36
|
-
const valibotIndex = cleanedStack.findIndex(frame =>
|
|
57
|
+
const valibotIndex = cleanedStack.findIndex((frame) =>
|
|
58
|
+
frame.includes('valibotParser')
|
|
59
|
+
);
|
|
37
60
|
if (valibotIndex >= 0 && valibotIndex + 1 < cleanedStack.length) {
|
|
38
61
|
return valibotIndex + 1;
|
|
39
62
|
}
|
|
@@ -42,17 +65,19 @@ export function findRelevantFrameIndex(error, cleanedStack) {
|
|
|
42
65
|
if (error.name === 'DetailedError') {
|
|
43
66
|
// Check if this DetailedError was created by Logger.error - look for Logger.error call first
|
|
44
67
|
// Handle both Firefox format (error@file) and Node.js format (at Logger.error (file))
|
|
45
|
-
const loggerErrorIndex = cleanedStack.findIndex(
|
|
46
|
-
(frame
|
|
47
|
-
|
|
68
|
+
const loggerErrorIndex = cleanedStack.findIndex(
|
|
69
|
+
(frame) =>
|
|
70
|
+
(frame.includes('Logger.error') &&
|
|
71
|
+
frame.includes('logger/Logger.js')) ||
|
|
72
|
+
(frame.includes('error@') && frame.includes('logger/Logger.js'))
|
|
48
73
|
);
|
|
49
74
|
if (loggerErrorIndex >= 0 && loggerErrorIndex + 1 < cleanedStack.length) {
|
|
50
75
|
return loggerErrorIndex + 1;
|
|
51
76
|
}
|
|
52
|
-
|
|
77
|
+
|
|
53
78
|
// Look for rethrow, user code is right after (handle both Firefox and Node.js format)
|
|
54
|
-
const rethrowIndex = cleanedStack.findIndex(
|
|
55
|
-
frame.includes('rethrow@') || frame.includes('at rethrow (')
|
|
79
|
+
const rethrowIndex = cleanedStack.findIndex(
|
|
80
|
+
(frame) => frame.includes('rethrow@') || frame.includes('at rethrow (')
|
|
56
81
|
);
|
|
57
82
|
if (rethrowIndex >= 0 && rethrowIndex + 1 < cleanedStack.length) {
|
|
58
83
|
return rethrowIndex + 1;
|
|
@@ -61,12 +86,13 @@ export function findRelevantFrameIndex(error, cleanedStack) {
|
|
|
61
86
|
|
|
62
87
|
if (error.name === 'PromiseError') {
|
|
63
88
|
// Look for HkPromise methods, user code is right after
|
|
64
|
-
const hkPromiseIndex = cleanedStack.findIndex(
|
|
65
|
-
frame
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
89
|
+
const hkPromiseIndex = cleanedStack.findIndex(
|
|
90
|
+
(frame) =>
|
|
91
|
+
frame.includes('reject@') ||
|
|
92
|
+
frame.includes('tryReject@') ||
|
|
93
|
+
frame.includes('setTimeout@') ||
|
|
94
|
+
frame.includes('cancel@') ||
|
|
95
|
+
frame.includes('tryCancel@')
|
|
70
96
|
);
|
|
71
97
|
if (hkPromiseIndex >= 0 && hkPromiseIndex + 1 < cleanedStack.length) {
|
|
72
98
|
return hkPromiseIndex + 1;
|
|
@@ -92,14 +118,18 @@ export function findRelevantFrameIndex(error, cleanedStack) {
|
|
|
92
118
|
|
|
93
119
|
/**
|
|
94
120
|
* Detect error metadata for structured logging and display
|
|
95
|
-
*
|
|
121
|
+
*
|
|
96
122
|
* @param {Error} error - The error object
|
|
97
123
|
* @param {string[]} cleanedStack - Array of cleaned stack trace frames
|
|
98
124
|
* @returns {import('./typedef.js').ErrorSummaryMeta} Error metadata
|
|
99
125
|
*/
|
|
100
126
|
export function detectErrorMeta(error, cleanedStack) {
|
|
101
|
-
const userFunctionName = extractUserFunctionName(error, cleanedStack);
|
|
102
127
|
const relevantFrameIndex = findRelevantFrameIndex(error, cleanedStack);
|
|
128
|
+
const userFunctionName = extractUserFunctionName(
|
|
129
|
+
error,
|
|
130
|
+
cleanedStack,
|
|
131
|
+
relevantFrameIndex
|
|
132
|
+
);
|
|
103
133
|
|
|
104
134
|
// Check if it's a LoggerError
|
|
105
135
|
if (error.name === 'LoggerError') {
|
|
@@ -115,11 +145,13 @@ export function detectErrorMeta(error, cleanedStack) {
|
|
|
115
145
|
if (error.name === 'DetailedError') {
|
|
116
146
|
// Check if this DetailedError was created by Logger.error
|
|
117
147
|
const cleanedStackArray = cleanedStack || [];
|
|
118
|
-
const loggerErrorIndex = cleanedStackArray.findIndex(
|
|
119
|
-
(frame
|
|
120
|
-
|
|
148
|
+
const loggerErrorIndex = cleanedStackArray.findIndex(
|
|
149
|
+
(frame) =>
|
|
150
|
+
(frame.includes('Logger.error') &&
|
|
151
|
+
frame.includes('logger/Logger.js')) ||
|
|
152
|
+
(frame.includes('error@') && frame.includes('logger/Logger.js'))
|
|
121
153
|
);
|
|
122
|
-
|
|
154
|
+
|
|
123
155
|
if (loggerErrorIndex >= 0) {
|
|
124
156
|
return {
|
|
125
157
|
category: 'logger',
|
|
@@ -128,7 +160,7 @@ export function detectErrorMeta(error, cleanedStack) {
|
|
|
128
160
|
relevantFrameIndex
|
|
129
161
|
};
|
|
130
162
|
}
|
|
131
|
-
|
|
163
|
+
|
|
132
164
|
// Otherwise it's a regular rethrow error
|
|
133
165
|
return {
|
|
134
166
|
category: 'rethrow',
|
|
@@ -163,15 +195,15 @@ export function detectErrorMeta(error, cleanedStack) {
|
|
|
163
195
|
// Check if it's a valibot validation error
|
|
164
196
|
if (error.name === 'ValiError' && cleanedStack.length > 0) {
|
|
165
197
|
// Look for our valibotParser wrapper function in the stack
|
|
166
|
-
const valibotFrame = cleanedStack.find(frame =>
|
|
198
|
+
const valibotFrame = cleanedStack.find((frame) =>
|
|
167
199
|
frame.includes('valibotParser')
|
|
168
200
|
);
|
|
169
|
-
|
|
201
|
+
|
|
170
202
|
// Also check if it's called via an expect_ function (handle Node.js format)
|
|
171
|
-
const expectFrame = cleanedStack.find(
|
|
172
|
-
frame.includes('expect_') || frame.includes('Module.expect_')
|
|
203
|
+
const expectFrame = cleanedStack.find(
|
|
204
|
+
(frame) => frame.includes('expect_') || frame.includes('Module.expect_')
|
|
173
205
|
);
|
|
174
|
-
|
|
206
|
+
|
|
175
207
|
if (valibotFrame || expectFrame) {
|
|
176
208
|
return {
|
|
177
209
|
category: 'validation',
|
|
@@ -193,7 +225,7 @@ export function detectErrorMeta(error, cleanedStack) {
|
|
|
193
225
|
|
|
194
226
|
/**
|
|
195
227
|
* Format error metadata for console display
|
|
196
|
-
*
|
|
228
|
+
*
|
|
197
229
|
* @param {{category: string, method: string, origin?: string|null}} errorMeta - Error metadata
|
|
198
230
|
* @returns {string} Formatted display string (e.g., "httpGet in myFunction")
|
|
199
231
|
*/
|
|
@@ -206,43 +238,44 @@ export function formatErrorDisplay(errorMeta) {
|
|
|
206
238
|
|
|
207
239
|
/**
|
|
208
240
|
* Get the specific HkPromise method that caused the error
|
|
209
|
-
*
|
|
241
|
+
*
|
|
210
242
|
* @param {string[]} cleanedStack - Array of cleaned stack trace frames
|
|
211
243
|
* @returns {string|null} HkPromise method name or null
|
|
212
244
|
*/
|
|
213
245
|
export function getHkPromiseMethod(cleanedStack) {
|
|
214
|
-
const hkPromiseFrame = cleanedStack.find(
|
|
215
|
-
frame
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
246
|
+
const hkPromiseFrame = cleanedStack.find(
|
|
247
|
+
(frame) =>
|
|
248
|
+
frame.includes('reject@') ||
|
|
249
|
+
frame.includes('tryReject@') ||
|
|
250
|
+
frame.includes('setTimeout@') ||
|
|
251
|
+
frame.includes('cancel@') ||
|
|
252
|
+
frame.includes('tryCancel@')
|
|
220
253
|
);
|
|
221
|
-
|
|
254
|
+
|
|
222
255
|
if (!hkPromiseFrame) return null;
|
|
223
|
-
|
|
256
|
+
|
|
224
257
|
if (hkPromiseFrame.includes('reject@')) return 'reject';
|
|
225
258
|
if (hkPromiseFrame.includes('tryReject@')) return 'tryReject';
|
|
226
259
|
if (hkPromiseFrame.includes('setTimeout@')) return 'setTimeout';
|
|
227
260
|
if (hkPromiseFrame.includes('cancel@')) return 'cancel';
|
|
228
261
|
if (hkPromiseFrame.includes('tryCancel@')) return 'tryCancel';
|
|
229
|
-
|
|
262
|
+
|
|
230
263
|
return null;
|
|
231
264
|
}
|
|
232
265
|
|
|
233
266
|
/**
|
|
234
267
|
* Get the specific HTTP method that caused the error
|
|
235
|
-
*
|
|
268
|
+
*
|
|
236
269
|
* @param {string[]} cleanedStack - Array of cleaned stack trace frames
|
|
237
270
|
* @returns {string|null} HTTP method name or null
|
|
238
271
|
*/
|
|
239
272
|
export function getHttpMethod(cleanedStack) {
|
|
240
|
-
const httpFrame = cleanedStack.find(frame =>
|
|
273
|
+
const httpFrame = cleanedStack.find((frame) =>
|
|
241
274
|
frame.includes('network/http/http-request.js')
|
|
242
275
|
);
|
|
243
|
-
|
|
276
|
+
|
|
244
277
|
if (!httpFrame) return null;
|
|
245
|
-
|
|
278
|
+
|
|
246
279
|
if (httpFrame.includes('httpGet@')) return 'httpGet';
|
|
247
280
|
if (httpFrame.includes('httpPost@')) return 'httpPost';
|
|
248
281
|
if (httpFrame.includes('httpPut@')) return 'httpPut';
|
|
@@ -250,22 +283,32 @@ export function getHttpMethod(cleanedStack) {
|
|
|
250
283
|
if (httpFrame.includes('httpPatch@')) return 'httpPatch';
|
|
251
284
|
if (httpFrame.includes('httpOptions@')) return 'httpOptions';
|
|
252
285
|
if (httpFrame.includes('httpRequest@')) return 'httpRequest';
|
|
253
|
-
|
|
286
|
+
|
|
254
287
|
return null;
|
|
255
288
|
}
|
|
256
289
|
|
|
257
290
|
/**
|
|
258
291
|
* Extract user function name from stack trace
|
|
259
|
-
*
|
|
292
|
+
*
|
|
260
293
|
* @param {Error} error - The error object
|
|
261
294
|
* @param {string[]} cleanedStack - Array of cleaned stack trace frames
|
|
295
|
+
* @param {number} [relevantFrameIndex] - Pre-computed relevant frame index to use
|
|
262
296
|
* @returns {string|null} User function name or null
|
|
263
297
|
*/
|
|
264
|
-
export function extractUserFunctionName(
|
|
298
|
+
export function extractUserFunctionName(
|
|
299
|
+
error,
|
|
300
|
+
cleanedStack,
|
|
301
|
+
relevantFrameIndex
|
|
302
|
+
) {
|
|
303
|
+
// If we have a pre-computed relevant frame index, use it
|
|
304
|
+
if (relevantFrameIndex >= 0 && relevantFrameIndex < cleanedStack.length) {
|
|
305
|
+
return parseFunctionName(cleanedStack[relevantFrameIndex]);
|
|
306
|
+
}
|
|
265
307
|
// Check if this is a LoggerError - look for the frame after Logger.error
|
|
266
308
|
if (error.name === 'LoggerError' && cleanedStack.length > 1) {
|
|
267
|
-
const loggerErrorIndex = cleanedStack.findIndex(
|
|
268
|
-
frame
|
|
309
|
+
const loggerErrorIndex = cleanedStack.findIndex(
|
|
310
|
+
(frame) =>
|
|
311
|
+
frame.includes('Logger.error') && frame.includes('logger/Logger.js')
|
|
269
312
|
);
|
|
270
313
|
if (loggerErrorIndex >= 0 && loggerErrorIndex + 1 < cleanedStack.length) {
|
|
271
314
|
return parseFunctionName(cleanedStack[loggerErrorIndex + 1]);
|
|
@@ -274,17 +317,19 @@ export function extractUserFunctionName(error, cleanedStack) {
|
|
|
274
317
|
|
|
275
318
|
if (error.name === 'DetailedError' && cleanedStack.length > 1) {
|
|
276
319
|
// Check if this DetailedError was created by Logger.error - look for the frame after Logger.error
|
|
277
|
-
const loggerErrorIndex = cleanedStack.findIndex(
|
|
278
|
-
(frame
|
|
279
|
-
|
|
320
|
+
const loggerErrorIndex = cleanedStack.findIndex(
|
|
321
|
+
(frame) =>
|
|
322
|
+
(frame.includes('Logger.error') &&
|
|
323
|
+
frame.includes('logger/Logger.js')) ||
|
|
324
|
+
(frame.includes('error@') && frame.includes('logger/Logger.js'))
|
|
280
325
|
);
|
|
281
326
|
if (loggerErrorIndex >= 0 && loggerErrorIndex + 1 < cleanedStack.length) {
|
|
282
327
|
return parseFunctionName(cleanedStack[loggerErrorIndex + 1]);
|
|
283
328
|
}
|
|
284
|
-
|
|
329
|
+
|
|
285
330
|
// For rethrow errors, look for the frame after rethrow (handle both formats)
|
|
286
|
-
const rethrowIndex = cleanedStack.findIndex(
|
|
287
|
-
frame.includes('rethrow@') || frame.includes('at rethrow (')
|
|
331
|
+
const rethrowIndex = cleanedStack.findIndex(
|
|
332
|
+
(frame) => frame.includes('rethrow@') || frame.includes('at rethrow (')
|
|
288
333
|
);
|
|
289
334
|
if (rethrowIndex >= 0 && rethrowIndex + 1 < cleanedStack.length) {
|
|
290
335
|
return parseFunctionName(cleanedStack[rethrowIndex + 1]);
|
|
@@ -293,12 +338,13 @@ export function extractUserFunctionName(error, cleanedStack) {
|
|
|
293
338
|
|
|
294
339
|
if (error.name === 'PromiseError' && cleanedStack.length > 1) {
|
|
295
340
|
// For PromiseError, look for the frame after HkPromise methods
|
|
296
|
-
const hkPromiseIndex = cleanedStack.findIndex(
|
|
297
|
-
frame
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
341
|
+
const hkPromiseIndex = cleanedStack.findIndex(
|
|
342
|
+
(frame) =>
|
|
343
|
+
frame.includes('reject@') ||
|
|
344
|
+
frame.includes('tryReject@') ||
|
|
345
|
+
frame.includes('setTimeout@') ||
|
|
346
|
+
frame.includes('cancel@') ||
|
|
347
|
+
frame.includes('tryCancel@')
|
|
302
348
|
);
|
|
303
349
|
if (hkPromiseIndex >= 0 && hkPromiseIndex + 1 < cleanedStack.length) {
|
|
304
350
|
return parseFunctionName(cleanedStack[hkPromiseIndex + 1]);
|
|
@@ -320,15 +366,17 @@ export function extractUserFunctionName(error, cleanedStack) {
|
|
|
320
366
|
|
|
321
367
|
if (error.name === 'ValiError' && cleanedStack.length > 1) {
|
|
322
368
|
// For validation errors, look for the frame after expect_ function first (handle Node.js format)
|
|
323
|
-
const expectIndex = cleanedStack.findIndex(
|
|
324
|
-
frame.includes('expect_') || frame.includes('Module.expect_')
|
|
369
|
+
const expectIndex = cleanedStack.findIndex(
|
|
370
|
+
(frame) => frame.includes('expect_') || frame.includes('Module.expect_')
|
|
325
371
|
);
|
|
326
372
|
if (expectIndex >= 0 && expectIndex + 1 < cleanedStack.length) {
|
|
327
373
|
return parseFunctionName(cleanedStack[expectIndex + 1]);
|
|
328
374
|
}
|
|
329
|
-
|
|
375
|
+
|
|
330
376
|
// If no expect_ function, look for valibotParser wrapper
|
|
331
|
-
const valibotIndex = cleanedStack.findIndex(frame =>
|
|
377
|
+
const valibotIndex = cleanedStack.findIndex((frame) =>
|
|
378
|
+
frame.includes('valibotParser')
|
|
379
|
+
);
|
|
332
380
|
if (valibotIndex >= 0 && valibotIndex + 1 < cleanedStack.length) {
|
|
333
381
|
return parseFunctionName(cleanedStack[valibotIndex + 1]);
|
|
334
382
|
}
|
|
@@ -347,49 +395,51 @@ export function extractUserFunctionName(error, cleanedStack) {
|
|
|
347
395
|
|
|
348
396
|
/**
|
|
349
397
|
* Check if function name is meaningful (not anonymous or framework code)
|
|
350
|
-
*
|
|
398
|
+
*
|
|
351
399
|
* @param {string} functionName - Function name to check
|
|
352
400
|
* @returns {boolean} True if the function name is meaningful
|
|
353
401
|
*/
|
|
354
402
|
export function isMeaningfulFunctionName(functionName) {
|
|
355
403
|
// Skip empty names, anonymous functions, and framework/internal functions
|
|
356
|
-
if (
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
404
|
+
if (
|
|
405
|
+
!functionName ||
|
|
406
|
+
functionName === '' ||
|
|
407
|
+
functionName.includes('<') ||
|
|
408
|
+
functionName.includes('/') ||
|
|
409
|
+
functionName.startsWith('async ') ||
|
|
410
|
+
functionName === 'async' ||
|
|
411
|
+
functionName === 'Promise' ||
|
|
412
|
+
functionName === 'new Promise' ||
|
|
413
|
+
functionName.includes('internal') ||
|
|
414
|
+
functionName.includes('node_modules')
|
|
415
|
+
) {
|
|
366
416
|
return false;
|
|
367
417
|
}
|
|
368
|
-
|
|
418
|
+
|
|
369
419
|
return true;
|
|
370
420
|
}
|
|
371
421
|
|
|
372
422
|
/**
|
|
373
423
|
* Parse function name from stack frame
|
|
374
|
-
*
|
|
424
|
+
*
|
|
375
425
|
* @param {string} frame - Stack trace frame
|
|
376
426
|
* @returns {string|null} Function name or null
|
|
377
427
|
*/
|
|
378
428
|
export function parseFunctionName(frame) {
|
|
379
429
|
// Handle both Firefox format: "functionName@file:line:col"
|
|
380
430
|
// and Node.js format: "at functionName (file:line:col)" or "at Module.functionName (file:line:col)"
|
|
381
|
-
|
|
431
|
+
|
|
382
432
|
// Firefox format
|
|
383
433
|
const firefoxMatch = frame.match(/^([^@]+)@/);
|
|
384
434
|
if (firefoxMatch) {
|
|
385
435
|
return firefoxMatch[1];
|
|
386
436
|
}
|
|
387
|
-
|
|
437
|
+
|
|
388
438
|
// Node.js format
|
|
389
439
|
const nodeMatch = frame.match(/^\s*at\s+(?:Module\.)?([^\s(]+)/);
|
|
390
440
|
if (nodeMatch) {
|
|
391
441
|
return nodeMatch[1];
|
|
392
442
|
}
|
|
393
|
-
|
|
443
|
+
|
|
394
444
|
return null;
|
|
395
|
-
}
|
|
445
|
+
}
|
|
@@ -209,9 +209,12 @@ export class PinoAdapter {
|
|
|
209
209
|
const pnpmRegex2 = /node_modules\/\.pnpm\/[^/]+\/node_modules\/([^/]+)/g;
|
|
210
210
|
cleaned = cleaned.replace(pnpmRegex2, 'node_modules/$1');
|
|
211
211
|
|
|
212
|
-
// Filter out Node.js internal modules
|
|
212
|
+
// Filter out Node.js internal modules and internal logger methods
|
|
213
213
|
const lines = cleaned.split('\n');
|
|
214
|
-
const filteredLines = lines.filter(line =>
|
|
214
|
+
const filteredLines = lines.filter(line =>
|
|
215
|
+
!line.includes('node:internal') &&
|
|
216
|
+
!(line.includes('#toError') && line.includes('logger/Logger.js'))
|
|
217
|
+
);
|
|
215
218
|
cleaned = filteredLines.join('\n');
|
|
216
219
|
|
|
217
220
|
return cleaned;
|
|
@@ -57,6 +57,7 @@ import { exportNotNullish } from '../../../util/object.js';
|
|
|
57
57
|
// } from './util.js';
|
|
58
58
|
|
|
59
59
|
import * as is from '../../../util/is.js';
|
|
60
|
+
import { HttpError } from '../../../network/errors.js';
|
|
60
61
|
|
|
61
62
|
/**
|
|
62
63
|
* Logger class for consistent logging
|
|
@@ -308,7 +309,8 @@ export default class Logger extends EventEmitter {
|
|
|
308
309
|
return (
|
|
309
310
|
thing instanceof Error ||
|
|
310
311
|
is.ErrorEvent(thing) ||
|
|
311
|
-
is.PromiseRejectionEvent(thing)
|
|
312
|
+
is.PromiseRejectionEvent(thing) ||
|
|
313
|
+
is.SveltekitHttpError(thing)
|
|
312
314
|
);
|
|
313
315
|
}
|
|
314
316
|
|
|
@@ -365,6 +367,18 @@ export default class Logger extends EventEmitter {
|
|
|
365
367
|
// reason is not an Error or string
|
|
366
368
|
return new DetailedError('Promise rejected', reason);
|
|
367
369
|
}
|
|
370
|
+
} else if (is.SveltekitHttpError(errorLike)) {
|
|
371
|
+
// errorLike is a SvelteKit HttpError
|
|
372
|
+
// => convert to lib's HttpError for consistent error handling
|
|
373
|
+
const svelteKitError = errorLike;
|
|
374
|
+
|
|
375
|
+
return new HttpError(
|
|
376
|
+
svelteKitError.status,
|
|
377
|
+
svelteKitError.body?.message || 'SvelteKit HttpError',
|
|
378
|
+
exportNotNullish(svelteKitError),
|
|
379
|
+
svelteKitError // Set original SvelteKit error as cause
|
|
380
|
+
);
|
|
381
|
+
|
|
368
382
|
} else if (errorLike instanceof Error) {
|
|
369
383
|
// errorLike is a plain Error
|
|
370
384
|
// => return it
|
|
@@ -33,3 +33,7 @@ export function throwRethrowChainError(): void;
|
|
|
33
33
|
* Raw valibot validation error (without expect wrapper)
|
|
34
34
|
*/
|
|
35
35
|
export function throwRawValibotError(): any;
|
|
36
|
+
/**
|
|
37
|
+
* SvelteKit error that goes through handleError hook
|
|
38
|
+
*/
|
|
39
|
+
export function throwSvelteKitError(): void;
|
|
@@ -3,6 +3,7 @@ import { rethrow } from '../../util/exceptions.js';
|
|
|
3
3
|
import { HkPromise } from '../../generic/promises.js';
|
|
4
4
|
import { httpGet } from '../../network/http/index.js';
|
|
5
5
|
import { v } from '../../valibot/valibot.js';
|
|
6
|
+
import { error } from '@sveltejs/kit';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Test functions for generating various types of errors for logging demonstration
|
|
@@ -137,3 +138,10 @@ export function throwRawValibotError() {
|
|
|
137
138
|
// This will throw a ValiError directly from our valibotParser wrapper
|
|
138
139
|
return v.parse(schema, invalidValue);
|
|
139
140
|
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* SvelteKit error that goes through handleError hook
|
|
144
|
+
*/
|
|
145
|
+
export function throwSvelteKitError() {
|
|
146
|
+
throw error(500, 'SvelteKit error test - this goes through handleError');
|
|
147
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if object is a SvelteKit HttpError
|
|
3
|
+
*
|
|
4
|
+
* @param {any} thing
|
|
5
|
+
*
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
export function SveltekitHttpError(thing) {
|
|
9
|
+
return Boolean(
|
|
10
|
+
thing instanceof Object &&
|
|
11
|
+
thing.constructor?.name === 'HttpError' &&
|
|
12
|
+
'status' in thing
|
|
13
|
+
);
|
|
14
|
+
}
|
package/dist/util/is.d.ts
CHANGED
package/dist/util/is.js
CHANGED