@lowdefy/engine 6.0.0 → 6.1.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/Actions.js +44 -15
- package/dist/callAPIHandler.js +6 -2
- package/dist/decodeServerError.js +43 -0
- package/dist/index.js +2 -1
- package/package.json +8 -8
package/dist/Actions.js
CHANGED
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { ActionError, ConfigError, UserError } from '@lowdefy/errors';
|
|
16
|
-
import { type } from '@lowdefy/helpers';
|
|
16
|
+
import { projectCaughtError, type } from '@lowdefy/helpers';
|
|
17
17
|
import getActionMethods from './actions/getActionMethods.js';
|
|
18
|
+
import { isDecodedServerError } from './decodeServerError.js';
|
|
18
19
|
import { isStopChain } from './stopChain.js';
|
|
19
20
|
const CONTROL_KEYS = [
|
|
20
21
|
':if',
|
|
@@ -27,24 +28,25 @@ function isControl(item) {
|
|
|
27
28
|
let Actions = class Actions {
|
|
28
29
|
logActionError({ error, action }) {
|
|
29
30
|
const handleError = this.context._internal.lowdefy._internal.handleError;
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
const errorKey = `${error?.message || ''}:${actionId}`;
|
|
33
|
-
if (this.loggedActionErrors.has(errorKey)) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
this.loggedActionErrors.add(errorKey);
|
|
37
|
-
// User-facing errors log to browser console only, never to terminal
|
|
31
|
+
// User-facing errors log to browser console only, never to terminal. This line
|
|
32
|
+
// bypasses handleError, so it dedups here.
|
|
38
33
|
if (error instanceof UserError) {
|
|
34
|
+
const errorKey = `${error.message}:${action?.id || ''}`;
|
|
35
|
+
if (this.loggedActionErrors.has(errorKey)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.loggedActionErrors.add(errorKey);
|
|
39
39
|
this.context._internal.lowdefy._internal.logger.error(error);
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
//
|
|
42
|
+
// Not deduped here: every server failure carries the same generic message, so a
|
|
43
|
+
// message + action key would hide each later failure of the action. handleError
|
|
44
|
+
// dedups on the message it displays plus the server's requestId.
|
|
43
45
|
if (handleError) {
|
|
44
46
|
handleError(error);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
|
-
async callAsyncAction({ action, arrayIndices, block, event, index, responses }) {
|
|
49
|
+
async callAsyncAction({ action, arrayIndices, block, event, index, parseScope, responses }) {
|
|
48
50
|
try {
|
|
49
51
|
const response = await this.callAction({
|
|
50
52
|
action,
|
|
@@ -52,6 +54,7 @@ let Actions = class Actions {
|
|
|
52
54
|
block,
|
|
53
55
|
event,
|
|
54
56
|
index,
|
|
57
|
+
parseScope,
|
|
55
58
|
responses
|
|
56
59
|
});
|
|
57
60
|
responses[action.id] = response;
|
|
@@ -63,7 +66,7 @@ let Actions = class Actions {
|
|
|
63
66
|
}
|
|
64
67
|
// Returns true when a ':return' control or an action ended the list, so callers can
|
|
65
68
|
// end the event.
|
|
66
|
-
async callActionLoop({ actions, arrayIndices, block, controls, counters, event, progress, responses }) {
|
|
69
|
+
async callActionLoop({ actions, arrayIndices, block, controls, counters, event, parseScope, progress, responses }) {
|
|
67
70
|
for (const [position, action] of actions.entries()){
|
|
68
71
|
if (isControl(action)) {
|
|
69
72
|
const returned = await this.callControl({
|
|
@@ -73,6 +76,7 @@ let Actions = class Actions {
|
|
|
73
76
|
controls,
|
|
74
77
|
counters,
|
|
75
78
|
event,
|
|
79
|
+
parseScope,
|
|
76
80
|
progress,
|
|
77
81
|
responses
|
|
78
82
|
});
|
|
@@ -99,6 +103,7 @@ let Actions = class Actions {
|
|
|
99
103
|
block,
|
|
100
104
|
event,
|
|
101
105
|
index,
|
|
106
|
+
parseScope,
|
|
102
107
|
progress,
|
|
103
108
|
responses
|
|
104
109
|
});
|
|
@@ -109,6 +114,7 @@ let Actions = class Actions {
|
|
|
109
114
|
block,
|
|
110
115
|
event,
|
|
111
116
|
index,
|
|
117
|
+
parseScope,
|
|
112
118
|
progress,
|
|
113
119
|
responses
|
|
114
120
|
});
|
|
@@ -134,7 +140,7 @@ let Actions = class Actions {
|
|
|
134
140
|
}
|
|
135
141
|
return false;
|
|
136
142
|
}
|
|
137
|
-
async callControl({ arrayIndices, block, control, controls, counters, event, progress, responses }) {
|
|
143
|
+
async callControl({ arrayIndices, block, control, controls, counters, event, parseScope, progress, responses }) {
|
|
138
144
|
const index = counters.control;
|
|
139
145
|
counters.control += 1;
|
|
140
146
|
if (':return' in control) {
|
|
@@ -144,6 +150,7 @@ let Actions = class Actions {
|
|
|
144
150
|
event,
|
|
145
151
|
input: control[':return'],
|
|
146
152
|
node: control,
|
|
153
|
+
parseScope,
|
|
147
154
|
responses
|
|
148
155
|
});
|
|
149
156
|
controls.push({
|
|
@@ -160,6 +167,7 @@ let Actions = class Actions {
|
|
|
160
167
|
event,
|
|
161
168
|
input: control[':if'],
|
|
162
169
|
node: control,
|
|
170
|
+
parseScope,
|
|
163
171
|
responses
|
|
164
172
|
});
|
|
165
173
|
// JS truthiness, matching the routine ':if' - not skip's strict === true.
|
|
@@ -176,6 +184,7 @@ let Actions = class Actions {
|
|
|
176
184
|
controls,
|
|
177
185
|
counters,
|
|
178
186
|
event,
|
|
187
|
+
parseScope,
|
|
179
188
|
progress,
|
|
180
189
|
responses
|
|
181
190
|
});
|
|
@@ -203,6 +212,7 @@ let Actions = class Actions {
|
|
|
203
212
|
controls,
|
|
204
213
|
counters,
|
|
205
214
|
event,
|
|
215
|
+
parseScope,
|
|
206
216
|
progress,
|
|
207
217
|
responses
|
|
208
218
|
});
|
|
@@ -219,6 +229,7 @@ let Actions = class Actions {
|
|
|
219
229
|
event,
|
|
220
230
|
input: caseObject[':case'],
|
|
221
231
|
node: caseObject,
|
|
232
|
+
parseScope,
|
|
222
233
|
responses
|
|
223
234
|
});
|
|
224
235
|
if (condition) {
|
|
@@ -235,6 +246,7 @@ let Actions = class Actions {
|
|
|
235
246
|
controls,
|
|
236
247
|
counters,
|
|
237
248
|
event,
|
|
249
|
+
parseScope,
|
|
238
250
|
progress,
|
|
239
251
|
responses
|
|
240
252
|
});
|
|
@@ -267,12 +279,14 @@ let Actions = class Actions {
|
|
|
267
279
|
controls,
|
|
268
280
|
counters,
|
|
269
281
|
event,
|
|
282
|
+
parseScope,
|
|
270
283
|
progress,
|
|
271
284
|
responses
|
|
272
285
|
});
|
|
273
286
|
}
|
|
274
|
-
evaluateControlValue({ arrayIndices, block, event, input, node, responses }) {
|
|
287
|
+
evaluateControlValue({ arrayIndices, block, event, input, node, parseScope, responses }) {
|
|
275
288
|
const { output, errors: parserErrors } = this.context._internal.parser.parse({
|
|
289
|
+
...parseScope,
|
|
276
290
|
actions: responses,
|
|
277
291
|
event,
|
|
278
292
|
arrayIndices,
|
|
@@ -353,11 +367,21 @@ let Actions = class Actions {
|
|
|
353
367
|
controls,
|
|
354
368
|
counters,
|
|
355
369
|
event,
|
|
370
|
+
parseScope: {
|
|
371
|
+
error: null
|
|
372
|
+
},
|
|
356
373
|
responses,
|
|
357
374
|
progress
|
|
358
375
|
});
|
|
359
376
|
} catch (error) {
|
|
360
377
|
this.logActionError(error);
|
|
378
|
+
// A server error is already the wire shape, generic unless the author wrote
|
|
379
|
+
// it. A client-side error was built in the browser from data it already
|
|
380
|
+
// holds, so it keeps its real message - only its fields are narrowed.
|
|
381
|
+
const thrown = error.error;
|
|
382
|
+
const caught = isDecodedServerError(thrown) ? thrown : Object.assign(projectCaughtError(thrown), {
|
|
383
|
+
actionId: error.action?.id
|
|
384
|
+
});
|
|
361
385
|
// Catch actions restart action numbering, matching flat-chain history; the control
|
|
362
386
|
// counter continues so every control entry keeps a unique index within the event.
|
|
363
387
|
counters.action = 0;
|
|
@@ -369,6 +393,9 @@ let Actions = class Actions {
|
|
|
369
393
|
controls,
|
|
370
394
|
counters,
|
|
371
395
|
event,
|
|
396
|
+
parseScope: {
|
|
397
|
+
error: caught
|
|
398
|
+
},
|
|
372
399
|
responses,
|
|
373
400
|
progress
|
|
374
401
|
});
|
|
@@ -419,7 +446,7 @@ let Actions = class Actions {
|
|
|
419
446
|
success: true
|
|
420
447
|
};
|
|
421
448
|
}
|
|
422
|
-
async callAction({ action, arrayIndices, block, event, index, progress, responses }) {
|
|
449
|
+
async callAction({ action, arrayIndices, block, event, index, parseScope, progress, responses }) {
|
|
423
450
|
if (!this.actions[action.type]) {
|
|
424
451
|
const error = new ConfigError(`Invalid action type "${action.type}" at "${block.blockId}".`, {
|
|
425
452
|
configKey: action['~k']
|
|
@@ -431,6 +458,7 @@ let Actions = class Actions {
|
|
|
431
458
|
};
|
|
432
459
|
}
|
|
433
460
|
const { output: parsedAction, errors: parserErrors } = this.context._internal.parser.parse({
|
|
461
|
+
...parseScope,
|
|
434
462
|
actions: responses,
|
|
435
463
|
event,
|
|
436
464
|
arrayIndices,
|
|
@@ -491,6 +519,7 @@ let Actions = class Actions {
|
|
|
491
519
|
type: action.type
|
|
492
520
|
};
|
|
493
521
|
const { output: parsedMessages, errors: parserErrors } = this.context._internal.parser.parse({
|
|
522
|
+
...parseScope,
|
|
494
523
|
actions: responses,
|
|
495
524
|
event,
|
|
496
525
|
arrayIndices,
|
package/dist/callAPIHandler.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { serializer } from '@lowdefy/helpers';
|
|
16
|
+
import decodeServerError from './decodeServerError.js';
|
|
16
17
|
async function callAPIHandler(context, { blockId, params }) {
|
|
17
18
|
if (!context._internal.lowdefy.apiResponses[params.endpointId]) {
|
|
18
19
|
context._internal.lowdefy.apiResponses[params.endpointId] = [];
|
|
@@ -55,7 +56,10 @@ async function callAPIHandler(context, { blockId, params }) {
|
|
|
55
56
|
throw error;
|
|
56
57
|
}
|
|
57
58
|
const { error, response, status, success } = apiResponse;
|
|
58
|
-
|
|
59
|
+
// Decoded once so the stored and the thrown error are the same object: the
|
|
60
|
+
// dev error is keyed by that object.
|
|
61
|
+
const decodedError = decodeServerError(error);
|
|
62
|
+
api.error = decodedError;
|
|
59
63
|
api.loading = false;
|
|
60
64
|
api.response = serializer.deserialize(response);
|
|
61
65
|
api.status = status;
|
|
@@ -64,7 +68,7 @@ async function callAPIHandler(context, { blockId, params }) {
|
|
|
64
68
|
api.responseTime = api.endTimestamp - api.startTimestamp;
|
|
65
69
|
context._internal.update();
|
|
66
70
|
if (!success) {
|
|
67
|
-
throw
|
|
71
|
+
throw decodedError;
|
|
68
72
|
}
|
|
69
73
|
return api;
|
|
70
74
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
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 { serializer, type } from '@lowdefy/helpers';
|
|
16
|
+
// The decoded error is stored as `request.error` / `api.error` and rethrown,
|
|
17
|
+
// and config reads it through `_actions`, `_request_details` and `_error`. Any
|
|
18
|
+
// property on it - enumerable or not - is one operator change away from config,
|
|
19
|
+
// so the dev server's full error is kept beside it here, keyed by the error
|
|
20
|
+
// itself, where only the dev tools look.
|
|
21
|
+
const devErrors = new WeakMap();
|
|
22
|
+
// A catch list's `_error` passes a server error through as decoded, but
|
|
23
|
+
// projects a client-side error. The two can share a name and class, so the
|
|
24
|
+
// engine tells them apart by identity.
|
|
25
|
+
const decoded = new WeakSet();
|
|
26
|
+
function decodeServerError(payload) {
|
|
27
|
+
if (type.isNone(payload)) return payload;
|
|
28
|
+
const { devError, ...rest } = payload;
|
|
29
|
+
const error = serializer.deserialize(rest);
|
|
30
|
+
if (!type.isNone(devError)) {
|
|
31
|
+
devErrors.set(error, serializer.deserialize(devError));
|
|
32
|
+
}
|
|
33
|
+
decoded.add(error);
|
|
34
|
+
return error;
|
|
35
|
+
}
|
|
36
|
+
function getDevError(error) {
|
|
37
|
+
return devErrors.get(error);
|
|
38
|
+
}
|
|
39
|
+
function isDecodedServerError(error) {
|
|
40
|
+
return decoded.has(error);
|
|
41
|
+
}
|
|
42
|
+
export { getDevError, isDecodedServerError };
|
|
43
|
+
export default decodeServerError;
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/ import Actions from './Actions.js';
|
|
16
16
|
import Slots from './Slots.js';
|
|
17
17
|
import createLink from './createLink.js';
|
|
18
|
+
import decodeServerError, { getDevError } from './decodeServerError.js';
|
|
18
19
|
import Events from './Events.js';
|
|
19
20
|
import getContext from './getContext.js';
|
|
20
21
|
import getHomePathname from './getHomePathname.js';
|
|
@@ -22,5 +23,5 @@ import Requests from './Requests.js';
|
|
|
22
23
|
import resolveTarget from './resolveTarget.js';
|
|
23
24
|
import State from './State.js';
|
|
24
25
|
import stopChain from './stopChain.js';
|
|
25
|
-
export { Actions, Slots, createLink, Events, getHomePathname, Requests, resolveTarget, State, stopChain };
|
|
26
|
+
export { Actions, Slots, createLink, decodeServerError, Events, getDevError, getHomePathname, Requests, resolveTarget, State, stopChain };
|
|
26
27
|
export default getContext;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowdefy/engine",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"homepage": "https://lowdefy.com",
|
|
@@ -30,16 +30,16 @@
|
|
|
30
30
|
"dist/*"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@lowdefy/errors": "6.
|
|
34
|
-
"@lowdefy/helpers": "6.
|
|
35
|
-
"@lowdefy/operators": "6.
|
|
33
|
+
"@lowdefy/errors": "6.1.0",
|
|
34
|
+
"@lowdefy/helpers": "6.1.0",
|
|
35
|
+
"@lowdefy/operators": "6.1.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@jest/globals": "28.1.3",
|
|
39
|
-
"@lowdefy/actions-core": "6.
|
|
40
|
-
"@lowdefy/build": "6.
|
|
41
|
-
"@lowdefy/operators-js": "6.
|
|
42
|
-
"@lowdefy/operators-mql": "6.
|
|
39
|
+
"@lowdefy/actions-core": "6.1.0",
|
|
40
|
+
"@lowdefy/build": "6.1.0",
|
|
41
|
+
"@lowdefy/operators-js": "6.1.0",
|
|
42
|
+
"@lowdefy/operators-mql": "6.1.0",
|
|
43
43
|
"@swc/cli": "0.8.1",
|
|
44
44
|
"@swc/core": "1.15.32",
|
|
45
45
|
"@swc/jest": "0.2.39",
|