@lowdefy/api 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/context/createEvaluateOperators.js +3 -1
- package/dist/context/getCurrentEnvironment.js +27 -0
- package/dist/index.js +2 -1
- package/dist/response/buildEndpointResult.js +3 -1
- package/dist/response/createWireProjection.js +88 -0
- package/dist/response/normalizeErrorSources.js +10 -13
- package/dist/response/redactErrorResponse.js +42 -8
- package/dist/response/redactResponse.js +10 -10
- package/dist/routes/agent/prepareAgent.js +6 -0
- package/dist/routes/auth/defaultAuthUrl.js +31 -0
- package/dist/routes/auth/getAuthConfig.js +5 -1
- package/dist/routes/endpoints/callEndpoint.js +1 -0
- package/dist/routes/endpoints/control/controlFor.js +4 -7
- package/dist/routes/endpoints/control/controlIf.js +4 -8
- package/dist/routes/endpoints/control/controlLog.js +6 -14
- package/dist/routes/endpoints/control/controlParallelFor.js +4 -7
- package/dist/routes/endpoints/control/controlReject.js +13 -15
- package/dist/routes/endpoints/control/controlReturn.js +4 -9
- package/dist/routes/endpoints/control/controlSetState.js +4 -8
- package/dist/routes/endpoints/control/controlSwitch.js +4 -8
- package/dist/routes/endpoints/control/controlThrow.js +17 -19
- package/dist/routes/endpoints/control/controlTry.js +20 -10
- package/dist/routes/endpoints/evaluateRoutineOperators.js +26 -0
- package/dist/routes/endpoints/forwardScheduledEndpoint.js +19 -14
- package/dist/routes/endpoints/getEnvironmentSchedules.js +5 -7
- package/dist/routes/endpoints/handleAgentCall.js +4 -7
- package/dist/routes/endpoints/handleEndpointCall.js +4 -7
- package/dist/routes/endpoints/handleRenderNotification.js +15 -8
- package/dist/routes/endpoints/handleRequest.js +1 -5
- package/dist/routes/endpoints/handleValidateSchema.js +12 -10
- package/dist/routes/endpoints/invokeEndpoint.js +1 -0
- package/dist/routes/endpoints/operatorScope.js +27 -0
- package/dist/routes/endpoints/resolveCronEnvironment.js +7 -6
- package/dist/routes/endpoints/runDetachedEndpoint.js +1 -0
- package/dist/routes/endpoints/runScheduledEndpoint.js +1 -0
- package/dist/routes/endpoints/runWebhookEndpoint.js +1 -0
- package/dist/routes/endpoints/test/runTest.js +17 -2
- package/dist/routes/mcp/createMcpServer.js +20 -2
- package/dist/routes/request/callRequest.js +9 -3
- package/dist/routes/request/callRequestResolver.js +6 -0
- package/dist/routes/request/evaluateOperators.js +8 -12
- package/dist/routes/websocket/createChannelRegistry.js +19 -5
- package/dist/routes/websocket/createWebSocketConnection.js +15 -3
- package/dist/test/testContext.js +4 -2
- package/package.json +9 -9
- package/dist/response/omitErrorProps.js +0 -51
|
@@ -23,8 +23,10 @@ function createEvaluateOperators(context) {
|
|
|
23
23
|
secrets,
|
|
24
24
|
user
|
|
25
25
|
});
|
|
26
|
-
function evaluateOperators({ input, items, location, payload, state, steps }) {
|
|
26
|
+
function evaluateOperators({ arrayIndices, error, input, items, location, payload, state, steps }) {
|
|
27
27
|
const { output, errors } = operatorsParser.parse({
|
|
28
|
+
arrayIndices,
|
|
29
|
+
error,
|
|
28
30
|
input,
|
|
29
31
|
items,
|
|
30
32
|
location,
|
|
@@ -0,0 +1,27 @@
|
|
|
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 environment this deployment is, resolved by the build from LOWDEFY_ENVIRONMENT into
|
|
16
|
+
// config.environment and config.environments. Null when no current environment is set or when it
|
|
17
|
+
// is not declared, so callers fall back to their own defaults.
|
|
18
|
+
function getCurrentEnvironment({ config }) {
|
|
19
|
+
const name = config?.environment;
|
|
20
|
+
const settings = config?.environments?.[name];
|
|
21
|
+
if (settings === undefined) return null;
|
|
22
|
+
return {
|
|
23
|
+
...settings,
|
|
24
|
+
name
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export default getCurrentEnvironment;
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import createApiContext from './context/createApiContext.js';
|
|
|
21
21
|
import createChannelRegistry from './routes/websocket/createChannelRegistry.js';
|
|
22
22
|
import createMcpServer from './routes/mcp/createMcpServer.js';
|
|
23
23
|
import createWebSocketConnection from './routes/websocket/createWebSocketConnection.js';
|
|
24
|
+
import createWireProjection from './response/createWireProjection.js';
|
|
24
25
|
import createSessionCallback from './routes/auth/callbacks/createSessionCallback.js';
|
|
25
26
|
import getAuthConfig from './routes/auth/getAuthConfig.js';
|
|
26
27
|
import getAuthStrategies from './routes/auth/strategies/getAuthStrategies.js';
|
|
@@ -35,4 +36,4 @@ import forwardScheduledEndpoint from './routes/endpoints/forwardScheduledEndpoin
|
|
|
35
36
|
import runDetachedEndpoint from './routes/endpoints/runDetachedEndpoint.js';
|
|
36
37
|
import runWebhookEndpoint from './routes/endpoints/runWebhookEndpoint.js';
|
|
37
38
|
import runScheduledEndpoint from './routes/endpoints/runScheduledEndpoint.js';
|
|
38
|
-
export { buildEndpointResult, callAgent, callEndpoint, getEndpointConfig, callRequest, createApiContext, createChannelRegistry, createMcpServer, createSessionCallback, createWebSocketConnection, getAuthConfig, getAuthStrategies, getHomeAndMenus, getPageConfig, getRootConfig, logClientError, redactErrorResponse, redactResponse, resolveStrategyCaller, forwardScheduledEndpoint, runDetachedEndpoint, runWebhookEndpoint, runScheduledEndpoint };
|
|
39
|
+
export { buildEndpointResult, callAgent, callEndpoint, getEndpointConfig, callRequest, createApiContext, createChannelRegistry, createMcpServer, createSessionCallback, createWebSocketConnection, createWireProjection, getAuthConfig, getAuthStrategies, getHomeAndMenus, getPageConfig, getRootConfig, logClientError, redactErrorResponse, redactResponse, resolveStrategyCaller, forwardScheduledEndpoint, runDetachedEndpoint, runWebhookEndpoint, runScheduledEndpoint };
|
|
@@ -17,7 +17,9 @@ import redactResponse from './redactResponse.js';
|
|
|
17
17
|
// The wire object every endpoint route returns after running its routine. One
|
|
18
18
|
// function rather than a copy of the same return statement per route, so the
|
|
19
19
|
// `response` field cannot end up policed differently from the `error` field beside
|
|
20
|
-
// it - see redactResponse for why the response needs the policy at all.
|
|
20
|
+
// it - see redactResponse for why the response needs the policy at all. `error` is
|
|
21
|
+
// redactErrorResponse's error payload, so in dev it carries `devError`; `response`
|
|
22
|
+
// never does.
|
|
21
23
|
function buildEndpointResult(context, { error, response, status }) {
|
|
22
24
|
const success = ![
|
|
23
25
|
'error',
|
|
@@ -0,0 +1,88 @@
|
|
|
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 { lowdefyErrorNames, readErrorCodes } from '@lowdefy/errors';
|
|
16
|
+
import { translate } from '@lowdefy/helpers';
|
|
17
|
+
// The framework writes these messages to reveal nothing, and clients branch on
|
|
18
|
+
// them, so they keep their text where every other non-author error does not.
|
|
19
|
+
const AUTH_REFUSAL_NAMES = new Set([
|
|
20
|
+
'AuthenticationError',
|
|
21
|
+
'AuthorizationError',
|
|
22
|
+
'TwoFactorEnrolmentRequiredError'
|
|
23
|
+
]);
|
|
24
|
+
// The client-bound error policy, as an allowlist. Passed to serializer.serialize
|
|
25
|
+
// as `projectError`, so it runs at every error node the walk emits - the cause
|
|
26
|
+
// chain, an Error-valued own property, an Error nested in a response value - and
|
|
27
|
+
// cannot become depth-limited.
|
|
28
|
+
//
|
|
29
|
+
// Only the author's message crosses. A library's message embeds whatever the
|
|
30
|
+
// library saw - URLs with credentials, SQL, hostnames - so every other error
|
|
31
|
+
// becomes one translated generic message plus the fields client config branches
|
|
32
|
+
// on. The full error stays in the server log, and in dev reaches the developer
|
|
33
|
+
// through `devError`, which config never reads.
|
|
34
|
+
//
|
|
35
|
+
// The context is optional: a websocket broadcast has no single request, so it
|
|
36
|
+
// passes no `rid`, and the server error handler can run before any request
|
|
37
|
+
// context exists.
|
|
38
|
+
function createWireProjection(context) {
|
|
39
|
+
const requestId = context?.rid;
|
|
40
|
+
const genericMessage = translate({
|
|
41
|
+
key: 'server.genericError',
|
|
42
|
+
i18n: context?.i18n
|
|
43
|
+
});
|
|
44
|
+
return function project(err) {
|
|
45
|
+
// A PluginError defaults configKey to null; the walk only drops undefined.
|
|
46
|
+
const configKey = err.configKey ?? undefined;
|
|
47
|
+
// Keyed on the name rather than instanceof: the error may come from another
|
|
48
|
+
// copy of @lowdefy/errors or from a serializer round trip, where the class
|
|
49
|
+
// identity is gone but the name survives. The cause is returned raw so the
|
|
50
|
+
// walk projects it too - an Error cause takes the generic shape, and a
|
|
51
|
+
// non-Error cause is author data cleaned as a value.
|
|
52
|
+
if (err.name === 'UserError') {
|
|
53
|
+
return {
|
|
54
|
+
name: err.name,
|
|
55
|
+
message: err.message,
|
|
56
|
+
cause: err.cause,
|
|
57
|
+
metaData: err.metaData,
|
|
58
|
+
blockId: err.blockId,
|
|
59
|
+
pageId: err.pageId,
|
|
60
|
+
isReject: err.isReject,
|
|
61
|
+
configKey,
|
|
62
|
+
// Not read from the node: a caught error rebuilt for `_error` keeps only
|
|
63
|
+
// its class, and without the flag the client wraps a rethrown UserError
|
|
64
|
+
// in an ActionError and reports it back to the server a second time.
|
|
65
|
+
isLowdefyError: true,
|
|
66
|
+
handled: err.handled,
|
|
67
|
+
requestId
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const { code, statusCode } = readErrorCodes(err);
|
|
71
|
+
return {
|
|
72
|
+
// A foreign class name can itself say which library or driver failed.
|
|
73
|
+
name: lowdefyErrorNames.has(err.name) ? err.name : 'Error',
|
|
74
|
+
message: AUTH_REFUSAL_NAMES.has(err.name) ? err.message : genericMessage,
|
|
75
|
+
code,
|
|
76
|
+
statusCode,
|
|
77
|
+
configKey,
|
|
78
|
+
requestId,
|
|
79
|
+
// The client revives errors without running a constructor, so this flag
|
|
80
|
+
// exists there only if the wire carries it. Without it the action runner
|
|
81
|
+
// wraps the error in a new ActionError without `handled`, POSTs it back to
|
|
82
|
+
// /api/client-error, and the server logs and reports it a second time.
|
|
83
|
+
isLowdefyError: true,
|
|
84
|
+
handled: err.handled
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export default createWireProjection;
|
|
@@ -16,13 +16,12 @@
|
|
|
16
16
|
import { type } from '@lowdefy/helpers';
|
|
17
17
|
// extractErrorProps emits a nested error as a plain props object, not as a second
|
|
18
18
|
// '~e' wrapper, so an error node is recognised by its shape. Keying on the shape
|
|
19
|
-
// rather than on a map of where errors can appear
|
|
20
|
-
//
|
|
21
|
-
// still visits every position.
|
|
19
|
+
// rather than on a map of where errors can appear means every position is visited
|
|
20
|
+
// without re-deriving where the walk puts errors.
|
|
22
21
|
//
|
|
23
|
-
// The check matters because the payload also carries author-written data
|
|
24
|
-
//
|
|
25
|
-
//
|
|
22
|
+
// The check matters because the payload also carries author-written data - a
|
|
23
|
+
// UserError's non-Error cause, its metaData - and a `source` key inside those
|
|
24
|
+
// belongs to the app, not to us.
|
|
26
25
|
function isErrorNode(value) {
|
|
27
26
|
return type.isString(value.name) && type.isString(value.message);
|
|
28
27
|
}
|
|
@@ -43,17 +42,15 @@ function stripConfigDirectory(value, prefix) {
|
|
|
43
42
|
}
|
|
44
43
|
Object.values(value).forEach((child)=>stripConfigDirectory(child, prefix));
|
|
45
44
|
}
|
|
46
|
-
//
|
|
47
|
-
// path
|
|
48
|
-
//
|
|
49
|
-
//
|
|
45
|
+
// Makes `source` in the dev-only `devError` config-relative, never an absolute
|
|
46
|
+
// server path, so the dev tools show the path the developer knows. The wire error
|
|
47
|
+
// carries no `source` at all. resolveConfigLocation makes it absolute whenever the
|
|
48
|
+
// context carries a configDirectory, which server-dev does.
|
|
50
49
|
//
|
|
51
50
|
// A rewrite rather than an omission, and it needs the context, so it runs as a pass
|
|
52
51
|
// over the serialized payload instead of inside the walk.
|
|
53
52
|
function normalizeErrorSources(context, payload) {
|
|
54
|
-
|
|
55
|
-
// missing context is a supported call - it only means no source to normalise.
|
|
56
|
-
const configDirectory = context?.configDirectory;
|
|
53
|
+
const configDirectory = context.configDirectory;
|
|
57
54
|
if (type.isNone(configDirectory)) return payload;
|
|
58
55
|
// configDirectory is `LOWDEFY_DIRECTORY_CONFIG || process.cwd()` at every site
|
|
59
56
|
// that sets it, so it may be relative or carry a trailing separator, while
|
|
@@ -13,18 +13,52 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { serializer, type } from '@lowdefy/helpers';
|
|
16
|
+
import createWireProjection from './createWireProjection.js';
|
|
16
17
|
import normalizeErrorSources from './normalizeErrorSources.js';
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
18
|
+
// The one error payload every route and transport sends for a thrown error, at
|
|
19
|
+
// any status. Owning the serialization as well as the policy leaves no bare
|
|
20
|
+
// serializer.serialize(error) in response position for a caller to forget.
|
|
21
|
+
//
|
|
22
|
+
// `~e` is the wire error - identical in dev and prod, because it is what app
|
|
23
|
+
// config reads. In dev the payload also carries `devError`, the error as the dev
|
|
24
|
+
// terminal logs it, for the dev tools. It sits beside `~e` rather than inside it:
|
|
25
|
+
// the serializer's reviver replaces any object holding `~e` with its error, so a
|
|
26
|
+
// plain deserialize of the payload drops `devError` and config never sees it.
|
|
27
|
+
//
|
|
28
|
+
// `received` is left out of devError at every node: on the request path it is
|
|
29
|
+
// the evaluated request properties, resolved _secret values included, and the
|
|
30
|
+
// dev server can be reached over a LAN or tunnel. The terminal still logs it.
|
|
31
|
+
function projectDevError(err) {
|
|
32
|
+
const props = {
|
|
33
|
+
message: err.message,
|
|
34
|
+
name: err.name,
|
|
35
|
+
stack: err.stack,
|
|
36
|
+
cause: err.cause,
|
|
37
|
+
...err
|
|
38
|
+
};
|
|
39
|
+
delete props.received;
|
|
40
|
+
return props;
|
|
41
|
+
}
|
|
22
42
|
function redactErrorResponse(context, error) {
|
|
23
43
|
// Endpoint routes serialize the error field on success too, where it is null.
|
|
24
44
|
// Passing that through unchanged keeps them from emitting an empty {'~e'}.
|
|
25
45
|
if (type.isNone(error)) return error;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})
|
|
46
|
+
const payload = serializer.serialize(error, {
|
|
47
|
+
projectError: createWireProjection(context)
|
|
48
|
+
});
|
|
49
|
+
// The server error handler has no request context when it fails before the
|
|
50
|
+
// context middleware runs, so there is no mode to read and no devError.
|
|
51
|
+
if (context?.mode === 'dev') {
|
|
52
|
+
const full = serializer.serialize(error, {
|
|
53
|
+
projectError: projectDevError
|
|
54
|
+
});
|
|
55
|
+
payload.devError = normalizeErrorSources(context, {
|
|
56
|
+
'~e': {
|
|
57
|
+
...full['~e'],
|
|
58
|
+
requestId: context.rid
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return payload;
|
|
29
63
|
}
|
|
30
64
|
export default redactErrorResponse;
|
|
@@ -13,19 +13,19 @@
|
|
|
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
|
|
17
|
-
import omitErrorProps from './omitErrorProps.js';
|
|
16
|
+
import createWireProjection from './createWireProjection.js';
|
|
18
17
|
// The response-value call shape, beside redactErrorResponse's error-only one.
|
|
19
18
|
// A response is not an error, but makeReplacer wraps any Error it meets anywhere
|
|
20
|
-
// in a value, so a response holding one is an error-serialization site too -
|
|
21
|
-
// grep
|
|
22
|
-
//
|
|
19
|
+
// in a value, so a response holding one is an error-serialization site too - a
|
|
20
|
+
// grep for serialize(error) cannot see those sites, which is why this exists as
|
|
21
|
+
// a function rather than as a rule to remember.
|
|
23
22
|
//
|
|
24
|
-
// Same
|
|
25
|
-
//
|
|
23
|
+
// Same wire projection as the error field, because it reaches the same audience.
|
|
24
|
+
// No devError, in any mode: an Error in a response value is data the routine
|
|
25
|
+
// returned, not a failure of this request.
|
|
26
26
|
function redactResponse(context, response) {
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
})
|
|
27
|
+
return serializer.serialize(response, {
|
|
28
|
+
projectError: createWireProjection(context)
|
|
29
|
+
});
|
|
30
30
|
}
|
|
31
31
|
export default redactResponse;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { type } from '@lowdefy/helpers';
|
|
16
16
|
import buildEndpointResult from '../../response/buildEndpointResult.js';
|
|
17
|
+
import createWireProjection from '../../response/createWireProjection.js';
|
|
17
18
|
import getEndpointConfig from '../endpoints/getEndpointConfig.js';
|
|
18
19
|
import invokeEndpoint from '../endpoints/invokeEndpoint.js';
|
|
19
20
|
import authorizeAgent from './authorizeAgent.js';
|
|
@@ -72,6 +73,11 @@ async function prepareAgent(context, { agentId, agentContext, endpointDepth = 0,
|
|
|
72
73
|
agentContext,
|
|
73
74
|
i18n: context.i18n,
|
|
74
75
|
mode,
|
|
76
|
+
// The agent stream's error text reaches the end user and AgentChat config, so it takes
|
|
77
|
+
// the wire policy. Built here because the agent plugins cannot import @lowdefy/api.
|
|
78
|
+
// The AI SDK types onError's argument as unknown: a tool can reject with null or a
|
|
79
|
+
// string, which takes the generic message like any other non-author error.
|
|
80
|
+
wireErrorMessage: (error)=>createWireProjection(context)(type.isError(error) ? error : new Error(String(error))).message,
|
|
75
81
|
evaluateOperators: (input)=>context.evaluateOperators({
|
|
76
82
|
input,
|
|
77
83
|
location: agentConfig.agentId,
|
|
@@ -0,0 +1,31 @@
|
|
|
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 { type } from '@lowdefy/helpers';
|
|
16
|
+
import getCurrentEnvironment from '../../context/getCurrentEnvironment.js';
|
|
17
|
+
// Auth.js reads its base URL from AUTH_URL (NEXTAUTH_URL is aliased to it at startup). Default it to
|
|
18
|
+
// the current environment's url so a deployment declared in config.environments needs no separate
|
|
19
|
+
// AUTH_URL / NEXTAUTH_URL. The dev server build drops the current environment's url, so the dev
|
|
20
|
+
// server keeps the request origin.
|
|
21
|
+
function defaultAuthUrl({ config }) {
|
|
22
|
+
// Same "is it set" test as resolveCookies, so both agree on whether an auth URL is configured.
|
|
23
|
+
if (!type.isNone(process.env.AUTH_URL ?? process.env.NEXTAUTH_URL)) return;
|
|
24
|
+
const url = getCurrentEnvironment({
|
|
25
|
+
config
|
|
26
|
+
})?.url;
|
|
27
|
+
if (!type.isNone(url)) {
|
|
28
|
+
process.env.AUTH_URL = url;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export default defaultAuthUrl;
|
|
@@ -19,11 +19,15 @@ import createCallbacks from './callbacks/createCallbacks.js';
|
|
|
19
19
|
import createEvents from './events/createEvents.js';
|
|
20
20
|
import createLogger from './createLogger.js';
|
|
21
21
|
import createProviders from './createProviders.js';
|
|
22
|
+
import defaultAuthUrl from './defaultAuthUrl.js';
|
|
22
23
|
import resolveCookies from './resolveCookies.js';
|
|
23
24
|
const authConfigCache = {};
|
|
24
25
|
let initialized = false;
|
|
25
|
-
function getAuthConfig({ appMeta, authJson, dev, logger, plugins, secrets }) {
|
|
26
|
+
function getAuthConfig({ appMeta, authJson, config, dev, logger, plugins, secrets }) {
|
|
26
27
|
if (initialized) return authConfigCache;
|
|
28
|
+
defaultAuthUrl({
|
|
29
|
+
config
|
|
30
|
+
});
|
|
27
31
|
const operatorsParser = new ServerParser({
|
|
28
32
|
lowdefyApp: appMeta,
|
|
29
33
|
operators: {
|
|
@@ -14,20 +14,17 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
import runRoutine from '../runRoutine.js';
|
|
17
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
17
18
|
async function controlFor(context, routineContext, { control }) {
|
|
18
|
-
const { endpointId, logger
|
|
19
|
+
const { endpointId, logger } = context;
|
|
19
20
|
const { items } = routineContext;
|
|
20
21
|
const itemName = control[':for'];
|
|
21
22
|
if (!itemName) {
|
|
22
23
|
throw new Error(`Invalid :for in endpoint "${endpointId}" - missing variable name in :for.`);
|
|
23
24
|
}
|
|
24
|
-
const array =
|
|
25
|
+
const array = evaluateRoutineOperators(context, routineContext, {
|
|
25
26
|
input: control[':in'],
|
|
26
|
-
|
|
27
|
-
location: control['~k'] ?? ':for',
|
|
28
|
-
payload: routineContext.payload,
|
|
29
|
-
state: routineContext.state,
|
|
30
|
-
steps: routineContext.steps
|
|
27
|
+
location: control['~k'] ?? ':for'
|
|
31
28
|
});
|
|
32
29
|
logger.debug({
|
|
33
30
|
event: 'debug_control_for',
|
|
@@ -13,16 +13,12 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import runRoutine from '../runRoutine.js';
|
|
16
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
16
17
|
async function controlIf(context, routineContext, { control }) {
|
|
17
|
-
const { endpointId, logger
|
|
18
|
-
const
|
|
19
|
-
const evaluatedIf = evaluateOperators({
|
|
18
|
+
const { endpointId, logger } = context;
|
|
19
|
+
const evaluatedIf = evaluateRoutineOperators(context, routineContext, {
|
|
20
20
|
input: control[':if'],
|
|
21
|
-
|
|
22
|
-
location: control['~k'] ?? ':if',
|
|
23
|
-
payload: routineContext.payload,
|
|
24
|
-
state: routineContext.state,
|
|
25
|
-
steps: routineContext.steps
|
|
21
|
+
location: control['~k'] ?? ':if'
|
|
26
22
|
});
|
|
27
23
|
logger.debug({
|
|
28
24
|
event: 'debug_control_if',
|
|
@@ -14,28 +14,20 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { type } from '@lowdefy/helpers';
|
|
16
16
|
import { ConfigError } from '@lowdefy/errors';
|
|
17
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
17
18
|
async function controlLog(context, routineContext, { control }) {
|
|
18
|
-
const { endpointId, logger
|
|
19
|
-
const { items } = routineContext;
|
|
19
|
+
const { endpointId, logger } = context;
|
|
20
20
|
const location = control['~k'] ?? ':log';
|
|
21
21
|
logger.debug({
|
|
22
22
|
event: 'debug_control_log'
|
|
23
23
|
});
|
|
24
|
-
const log =
|
|
24
|
+
const log = evaluateRoutineOperators(context, routineContext, {
|
|
25
25
|
input: control[':log'],
|
|
26
|
-
|
|
27
|
-
location,
|
|
28
|
-
payload: routineContext.payload,
|
|
29
|
-
state: routineContext.state,
|
|
30
|
-
steps: routineContext.steps
|
|
26
|
+
location
|
|
31
27
|
});
|
|
32
|
-
const logLevel =
|
|
28
|
+
const logLevel = evaluateRoutineOperators(context, routineContext, {
|
|
33
29
|
input: control[':level'],
|
|
34
|
-
|
|
35
|
-
location,
|
|
36
|
-
payload: routineContext.payload,
|
|
37
|
-
state: routineContext.state,
|
|
38
|
-
steps: routineContext.steps
|
|
30
|
+
location
|
|
39
31
|
}) ?? 'info';
|
|
40
32
|
if (!type.isString(logLevel)) {
|
|
41
33
|
throw new ConfigError(`Invalid :log in endpoint "${endpointId}" - :level must be a string.`, {
|
|
@@ -14,20 +14,17 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
import runRoutine from '../runRoutine.js';
|
|
17
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
17
18
|
async function controlParallelFor(context, routineContext, { control }) {
|
|
18
|
-
const { endpointId, logger
|
|
19
|
+
const { endpointId, logger } = context;
|
|
19
20
|
const { items } = routineContext;
|
|
20
21
|
const itemName = control[':parallel_for'];
|
|
21
22
|
if (!itemName) {
|
|
22
23
|
throw new Error(`Invalid :parallel_for in endpoint "${endpointId}" - missing variable name in :parallel_for.`);
|
|
23
24
|
}
|
|
24
|
-
const array =
|
|
25
|
+
const array = evaluateRoutineOperators(context, routineContext, {
|
|
25
26
|
input: control[':in'],
|
|
26
|
-
|
|
27
|
-
location: control['~k'] ?? ':parallel_for',
|
|
28
|
-
payload: routineContext.payload,
|
|
29
|
-
state: routineContext.state,
|
|
30
|
-
steps: routineContext.steps
|
|
27
|
+
location: control['~k'] ?? ':parallel_for'
|
|
31
28
|
});
|
|
32
29
|
logger.debug({
|
|
33
30
|
event: 'debug_control_parallel',
|
|
@@ -13,27 +13,25 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { UserError } from '@lowdefy/errors';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
import createWireProjection from '../../../response/createWireProjection.js';
|
|
18
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
16
19
|
async function controlReject(context, routineContext, { control }) {
|
|
17
|
-
const { evaluateOperators } = context;
|
|
18
|
-
const { items } = routineContext;
|
|
19
20
|
const location = control['~k'] ?? ':reject';
|
|
20
|
-
const message =
|
|
21
|
+
const message = evaluateRoutineOperators(context, routineContext, {
|
|
21
22
|
input: control[':reject'],
|
|
22
|
-
|
|
23
|
-
location,
|
|
24
|
-
payload: routineContext.payload,
|
|
25
|
-
state: routineContext.state,
|
|
26
|
-
steps: routineContext.steps
|
|
23
|
+
location
|
|
27
24
|
});
|
|
28
|
-
const cause =
|
|
25
|
+
const cause = evaluateRoutineOperators(context, routineContext, {
|
|
29
26
|
input: control[':cause'],
|
|
30
|
-
|
|
31
|
-
location,
|
|
32
|
-
payload: routineContext.payload,
|
|
33
|
-
state: routineContext.state,
|
|
34
|
-
steps: routineContext.steps
|
|
27
|
+
location
|
|
35
28
|
});
|
|
36
|
-
|
|
29
|
+
// A reject is the author telling the user something, so it stays a UserError, whose message the
|
|
30
|
+
// wire passes through as written. An Error given as the message is reduced to what the wire
|
|
31
|
+
// would show for it - the author's text for a UserError, the generic message for a plugin error
|
|
32
|
+
// - rather than stringified with its library text; `{ _error: message }` opts into the real text.
|
|
33
|
+
const text = type.isError(message) ? createWireProjection(context)(message).message : message;
|
|
34
|
+
const error = new UserError(text, {
|
|
37
35
|
cause,
|
|
38
36
|
isReject: true
|
|
39
37
|
});
|
|
@@ -12,16 +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
|
-
*/
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
const response = evaluateOperators({
|
|
15
|
+
*/ import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
16
|
+
async function controlReturn(context, routineContext, { control }) {
|
|
17
|
+
const response = evaluateRoutineOperators(context, routineContext, {
|
|
19
18
|
input: control[':return'],
|
|
20
|
-
|
|
21
|
-
location: control['~k'] ?? ':return',
|
|
22
|
-
payload: routineContext.payload,
|
|
23
|
-
state: routineContext.state,
|
|
24
|
-
steps: routineContext.steps
|
|
19
|
+
location: control['~k'] ?? ':return'
|
|
25
20
|
});
|
|
26
21
|
context.logger.debug({
|
|
27
22
|
event: 'debug_control_return',
|
|
@@ -14,16 +14,12 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
import { ReservedKeyError, set } from '@lowdefy/helpers';
|
|
17
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
17
18
|
function controlSetState(context, routineContext, { control }) {
|
|
18
|
-
const { logger
|
|
19
|
-
const
|
|
20
|
-
const evaluatedSetState = evaluateOperators({
|
|
19
|
+
const { logger } = context;
|
|
20
|
+
const evaluatedSetState = evaluateRoutineOperators(context, routineContext, {
|
|
21
21
|
input: control[':set_state'],
|
|
22
|
-
|
|
23
|
-
location: control['~k'] ?? ':set_state',
|
|
24
|
-
payload: routineContext.payload,
|
|
25
|
-
state: routineContext.state,
|
|
26
|
-
steps: routineContext.steps
|
|
22
|
+
location: control['~k'] ?? ':set_state'
|
|
27
23
|
});
|
|
28
24
|
logger.debug({
|
|
29
25
|
event: 'debug_control_set_state',
|
|
@@ -13,21 +13,17 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import runRoutine from '../runRoutine.js';
|
|
16
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
16
17
|
async function controlSwitch(context, routineContext, { control }) {
|
|
17
|
-
const { endpointId, logger
|
|
18
|
-
const { items } = routineContext;
|
|
18
|
+
const { endpointId, logger } = context;
|
|
19
19
|
const cases = control[':switch'];
|
|
20
20
|
logger.debug({
|
|
21
21
|
event: 'debug_control_switch'
|
|
22
22
|
});
|
|
23
23
|
for (const caseObj of cases){
|
|
24
|
-
const evaluatedCase =
|
|
24
|
+
const evaluatedCase = evaluateRoutineOperators(context, routineContext, {
|
|
25
25
|
input: caseObj[':case'],
|
|
26
|
-
|
|
27
|
-
location: caseObj['~k'] ?? control['~k'] ?? ':switch',
|
|
28
|
-
payload: routineContext.payload,
|
|
29
|
-
state: routineContext.state,
|
|
30
|
-
steps: routineContext.steps
|
|
26
|
+
location: caseObj['~k'] ?? control['~k'] ?? ':switch'
|
|
31
27
|
});
|
|
32
28
|
logger.debug({
|
|
33
29
|
event: 'debug_control_switch_case',
|
|
@@ -13,29 +13,27 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { UserError } from '@lowdefy/errors';
|
|
16
|
+
import { type } from '@lowdefy/helpers';
|
|
17
|
+
import evaluateRoutineOperators from '../evaluateRoutineOperators.js';
|
|
16
18
|
async function controlThrow(context, routineContext, { control }) {
|
|
17
|
-
const { evaluateOperators } = context;
|
|
18
|
-
const { items } = routineContext;
|
|
19
19
|
const location = control['~k'] ?? ':throw';
|
|
20
|
-
const message =
|
|
20
|
+
const message = evaluateRoutineOperators(context, routineContext, {
|
|
21
21
|
input: control[':throw'],
|
|
22
|
-
|
|
23
|
-
location,
|
|
24
|
-
payload: routineContext.payload,
|
|
25
|
-
state: routineContext.state,
|
|
26
|
-
steps: routineContext.steps
|
|
27
|
-
});
|
|
28
|
-
const cause = evaluateOperators({
|
|
29
|
-
input: control[':cause'],
|
|
30
|
-
items,
|
|
31
|
-
location,
|
|
32
|
-
payload: routineContext.payload,
|
|
33
|
-
state: routineContext.state,
|
|
34
|
-
steps: routineContext.steps
|
|
35
|
-
});
|
|
36
|
-
const error = new UserError(message, {
|
|
37
|
-
cause
|
|
22
|
+
location
|
|
38
23
|
});
|
|
24
|
+
// An Error, such as a rethrown `_error`, goes on unchanged. Wrapped in a UserError it would be
|
|
25
|
+
// stringified into the message, which the wire sends as author text; under its own class the
|
|
26
|
+
// wire makes it generic unless it was a UserError. It carries its own cause, so :cause is unused.
|
|
27
|
+
let error = message;
|
|
28
|
+
if (!type.isError(message)) {
|
|
29
|
+
const cause = evaluateRoutineOperators(context, routineContext, {
|
|
30
|
+
input: control[':cause'],
|
|
31
|
+
location
|
|
32
|
+
});
|
|
33
|
+
error = new UserError(message, {
|
|
34
|
+
cause
|
|
35
|
+
});
|
|
36
|
+
}
|
|
39
37
|
// Log under `err` — the pino error serializer (createNodeLogger) is registered
|
|
40
38
|
// for the `err` key only; an Error passed as `error` is JSON-dumped without its
|
|
41
39
|
// non-enumerable `message`/`stack`, producing a log line with no message.
|