@lowdefy/api 4.5.1 → 4.6.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/createApiContext.js +1 -1
- package/dist/context/createAuthorize.js +8 -4
- package/dist/context/createEvaluateOperators.js +16 -2
- package/dist/context/createReadConfigFile.js +3 -3
- package/dist/index.js +4 -3
- package/dist/routes/auth/callbacks/addUserFieldsToSession.js +1 -1
- package/dist/routes/auth/callbacks/addUserFieldsToToken.js +1 -1
- package/dist/routes/auth/callbacks/createCallbackPlugins.js +1 -1
- package/dist/routes/auth/callbacks/createCallbacks.js +1 -1
- package/dist/routes/auth/callbacks/createJWTCallback.js +1 -1
- package/dist/routes/auth/callbacks/createRedirectCallback.js +1 -1
- package/dist/routes/auth/callbacks/createSessionCallback.js +1 -1
- package/dist/routes/auth/callbacks/createSignInCallback.js +1 -1
- package/dist/routes/auth/createAdapter.js +1 -1
- package/dist/routes/auth/createLogger.js +21 -17
- package/dist/routes/auth/createProviders.js +1 -1
- package/dist/routes/auth/events/createCreateUserEvent.js +1 -1
- package/dist/routes/auth/events/createEventPlugins.js +1 -1
- package/dist/routes/auth/events/createEvents.js +1 -1
- package/dist/routes/auth/events/createLinkAccountEvent.js +1 -1
- package/dist/routes/auth/events/createSessionEvent.js +1 -1
- package/dist/routes/auth/events/createSignInEvent.js +1 -1
- package/dist/routes/auth/events/createSignOutEvent.js +1 -1
- package/dist/routes/auth/events/createUpdateUserEvent.js +1 -1
- package/dist/routes/auth/getNextAuthConfig.js +2 -2
- package/dist/routes/endpoints/addStepResult.js +1 -1
- package/dist/routes/endpoints/authorizeApiEndpoint.js +3 -3
- package/dist/routes/endpoints/callEndpoint.js +1 -1
- package/dist/routes/endpoints/control/controlFor.js +11 -7
- package/dist/routes/endpoints/control/controlIf.js +4 -4
- package/dist/routes/endpoints/control/controlLog.js +11 -6
- package/dist/routes/endpoints/control/controlParallel.js +1 -1
- package/dist/routes/endpoints/control/controlParallelFor.js +11 -7
- package/dist/routes/endpoints/control/controlReject.js +4 -3
- package/dist/routes/endpoints/control/controlReturn.js +2 -2
- package/dist/routes/endpoints/control/controlSetState.js +1 -1
- package/dist/routes/endpoints/control/controlSwitch.js +4 -4
- package/dist/routes/endpoints/control/controlThrow.js +4 -3
- package/dist/routes/endpoints/control/controlTry.js +1 -1
- package/dist/routes/endpoints/control/handleControl.js +1 -1
- package/dist/routes/endpoints/getEndpointConfig.js +3 -3
- package/dist/routes/endpoints/handleRequest.js +1 -1
- package/dist/routes/endpoints/runRoutine.js +2 -2
- package/dist/routes/log/formatValidationError.js +31 -0
- package/dist/routes/log/logClientError.js +109 -0
- package/dist/routes/log/validatePluginSchema.js +25 -0
- package/dist/routes/page/getPageConfig.js +6 -5
- package/dist/routes/request/authorizeRequest.js +5 -3
- package/dist/routes/request/callRequest.js +1 -1
- package/dist/routes/request/callRequestResolver.js +43 -6
- package/dist/routes/request/checkConnectionRead.js +8 -4
- package/dist/routes/request/checkConnectionWrite.js +8 -4
- package/dist/routes/request/evaluateOperators.js +1 -1
- package/dist/routes/request/getConnection.js +5 -3
- package/dist/routes/request/getConnectionConfig.js +8 -4
- package/dist/routes/request/getRequestConfig.js +3 -3
- package/dist/routes/request/getRequestResolver.js +5 -3
- package/dist/routes/request/validateSchemas.js +39 -20
- package/dist/routes/rootConfig/getHomeAndMenus.js +1 -1
- package/dist/routes/rootConfig/getLowdefyGlobal.js +1 -1
- package/dist/routes/rootConfig/getRootConfig.js +1 -1
- package/dist/routes/rootConfig/menus/filterMenuList.js +1 -1
- package/dist/routes/rootConfig/menus/filterMenus.js +1 -1
- package/dist/routes/rootConfig/menus/getMenus.js +1 -1
- package/dist/test/testContext.js +4 -1
- package/package.json +8 -7
- package/dist/context/errors.js +0 -33
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -15,15 +15,16 @@
|
|
|
15
15
|
*/ async function controlThrow(context, routineContext, { control }) {
|
|
16
16
|
const { evaluateOperators } = context;
|
|
17
17
|
const { items } = routineContext;
|
|
18
|
+
const location = control['~k'] ?? ':throw';
|
|
18
19
|
const message = evaluateOperators({
|
|
19
20
|
input: control[':throw'],
|
|
20
21
|
items,
|
|
21
|
-
location
|
|
22
|
+
location
|
|
22
23
|
});
|
|
23
24
|
const cause = evaluateOperators({
|
|
24
25
|
input: control[':cause'],
|
|
25
26
|
items,
|
|
26
|
-
location
|
|
27
|
+
location
|
|
27
28
|
});
|
|
28
29
|
const error = new Error(message, {
|
|
29
30
|
cause
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,11 +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 {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
async function getEndpointConfig({ logger, readConfigFile }, { endpointId }) {
|
|
17
17
|
const endpoint = await readConfigFile(`api/${endpointId}.json`);
|
|
18
18
|
if (!endpoint) {
|
|
19
|
-
const err = new
|
|
19
|
+
const err = new ConfigError(`API Endpoint "${endpointId}" does not exist.`);
|
|
20
20
|
logger.debug({
|
|
21
21
|
params: {
|
|
22
22
|
endpointId
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -50,7 +50,7 @@ async function runRoutine(context, routineContext, { routine }) {
|
|
|
50
50
|
}
|
|
51
51
|
});
|
|
52
52
|
} catch (error) {
|
|
53
|
-
context.
|
|
53
|
+
await context.handleError(error);
|
|
54
54
|
return {
|
|
55
55
|
status: 'error',
|
|
56
56
|
error
|
|
@@ -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
|
+
*/ function formatValidationError({ ajvError, pluginLabel, typeName, fieldLabel }) {
|
|
16
|
+
const path = ajvError.instancePath ? ajvError.instancePath.substring(1).replace(/\//g, '.') : null;
|
|
17
|
+
const fieldName = path || ajvError.params?.missingProperty || 'unknown';
|
|
18
|
+
switch(ajvError.keyword){
|
|
19
|
+
case 'type':
|
|
20
|
+
return `${pluginLabel} "${typeName}" ${fieldLabel} "${fieldName}" must be type "${ajvError.params.type}".`;
|
|
21
|
+
case 'enum':
|
|
22
|
+
return `${pluginLabel} "${typeName}" ${fieldLabel} "${fieldName}" must be one of ${JSON.stringify(ajvError.params.allowedValues)}.`;
|
|
23
|
+
case 'additionalProperties':
|
|
24
|
+
return `${pluginLabel} "${typeName}" ${fieldLabel} "${ajvError.params.additionalProperty}" is not allowed.`;
|
|
25
|
+
case 'required':
|
|
26
|
+
return `${pluginLabel} "${typeName}" required ${fieldLabel} "${ajvError.params.missingProperty}" is missing.`;
|
|
27
|
+
default:
|
|
28
|
+
return `${pluginLabel} "${typeName}" ${fieldLabel} "${fieldName}" ${ajvError.message}.`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export default formatValidationError;
|
|
@@ -0,0 +1,109 @@
|
|
|
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 { ConfigError, loadAndResolveErrorLocation } from '@lowdefy/errors';
|
|
16
|
+
import { serializer, type } from '@lowdefy/helpers';
|
|
17
|
+
import formatValidationError from './formatValidationError.js';
|
|
18
|
+
import validatePluginSchema from './validatePluginSchema.js';
|
|
19
|
+
const validationConfigs = {
|
|
20
|
+
BlockError: {
|
|
21
|
+
schemaFile: 'plugins/blockSchemas.json',
|
|
22
|
+
schemaKey: 'properties',
|
|
23
|
+
pluginLabel: 'Block',
|
|
24
|
+
fieldLabel: 'property'
|
|
25
|
+
},
|
|
26
|
+
ActionError: {
|
|
27
|
+
schemaFile: 'plugins/actionSchemas.json',
|
|
28
|
+
schemaKey: 'params',
|
|
29
|
+
pluginLabel: 'Action',
|
|
30
|
+
fieldLabel: 'param'
|
|
31
|
+
},
|
|
32
|
+
OperatorError: {
|
|
33
|
+
schemaFile: 'plugins/operatorSchemas.json',
|
|
34
|
+
schemaKey: 'params',
|
|
35
|
+
pluginLabel: 'Operator',
|
|
36
|
+
fieldLabel: 'param'
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
async function logClientError(context, serializedError) {
|
|
40
|
+
const { logger } = context;
|
|
41
|
+
const error = serializer.deserialize(serializedError);
|
|
42
|
+
// Schema validation for plugin errors with received data
|
|
43
|
+
const validationConfig = validationConfigs[error.name];
|
|
44
|
+
let validationError = null;
|
|
45
|
+
if (validationConfig && !type.isNone(error.received)) {
|
|
46
|
+
try {
|
|
47
|
+
const schemas = await context.readConfigFile(validationConfig.schemaFile);
|
|
48
|
+
if (schemas) {
|
|
49
|
+
const schema = schemas[error.typeName];
|
|
50
|
+
if (schema) {
|
|
51
|
+
const data = error.name === 'OperatorError' ? Object.values(error.received)[0] : error.received;
|
|
52
|
+
const ajvErrors = validatePluginSchema({
|
|
53
|
+
data,
|
|
54
|
+
schema,
|
|
55
|
+
schemaKey: validationConfig.schemaKey
|
|
56
|
+
});
|
|
57
|
+
if (ajvErrors) {
|
|
58
|
+
const displayName = error.name === 'OperatorError' && error.methodName ? `${error.typeName}.${error.methodName}` : error.typeName;
|
|
59
|
+
const messages = ajvErrors.map((ajvError)=>formatValidationError({
|
|
60
|
+
ajvError,
|
|
61
|
+
pluginLabel: validationConfig.pluginLabel,
|
|
62
|
+
typeName: displayName,
|
|
63
|
+
fieldLabel: validationConfig.fieldLabel
|
|
64
|
+
}));
|
|
65
|
+
const message = messages.length === 1 ? messages[0] : `${validationConfig.pluginLabel} "${displayName}" has invalid ${validationConfig.schemaKey}:\n${messages.map((m)=>` - ${m}`).join('\n')}`;
|
|
66
|
+
validationError = new ConfigError(message, {
|
|
67
|
+
configKey: error.configKey,
|
|
68
|
+
cause: error
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch (e) {
|
|
74
|
+
logger.warn(e);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const location = await loadAndResolveErrorLocation({
|
|
78
|
+
error,
|
|
79
|
+
readConfigFile: context.readConfigFile,
|
|
80
|
+
configDirectory: context.configDirectory
|
|
81
|
+
});
|
|
82
|
+
if (location) {
|
|
83
|
+
error.source = location.source;
|
|
84
|
+
error.config = location.config;
|
|
85
|
+
}
|
|
86
|
+
// If validation produced a ConfigError, log only that (cause chain shows original)
|
|
87
|
+
if (validationError) {
|
|
88
|
+
if (location) {
|
|
89
|
+
validationError.source = location.source;
|
|
90
|
+
validationError.config = location.config;
|
|
91
|
+
}
|
|
92
|
+
logger.error(validationError);
|
|
93
|
+
return {
|
|
94
|
+
success: true,
|
|
95
|
+
source: error.source ?? null,
|
|
96
|
+
config: error.config ?? null,
|
|
97
|
+
error,
|
|
98
|
+
configError: serializer.serialize(validationError)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
logger.error(error);
|
|
102
|
+
return {
|
|
103
|
+
success: true,
|
|
104
|
+
source: error.source ?? null,
|
|
105
|
+
config: error.config ?? null,
|
|
106
|
+
error
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export default logClientError;
|
|
@@ -0,0 +1,25 @@
|
|
|
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 { validate } from '@lowdefy/ajv';
|
|
16
|
+
function validatePluginSchema({ data, schema, schemaKey }) {
|
|
17
|
+
if (!schema?.[schemaKey]) return null;
|
|
18
|
+
const { valid, errors } = validate({
|
|
19
|
+
schema: schema[schemaKey],
|
|
20
|
+
data,
|
|
21
|
+
returnErrors: true
|
|
22
|
+
});
|
|
23
|
+
return valid ? null : errors;
|
|
24
|
+
}
|
|
25
|
+
export default validatePluginSchema;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,14 +12,15 @@
|
|
|
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 { serializer } from '@lowdefy/helpers';
|
|
16
|
+
async function getPageConfig({ authorize, readConfigFile }, { pageId }) {
|
|
16
17
|
const pageConfig = await readConfigFile(`pages/${pageId}/${pageId}.json`);
|
|
17
18
|
if (pageConfig && authorize(pageConfig)) {
|
|
18
19
|
// eslint-disable-next-line no-unused-vars
|
|
19
20
|
const { auth, ...rest } = pageConfig;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// Use serializer.serialize to ensure ~k keys (non-enumerable after deserialize)
|
|
22
|
+
// are made enumerable again for JSON transfer to client
|
|
23
|
+
return serializer.serialize(rest);
|
|
23
24
|
}
|
|
24
25
|
return null;
|
|
25
26
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,7 +12,7 @@
|
|
|
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 {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
function authorizeRequest({ authorize, logger }, { requestConfig }) {
|
|
17
17
|
if (!authorize(requestConfig)) {
|
|
18
18
|
logger.debug({
|
|
@@ -21,7 +21,9 @@ function authorizeRequest({ authorize, logger }, { requestConfig }) {
|
|
|
21
21
|
auth_config: requestConfig.auth
|
|
22
22
|
});
|
|
23
23
|
// Throw does not exist error to avoid leaking information that request exists to unauthorized users
|
|
24
|
-
throw new
|
|
24
|
+
throw new ConfigError(`Request "${requestConfig.requestId}" does not exist.`, {
|
|
25
|
+
configKey: requestConfig['~k']
|
|
26
|
+
});
|
|
25
27
|
}
|
|
26
28
|
logger.debug({
|
|
27
29
|
event: 'debug_request_authorize',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,7 +12,7 @@
|
|
|
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 { RequestError } from '
|
|
15
|
+
*/ import { ConfigError, RequestError, ServiceError } from '@lowdefy/errors';
|
|
16
16
|
async function callRequestResolver({ blockId, endpointId, logger, pageId, payload }, { connectionProperties, requestConfig, requestProperties, requestResolver }) {
|
|
17
17
|
try {
|
|
18
18
|
const response = await requestResolver({
|
|
@@ -27,15 +27,52 @@ async function callRequestResolver({ blockId, endpointId, logger, pageId, payloa
|
|
|
27
27
|
});
|
|
28
28
|
return response;
|
|
29
29
|
} catch (error) {
|
|
30
|
-
|
|
30
|
+
// Add configKey to any error for location tracing
|
|
31
|
+
if (!error.configKey) {
|
|
32
|
+
error.configKey = requestConfig['~k'];
|
|
33
|
+
}
|
|
34
|
+
if (error instanceof ConfigError) {
|
|
35
|
+
logger.debug({
|
|
36
|
+
params: {
|
|
37
|
+
id: requestConfig.requestId,
|
|
38
|
+
type: requestConfig.type
|
|
39
|
+
},
|
|
40
|
+
err: error
|
|
41
|
+
}, error.message);
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
// Check if this is a service error (network, timeout, 5xx)
|
|
45
|
+
if (ServiceError.isServiceError(error)) {
|
|
46
|
+
const serviceError = new ServiceError(undefined, {
|
|
47
|
+
cause: error,
|
|
48
|
+
service: requestConfig.connectionId,
|
|
49
|
+
configKey: requestConfig['~k']
|
|
50
|
+
});
|
|
51
|
+
logger.debug({
|
|
52
|
+
params: {
|
|
53
|
+
id: requestConfig.requestId,
|
|
54
|
+
type: requestConfig.type
|
|
55
|
+
},
|
|
56
|
+
err: serviceError
|
|
57
|
+
}, serviceError.message);
|
|
58
|
+
throw serviceError;
|
|
59
|
+
}
|
|
60
|
+
// Wrap other errors in RequestError (request/connection logic error)
|
|
61
|
+
const requestError = new RequestError(error.message, {
|
|
62
|
+
cause: error,
|
|
63
|
+
typeName: requestConfig.type,
|
|
64
|
+
received: requestProperties,
|
|
65
|
+
location: `${requestConfig.connectionId}/${requestConfig.requestId}`,
|
|
66
|
+
configKey: requestConfig['~k']
|
|
67
|
+
});
|
|
31
68
|
logger.debug({
|
|
32
69
|
params: {
|
|
33
70
|
id: requestConfig.requestId,
|
|
34
71
|
type: requestConfig.type
|
|
35
72
|
},
|
|
36
|
-
err
|
|
37
|
-
},
|
|
38
|
-
throw
|
|
73
|
+
err: requestError
|
|
74
|
+
}, requestError.message);
|
|
75
|
+
throw requestError;
|
|
39
76
|
}
|
|
40
77
|
}
|
|
41
78
|
export default callRequestResolver;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,14 +12,18 @@
|
|
|
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 {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
function checkConnectionRead({ logger }, { connectionConfig, connectionProperties, requestConfig, requestResolver }) {
|
|
17
17
|
if (requestResolver.meta.checkRead && connectionProperties.read === false) {
|
|
18
|
-
const
|
|
18
|
+
const configKey = requestConfig['~k'];
|
|
19
|
+
const err = new ConfigError(`Connection "${connectionConfig.connectionId}" does not allow reads.`, {
|
|
20
|
+
configKey
|
|
21
|
+
});
|
|
19
22
|
logger.debug({
|
|
20
23
|
params: {
|
|
21
24
|
connectionId: connectionConfig.connectionId,
|
|
22
|
-
requestId: requestConfig.requestId
|
|
25
|
+
requestId: requestConfig.requestId,
|
|
26
|
+
configKey
|
|
23
27
|
},
|
|
24
28
|
err
|
|
25
29
|
}, err.message);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,14 +12,18 @@
|
|
|
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 {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
function checkConnectionWrite({ logger }, { connectionConfig, connectionProperties, requestConfig, requestResolver }) {
|
|
17
17
|
if (requestResolver.meta.checkWrite && connectionProperties.write !== true) {
|
|
18
|
-
const
|
|
18
|
+
const configKey = requestConfig['~k'];
|
|
19
|
+
const err = new ConfigError(`Connection "${connectionConfig.connectionId}" does not allow writes.`, {
|
|
20
|
+
configKey
|
|
21
|
+
});
|
|
19
22
|
logger.debug({
|
|
20
23
|
params: {
|
|
21
24
|
connectionId: connectionConfig.connectionId,
|
|
22
|
-
requestId: requestConfig.requestId
|
|
25
|
+
requestId: requestConfig.requestId,
|
|
26
|
+
configKey
|
|
23
27
|
},
|
|
24
28
|
err
|
|
25
29
|
}, err.message);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,11 +12,13 @@
|
|
|
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 {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
function getConnection({ connections, logger }, { connectionConfig }) {
|
|
17
17
|
const connection = connections[connectionConfig.type];
|
|
18
18
|
if (!connection) {
|
|
19
|
-
const err = new
|
|
19
|
+
const err = new ConfigError(`Connection type "${connectionConfig.type}" can not be found.`, {
|
|
20
|
+
configKey: connectionConfig['~k']
|
|
21
|
+
});
|
|
20
22
|
logger.debug({
|
|
21
23
|
params: {
|
|
22
24
|
id: connectionConfig.connectionId,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
async function getConnectionConfig({ logger, readConfigFile }, { requestConfig }) {
|
|
17
17
|
const { connectionId, requestId } = requestConfig;
|
|
18
18
|
let err;
|
|
19
19
|
if (!connectionId) {
|
|
20
|
-
err = new
|
|
20
|
+
err = new ConfigError(`Request "${requestId}" does not specify a connection.`, {
|
|
21
|
+
configKey: requestConfig['~k']
|
|
22
|
+
});
|
|
21
23
|
logger.debug({
|
|
22
24
|
params: {
|
|
23
25
|
requestId
|
|
@@ -28,7 +30,9 @@ async function getConnectionConfig({ logger, readConfigFile }, { requestConfig }
|
|
|
28
30
|
}
|
|
29
31
|
const connection = await readConfigFile(`connections/${connectionId}.json`);
|
|
30
32
|
if (!connection) {
|
|
31
|
-
err = new
|
|
33
|
+
err = new ConfigError(`Connection "${connectionId}" does not exist.`, {
|
|
34
|
+
configKey: requestConfig['~k']
|
|
35
|
+
});
|
|
32
36
|
logger.debug({
|
|
33
37
|
params: {
|
|
34
38
|
requestId
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,11 +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 {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
async function getRequestConfig({ logger, readConfigFile }, { pageId, requestId }) {
|
|
17
17
|
const request = await readConfigFile(`pages/${pageId}/requests/${requestId}.json`);
|
|
18
18
|
if (!request) {
|
|
19
|
-
const err = new
|
|
19
|
+
const err = new ConfigError(`Request "${requestId}" does not exist.`);
|
|
20
20
|
logger.debug({
|
|
21
21
|
params: {
|
|
22
22
|
pageId,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -12,11 +12,13 @@
|
|
|
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 {
|
|
15
|
+
*/ import { ConfigError } from '@lowdefy/errors';
|
|
16
16
|
function getRequestResolver({ logger }, { connection, requestConfig }) {
|
|
17
17
|
const requestResolver = connection.requests[requestConfig.type];
|
|
18
18
|
if (!requestResolver) {
|
|
19
|
-
const err = new
|
|
19
|
+
const err = new ConfigError(`Request type "${requestConfig.type}" can not be found.`, {
|
|
20
|
+
configKey: requestConfig['~k']
|
|
21
|
+
});
|
|
20
22
|
logger.debug({
|
|
21
23
|
params: {
|
|
22
24
|
id: requestConfig.requestId,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2020-
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
3
|
|
|
4
4
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
you may not use this file except in compliance with the License.
|
|
@@ -13,27 +13,46 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/ import { validate } from '@lowdefy/ajv';
|
|
16
|
-
import {
|
|
16
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
17
|
+
import formatValidationError from '../log/formatValidationError.js';
|
|
17
18
|
function validateSchemas({ logger }, { connection, connectionProperties, requestConfig, requestResolver, requestProperties }) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const configKey = requestConfig['~k'];
|
|
20
|
+
const messages = [];
|
|
21
|
+
const connectionResult = validate({
|
|
22
|
+
schema: connection.schema,
|
|
23
|
+
data: connectionProperties,
|
|
24
|
+
returnErrors: true
|
|
25
|
+
});
|
|
26
|
+
if (!connectionResult.valid) {
|
|
27
|
+
for (const ajvError of connectionResult.errors){
|
|
28
|
+
messages.push(formatValidationError({
|
|
29
|
+
ajvError,
|
|
30
|
+
pluginLabel: 'Connection',
|
|
31
|
+
typeName: requestConfig.connectionId,
|
|
32
|
+
fieldLabel: 'property'
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const requestResult = validate({
|
|
37
|
+
schema: requestResolver.schema,
|
|
38
|
+
data: requestProperties,
|
|
39
|
+
returnErrors: true
|
|
40
|
+
});
|
|
41
|
+
if (!requestResult.valid) {
|
|
42
|
+
for (const ajvError of requestResult.errors){
|
|
43
|
+
messages.push(formatValidationError({
|
|
44
|
+
ajvError,
|
|
45
|
+
pluginLabel: 'Request',
|
|
46
|
+
typeName: requestConfig.type,
|
|
47
|
+
fieldLabel: 'property'
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (messages.length > 0) {
|
|
52
|
+
const message = messages.length === 1 ? messages[0] : `Request "${requestConfig.requestId}" has schema validation errors:\n${messages.map((m)=>` - ${m}`).join('\n')}`;
|
|
53
|
+
throw new ConfigError(message, {
|
|
54
|
+
configKey
|
|
26
55
|
});
|
|
27
|
-
} catch (error) {
|
|
28
|
-
const err = new ConfigurationError(error.message);
|
|
29
|
-
logger.debug({
|
|
30
|
-
params: {
|
|
31
|
-
id: requestConfig.requestId,
|
|
32
|
-
type: requestConfig.type
|
|
33
|
-
},
|
|
34
|
-
err
|
|
35
|
-
}, err.message);
|
|
36
|
-
throw err;
|
|
37
56
|
}
|
|
38
57
|
}
|
|
39
58
|
export default validateSchemas;
|