@lowdefy/errors 7.1.0 → 7.2.0
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/ServiceError.js +43 -22
- package/dist/errorSummaryForLog.js +68 -0
- package/dist/findInErrorChain.js +22 -0
- package/dist/hasTimeoutInChain.js +22 -0
- package/dist/index.js +5 -1
- package/dist/isExpectedError.js +24 -0
- package/dist/isTimeoutError.js +37 -0
- package/dist/shouldSuppressBuildCheck.js +1 -0
- package/package.json +3 -5
package/dist/ServiceError.js
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
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 findInErrorChain from './findInErrorChain.js';
|
|
16
|
+
import hasTimeoutInChain from './hasTimeoutInChain.js';
|
|
17
|
+
import isTimeoutError from './isTimeoutError.js';
|
|
18
|
+
/**
|
|
16
19
|
* Network error codes that indicate service issues (not config problems).
|
|
17
20
|
*/ const SERVICE_ERROR_CODES = new Set([
|
|
18
21
|
'ECONNREFUSED',
|
|
@@ -37,11 +40,22 @@ function readHttpStatus(error) {
|
|
|
37
40
|
const numericCode = Number.isInteger(error.code) && error.code >= 100 && error.code < 600 ? error.code : undefined;
|
|
38
41
|
return error.statusCode ?? error.status ?? error.response?.status ?? error.$metadata?.httpStatusCode ?? numericCode;
|
|
39
42
|
}
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// What failed, read once from the error and its chain. A call that ran out of time got no
|
|
44
|
+
// answer, so any status attached above the cancellation is one a client made up, not a
|
|
45
|
+
// server response: the AI gateway client reports 500 for an AbortSignal.timeout, and 408
|
|
46
|
+
// for an undici timeout. A real 5xx or 429 wrapped around a timeout looks the same, so the
|
|
47
|
+
// timeout wins.
|
|
48
|
+
function classifyFailure(error) {
|
|
49
|
+
if (hasTimeoutInChain(error)) {
|
|
50
|
+
return {
|
|
51
|
+
timedOut: true,
|
|
52
|
+
statusCode: undefined
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
timedOut: false,
|
|
57
|
+
statusCode: findInErrorChain(error, readHttpStatus)
|
|
58
|
+
};
|
|
45
59
|
}
|
|
46
60
|
// 5xx is a failing service; 429 is a service throttling its callers. Both pass with
|
|
47
61
|
// time, and neither is fixed by changing config.
|
|
@@ -87,6 +101,10 @@ function readRetryAfterHeader(headers) {
|
|
|
87
101
|
*/ static isServiceError(error, seen = new Set()) {
|
|
88
102
|
if (!error || seen.has(error)) return false;
|
|
89
103
|
seen.add(error);
|
|
104
|
+
// A connection that has already classified its error as the service refusing the request
|
|
105
|
+
// (a duplicate key, an invalid query) says so. The message checks below would otherwise
|
|
106
|
+
// match words in a collection name or in the document values a driver message quotes.
|
|
107
|
+
if (error.isServiceError === false) return false;
|
|
90
108
|
// A client that retried and gave up (the AI SDK's RetryError) carries the
|
|
91
109
|
// failure it retried on; its own message and fields hold no status.
|
|
92
110
|
if (error.lastError) {
|
|
@@ -97,8 +115,8 @@ function readRetryAfterHeader(headers) {
|
|
|
97
115
|
return true;
|
|
98
116
|
}
|
|
99
117
|
// A call cancelled because it ran out of time (AbortSignal.timeout, the AI SDK's
|
|
100
|
-
// timeout option, the server's request timeout).
|
|
101
|
-
if (error
|
|
118
|
+
// timeout option, the server's request timeout, undici's timeouts).
|
|
119
|
+
if (isTimeoutError(error)) {
|
|
102
120
|
return true;
|
|
103
121
|
}
|
|
104
122
|
// AWS SDK v3 marks throttling exceptions as retryable throttling; some services
|
|
@@ -121,10 +139,12 @@ function readRetryAfterHeader(headers) {
|
|
|
121
139
|
/**
|
|
122
140
|
* Enhances an error message with more helpful context.
|
|
123
141
|
* @param {Error} error - The original error
|
|
142
|
+
* @param {Object} [failure] - Whether the call timed out and the status it failed with,
|
|
143
|
+
* when the caller already worked them out
|
|
124
144
|
* @returns {string} Enhanced error message
|
|
125
|
-
*/ static enhanceMessage(error) {
|
|
145
|
+
*/ static enhanceMessage(error, failure = classifyFailure(error)) {
|
|
126
146
|
const code = error.code;
|
|
127
|
-
const statusCode =
|
|
147
|
+
const { timedOut, statusCode } = failure;
|
|
128
148
|
if (code === 'ECONNREFUSED') {
|
|
129
149
|
return `Connection refused. The service may be down or the address may be incorrect. ${error.message ?? ''}`;
|
|
130
150
|
}
|
|
@@ -137,6 +157,9 @@ function readRetryAfterHeader(headers) {
|
|
|
137
157
|
if (code === 'ECONNRESET') {
|
|
138
158
|
return `Connection reset by the server. ${error.message ?? ''}`;
|
|
139
159
|
}
|
|
160
|
+
if (timedOut) {
|
|
161
|
+
return `Request timed out. The service may be slow, or the timeout too short. ${error.message ?? ''}`;
|
|
162
|
+
}
|
|
140
163
|
if (statusCode === 429) {
|
|
141
164
|
const retryAfter = ServiceError.readRetryAfter(error);
|
|
142
165
|
const retry = retryAfter ? ` Retry after ${retryAfter}.` : '';
|
|
@@ -151,16 +174,10 @@ function readRetryAfterHeader(headers) {
|
|
|
151
174
|
* Reads the Retry-After header a throttling service sent, from the error, the
|
|
152
175
|
* failure a retrying client gave up on, or its cause chain.
|
|
153
176
|
* @param {Error} error - The error to read
|
|
154
|
-
* @param {Set} [seen] - Errors already read, so a cyclic cause chain ends
|
|
155
177
|
* @returns {string|null} The header value (seconds or an HTTP date), or null
|
|
156
|
-
*/ static readRetryAfter(error
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const retryAfter = readRetryAfterHeader(error.responseHeaders) ?? readRetryAfterHeader(error.response?.headers) ?? readRetryAfterHeader(error.headers) ?? readRetryAfterHeader(error.$response?.headers);
|
|
160
|
-
if (retryAfter !== undefined && retryAfter !== null) {
|
|
161
|
-
return String(retryAfter);
|
|
162
|
-
}
|
|
163
|
-
return ServiceError.readRetryAfter(error.lastError, seen) ?? ServiceError.readRetryAfter(error.cause, seen);
|
|
178
|
+
*/ static readRetryAfter(error) {
|
|
179
|
+
const retryAfter = findInErrorChain(error, (node)=>readRetryAfterHeader(node.responseHeaders) ?? readRetryAfterHeader(node.response?.headers) ?? readRetryAfterHeader(node.headers) ?? readRetryAfterHeader(node.$response?.headers) ?? undefined);
|
|
180
|
+
return retryAfter === undefined ? null : String(retryAfter);
|
|
164
181
|
}
|
|
165
182
|
/**
|
|
166
183
|
* Creates a ServiceError instance with formatted message.
|
|
@@ -178,9 +195,13 @@ function readRetryAfterHeader(headers) {
|
|
|
178
195
|
*/ constructor(message, { cause, service, code, statusCode, configKey, hint, retryAfter } = {}){
|
|
179
196
|
// Extract info from wrapped error if provided
|
|
180
197
|
const errorCode = code ?? cause?.code;
|
|
181
|
-
|
|
198
|
+
// A status passed in is the caller saying a service answered with it.
|
|
199
|
+
const failure = statusCode === undefined || statusCode === null ? classifyFailure(cause) : {
|
|
200
|
+
timedOut: false,
|
|
201
|
+
statusCode
|
|
202
|
+
};
|
|
182
203
|
// Use provided message, or enhance wrapped error's message
|
|
183
|
-
const baseMessage = message ?? (cause ? ServiceError.enhanceMessage(cause) : 'Service error');
|
|
204
|
+
const baseMessage = message ?? (cause ? ServiceError.enhanceMessage(cause, failure) : 'Service error');
|
|
184
205
|
// Message without prefix - logger uses error.name for display
|
|
185
206
|
// Include service in message if provided
|
|
186
207
|
const formattedMessage = service ? `${service}: ${baseMessage}` : baseMessage;
|
|
@@ -193,7 +214,7 @@ function readRetryAfterHeader(headers) {
|
|
|
193
214
|
this.service = service;
|
|
194
215
|
this.code = errorCode;
|
|
195
216
|
this.hint = hint ?? cause?.hint ?? null;
|
|
196
|
-
this.statusCode =
|
|
217
|
+
this.statusCode = failure.statusCode;
|
|
197
218
|
this.retryAfter = retryAfter ?? ServiceError.readRetryAfter(cause);
|
|
198
219
|
// Extract from the wrapped error like PluginError does, so a ServiceError
|
|
199
220
|
// wrapped around an error that already resolved its config location keeps it.
|
|
@@ -0,0 +1,68 @@
|
|
|
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 hasTimeoutInChain from './hasTimeoutInChain.js';
|
|
16
|
+
import readErrorCodes from './readErrorCodes.js';
|
|
17
|
+
// What a log may say about an error. Chat text and other inputs can hold personal information,
|
|
18
|
+
// and logs have their own retention and access, so a log carries no prompt, request property,
|
|
19
|
+
// tool input or document. An error carries them where a plain `{ err }` log would write them: a
|
|
20
|
+
// driver's error embeds the document it rejected, an AI SDK TypeValidationError's or
|
|
21
|
+
// JSONParseError's message embeds the value it rejected (the whole conversation, a tool's
|
|
22
|
+
// input), InvalidToolInputError, ToolCallRepairError and RetryError repeat their cause's
|
|
23
|
+
// message, and every stack opens with its message. So an AI SDK error is summarised by name
|
|
24
|
+
// and code alone, except APICallError, whose message is the provider's reply; any other error
|
|
25
|
+
// keeps its name, code, status code and message, cut to 500 characters, and none of its other
|
|
26
|
+
// fields. Causes are followed the same way, three deep.
|
|
27
|
+
const MESSAGE_LIMIT = 500;
|
|
28
|
+
const CAUSE_DEPTH = 3;
|
|
29
|
+
// AISDKError.isInstance reads this marker; the error classes themselves are not imported so
|
|
30
|
+
// any copy of the AI SDK in the app is recognised.
|
|
31
|
+
const aiSdkErrorMarker = Symbol.for('vercel.ai.error');
|
|
32
|
+
function isAiSdkError(error) {
|
|
33
|
+
return error[aiSdkErrorMarker] === true;
|
|
34
|
+
}
|
|
35
|
+
// An error from another realm, such as a DOMException in a VM context, fails instanceof Error.
|
|
36
|
+
function isError(value) {
|
|
37
|
+
if (value instanceof Error) return true;
|
|
38
|
+
return typeof value === 'object' && value !== null && typeof value.stack === 'string' && typeof value.message === 'string';
|
|
39
|
+
}
|
|
40
|
+
function truncate(text) {
|
|
41
|
+
if (text.length <= MESSAGE_LIMIT) return text;
|
|
42
|
+
return `${text.slice(0, MESSAGE_LIMIT - 1)}…`;
|
|
43
|
+
}
|
|
44
|
+
function errorSummaryForLog(error, depth = 0) {
|
|
45
|
+
if (!isError(error)) {
|
|
46
|
+
return {
|
|
47
|
+
name: typeof error
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const summary = {
|
|
51
|
+
name: error.name
|
|
52
|
+
};
|
|
53
|
+
if (!isAiSdkError(error) || error.name === 'AI_APICallError') {
|
|
54
|
+
summary.message = truncate(String(error.message));
|
|
55
|
+
}
|
|
56
|
+
const { code, statusCode } = readErrorCodes(error);
|
|
57
|
+
if (code !== undefined) summary.code = code;
|
|
58
|
+
// A status above a call that ran out of time is one the client made up, not a server
|
|
59
|
+
// response (see ServiceError), so neither the log nor the client is told it.
|
|
60
|
+
if (statusCode !== undefined && !hasTimeoutInChain(error)) summary.statusCode = statusCode;
|
|
61
|
+
// A RetryError holds the attempt that failed last as lastError rather than as its cause.
|
|
62
|
+
const cause = error.lastError ?? error.cause;
|
|
63
|
+
if (cause !== undefined && depth < CAUSE_DEPTH) {
|
|
64
|
+
summary.cause = errorSummaryForLog(cause, depth + 1);
|
|
65
|
+
}
|
|
66
|
+
return summary;
|
|
67
|
+
}
|
|
68
|
+
export default errorSummaryForLog;
|
|
@@ -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
|
+
*/ // The first value `read` gives for an error, the failure a retrying client gave up on
|
|
16
|
+
// (lastError), or the cause chain, in that order. Stops on a cycle.
|
|
17
|
+
function findInErrorChain(error, read, seen = new Set()) {
|
|
18
|
+
if (!error || typeof error !== 'object' || seen.has(error)) return undefined;
|
|
19
|
+
seen.add(error);
|
|
20
|
+
return read(error) ?? findInErrorChain(error.lastError, read, seen) ?? findInErrorChain(error.cause, read, seen);
|
|
21
|
+
}
|
|
22
|
+
export default findInErrorChain;
|
|
@@ -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 findInErrorChain from './findInErrorChain.js';
|
|
16
|
+
import isTimeoutError from './isTimeoutError.js';
|
|
17
|
+
// Whether the error, or anything down its lastError and cause chain, is a call cancelled
|
|
18
|
+
// because it ran out of time.
|
|
19
|
+
function hasTimeoutInChain(error) {
|
|
20
|
+
return findInErrorChain(error, (node)=>isTimeoutError(node) ? true : undefined) === true;
|
|
21
|
+
}
|
|
22
|
+
export default hasTimeoutInChain;
|
package/dist/index.js
CHANGED
|
@@ -73,7 +73,9 @@
|
|
|
73
73
|
* shouldSuppressBuildCheck - Check ~ignoreBuildChecks in parent chain
|
|
74
74
|
*
|
|
75
75
|
* Error Field Utilities:
|
|
76
|
+
* errorSummaryForLog - {name, message, code, statusCode, cause} an error may log
|
|
76
77
|
* expectedErrorNames - Set of error class names that are expected outcomes, not faults
|
|
78
|
+
* isExpectedError - The one test for an expected outcome versus a fault
|
|
77
79
|
* readErrorCodes - {code, statusCode} from one error node's own fields
|
|
78
80
|
* lowdefyErrorNames - Set of Lowdefy error class names
|
|
79
81
|
* lowdefyErrorTypes - Lowdefy error class by name, for reviving and reshaping errors
|
|
@@ -84,8 +86,10 @@ import BlockError from './BlockError.js';
|
|
|
84
86
|
import BuildError from './BuildError.js';
|
|
85
87
|
import ConfigError from './ConfigError.js';
|
|
86
88
|
import ConfigWarning from './ConfigWarning.js';
|
|
89
|
+
import errorSummaryForLog from './errorSummaryForLog.js';
|
|
87
90
|
import errorToDisplayString from './errorToDisplayString.js';
|
|
88
91
|
import expectedErrorNames from './expectedErrorNames.js';
|
|
92
|
+
import isExpectedError from './isExpectedError.js';
|
|
89
93
|
import LowdefyInternalError from './LowdefyInternalError.js';
|
|
90
94
|
import lowdefyErrorNames from './lowdefyErrorNames.js';
|
|
91
95
|
import lowdefyErrorTypes from './lowdefyErrorTypes.js';
|
|
@@ -101,4 +105,4 @@ import shouldSuppressBuildCheck, { PLUGIN_CHECKS_SLUG, PLUGIN_SCHEMA_SLUG, VALID
|
|
|
101
105
|
import TenantIntegrityError from './TenantIntegrityError.js';
|
|
102
106
|
import TwoFactorEnrolmentRequiredError from './TwoFactorEnrolmentRequiredError.js';
|
|
103
107
|
import UserError from './UserError.js';
|
|
104
|
-
export { ActionError, AuthenticationError, AuthorizationError, BlockError, BuildError, ConfigError, ConfigWarning, errorToDisplayString, expectedErrorNames, LowdefyInternalError, lowdefyErrorNames, lowdefyErrorTypes, OperatorError, PluginError, PLUGIN_CHECKS_SLUG, PLUGIN_SCHEMA_SLUG, readErrorCodes, RequestError, resolveConfigLocation, loadAndResolveErrorLocation, resolveErrorLocation, ServiceError, shouldSuppressBuildCheck, TenantIntegrityError, TwoFactorEnrolmentRequiredError, UserError, VALID_CHECK_SLUGS };
|
|
108
|
+
export { ActionError, AuthenticationError, AuthorizationError, BlockError, BuildError, ConfigError, ConfigWarning, errorSummaryForLog, errorToDisplayString, expectedErrorNames, isExpectedError, LowdefyInternalError, lowdefyErrorNames, lowdefyErrorTypes, OperatorError, PluginError, PLUGIN_CHECKS_SLUG, PLUGIN_SCHEMA_SLUG, readErrorCodes, RequestError, resolveConfigLocation, loadAndResolveErrorLocation, resolveErrorLocation, ServiceError, shouldSuppressBuildCheck, TenantIntegrityError, TwoFactorEnrolmentRequiredError, UserError, VALID_CHECK_SLUGS };
|
|
@@ -0,0 +1,24 @@
|
|
|
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 expectedErrorNames from './expectedErrorNames.js';
|
|
16
|
+
// The one test for "the system worked and said no" (an expected outcome) versus a
|
|
17
|
+
// fault. Every site that picks a log level, decides on Sentry or feeds the dev
|
|
18
|
+
// agent feed asks this, so a refusal is classified the same way on every route
|
|
19
|
+
// and transport. Keyed on the name: a serializer round trip or another package's
|
|
20
|
+
// copy of a class keeps the name but not the class identity.
|
|
21
|
+
function isExpectedError(error) {
|
|
22
|
+
return expectedErrorNames.has(error?.name);
|
|
23
|
+
}
|
|
24
|
+
export default isExpectedError;
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
*/ // Codes a client sets when it gave up waiting: Node sockets, request, and undici's
|
|
16
|
+
// connect, headers and body timeouts.
|
|
17
|
+
const TIMEOUT_CODES = new Set([
|
|
18
|
+
'ETIMEDOUT',
|
|
19
|
+
'ESOCKETTIMEDOUT',
|
|
20
|
+
'UND_ERR_CONNECT_TIMEOUT',
|
|
21
|
+
'UND_ERR_HEADERS_TIMEOUT',
|
|
22
|
+
'UND_ERR_BODY_TIMEOUT'
|
|
23
|
+
]);
|
|
24
|
+
// Names of the errors undici and AbortSignal.timeout throw when a call runs out of time.
|
|
25
|
+
const TIMEOUT_NAMES = new Set([
|
|
26
|
+
'TimeoutError',
|
|
27
|
+
'ConnectTimeoutError',
|
|
28
|
+
'HeadersTimeoutError',
|
|
29
|
+
'BodyTimeoutError'
|
|
30
|
+
]);
|
|
31
|
+
// Whether this one error is a call cancelled because it ran out of time. Read from the
|
|
32
|
+
// error's own name and code only; a message that mentions a timeout is not enough.
|
|
33
|
+
function isTimeoutError(error) {
|
|
34
|
+
if (!error || typeof error !== 'object') return false;
|
|
35
|
+
return TIMEOUT_NAMES.has(error.name) || TIMEOUT_CODES.has(error.code);
|
|
36
|
+
}
|
|
37
|
+
export default isTimeoutError;
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
'websocket-refs': 'Invalid websocket action reference warnings',
|
|
30
30
|
'callmethod-refs': 'CallMethod actions targeting blocks not defined on the page',
|
|
31
31
|
icons: 'Unresolvable icon name warnings',
|
|
32
|
+
'native-ignored': 'Properties set on a mobile page that the native block ignores',
|
|
32
33
|
types: 'All type validation (blocks, operators, actions, requests, connections)',
|
|
33
34
|
schema: 'JSON schema validation errors',
|
|
34
35
|
secrets: 'Environment variable names that are not set in the build environment',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/errors",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.2.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Lowdefy error classes for consistent error handling across build, server, and client",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -34,11 +34,9 @@
|
|
|
34
34
|
"dist/*"
|
|
35
35
|
],
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@jest/globals": "28.1.3",
|
|
38
37
|
"@swc/cli": "0.8.1",
|
|
39
38
|
"@swc/core": "1.15.32",
|
|
40
|
-
"
|
|
41
|
-
"jest": "28.1.3"
|
|
39
|
+
"vitest": "4.1.12"
|
|
42
40
|
},
|
|
43
41
|
"publishConfig": {
|
|
44
42
|
"access": "public"
|
|
@@ -46,6 +44,6 @@
|
|
|
46
44
|
"scripts": {
|
|
47
45
|
"build": "swc src --out-dir dist --config-file ../../../.swcrc --cli-config-file ../../../.swc-cli.json",
|
|
48
46
|
"clean": "rm -rf dist",
|
|
49
|
-
"test": "
|
|
47
|
+
"test": "vitest run --passWithNoTests"
|
|
50
48
|
}
|
|
51
49
|
}
|