@lowdefy/errors 0.0.0-experimental-20260219135421 → 0.0.0-experimental-20260220095000

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.
@@ -0,0 +1,22 @@
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 PluginError from './PluginError.js';
16
+ let ActionError = class ActionError extends PluginError {
17
+ constructor(message, options = {}){
18
+ super(message, options);
19
+ this.name = 'ActionError';
20
+ }
21
+ };
22
+ export default ActionError;
@@ -0,0 +1,22 @@
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 PluginError from './PluginError.js';
16
+ let BlockError = class BlockError extends PluginError {
17
+ constructor(message, options = {}){
18
+ super(message, options);
19
+ this.name = 'BlockError';
20
+ }
21
+ };
22
+ export default BlockError;
@@ -0,0 +1,34 @@
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
+ */ /**
16
+ * Summary error thrown after build errors have already been logged.
17
+ *
18
+ * Used to stop the build process with a summary message like
19
+ * "Build failed with 5 error(s). See above for details."
20
+ * The real errors are logged individually before this is thrown.
21
+ *
22
+ * Stack traces are suppressed by the CLI logger via isLowdefyError marker.
23
+ *
24
+ * @example
25
+ * context.handleError(configError); // log the real error
26
+ * throw new BuildError('Build failed with 1 error(s). See above for details.');
27
+ */ let BuildError = class BuildError extends Error {
28
+ constructor(message){
29
+ super(message);
30
+ this.name = 'BuildError';
31
+ this.isLowdefyError = true;
32
+ }
33
+ };
34
+ export default BuildError;
@@ -15,10 +15,7 @@
15
15
  */ /**
16
16
  * Base error class for configuration errors (invalid YAML, schema violations, validation errors).
17
17
  *
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)
18
+ * Import from @lowdefy/errors for general use.
22
19
  *
23
20
  * @example
24
21
  * // Simple string (for plugins - configKey added by interface layer)
@@ -26,71 +23,46 @@
26
23
  *
27
24
  * @example
28
25
  * // With options
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' }
26
+ * throw new ConfigError('Invalid block type', { configKey: block['~k'] });
27
+ *
28
+ * @example
29
+ * // With raw file location (YAML parse errors, pre-addKeys)
30
+ * throw new ConfigError('Error parsing file', {
31
+ * filePath: 'pages/home.yaml',
32
+ * lineNumber: 6,
33
33
  * });
34
- */ import formatErrorMessage from './formatErrorMessage.js';
35
- let ConfigError = class ConfigError extends Error {
36
- print() {
37
- return formatErrorMessage(this);
38
- }
39
- /**
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
57
- });
58
- }
34
+ *
35
+ * @example
36
+ * // Wrapping an error
37
+ * throw new ConfigError(error.message, { cause: error, filePath });
38
+ */ let ConfigError = class ConfigError extends Error {
59
39
  /**
60
40
  * 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);
41
+ * @param {string} [message] - Error message (falls back to cause.message)
42
+ * @param {Object} [options]
43
+ * @param {Error} [options.cause] - Original error to wrap
44
+ * @param {string} [options.configKey] - Config key (~k) for location resolution
45
+ * @param {string} [options.filePath] - Raw file path for pre-addKeys errors
46
+ * @param {string|number} [options.lineNumber] - Line number for pre-addKeys errors
47
+ * @param {string} [options.checkSlug] - The build check that triggered this error
48
+ * @param {*} [options.received] - The input that caused the error
49
+ */ constructor(message, { cause, configKey, filePath, lineNumber, checkSlug, received } = {}){
50
+ const resolvedMessage = message ?? cause?.message;
51
+ super(resolvedMessage, {
52
+ cause
53
+ });
79
54
  this.name = 'ConfigError';
80
- this.configKey = configKey ?? null;
55
+ this.isLowdefyError = true;
56
+ this.configKey = configKey ?? cause?.configKey ?? null;
81
57
  this.checkSlug = checkSlug;
82
58
  // For logger formatting
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
- }
59
+ this.received = received !== undefined ? received : cause?.received;
60
+ // Raw file location for pre-addKeys errors (resolved by handleError/handleWarning)
61
+ this.filePath = filePath ?? null;
62
+ this.lineNumber = lineNumber ?? null;
63
+ // Location outputs (set by handlers via resolveErrorLocation, not at construction)
64
+ this.source = null;
65
+ this.config = null;
94
66
  }
95
67
  };
96
68
  export default ConfigError;
@@ -12,31 +12,19 @@
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
- * 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;
15
+ */ import ConfigError from './ConfigError.js';
16
+ let ConfigWarning = class ConfigWarning extends ConfigError {
17
+ constructor(message, { cause, configKey, checkSlug, filePath, lineNumber, received, prodError } = {}){
18
+ super(message, {
19
+ cause,
20
+ configKey,
21
+ checkSlug,
22
+ filePath,
23
+ lineNumber,
24
+ received
25
+ });
26
+ this.name = 'ConfigWarning';
27
+ this.prodError = prodError ?? false;
40
28
  }
41
29
  };
42
30
  export default ConfigWarning;
@@ -20,7 +20,7 @@
20
20
  *
21
21
  * @example
22
22
  * // Create a new error
23
- * throw new LowdefyError('Unexpected condition');
23
+ * throw new LowdefyInternalError('Unexpected condition');
24
24
  *
25
25
  * @example
26
26
  * // At top-level catch, log the error with stack
@@ -28,46 +28,18 @@
28
28
  * console.error(err.message);
29
29
  * console.error(err.stack);
30
30
  * }
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
- }
31
+ */ let LowdefyInternalError = class LowdefyInternalError extends Error {
61
32
  /**
62
- * Creates a LowdefyError instance.
33
+ * Creates a LowdefyInternalError instance.
63
34
  * @param {string} message - The error message
64
35
  * @param {Object} [options]
65
36
  * @param {Error} [options.cause] - The original error that caused this
66
37
  */ constructor(message, options = {}){
67
38
  // Message without prefix - logger uses error.name for display
68
39
  super(message, options);
69
- this.name = 'LowdefyError';
40
+ this.name = 'LowdefyInternalError';
41
+ this.isLowdefyError = true;
70
42
  this.configKey = null;
71
43
  }
72
44
  };
73
- export default LowdefyError;
45
+ export default LowdefyInternalError;
@@ -0,0 +1,22 @@
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 PluginError from './PluginError.js';
16
+ let OperatorError = class OperatorError extends PluginError {
17
+ constructor(message, options = {}){
18
+ super(message, options);
19
+ this.name = 'OperatorError';
20
+ }
21
+ };
22
+ export default OperatorError;
@@ -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
- * Error class for plugin failures (operators, actions, blocks, connections, requests).
16
+ * Base error class for plugin failures (operators, actions, blocks, requests).
17
17
  *
18
18
  * Plugins throw plain Error objects with simple messages.
19
- * The plugin interface layer catches these and wraps them in PluginError
20
- * with additional context (received values, location, plugin type).
19
+ * The plugin interface layer catches these and wraps them in a typed subclass
20
+ * (OperatorError, ActionError, BlockError, RequestError) with additional context.
21
21
  *
22
22
  * @example
23
23
  * // In operator parser (plugin interface layer):
@@ -25,96 +25,43 @@
25
25
  * return operator({ params });
26
26
  * } catch (error) {
27
27
  * if (error instanceof ConfigError) throw error;
28
- * throw new PluginError({
29
- * error,
30
- * pluginType: 'operator',
31
- * pluginName: '_if',
28
+ * throw new OperatorError(error.message, {
29
+ * cause: error,
30
+ * typeName: '_if',
32
31
  * received: params,
33
32
  * location: 'blocks.0.properties.visible',
34
33
  * configKey: block['~k'],
35
34
  * });
36
35
  * }
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
- }
36
+ */ let PluginError = class PluginError extends Error {
84
37
  /**
85
38
  * Creates a PluginError instance with formatted message.
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;
39
+ * @param {string} [message] - Error message (falls back to cause.message)
40
+ * @param {Object} [options]
41
+ * @param {Error} [options.cause] - The original error thrown by the plugin
42
+ * @param {string} [options.typeName] - The config type name (e.g., '_if', 'SetState', 'MongoDBFind')
43
+ * @param {*} [options.received] - The input that caused the error
44
+ * @param {string} [options.location] - Where in the config the error occurred
45
+ * @param {string} [options.configKey] - Config key (~k) for location resolution
46
+ */ constructor(message, { cause, typeName, received, location, configKey } = {}){
47
+ const rawMessage = message ?? cause?.message;
97
48
  let formattedMessage = rawMessage;
98
49
  if (location) {
99
- formattedMessage = rawMessage != null ? `${rawMessage} at ${location}.` : `at ${location}.`;
50
+ formattedMessage = rawMessage ? `${rawMessage} at ${location}.` : `at ${location}.`;
100
51
  }
101
52
  super(formattedMessage, {
102
- cause: error
53
+ cause
103
54
  });
104
55
  this.name = 'PluginError';
105
- this.pluginType = pluginType;
106
- this.pluginName = pluginName;
107
- this.rawMessage = rawMessage; // Original message without location
108
- this.received = received !== undefined ? received : error?.received;
56
+ this.isLowdefyError = true;
57
+ this.typeName = typeName;
58
+ this._message = rawMessage;
59
+ this.received = received !== undefined ? received : cause?.received;
109
60
  this.location = location;
110
- this.configKey = error?.configKey ?? configKey ?? null;
111
- // Location info (set by server-side resolution)
61
+ this.configKey = configKey ?? cause?.configKey ?? null;
62
+ // Location outputs (set by server-side resolution)
112
63
  this.source = null;
113
64
  this.config = null;
114
- this.link = null;
115
- if (error?.stack) {
116
- this.stack = error.stack;
117
- }
118
65
  }
119
66
  };
120
67
  export default PluginError;
@@ -0,0 +1,22 @@
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 PluginError from './PluginError.js';
16
+ let RequestError = class RequestError extends PluginError {
17
+ constructor(message, options = {}){
18
+ super(message, options);
19
+ this.name = 'RequestError';
20
+ }
21
+ };
22
+ export default RequestError;
@@ -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. These errors should not include config location info
36
- * since the config is correct - the external service is the problem.
35
+ * invalid configuration. The config location is still resolved to help developers
36
+ * identify which request/connection triggered the service failure.
37
37
  *
38
38
  * The message is formatted in the constructor - no format() method needed.
39
39
  *
@@ -43,13 +43,12 @@
43
43
  * return await fetch(url);
44
44
  * } catch (error) {
45
45
  * if (ServiceError.isServiceError(error)) {
46
- * throw ServiceError.from(error, 'MongoDB');
46
+ * throw new ServiceError(undefined, { cause: error, service: 'MongoDB' });
47
47
  * }
48
- * throw new PluginError({ error, ... });
48
+ * throw new PluginError(error.message, { cause: error, ... });
49
49
  * }
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 {
50
+ * // error.message = "MongoDB: Connection refused. The service may be down..."
51
+ */ let ServiceError = class ServiceError extends Error {
53
52
  /**
54
53
  * Checks if an error is a service error (network issues, timeouts, 5xx).
55
54
  * @param {Error} error - The error to check
@@ -80,82 +79,50 @@ let ServiceError = class ServiceError extends Error {
80
79
  const code = error.code;
81
80
  const statusCode = error.statusCode ?? error.status ?? error.response?.status;
82
81
  if (code === 'ECONNREFUSED') {
83
- return `Connection refused. The service may be down or the address may be incorrect. ${error.message}`;
82
+ return `Connection refused. The service may be down or the address may be incorrect. ${error.message ?? ''}`;
84
83
  }
85
84
  if (code === 'ENOTFOUND') {
86
- return `DNS lookup failed. The hostname could not be resolved. ${error.message}`;
85
+ return `DNS lookup failed. The hostname could not be resolved. ${error.message ?? ''}`;
87
86
  }
88
87
  if (code === 'ETIMEDOUT') {
89
- return `Connection timed out. The service may be slow or unreachable. ${error.message}`;
88
+ return `Connection timed out. The service may be slow or unreachable. ${error.message ?? ''}`;
90
89
  }
91
90
  if (code === 'ECONNRESET') {
92
- return `Connection reset by the server. ${error.message}`;
91
+ return `Connection reset by the server. ${error.message ?? ''}`;
93
92
  }
94
93
  if (statusCode && statusCode >= 500) {
95
- return `Server returned error ${statusCode}. ${error.message}`;
94
+ return `Server returned error ${statusCode}. ${error.message ?? ''}`;
96
95
  }
97
96
  return error.message;
98
97
  }
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
- }
130
98
  /**
131
99
  * Creates a ServiceError instance with formatted 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 }){
100
+ * @param {string} [message] - Error message (falls back to enhanced cause message)
101
+ * @param {Object} [options]
102
+ * @param {Error} [options.cause] - Original error to wrap (auto-enhances message)
103
+ * @param {string} [options.service] - Name of the service that failed
104
+ * @param {string} [options.code] - Error code (e.g., 'ECONNREFUSED')
105
+ * @param {number} [options.statusCode] - HTTP status code if applicable
106
+ * @param {string} [options.configKey] - Config key for location resolution
107
+ */ constructor(message, { cause, service, code, statusCode, configKey } = {}){
140
108
  // Extract info from wrapped error if provided
141
- const errorCode = code ?? error?.code;
142
- const errorStatusCode = statusCode ?? error?.statusCode ?? error?.status ?? error?.response?.status;
109
+ const errorCode = code ?? cause?.code;
110
+ const errorStatusCode = statusCode ?? cause?.statusCode ?? cause?.status ?? cause?.response?.status;
143
111
  // Use provided message, or enhance wrapped error's message
144
- const baseMessage = message ?? (error ? ServiceError.enhanceMessage(error) : 'Service error');
112
+ const baseMessage = message ?? (cause ? ServiceError.enhanceMessage(cause) : 'Service error');
145
113
  // Message without prefix - logger uses error.name for display
146
114
  // Include service in message if provided
147
115
  const formattedMessage = service ? `${service}: ${baseMessage}` : baseMessage;
148
116
  super(formattedMessage, {
149
- cause: error
117
+ cause
150
118
  });
151
119
  this.name = 'ServiceError';
120
+ this.isLowdefyError = true;
121
+ this._message = baseMessage;
152
122
  this.service = service;
153
123
  this.code = errorCode;
154
124
  this.statusCode = errorStatusCode;
155
125
  this.configKey = configKey ?? null;
156
- if (error?.stack) {
157
- this.stack = error.stack;
158
- }
159
126
  }
160
127
  };
161
128
  export default ServiceError;
package/dist/UserError.js CHANGED
@@ -12,14 +12,11 @@
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
- */ import formatErrorMessage from './formatErrorMessage.js';
16
- let UserError = class UserError extends Error {
17
- print() {
18
- return formatErrorMessage(this);
19
- }
15
+ */ let UserError = class UserError extends Error {
20
16
  constructor(message, { blockId, metaData, pageId } = {}){
21
17
  super(message);
22
18
  this.name = 'UserError';
19
+ this.isLowdefyError = true;
23
20
  this.blockId = blockId;
24
21
  this.metaData = metaData;
25
22
  this.pageId = pageId;