@lowdefy/build 0.0.0-experimental-20260114142524 → 0.0.0-experimental-20260122074446

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.
Files changed (57) hide show
  1. package/dist/build/addKeys.js +31 -18
  2. package/dist/build/buildApi/validateStepReferences.js +3 -4
  3. package/dist/build/buildAuth/buildAuth.js +2 -1
  4. package/dist/build/buildAuth/buildAuthPlugins.js +13 -13
  5. package/dist/build/buildAuth/validateAuthConfig.js +40 -8
  6. package/dist/build/buildAuth/validateMutualExclusivity.js +7 -7
  7. package/dist/build/buildConnections.js +20 -39
  8. package/dist/build/buildMenu.js +9 -14
  9. package/dist/build/buildPages/buildBlock/buildEvents.js +13 -13
  10. package/dist/build/buildPages/buildBlock/buildRequests.js +15 -15
  11. package/dist/build/buildPages/buildBlock/validateBlock.js +13 -13
  12. package/dist/build/buildPages/buildPage.js +5 -5
  13. package/dist/build/buildPages/validateLinkReferences.js +8 -9
  14. package/dist/build/buildPages/validatePayloadReferences.js +3 -4
  15. package/dist/build/buildPages/validateRequestReferences.js +7 -8
  16. package/dist/build/buildPages/validateStateReferences.js +3 -4
  17. package/dist/build/buildRefs/buildRefs.js +8 -0
  18. package/dist/build/buildRefs/evaluateBuildOperators.js +11 -1
  19. package/dist/build/buildRefs/evaluateStaticOperators.js +54 -0
  20. package/dist/build/buildRefs/getConfigFile.js +18 -13
  21. package/dist/build/buildRefs/getRefContent.js +15 -5
  22. package/dist/build/buildRefs/makeRefDefinition.js +1 -1
  23. package/dist/build/buildRefs/parseRefContent.js +32 -2
  24. package/dist/build/buildRefs/recursiveBuild.js +9 -7
  25. package/dist/build/buildRefs/runRefResolver.js +13 -2
  26. package/dist/build/buildTypes.js +9 -0
  27. package/dist/build/collectDynamicIdentifiers.js +35 -0
  28. package/dist/{utils/formatConfigError.js → build/collectTypeNames.js} +20 -8
  29. package/dist/build/formatBuildError.js +1 -1
  30. package/dist/build/testSchema.js +45 -6
  31. package/dist/build/validateOperatorsDynamic.js +28 -0
  32. package/dist/build/writeRequests.js +3 -3
  33. package/dist/createContext.js +42 -1
  34. package/dist/defaultTypesMap.js +447 -447
  35. package/dist/index.js +43 -4
  36. package/dist/lowdefySchema.js +60 -0
  37. package/dist/test-utils/parseTestYaml.js +110 -0
  38. package/dist/test-utils/runBuild.js +270 -0
  39. package/dist/test-utils/runBuildForSnapshots.js +698 -0
  40. package/dist/{test → test-utils}/testContext.js +15 -1
  41. package/dist/utils/collectConfigError.js +6 -6
  42. package/dist/utils/countOperators.js +5 -3
  43. package/dist/utils/createCheckDuplicateId.js +1 -1
  44. package/dist/utils/findConfigKey.js +37 -0
  45. package/dist/utils/makeId.js +12 -7
  46. package/dist/utils/tryBuildStep.js +12 -5
  47. package/package.json +39 -39
  48. package/dist/utils/formatConfigMessage.js +0 -33
  49. package/dist/utils/formatConfigWarning.js +0 -24
  50. package/dist/utils/formatErrorMessage.js +0 -56
  51. /package/dist/{test → test-utils}/buildRefs/testBuildRefsAsyncFunction.js +0 -0
  52. /package/dist/{test → test-utils}/buildRefs/testBuildRefsErrorResolver.js +0 -0
  53. /package/dist/{test → test-utils}/buildRefs/testBuildRefsNullResolver.js +0 -0
  54. /package/dist/{test → test-utils}/buildRefs/testBuildRefsParsingResolver.js +0 -0
  55. /package/dist/{test → test-utils}/buildRefs/testBuildRefsResolver.js +0 -0
  56. /package/dist/{test → test-utils}/buildRefs/testBuildRefsTransform.js +0 -0
  57. /package/dist/{test → test-utils}/buildRefs/testBuildRefsTransformIdentity.js +0 -0
@@ -45,26 +45,39 @@ function recArray({ array, nextKey, key, keyMap, keyMapId }) {
45
45
  });
46
46
  }
47
47
  function recAddKeys({ object, key, keyMap, parentKeyMapId }) {
48
- const keyMapId = makeId();
49
- keyMap[keyMapId] = {
50
- key,
51
- '~r': object['~r'],
52
- '~l': object['~l'],
53
- '~k_parent': parentKeyMapId
54
- };
55
- Object.defineProperty(object, '~k', {
56
- value: keyMapId,
57
- enumerable: false,
58
- writable: true,
59
- configurable: true
60
- });
61
- delete object['~r'];
62
- delete object['~l'];
48
+ let keyMapId;
49
+ let storedKey = key;
50
+ // Skip objects that already have a ~k (already processed)
51
+ if (object['~k']) {
52
+ keyMapId = object['~k'];
53
+ // Use the stored key from keyMap for correct child paths
54
+ storedKey = keyMap[keyMapId]?.key ?? key;
55
+ } else {
56
+ keyMapId = makeId.next();
57
+ const entry = {
58
+ key,
59
+ '~k_parent': parentKeyMapId
60
+ };
61
+ if (object['~r'] !== undefined) entry['~r'] = object['~r'];
62
+ if (object['~l'] !== undefined) entry['~l'] = object['~l'];
63
+ if (object['~ignoreBuildCheck'] !== undefined) entry['~ignoreBuildCheck'] = object['~ignoreBuildCheck'];
64
+ keyMap[keyMapId] = entry;
65
+ Object.defineProperty(object, '~k', {
66
+ value: keyMapId,
67
+ enumerable: false,
68
+ writable: true,
69
+ configurable: true
70
+ });
71
+ delete object['~r'];
72
+ delete object['~l'];
73
+ delete object['~ignoreBuildCheck'];
74
+ }
75
+ // Always recurse into children (they may be new objects without keys)
63
76
  Object.keys(object).forEach((nextKey)=>{
64
77
  if (type.isObject(object[nextKey])) {
65
78
  recAddKeys({
66
79
  object: object[nextKey],
67
- key: `${key}.${nextKey}`,
80
+ key: `${storedKey}.${nextKey}`,
68
81
  keyMap: keyMap,
69
82
  parentKeyMapId: keyMapId
70
83
  });
@@ -73,7 +86,7 @@ function recAddKeys({ object, key, keyMap, parentKeyMapId }) {
73
86
  recArray({
74
87
  array: object[nextKey],
75
88
  nextKey,
76
- key,
89
+ key: storedKey,
77
90
  keyMap,
78
91
  keyMapId
79
92
  });
@@ -81,7 +94,7 @@ function recAddKeys({ object, key, keyMap, parentKeyMapId }) {
81
94
  });
82
95
  }
83
96
  function addKeys({ components, context }) {
84
- const keyMapId = makeId(true);
97
+ const keyMapId = makeId.next();
85
98
  recAddKeys({
86
99
  object: components,
87
100
  key: 'root',
@@ -14,7 +14,6 @@
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
16
  import extractOperatorKey from '../../utils/extractOperatorKey.js';
17
- import formatConfigWarning from '../../utils/formatConfigWarning.js';
18
17
  import traverseConfig from '../../utils/traverseConfig.js';
19
18
  // Collect all step IDs from a routine (including nested control structures)
20
19
  // Note: After buildRoutine, steps have requestId (original id) and id is modified
@@ -55,11 +54,11 @@ function validateStepReferences({ endpoint, context }) {
55
54
  stepRefs.forEach((configKey, stepId)=>{
56
55
  if (stepIds.has(stepId)) return;
57
56
  const message = `_step references "${stepId}" in endpoint "${endpoint.endpointId}", ` + `but no step with id "${stepId}" exists in the routine. ` + `Step IDs are defined by the "id" property of each step. ` + `Check for typos or add a step with this id.`;
58
- context.logger.warn(formatConfigWarning({
57
+ context.logger.configWarning({
59
58
  message,
60
59
  configKey,
61
- context
62
- }));
60
+ prodError: true
61
+ });
63
62
  });
64
63
  }
65
64
  export default validateStepReferences;
@@ -20,7 +20,8 @@ import validateAuthConfig from './validateAuthConfig.js';
20
20
  function buildAuth({ components, context }) {
21
21
  const configured = !type.isNone(components.auth);
22
22
  validateAuthConfig({
23
- components
23
+ components,
24
+ context
24
25
  });
25
26
  components.auth.configured = configured;
26
27
  buildApiAuth({
@@ -13,31 +13,31 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
- import formatConfigError from '../../utils/formatConfigError.js';
16
+ import { ConfigError } from '@lowdefy/node-utils';
17
17
  function buildAuthPlugin({ counter, pluginConfig, typeClass, context }) {
18
18
  if (type.isArray(pluginConfig)) {
19
19
  pluginConfig.forEach((plugin)=>{
20
20
  const configKey = plugin['~k'];
21
21
  if (type.isUndefined(plugin.id)) {
22
- throw new Error(formatConfigError({
22
+ throw new ConfigError({
23
23
  message: `Auth ${typeClass} id missing.`,
24
24
  configKey,
25
25
  context
26
- }));
26
+ });
27
27
  }
28
28
  if (!type.isString(plugin.id)) {
29
- throw new Error(formatConfigError({
29
+ throw new ConfigError({
30
30
  message: `Auth ${typeClass} id is not a string. Received ${JSON.stringify(plugin.id)}.`,
31
31
  configKey,
32
32
  context
33
- }));
33
+ });
34
34
  }
35
35
  if (!type.isString(plugin.type)) {
36
- throw new Error(formatConfigError({
36
+ throw new ConfigError({
37
37
  message: `Auth ${typeClass} type is not a string at ${typeClass} "${plugin.id}". Received ${JSON.stringify(plugin.type)}.`,
38
38
  configKey,
39
39
  context
40
- }));
40
+ });
41
41
  }
42
42
  counter.increment(plugin.type, plugin['~k']);
43
43
  });
@@ -50,25 +50,25 @@ function buildAdapter({ components, context }) {
50
50
  }
51
51
  const configKey = adapter['~k'];
52
52
  if (type.isUndefined(adapter.id)) {
53
- throw new Error(formatConfigError({
53
+ throw new ConfigError({
54
54
  message: 'Auth adapter id missing.',
55
55
  configKey,
56
56
  context
57
- }));
57
+ });
58
58
  }
59
59
  if (!type.isString(adapter.id)) {
60
- throw new Error(formatConfigError({
60
+ throw new ConfigError({
61
61
  message: `Auth adapter id is not a string. Received ${JSON.stringify(adapter.id)}.`,
62
62
  configKey,
63
63
  context
64
- }));
64
+ });
65
65
  }
66
66
  if (!type.isString(adapter.type)) {
67
- throw new Error(formatConfigError({
67
+ throw new ConfigError({
68
68
  message: `Auth adapter type is not a string at adapter "${adapter.id}". Received ${JSON.stringify(adapter.type)}.`,
69
69
  configKey,
70
70
  context
71
- }));
71
+ });
72
72
  }
73
73
  context.typeCounters.auth.adapters.increment(adapter.type, adapter['~k']);
74
74
  }
@@ -14,20 +14,19 @@
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
16
  import { validate } from '@lowdefy/ajv';
17
+ import { ConfigError } from '@lowdefy/node-utils';
17
18
  import lowdefySchema from '../../lowdefySchema.js';
18
- import formatConfigError from '../../utils/formatConfigError.js';
19
19
  import validateMutualExclusivity from './validateMutualExclusivity.js';
20
- async function validateAuthConfig({ components, context }) {
20
+ function validateAuthConfig({ components, context }) {
21
21
  if (type.isNone(components.auth)) {
22
22
  components.auth = {};
23
23
  }
24
24
  if (!type.isObject(components.auth)) {
25
- const configKey = components.auth?.['~k'];
26
- throw new Error(formatConfigError({
25
+ throw new ConfigError({
27
26
  message: 'lowdefy.auth is not an object.',
28
- configKey,
27
+ configKey: components['~k'],
29
28
  context
30
- }));
29
+ });
31
30
  }
32
31
  if (type.isNone(components.auth.api)) {
33
32
  components.auth.api = {};
@@ -59,10 +58,35 @@ async function validateAuthConfig({ components, context }) {
59
58
  if (type.isNone(components.auth.theme)) {
60
59
  components.auth.theme = {};
61
60
  }
62
- validate({
61
+ const { valid, errors } = validate({
63
62
  schema: lowdefySchema.definitions.authConfig,
64
- data: components.auth
63
+ data: components.auth,
64
+ returnErrors: true
65
65
  });
66
+ if (!valid) {
67
+ errors.forEach((error)=>{
68
+ // Try to get configKey from the item in the error path
69
+ const instancePath = error.instancePath.split('/').filter(Boolean);
70
+ let configKey = components.auth['~k'];
71
+ let currentData = components.auth;
72
+ for (const part of instancePath){
73
+ if (type.isArray(currentData)) {
74
+ const index = parseInt(part, 10);
75
+ currentData = currentData[index];
76
+ } else {
77
+ currentData = currentData?.[part];
78
+ }
79
+ if (currentData?.['~k']) {
80
+ configKey = currentData['~k'];
81
+ }
82
+ }
83
+ throw new ConfigError({
84
+ message: `Auth ${error.message}.`,
85
+ configKey,
86
+ context
87
+ });
88
+ });
89
+ }
66
90
  validateMutualExclusivity({
67
91
  components,
68
92
  context,
@@ -73,6 +97,14 @@ async function validateAuthConfig({ components, context }) {
73
97
  context,
74
98
  entity: 'pages'
75
99
  });
100
+ // Validate NEXTAUTH_SECRET is set when auth providers are configured
101
+ if (components.auth.providers.length > 0 && type.isNone(process.env.NEXTAUTH_SECRET)) {
102
+ throw new ConfigError({
103
+ message: 'Auth providers are configured but NEXTAUTH_SECRET environment variable is not set. ' + 'Set NEXTAUTH_SECRET to a secure random string (e.g., generate with `openssl rand -base64 32`).',
104
+ configKey: components.auth.providers['~k'] ?? components.auth['~k'],
105
+ context
106
+ });
107
+ }
76
108
  return components;
77
109
  }
78
110
  export default validateAuthConfig;
@@ -13,29 +13,29 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
- import formatConfigError from '../../utils/formatConfigError.js';
16
+ import { ConfigError } from '@lowdefy/node-utils';
17
17
  function validateMutualExclusivity({ components, context, entity }) {
18
18
  const configKey = components.auth[entity]?.['~k'] || components.auth?.['~k'];
19
19
  if (components.auth[entity].protected === true && components.auth[entity].public === true || type.isArray(components.auth[entity].protected) && type.isArray(components.auth[entity].public)) {
20
- throw new Error(formatConfigError({
20
+ throw new ConfigError({
21
21
  message: `Protected and public ${entity} are mutually exclusive. When protected ${entity} are listed, all unlisted ${entity} are public by default and vice versa.`,
22
22
  configKey,
23
23
  context
24
- }));
24
+ });
25
25
  }
26
26
  if (components.auth[entity].protected === false) {
27
- throw new Error(formatConfigError({
27
+ throw new ConfigError({
28
28
  message: `Protected ${entity} can not be set to false.`,
29
29
  configKey,
30
30
  context
31
- }));
31
+ });
32
32
  }
33
33
  if (components.auth[entity].public === false) {
34
- throw new Error(formatConfigError({
34
+ throw new ConfigError({
35
35
  message: `Public ${entity} can not be set to false.`,
36
36
  configKey,
37
37
  context
38
- }));
38
+ });
39
39
  }
40
40
  }
41
41
  export default validateMutualExclusivity;
@@ -12,54 +12,35 @@
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 { type } from '@lowdefy/helpers';
16
- import collectConfigError from '../utils/collectConfigError.js';
17
- import countOperators from '../utils/countOperators.js';
15
+ */ import countOperators from '../utils/countOperators.js';
18
16
  import createCheckDuplicateId from '../utils/createCheckDuplicateId.js';
19
17
  function buildConnections({ components, context }) {
20
18
  // Store connection IDs for validation in buildRequests
21
19
  context.connectionIds = new Set();
20
+ // Schema validates: id required, id is string, type is string
21
+ // Only check for duplicates here (schema can't do that)
22
22
  const checkDuplicateConnectionId = createCheckDuplicateId({
23
23
  message: 'Duplicate connectionId "{{ id }}".',
24
24
  context
25
25
  });
26
- if (type.isArray(components.connections)) {
27
- components.connections.forEach((connection)=>{
28
- const configKey = connection['~k'];
29
- if (type.isUndefined(connection.id)) {
30
- collectConfigError({
31
- message: 'Connection id missing.',
32
- configKey,
33
- context
34
- });
35
- }
36
- if (!type.isString(connection.id)) {
37
- collectConfigError({
38
- message: `Connection id is not a string. Received ${JSON.stringify(connection.id)}.`,
39
- configKey,
40
- context
41
- });
42
- }
43
- checkDuplicateConnectionId({
44
- id: connection.id,
45
- configKey
46
- });
47
- if (!type.isString(connection.type)) {
48
- collectConfigError({
49
- message: `Connection type is not a string at connection "${connection.id}". Received ${JSON.stringify(connection.type)}.`,
50
- configKey,
51
- context
52
- });
53
- }
54
- context.typeCounters.connections.increment(connection.type, connection['~k']);
55
- connection.connectionId = connection.id;
56
- context.connectionIds.add(connection.connectionId);
57
- connection.id = `connection:${connection.id}`;
58
- countOperators(connection.properties || {}, {
59
- counter: context.typeCounters.operators.server
60
- });
26
+ (components.connections ?? []).forEach((connection)=>{
27
+ const configKey = connection['~k'];
28
+ // Check duplicates (schema can't validate this)
29
+ checkDuplicateConnectionId({
30
+ id: connection.id,
31
+ configKey
61
32
  });
62
- }
33
+ // Track type usage for buildTypes validation
34
+ context.typeCounters.connections.increment(connection.type, configKey);
35
+ // Store connectionId for request validation and rename id
36
+ connection.connectionId = connection.id;
37
+ context.connectionIds.add(connection.connectionId);
38
+ connection.id = `connection:${connection.id}`;
39
+ // Count operators in connection properties
40
+ countOperators(connection.properties ?? {}, {
41
+ counter: context.typeCounters.operators.server
42
+ });
43
+ });
63
44
  return components;
64
45
  }
65
46
  export default buildConnections;
@@ -12,9 +12,9 @@
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 { type, resolveConfigLocation } from '@lowdefy/helpers';
15
+ */ import { type } from '@lowdefy/helpers';
16
+ import { ConfigError, resolveConfigLocation } from '@lowdefy/node-utils';
16
17
  import createCheckDuplicateId from '../utils/createCheckDuplicateId.js';
17
- import formatConfigError from '../utils/formatConfigError.js';
18
18
  function buildDefaultMenu({ components, context }) {
19
19
  context.logger.warn('No menus found. Building default menu.');
20
20
  const pages = type.isArray(components.pages) ? components.pages : [];
@@ -96,18 +96,18 @@ function buildMenu({ components, context }) {
96
96
  components.menus.forEach((menu)=>{
97
97
  const configKey = menu['~k'];
98
98
  if (type.isUndefined(menu.id)) {
99
- throw new Error(formatConfigError({
99
+ throw new ConfigError({
100
100
  message: 'Menu id missing.',
101
101
  configKey,
102
102
  context
103
- }));
103
+ });
104
104
  }
105
105
  if (!type.isString(menu.id)) {
106
- throw new Error(formatConfigError({
106
+ throw new ConfigError({
107
107
  message: `Menu id is not a string. Received ${JSON.stringify(menu.id)}.`,
108
108
  configKey,
109
109
  context
110
- }));
110
+ });
111
111
  }
112
112
  checkDuplicateMenuId({
113
113
  id: menu.id,
@@ -129,16 +129,11 @@ function buildMenu({ components, context }) {
129
129
  });
130
130
  });
131
131
  missingPageWarnings.forEach((warning)=>{
132
- const location = resolveConfigLocation({
132
+ context.logger.configWarning({
133
+ message: `Page "${warning.pageId}" referenced in menu link "${warning.menuItemId}" not found.`,
133
134
  configKey: warning.configKey,
134
- keyMap: context.keyMap,
135
- refMap: context.refMap,
136
- configDirectory: context.directories.config
135
+ prodError: true
137
136
  });
138
- const source = location?.source ? `${location.source} at ${location.config}` : '';
139
- const link = location?.link || '';
140
- const message = `Page "${warning.pageId}" referenced in menu link "${warning.menuItemId}" not found.`;
141
- context.logger.warn(`[Config Error] ${message}\n ${source}\n ${link}`);
142
137
  });
143
138
  return components;
144
139
  }
@@ -13,23 +13,23 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
+ import { ConfigError } from '@lowdefy/node-utils';
16
17
  import createCheckDuplicateId from '../../../utils/createCheckDuplicateId.js';
17
- import formatConfigError from '../../../utils/formatConfigError.js';
18
18
  function checkAction(action, { blockId, checkDuplicateActionId, context, eventId, linkActionRefs, pageId, requestActionRefs, typeCounters }) {
19
19
  const configKey = action['~k'];
20
20
  if (type.isUndefined(action.id)) {
21
- throw new Error(formatConfigError({
21
+ throw new ConfigError({
22
22
  message: `Action id missing on event "${eventId}" on block "${blockId}" on page "${pageId}".`,
23
23
  configKey,
24
24
  context
25
- }));
25
+ });
26
26
  }
27
27
  if (!type.isString(action.id)) {
28
- throw new Error(formatConfigError({
28
+ throw new ConfigError({
29
29
  message: `Action id is not a string on event "${eventId}" on block "${blockId}" on page "${pageId}". Received ${JSON.stringify(action.id)}.`,
30
30
  configKey,
31
31
  context
32
- }));
32
+ });
33
33
  }
34
34
  checkDuplicateActionId({
35
35
  id: action.id,
@@ -39,11 +39,11 @@ function checkAction(action, { blockId, checkDuplicateActionId, context, eventId
39
39
  pageId
40
40
  });
41
41
  if (!type.isString(action.type)) {
42
- throw new Error(formatConfigError({
42
+ throw new ConfigError({
43
43
  message: `Action type is not a string on action "${action.id}" on event "${eventId}" on block "${blockId}" on page "${pageId}". Received ${JSON.stringify(action.type)}.`,
44
44
  configKey,
45
45
  context
46
- }));
46
+ });
47
47
  }
48
48
  typeCounters.actions.increment(action.type, configKey);
49
49
  // Collect static Request action references for validation
@@ -98,11 +98,11 @@ function buildEvents(block, pageContext) {
98
98
  Object.keys(block.events).map((key)=>{
99
99
  const eventConfigKey = block.events[key]?.['~k'] || block['~k'];
100
100
  if (!type.isArray(block.events[key]) && !type.isObject(block.events[key]) || type.isObject(block.events[key]) && type.isNone(block.events[key].try)) {
101
- throw new Error(formatConfigError({
101
+ throw new ConfigError({
102
102
  message: `Actions must be an array at "${block.blockId}" in event "${key}" on page "${pageContext.pageId}". Received ${JSON.stringify(block.events[key]?.try)}`,
103
103
  configKey: eventConfigKey,
104
104
  context
105
- }));
105
+ });
106
106
  }
107
107
  if (type.isArray(block.events[key])) {
108
108
  block.events[key] = {
@@ -111,21 +111,21 @@ function buildEvents(block, pageContext) {
111
111
  };
112
112
  }
113
113
  if (!type.isArray(block.events[key].try)) {
114
- throw new Error(formatConfigError({
114
+ throw new ConfigError({
115
115
  message: `Try actions must be an array at "${block.blockId}" in event "${key}.try" on page "${pageContext.pageId}". Received ${JSON.stringify(block.events[key].try)}`,
116
116
  configKey: eventConfigKey,
117
117
  context
118
- }));
118
+ });
119
119
  }
120
120
  if (type.isNone(block.events[key].catch)) {
121
121
  block.events[key].catch = [];
122
122
  }
123
123
  if (!type.isArray(block.events[key].catch)) {
124
- throw new Error(formatConfigError({
124
+ throw new ConfigError({
125
125
  message: `Catch actions must be an array at "${block.blockId}" in event "${key}.catch" on page "${pageContext.pageId}". Received ${JSON.stringify(block.events[key].catch)}`,
126
126
  configKey: eventConfigKey,
127
127
  context
128
- }));
128
+ });
129
129
  }
130
130
  const checkDuplicateActionId = createCheckDuplicateId({
131
131
  message: 'Duplicate actionId "{{ id }}" on event "{{ eventId }}" on block "{{ blockId }}" on page "{{ pageId }}".',
@@ -13,23 +13,23 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
- import formatConfigError from '../../../utils/formatConfigError.js';
16
+ import { ConfigError } from '@lowdefy/node-utils';
17
17
  function buildRequest(request, pageContext) {
18
18
  const { auth, checkDuplicateRequestId, context, pageId, typeCounters } = pageContext;
19
19
  const configKey = request['~k'];
20
20
  if (type.isUndefined(request.id)) {
21
- throw new Error(formatConfigError({
21
+ throw new ConfigError({
22
22
  message: `Request id missing at page "${pageId}".`,
23
23
  configKey,
24
24
  context
25
- }));
25
+ });
26
26
  }
27
27
  if (!type.isString(request.id)) {
28
- throw new Error(formatConfigError({
28
+ throw new ConfigError({
29
29
  message: `Request id is not a string at page "${pageId}". Received ${JSON.stringify(request.id)}.`,
30
30
  configKey,
31
31
  context
32
- }));
32
+ });
33
33
  }
34
34
  checkDuplicateRequestId({
35
35
  id: request.id,
@@ -37,44 +37,44 @@ function buildRequest(request, pageContext) {
37
37
  pageId
38
38
  });
39
39
  if (request.id.includes('.')) {
40
- throw new Error(formatConfigError({
40
+ throw new ConfigError({
41
41
  message: `Request id "${request.id}" at page "${pageId}" should not include a period (".").`,
42
42
  configKey,
43
43
  context
44
- }));
44
+ });
45
45
  }
46
46
  if (!type.isString(request.type)) {
47
- throw new Error(formatConfigError({
47
+ throw new ConfigError({
48
48
  message: `Request type is not a string at request "${request.id}" at page "${pageId}". Received ${JSON.stringify(request.type)}.`,
49
49
  configKey,
50
50
  context
51
- }));
51
+ });
52
52
  }
53
53
  typeCounters.requests.increment(request.type, configKey);
54
54
  // Validate connectionId references an existing connection
55
55
  if (!type.isNone(request.connectionId)) {
56
56
  if (!type.isString(request.connectionId)) {
57
- throw new Error(formatConfigError({
57
+ throw new ConfigError({
58
58
  message: `Request "${request.id}" at page "${pageId}" connectionId is not a string. Received ${JSON.stringify(request.connectionId)}.`,
59
59
  configKey,
60
60
  context
61
- }));
61
+ });
62
62
  }
63
63
  if (!context.connectionIds.has(request.connectionId)) {
64
- throw new Error(formatConfigError({
64
+ throw new ConfigError({
65
65
  message: `Request "${request.id}" at page "${pageId}" references non-existent connection "${request.connectionId}".`,
66
66
  configKey,
67
67
  context
68
- }));
68
+ });
69
69
  }
70
70
  }
71
71
  if (type.isUndefined(request.payload)) request.payload = {};
72
72
  if (!type.isObject(request.payload)) {
73
- throw new Error(formatConfigError({
73
+ throw new ConfigError({
74
74
  message: `Request "${request.id}" at page "${pageId}" payload should be an object.`,
75
75
  configKey,
76
76
  context
77
- }));
77
+ });
78
78
  }
79
79
  request.auth = auth;
80
80
  request.requestId = request.id;
@@ -13,51 +13,51 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
- import formatConfigError from '../../../utils/formatConfigError.js';
16
+ import { ConfigError } from '@lowdefy/node-utils';
17
17
  function validateBlock(block, { pageId, context }) {
18
18
  const configKey = block?.['~k'];
19
19
  if (!type.isObject(block)) {
20
- throw new Error(formatConfigError({
20
+ throw new ConfigError({
21
21
  message: `Expected block to be an object on page "${pageId}". Received ${JSON.stringify(block)}.`,
22
22
  configKey,
23
23
  context
24
- }));
24
+ });
25
25
  }
26
26
  if (type.isUndefined(block.id)) {
27
- throw new Error(formatConfigError({
27
+ throw new ConfigError({
28
28
  message: `Block id missing at page "${pageId}".`,
29
29
  configKey,
30
30
  context
31
- }));
31
+ });
32
32
  }
33
33
  if (!type.isString(block.id)) {
34
- throw new Error(formatConfigError({
34
+ throw new ConfigError({
35
35
  message: `Block id is not a string at page "${pageId}". Received ${JSON.stringify(block.id)}.`,
36
36
  configKey,
37
37
  context
38
- }));
38
+ });
39
39
  }
40
40
  if (type.isNone(block.type)) {
41
- throw new Error(formatConfigError({
41
+ throw new ConfigError({
42
42
  message: `Block type is not defined at "${block.id}" on page "${pageId}".`,
43
43
  configKey,
44
44
  context
45
- }));
45
+ });
46
46
  }
47
47
  if (!type.isString(block.type)) {
48
- throw new Error(formatConfigError({
48
+ throw new ConfigError({
49
49
  message: `Block type is not a string at "${block.id}" on page "${pageId}". Received ${JSON.stringify(block.type)}.`,
50
50
  configKey,
51
51
  context
52
- }));
52
+ });
53
53
  }
54
54
  if (!type.isNone(block.requests)) {
55
55
  if (!type.isArray(block.requests)) {
56
- throw new Error(formatConfigError({
56
+ throw new ConfigError({
57
57
  message: `Requests is not an array at "${block.id}" on page "${pageId}". Received ${JSON.stringify(block.requests)}`,
58
58
  configKey,
59
59
  context
60
- }));
60
+ });
61
61
  }
62
62
  }
63
63
  }