@lowdefy/errors 0.0.0-experimental-20260220095000 → 0.0.0-experimental-20260220142815
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/ConfigError.js +63 -35
- package/dist/ConfigWarning.js +25 -13
- package/dist/{LowdefyInternalError.js → LowdefyError.js} +34 -6
- package/dist/PluginError.js +77 -24
- package/dist/ServiceError.js +58 -25
- package/dist/UserError.js +5 -2
- package/dist/build/ConfigError.js +119 -0
- package/dist/build/ConfigMessage.js +123 -0
- package/dist/build/ConfigWarning.js +111 -0
- package/dist/build/index.js +37 -0
- package/dist/{resolveConfigLocation.js → build/resolveConfigLocation.js} +4 -2
- package/dist/build/resolveErrorConfigLocation.js +45 -0
- package/dist/client/ConfigError.js +79 -0
- package/dist/client/LowdefyError.js +55 -0
- package/dist/client/index.js +31 -0
- package/dist/deserializeError.js +36 -0
- package/dist/{errorToDisplayString.js → formatErrorMessage.js} +11 -9
- package/dist/index.js +8 -30
- package/dist/server/index.js +30 -0
- package/package.json +5 -2
- package/dist/ActionError.js +0 -22
- package/dist/BlockError.js +0 -22
- package/dist/BuildError.js +0 -34
- package/dist/OperatorError.js +0 -22
- package/dist/RequestError.js +0 -22
- package/dist/loadAndResolveErrorLocation.js +0 -63
- package/dist/resolveErrorLocation.js +0 -58
- package/dist/shouldSuppressBuildCheck.js +0 -58
package/dist/ConfigError.js
CHANGED
|
@@ -15,7 +15,10 @@
|
|
|
15
15
|
*/ /**
|
|
16
16
|
* Base error class for configuration errors (invalid YAML, schema violations, validation errors).
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* This is the environment-agnostic base class. For environment-specific behavior:
|
|
19
|
+
* - Build-time: Use @lowdefy/errors/build (sync resolution via keyMap/refMap)
|
|
20
|
+
* - Server-side: Use @lowdefy/errors/server (re-exports base)
|
|
21
|
+
* - Client-side: Use @lowdefy/errors/client (async resolution via API)
|
|
19
22
|
*
|
|
20
23
|
* @example
|
|
21
24
|
* // Simple string (for plugins - configKey added by interface layer)
|
|
@@ -23,46 +26,71 @@
|
|
|
23
26
|
*
|
|
24
27
|
* @example
|
|
25
28
|
* // With options
|
|
26
|
-
* throw new ConfigError(
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* throw new ConfigError('Error parsing file', {
|
|
31
|
-
* filePath: 'pages/home.yaml',
|
|
32
|
-
* lineNumber: 6,
|
|
29
|
+
* throw new ConfigError({
|
|
30
|
+
* message: 'Invalid block type',
|
|
31
|
+
* configKey: block['~k'],
|
|
32
|
+
* location: { source: 'pages/home.yaml:42', link: '/path/to/pages/home.yaml:42' }
|
|
33
33
|
* });
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
*/ import formatErrorMessage from './formatErrorMessage.js';
|
|
35
|
+
let ConfigError = class ConfigError extends Error {
|
|
36
|
+
print() {
|
|
37
|
+
return formatErrorMessage(this);
|
|
38
|
+
}
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
41
|
-
* @
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
* Serializes the error for transport (e.g., client to server).
|
|
41
|
+
* @returns {Object} Serialized error data with type marker
|
|
42
|
+
*/ serialize() {
|
|
43
|
+
return {
|
|
44
|
+
'~err': 'ConfigError',
|
|
45
|
+
message: this.message,
|
|
46
|
+
configKey: this.configKey
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Deserializes error data back into a ConfigError.
|
|
51
|
+
* @param {Object} data - Serialized error data
|
|
52
|
+
* @returns {ConfigError}
|
|
53
|
+
*/ static deserialize(data) {
|
|
54
|
+
return new ConfigError({
|
|
55
|
+
message: data.message,
|
|
56
|
+
configKey: data.configKey
|
|
53
57
|
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Creates a ConfigError instance with formatted message.
|
|
61
|
+
* @param {string|Object} messageOrParams - Error message string, or params object
|
|
62
|
+
* @param {string} [messageOrParams.message] - The error message (if object)
|
|
63
|
+
* @param {Error} [messageOrParams.error] - Original error to wrap (extracts message/configKey/stack)
|
|
64
|
+
* @param {string} [messageOrParams.configKey] - Config key (~k) for location resolution
|
|
65
|
+
* @param {Object} [messageOrParams.location] - Pre-resolved location { source, link, config }
|
|
66
|
+
* @param {string} [messageOrParams.checkSlug] - The build check that triggered this error
|
|
67
|
+
*/ constructor(messageOrParams){
|
|
68
|
+
// Support both string and object parameter
|
|
69
|
+
const isString = typeof messageOrParams === 'string';
|
|
70
|
+
const error = isString ? null : messageOrParams.error;
|
|
71
|
+
const message = isString ? messageOrParams : messageOrParams.message ?? error?.message;
|
|
72
|
+
const configKey = isString ? null : messageOrParams.configKey ?? error?.configKey;
|
|
73
|
+
const location = isString ? null : messageOrParams.location;
|
|
74
|
+
const checkSlug = isString ? undefined : messageOrParams.checkSlug;
|
|
75
|
+
const received = isString ? undefined : messageOrParams.received !== undefined ? messageOrParams.received : error?.received;
|
|
76
|
+
const operatorLocation = isString ? null : messageOrParams.operatorLocation;
|
|
77
|
+
// Message without prefix - logger uses error.name for display
|
|
78
|
+
super(message);
|
|
54
79
|
this.name = 'ConfigError';
|
|
55
|
-
this.
|
|
56
|
-
this.configKey = configKey ?? cause?.configKey ?? null;
|
|
80
|
+
this.configKey = configKey ?? null;
|
|
57
81
|
this.checkSlug = checkSlug;
|
|
58
82
|
// For logger formatting
|
|
59
|
-
this.received = received
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.
|
|
63
|
-
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
83
|
+
this.received = received;
|
|
84
|
+
this.operatorLocation = operatorLocation;
|
|
85
|
+
// Location info (can be set via constructor or subclass)
|
|
86
|
+
this.source = location?.source ?? null;
|
|
87
|
+
this.link = location?.link ?? null;
|
|
88
|
+
this.config = location?.config ?? null;
|
|
89
|
+
this.resolved = !!location;
|
|
90
|
+
// Preserve original error's stack if wrapping
|
|
91
|
+
if (error?.stack) {
|
|
92
|
+
this.stack = error.stack;
|
|
93
|
+
}
|
|
66
94
|
}
|
|
67
95
|
};
|
|
68
96
|
export default ConfigError;
|
package/dist/ConfigWarning.js
CHANGED
|
@@ -12,19 +12,31 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
*/ /**
|
|
16
|
+
* Base configuration warning class.
|
|
17
|
+
*
|
|
18
|
+
* This is the environment-agnostic base class. For environment-specific behavior:
|
|
19
|
+
* - Build-time: Use @lowdefy/errors/build (prodError flag, suppression logic)
|
|
20
|
+
* - Server-side: Use @lowdefy/errors/server (re-exports base)
|
|
21
|
+
* - Client-side: Use @lowdefy/errors/client (re-exports base)
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const warning = new ConfigWarning({ message: 'Deprecated feature used', source: 'config.yaml:10' });
|
|
25
|
+
* console.warn(warning.message);
|
|
26
|
+
*/ import formatErrorMessage from './formatErrorMessage.js';
|
|
27
|
+
let ConfigWarning = class ConfigWarning {
|
|
28
|
+
print() {
|
|
29
|
+
return formatErrorMessage(this);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* @param {Object} params
|
|
33
|
+
* @param {string} params.message - The warning message
|
|
34
|
+
* @param {string} [params.source] - Source file:line
|
|
35
|
+
*/ constructor({ message, source }){
|
|
36
|
+
this.name = 'Config Warning';
|
|
37
|
+
// Message without prefix - logger uses class name for display
|
|
38
|
+
this.message = message;
|
|
39
|
+
this.source = source ?? null;
|
|
28
40
|
}
|
|
29
41
|
};
|
|
30
42
|
export default ConfigWarning;
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
22
|
* // Create a new error
|
|
23
|
-
* throw new
|
|
23
|
+
* throw new LowdefyError('Unexpected condition');
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
26
|
* // At top-level catch, log the error with stack
|
|
@@ -28,18 +28,46 @@
|
|
|
28
28
|
* console.error(err.message);
|
|
29
29
|
* console.error(err.stack);
|
|
30
30
|
* }
|
|
31
|
-
*/
|
|
31
|
+
*/ import formatErrorMessage from './formatErrorMessage.js';
|
|
32
|
+
let LowdefyError = class LowdefyError extends Error {
|
|
33
|
+
print() {
|
|
34
|
+
const message = formatErrorMessage(this);
|
|
35
|
+
if (this.stack) {
|
|
36
|
+
return `${message}\n${this.stack}`;
|
|
37
|
+
}
|
|
38
|
+
return message;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Serializes the error for transport (e.g., client to server).
|
|
42
|
+
* @returns {Object} Serialized error data with type marker
|
|
43
|
+
*/ serialize() {
|
|
44
|
+
return {
|
|
45
|
+
'~err': 'LowdefyError',
|
|
46
|
+
message: this.message,
|
|
47
|
+
stack: this.stack
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Deserializes error data back into a LowdefyError.
|
|
52
|
+
* @param {Object} data - Serialized error data
|
|
53
|
+
* @returns {LowdefyError}
|
|
54
|
+
*/ static deserialize(data) {
|
|
55
|
+
const error = new LowdefyError(data.message);
|
|
56
|
+
if (data.stack) {
|
|
57
|
+
error.stack = data.stack;
|
|
58
|
+
}
|
|
59
|
+
return error;
|
|
60
|
+
}
|
|
32
61
|
/**
|
|
33
|
-
* Creates a
|
|
62
|
+
* Creates a LowdefyError instance.
|
|
34
63
|
* @param {string} message - The error message
|
|
35
64
|
* @param {Object} [options]
|
|
36
65
|
* @param {Error} [options.cause] - The original error that caused this
|
|
37
66
|
*/ constructor(message, options = {}){
|
|
38
67
|
// Message without prefix - logger uses error.name for display
|
|
39
68
|
super(message, options);
|
|
40
|
-
this.name = '
|
|
41
|
-
this.isLowdefyError = true;
|
|
69
|
+
this.name = 'LowdefyError';
|
|
42
70
|
this.configKey = null;
|
|
43
71
|
}
|
|
44
72
|
};
|
|
45
|
-
export default
|
|
73
|
+
export default LowdefyError;
|
package/dist/PluginError.js
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ /**
|
|
16
|
-
*
|
|
16
|
+
* Error class for plugin failures (operators, actions, blocks, connections, requests).
|
|
17
17
|
*
|
|
18
18
|
* Plugins throw plain Error objects with simple messages.
|
|
19
|
-
* The plugin interface layer catches these and wraps them in
|
|
20
|
-
* (
|
|
19
|
+
* The plugin interface layer catches these and wraps them in PluginError
|
|
20
|
+
* with additional context (received values, location, plugin type).
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* // In operator parser (plugin interface layer):
|
|
@@ -25,43 +25,96 @@
|
|
|
25
25
|
* return operator({ params });
|
|
26
26
|
* } catch (error) {
|
|
27
27
|
* if (error instanceof ConfigError) throw error;
|
|
28
|
-
* throw new
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* throw new PluginError({
|
|
29
|
+
* error,
|
|
30
|
+
* pluginType: 'operator',
|
|
31
|
+
* pluginName: '_if',
|
|
31
32
|
* received: params,
|
|
32
33
|
* location: 'blocks.0.properties.visible',
|
|
33
34
|
* configKey: block['~k'],
|
|
34
35
|
* });
|
|
35
36
|
* }
|
|
36
|
-
|
|
37
|
+
* // error.message = "[Plugin Error] _if requires boolean test. Received: {...} at blocks.0.properties.visible."
|
|
38
|
+
*/ import formatErrorMessage from './formatErrorMessage.js';
|
|
39
|
+
let PluginError = class PluginError extends Error {
|
|
40
|
+
print() {
|
|
41
|
+
return formatErrorMessage(this);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Serializes the error for transport (e.g., client to server).
|
|
45
|
+
* @returns {Object} Serialized error data with type marker
|
|
46
|
+
*/ serialize() {
|
|
47
|
+
return {
|
|
48
|
+
'~err': 'PluginError',
|
|
49
|
+
message: this.message,
|
|
50
|
+
rawMessage: this.rawMessage,
|
|
51
|
+
pluginType: this.pluginType,
|
|
52
|
+
pluginName: this.pluginName,
|
|
53
|
+
location: this.location,
|
|
54
|
+
configKey: this.configKey,
|
|
55
|
+
stack: this.stack
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Deserializes error data back into a PluginError.
|
|
60
|
+
* Note: message already contains location/received, so we don't pass them
|
|
61
|
+
* to avoid double-formatting.
|
|
62
|
+
* @param {Object} data - Serialized error data
|
|
63
|
+
* @returns {PluginError}
|
|
64
|
+
*/ static deserialize(data) {
|
|
65
|
+
// Use rawMessage if available, fallback to message
|
|
66
|
+
const messageToUse = data.rawMessage || data.message;
|
|
67
|
+
const error = new PluginError({
|
|
68
|
+
message: messageToUse,
|
|
69
|
+
pluginType: data.pluginType,
|
|
70
|
+
pluginName: data.pluginName,
|
|
71
|
+
configKey: data.configKey
|
|
72
|
+
});
|
|
73
|
+
// Set location separately to preserve it without re-formatting message
|
|
74
|
+
error.location = data.location;
|
|
75
|
+
// Preserve the formatted message if different from rawMessage
|
|
76
|
+
if (data.message && data.message !== messageToUse) {
|
|
77
|
+
error.message = data.message;
|
|
78
|
+
}
|
|
79
|
+
if (data.stack) {
|
|
80
|
+
error.stack = data.stack;
|
|
81
|
+
}
|
|
82
|
+
return error;
|
|
83
|
+
}
|
|
37
84
|
/**
|
|
38
85
|
* Creates a PluginError instance with formatted message.
|
|
39
|
-
* @param {
|
|
40
|
-
* @param {
|
|
41
|
-
* @param {
|
|
42
|
-
* @param {string} [
|
|
43
|
-
* @param {*} [
|
|
44
|
-
* @param {string} [
|
|
45
|
-
* @param {string} [
|
|
46
|
-
*/ constructor(message,
|
|
47
|
-
|
|
86
|
+
* @param {Object} params
|
|
87
|
+
* @param {Error} params.error - The original error thrown by the plugin
|
|
88
|
+
* @param {string} [params.pluginType] - Type of plugin (operator, action, block, request, connection)
|
|
89
|
+
* @param {string} [params.pluginName] - Name of the plugin (e.g., '_if', 'SetState')
|
|
90
|
+
* @param {*} [params.received] - The input that caused the error
|
|
91
|
+
* @param {string} [params.location] - Where in the config the error occurred
|
|
92
|
+
* @param {string} [params.configKey] - Config key (~k) for location resolution
|
|
93
|
+
*/ constructor({ error, message, pluginType, pluginName, received, location, configKey }){
|
|
94
|
+
// Store raw message - logger formats received value
|
|
95
|
+
// Accept either error object or direct message string
|
|
96
|
+
const rawMessage = message ?? error?.message;
|
|
48
97
|
let formattedMessage = rawMessage;
|
|
49
98
|
if (location) {
|
|
50
|
-
formattedMessage = rawMessage ? `${rawMessage} at ${location}.` : `at ${location}.`;
|
|
99
|
+
formattedMessage = rawMessage != null ? `${rawMessage} at ${location}.` : `at ${location}.`;
|
|
51
100
|
}
|
|
52
101
|
super(formattedMessage, {
|
|
53
|
-
cause
|
|
102
|
+
cause: error
|
|
54
103
|
});
|
|
55
104
|
this.name = 'PluginError';
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
this.
|
|
59
|
-
this.received = received !== undefined ? received :
|
|
105
|
+
this.pluginType = pluginType;
|
|
106
|
+
this.pluginName = pluginName;
|
|
107
|
+
this.rawMessage = rawMessage; // Original message without location
|
|
108
|
+
this.received = received !== undefined ? received : error?.received;
|
|
60
109
|
this.location = location;
|
|
61
|
-
this.configKey = configKey ??
|
|
62
|
-
// Location
|
|
110
|
+
this.configKey = error?.configKey ?? configKey ?? null;
|
|
111
|
+
// Location info (set by server-side resolution)
|
|
63
112
|
this.source = null;
|
|
64
113
|
this.config = null;
|
|
114
|
+
this.link = null;
|
|
115
|
+
if (error?.stack) {
|
|
116
|
+
this.stack = error.stack;
|
|
117
|
+
}
|
|
65
118
|
}
|
|
66
119
|
};
|
|
67
120
|
export default PluginError;
|
package/dist/ServiceError.js
CHANGED
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
* Error class for external service failures (network, timeout, database, 5xx).
|
|
33
33
|
*
|
|
34
34
|
* ServiceError represents infrastructure/service issues that are NOT caused by
|
|
35
|
-
* invalid configuration.
|
|
36
|
-
*
|
|
35
|
+
* invalid configuration. These errors should not include config location info
|
|
36
|
+
* since the config is correct - the external service is the problem.
|
|
37
37
|
*
|
|
38
38
|
* The message is formatted in the constructor - no format() method needed.
|
|
39
39
|
*
|
|
@@ -43,12 +43,13 @@
|
|
|
43
43
|
* return await fetch(url);
|
|
44
44
|
* } catch (error) {
|
|
45
45
|
* if (ServiceError.isServiceError(error)) {
|
|
46
|
-
* throw
|
|
46
|
+
* throw ServiceError.from(error, 'MongoDB');
|
|
47
47
|
* }
|
|
48
|
-
* throw new PluginError(
|
|
48
|
+
* throw new PluginError({ error, ... });
|
|
49
49
|
* }
|
|
50
|
-
* // error.message = "MongoDB: Connection refused. The service may be down..."
|
|
51
|
-
*/
|
|
50
|
+
* // error.message = "[Service Error] MongoDB: Connection refused. The service may be down..."
|
|
51
|
+
*/ import formatErrorMessage from './formatErrorMessage.js';
|
|
52
|
+
let ServiceError = class ServiceError extends Error {
|
|
52
53
|
/**
|
|
53
54
|
* Checks if an error is a service error (network issues, timeouts, 5xx).
|
|
54
55
|
* @param {Error} error - The error to check
|
|
@@ -79,50 +80,82 @@
|
|
|
79
80
|
const code = error.code;
|
|
80
81
|
const statusCode = error.statusCode ?? error.status ?? error.response?.status;
|
|
81
82
|
if (code === 'ECONNREFUSED') {
|
|
82
|
-
return `Connection refused. The service may be down or the address may be incorrect. ${error.message
|
|
83
|
+
return `Connection refused. The service may be down or the address may be incorrect. ${error.message}`;
|
|
83
84
|
}
|
|
84
85
|
if (code === 'ENOTFOUND') {
|
|
85
|
-
return `DNS lookup failed. The hostname could not be resolved. ${error.message
|
|
86
|
+
return `DNS lookup failed. The hostname could not be resolved. ${error.message}`;
|
|
86
87
|
}
|
|
87
88
|
if (code === 'ETIMEDOUT') {
|
|
88
|
-
return `Connection timed out. The service may be slow or unreachable. ${error.message
|
|
89
|
+
return `Connection timed out. The service may be slow or unreachable. ${error.message}`;
|
|
89
90
|
}
|
|
90
91
|
if (code === 'ECONNRESET') {
|
|
91
|
-
return `Connection reset by the server. ${error.message
|
|
92
|
+
return `Connection reset by the server. ${error.message}`;
|
|
92
93
|
}
|
|
93
94
|
if (statusCode && statusCode >= 500) {
|
|
94
|
-
return `Server returned error ${statusCode}. ${error.message
|
|
95
|
+
return `Server returned error ${statusCode}. ${error.message}`;
|
|
95
96
|
}
|
|
96
97
|
return error.message;
|
|
97
98
|
}
|
|
99
|
+
print() {
|
|
100
|
+
return formatErrorMessage(this);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Serializes the error for transport (e.g., client to server).
|
|
104
|
+
* @returns {Object} Serialized error data with type marker
|
|
105
|
+
*/ serialize() {
|
|
106
|
+
return {
|
|
107
|
+
'~err': 'ServiceError',
|
|
108
|
+
message: this.message,
|
|
109
|
+
service: this.service,
|
|
110
|
+
code: this.code,
|
|
111
|
+
statusCode: this.statusCode
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Deserializes error data back into a ServiceError.
|
|
116
|
+
* Note: message already contains service prefix, so we don't pass service
|
|
117
|
+
* to avoid double-prefixing.
|
|
118
|
+
* @param {Object} data - Serialized error data
|
|
119
|
+
* @returns {ServiceError}
|
|
120
|
+
*/ static deserialize(data) {
|
|
121
|
+
const error = new ServiceError({
|
|
122
|
+
message: data.message,
|
|
123
|
+
code: data.code,
|
|
124
|
+
statusCode: data.statusCode
|
|
125
|
+
});
|
|
126
|
+
// Set service separately to preserve it without re-prefixing the message
|
|
127
|
+
error.service = data.service;
|
|
128
|
+
return error;
|
|
129
|
+
}
|
|
98
130
|
/**
|
|
99
131
|
* Creates a ServiceError instance with formatted message.
|
|
100
|
-
* @param {
|
|
101
|
-
* @param {
|
|
102
|
-
* @param {Error} [
|
|
103
|
-
* @param {string} [
|
|
104
|
-
* @param {string} [
|
|
105
|
-
* @param {number} [
|
|
106
|
-
* @param {string} [
|
|
107
|
-
*/ constructor(message,
|
|
132
|
+
* @param {Object} params
|
|
133
|
+
* @param {string} [params.message] - The error message (required if no error)
|
|
134
|
+
* @param {Error} [params.error] - Original error to wrap (auto-enhances message)
|
|
135
|
+
* @param {string} [params.service] - Name of the service that failed
|
|
136
|
+
* @param {string} [params.code] - Error code (e.g., 'ECONNREFUSED')
|
|
137
|
+
* @param {number} [params.statusCode] - HTTP status code if applicable
|
|
138
|
+
* @param {string} [params.configKey] - Config key for location resolution
|
|
139
|
+
*/ constructor({ message, error, service, code, statusCode, configKey }){
|
|
108
140
|
// Extract info from wrapped error if provided
|
|
109
|
-
const errorCode = code ??
|
|
110
|
-
const errorStatusCode = statusCode ??
|
|
141
|
+
const errorCode = code ?? error?.code;
|
|
142
|
+
const errorStatusCode = statusCode ?? error?.statusCode ?? error?.status ?? error?.response?.status;
|
|
111
143
|
// Use provided message, or enhance wrapped error's message
|
|
112
|
-
const baseMessage = message ?? (
|
|
144
|
+
const baseMessage = message ?? (error ? ServiceError.enhanceMessage(error) : 'Service error');
|
|
113
145
|
// Message without prefix - logger uses error.name for display
|
|
114
146
|
// Include service in message if provided
|
|
115
147
|
const formattedMessage = service ? `${service}: ${baseMessage}` : baseMessage;
|
|
116
148
|
super(formattedMessage, {
|
|
117
|
-
cause
|
|
149
|
+
cause: error
|
|
118
150
|
});
|
|
119
151
|
this.name = 'ServiceError';
|
|
120
|
-
this.isLowdefyError = true;
|
|
121
|
-
this._message = baseMessage;
|
|
122
152
|
this.service = service;
|
|
123
153
|
this.code = errorCode;
|
|
124
154
|
this.statusCode = errorStatusCode;
|
|
125
155
|
this.configKey = configKey ?? null;
|
|
156
|
+
if (error?.stack) {
|
|
157
|
+
this.stack = error.stack;
|
|
158
|
+
}
|
|
126
159
|
}
|
|
127
160
|
};
|
|
128
161
|
export default ServiceError;
|
package/dist/UserError.js
CHANGED
|
@@ -12,11 +12,14 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/
|
|
15
|
+
*/ import formatErrorMessage from './formatErrorMessage.js';
|
|
16
|
+
let UserError = class UserError extends Error {
|
|
17
|
+
print() {
|
|
18
|
+
return formatErrorMessage(this);
|
|
19
|
+
}
|
|
16
20
|
constructor(message, { blockId, metaData, pageId } = {}){
|
|
17
21
|
super(message);
|
|
18
22
|
this.name = 'UserError';
|
|
19
|
-
this.isLowdefyError = true;
|
|
20
23
|
this.blockId = blockId;
|
|
21
24
|
this.metaData = metaData;
|
|
22
25
|
this.pageId = pageId;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import BaseConfigError from '../ConfigError.js';
|
|
16
|
+
import ConfigMessage from './ConfigMessage.js';
|
|
17
|
+
/**
|
|
18
|
+
* Build-time configuration error class.
|
|
19
|
+
* Extends base ConfigError with synchronous location resolution using keyMap/refMap.
|
|
20
|
+
* All formatting happens in the constructor - properties are ready for the logger.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Standard usage with message and context
|
|
24
|
+
* throw new ConfigError({
|
|
25
|
+
* message: 'Connection id missing.',
|
|
26
|
+
* configKey: block['~k'],
|
|
27
|
+
* context,
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // YAML parse error - pass error object instead of message
|
|
32
|
+
* throw new ConfigError({
|
|
33
|
+
* error: yamlParseError,
|
|
34
|
+
* filePath: 'lowdefy.yaml',
|
|
35
|
+
* configDirectory,
|
|
36
|
+
* });
|
|
37
|
+
*/ let ConfigError = class ConfigError extends BaseConfigError {
|
|
38
|
+
/**
|
|
39
|
+
* Creates a ConfigError instance with build-time formatting.
|
|
40
|
+
* All location resolution happens here - no format() method needed.
|
|
41
|
+
*
|
|
42
|
+
* @param {Object} params
|
|
43
|
+
* @param {string} [params.message] - The error message (or use params.error for YAML errors)
|
|
44
|
+
* @param {Error} [params.error] - Original error (for YAML parse errors - extracts line number)
|
|
45
|
+
* @param {string} [params.configKey] - Config key (~k) for keyMap lookup
|
|
46
|
+
* @param {Object} [params.operatorLocation] - { ref, line } for direct refMap lookup
|
|
47
|
+
* @param {string} [params.filePath] - Direct file path (for raw mode)
|
|
48
|
+
* @param {number|string} [params.lineNumber] - Direct line number (for raw mode)
|
|
49
|
+
* @param {Object} [params.context] - Build context with keyMap, refMap, directories
|
|
50
|
+
* @param {string} [params.configDirectory] - Config directory (for raw mode without context)
|
|
51
|
+
* @param {string} [params.checkSlug] - The specific check being performed
|
|
52
|
+
* @param {*} [params.received] - The value that caused the error (for logger to format)
|
|
53
|
+
*/ constructor({ message, error, configKey, operatorLocation, filePath, lineNumber, context, configDirectory, checkSlug, received }){
|
|
54
|
+
// Handle YAML parse errors - extract line number from error message
|
|
55
|
+
let finalMessage = message;
|
|
56
|
+
let finalLineNumber = lineNumber;
|
|
57
|
+
if (error instanceof Error) {
|
|
58
|
+
finalMessage = `Could not parse YAML. ${error.message}`;
|
|
59
|
+
const lineMatch = error.message.match(/at line (\d+)/);
|
|
60
|
+
finalLineNumber = lineMatch ? lineMatch[1] : null;
|
|
61
|
+
}
|
|
62
|
+
// Call base constructor with minimal info first
|
|
63
|
+
super({
|
|
64
|
+
message: finalMessage,
|
|
65
|
+
configKey,
|
|
66
|
+
checkSlug
|
|
67
|
+
});
|
|
68
|
+
// Store all properties for the logger
|
|
69
|
+
this.configKey = configKey ?? null;
|
|
70
|
+
this.checkSlug = checkSlug;
|
|
71
|
+
this.operatorLocation = operatorLocation;
|
|
72
|
+
this.received = received;
|
|
73
|
+
// Check for ~ignoreBuildChecks suppression
|
|
74
|
+
this.suppressed = ConfigMessage.shouldSuppress({
|
|
75
|
+
configKey,
|
|
76
|
+
keyMap: context?.keyMap,
|
|
77
|
+
checkSlug
|
|
78
|
+
});
|
|
79
|
+
if (this.suppressed) {
|
|
80
|
+
this.message = '';
|
|
81
|
+
this.source = null;
|
|
82
|
+
this.config = null;
|
|
83
|
+
this.link = null;
|
|
84
|
+
this.resolved = true;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Resolve location based on available info, falling through if a method returns null
|
|
88
|
+
let location = null;
|
|
89
|
+
const configDir = configDirectory ?? context?.directories?.config;
|
|
90
|
+
if (configKey && context?.keyMap) {
|
|
91
|
+
location = ConfigMessage.resolveLocation({
|
|
92
|
+
configKey,
|
|
93
|
+
context
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (!location && operatorLocation && context?.refMap) {
|
|
97
|
+
location = ConfigMessage.resolveOperatorLocation({
|
|
98
|
+
operatorLocation,
|
|
99
|
+
context
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (!location && filePath) {
|
|
103
|
+
location = ConfigMessage.resolveRawLocation({
|
|
104
|
+
filePath,
|
|
105
|
+
lineNumber: finalLineNumber,
|
|
106
|
+
configDirectory: configDir
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Set location properties
|
|
110
|
+
this.source = location?.source ?? null;
|
|
111
|
+
this.config = location?.config ?? null;
|
|
112
|
+
this.link = location?.link ?? null;
|
|
113
|
+
// Set message (no prefix - logger uses error.name for display)
|
|
114
|
+
this.message = finalMessage;
|
|
115
|
+
// Mark as resolved
|
|
116
|
+
this.resolved = true;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
export default ConfigError;
|