@lowdefy/build 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/index.js CHANGED
@@ -144,11 +144,12 @@ async function build(options) {
144
144
  // appMeta is computed in Phase 0; attach it here (where buildApp used to
145
145
  // create it) so the following addKeys pass keys it identically.
146
146
  components.appMeta = context.appMeta;
147
- tryBuildStep(buildLogger, 'buildLogger', {
147
+ // validateConfig resolves the current environment, which buildLogger reads for Sentry.
148
+ tryBuildStep(validateConfig, 'validateConfig', {
148
149
  components,
149
150
  context
150
151
  });
151
- tryBuildStep(validateConfig, 'validateConfig', {
152
+ tryBuildStep(buildLogger, 'buildLogger', {
152
153
  components,
153
154
  context
154
155
  });
@@ -1545,7 +1545,7 @@ export default {
1545
1545
  }
1546
1546
  },
1547
1547
  schedules: {
1548
- description: 'Cron schedules that run the routine on a timer: an array (the same in every environment), or with config.cron.environments declared an object keyed by environment name with an optional "default" key that every other environment inherits ("staging: []" turns crons off for staging).',
1548
+ description: 'Cron schedules that run the routine on a timer: an array (the same in every environment), or with config.environments declared an object keyed by environment name with an optional "default" key that every other environment inherits ("staging: []" turns crons off for staging).',
1549
1549
  anyOf: [
1550
1550
  {
1551
1551
  type: 'array',
@@ -2452,63 +2452,171 @@ export default {
2452
2452
  }
2453
2453
  }
2454
2454
  },
2455
- cron: {
2456
- type: 'object',
2457
- additionalProperties: false,
2458
- description: "Deployment environments for scheduled endpoints. Vercel fires cron jobs only on the production deployment, so every environment's schedules are registered there and production forwards the ones for other environments to their own /api/cron route.",
2459
- required: [
2460
- 'environments'
2461
- ],
2455
+ environment: {
2456
+ type: 'string',
2457
+ description: 'The environment this build is for, one of the names in "config.environments". Used when the LOWDEFY_ENVIRONMENT environment variable is not set; the variable always wins.',
2462
2458
  errorMessage: {
2463
- type: 'App "config.cron" should be an object.',
2464
- required: {
2465
- environments: 'App "config.cron" should have required property "environments".'
2466
- }
2467
- },
2468
- properties: {
2469
- '~k': {},
2470
- '~r': {},
2471
- '~l': {},
2472
- environments: {
2473
- type: 'object',
2474
- description: 'Environments keyed by name. Exactly one environment has no "url": the deployment whose crons Vercel fires. Every other environment needs a "url" (its deployment origin) and a "secret" (the Lowdefy secret name holding that environment\'s CRON_SECRET, set on the production deployment).',
2475
- additionalProperties: {
2459
+ type: 'App "config.environment" should be a string.'
2460
+ }
2461
+ },
2462
+ environments: {
2463
+ type: 'object',
2464
+ description: 'The deployment environments of the app, keyed by name. The current environment (LOWDEFY_ENVIRONMENT) supplies the defaults for everything environment-specific: the app url (auth, notification links), cron forwarding, the email delivery filter and the Sentry environment. Endpoint "schedules" can be keyed by these names.',
2465
+ additionalProperties: {
2466
+ type: 'object',
2467
+ additionalProperties: false,
2468
+ properties: {
2469
+ '~k': {},
2470
+ '~r': {},
2471
+ '~l': {},
2472
+ url: {
2473
+ type: 'string',
2474
+ description: 'The environment deployment origin, e.g. https://staging.example.com. Default for the auth base URL and notification links, and where crons are forwarded to.',
2475
+ errorMessage: {
2476
+ type: 'App "config.environments.<name>.url" should be a string.'
2477
+ }
2478
+ },
2479
+ cron: {
2476
2480
  type: 'object',
2477
2481
  additionalProperties: false,
2478
2482
  properties: {
2479
2483
  '~k': {},
2480
2484
  '~r': {},
2481
2485
  '~l': {},
2482
- url: {
2483
- type: 'string',
2484
- description: 'The environment deployment origin, e.g. https://staging.example.com.',
2485
- errorMessage: {
2486
- type: 'App "config.cron.environments.<name>.url" should be a string.'
2487
- }
2488
- },
2489
2486
  secret: {
2490
2487
  type: 'string',
2491
- description: "Lowdefy secret name (LOWDEFY_SECRET_<name> env var) holding this environment's CRON_SECRET.",
2488
+ description: "The NAME of the Lowdefy secret (a plain string, not a _secret operator; read from the LOWDEFY_SECRET_<name> env var on the deployment that forwards) holding this environment's CRON_SECRET. An environment with a secret is forwarded to: the environment Vercel fires crons on pings its /api/cron route when one of its schedules fires.",
2492
2489
  errorMessage: {
2493
- type: 'App "config.cron.environments.<name>.secret" should be a string.'
2490
+ type: 'App "config.environments.<name>.cron.secret" should be a string.'
2494
2491
  }
2495
2492
  },
2496
2493
  enabled: {
2497
2494
  type: 'boolean',
2498
2495
  description: 'Set false to register no cron jobs for this environment. Defaults to true.',
2499
2496
  errorMessage: {
2500
- type: 'App "config.cron.environments.<name>.enabled" should be a boolean.'
2497
+ type: 'App "config.environments.<name>.cron.enabled" should be a boolean.'
2501
2498
  }
2502
2499
  }
2503
2500
  },
2504
2501
  errorMessage: {
2505
- type: 'App "config.cron.environments.<name>" should be an object.'
2502
+ type: 'App "config.environments.<name>.cron" should be an object.'
2506
2503
  }
2507
2504
  },
2508
- errorMessage: {
2509
- type: 'App "config.cron.environments" should be an object.'
2505
+ email: {
2506
+ type: 'object',
2507
+ additionalProperties: false,
2508
+ properties: {
2509
+ '~k': {},
2510
+ '~r': {},
2511
+ '~l': {},
2512
+ enabled: {
2513
+ type: 'boolean',
2514
+ description: 'Set false to send no email from SMTPMailSend and SendGridMailSend requests in this environment. Auth emails still send. Defaults to true.',
2515
+ errorMessage: {
2516
+ type: 'App "config.environments.<name>.email.enabled" should be a boolean.'
2517
+ }
2518
+ },
2519
+ filter: {
2520
+ type: 'object',
2521
+ description: 'Delivery filter applied to every SMTPMailSend and SendGridMailSend request in this environment, unless the connection sets its own "filter" (false turns filtering off for that connection). Auth emails are not filtered.',
2522
+ additionalProperties: false,
2523
+ properties: {
2524
+ '~k': {},
2525
+ '~r': {},
2526
+ '~l': {},
2527
+ replaceAddress: {
2528
+ type: [
2529
+ 'string',
2530
+ 'null'
2531
+ ],
2532
+ description: 'Send every email to this address instead of its recipients.'
2533
+ },
2534
+ allowlist: {
2535
+ type: 'array',
2536
+ items: {
2537
+ type: 'string'
2538
+ },
2539
+ description: 'Only deliver to recipients on these domains.'
2540
+ },
2541
+ regex: {
2542
+ type: 'string',
2543
+ description: 'Only deliver to recipients matching this regular expression.'
2544
+ }
2545
+ },
2546
+ errorMessage: {
2547
+ type: 'App "config.environments.<name>.email.filter" should be an object.'
2548
+ }
2549
+ }
2550
+ },
2551
+ errorMessage: {
2552
+ type: 'App "config.environments.<name>.email" should be an object.'
2553
+ }
2554
+ },
2555
+ guards: {
2556
+ type: 'object',
2557
+ additionalProperties: false,
2558
+ description: 'Pin secrets and environment variables to a regular expression kept in config: in this environment the build fails unless each value matches (a missing value fails too). Changing a guarded value then takes a config change as well. Values are never printed.',
2559
+ properties: {
2560
+ '~k': {},
2561
+ '~r': {},
2562
+ '~l': {},
2563
+ secrets: {
2564
+ type: 'object',
2565
+ description: 'Lowdefy secret name (LOWDEFY_SECRET_<name>) to the regular expression its value must match.',
2566
+ additionalProperties: {
2567
+ type: 'string',
2568
+ errorMessage: {
2569
+ type: 'App "config.environments.<name>.guards.secrets.<name>" should be a regular expression string.'
2570
+ }
2571
+ },
2572
+ errorMessage: {
2573
+ type: 'App "config.environments.<name>.guards.secrets" should be an object.'
2574
+ }
2575
+ },
2576
+ env: {
2577
+ type: 'object',
2578
+ description: 'Environment variable name to the regular expression its value must match.',
2579
+ additionalProperties: {
2580
+ type: 'string',
2581
+ errorMessage: {
2582
+ type: 'App "config.environments.<name>.guards.env.<name>" should be a regular expression string.'
2583
+ }
2584
+ },
2585
+ errorMessage: {
2586
+ type: 'App "config.environments.<name>.guards.env" should be an object.'
2587
+ }
2588
+ }
2589
+ },
2590
+ errorMessage: {
2591
+ type: 'App "config.environments.<name>.guards" should be an object.'
2592
+ }
2593
+ },
2594
+ sentry: {
2595
+ type: 'object',
2596
+ additionalProperties: false,
2597
+ properties: {
2598
+ '~k': {},
2599
+ '~r': {},
2600
+ '~l': {},
2601
+ enabled: {
2602
+ type: 'boolean',
2603
+ description: 'Set false to turn Sentry off (server and client) in this environment. Defaults to true.',
2604
+ errorMessage: {
2605
+ type: 'App "config.environments.<name>.sentry.enabled" should be a boolean.'
2606
+ }
2607
+ }
2608
+ },
2609
+ errorMessage: {
2610
+ type: 'App "config.environments.<name>.sentry" should be an object.'
2611
+ }
2510
2612
  }
2613
+ },
2614
+ errorMessage: {
2615
+ type: 'App "config.environments.<name>" should be an object.'
2511
2616
  }
2617
+ },
2618
+ errorMessage: {
2619
+ type: 'App "config.environments" should be an object.'
2512
2620
  }
2513
2621
  },
2514
2622
  requestTimeout: {
@@ -54,6 +54,9 @@ import createTestLogger from './createTestLogger.js';
54
54
  Button: {
55
55
  package: '@lowdefy/blocks-basic'
56
56
  },
57
+ ClickableHtml: {
58
+ package: '@lowdefy/blocks-basic'
59
+ },
57
60
  DangerousHtml: {
58
61
  package: '@lowdefy/blocks-basic'
59
62
  },
@@ -87,6 +87,9 @@ import path from 'path';
87
87
  Button: {
88
88
  package: '@lowdefy/blocks-basic'
89
89
  },
90
+ ClickableHtml: {
91
+ package: '@lowdefy/blocks-basic'
92
+ },
90
93
  DangerousHtml: {
91
94
  package: '@lowdefy/blocks-basic'
92
95
  },
@@ -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
- */ // The declared environment names in config.cron.environments. Build key markers (~k, ~r, ~l) live
16
- // on the same object as the environments, so they are skipped rather than treated as names.
15
+ */ // The declared environment names in config.environments.
16
+ // Build key markers (~k, ~r, ~l) live on the same object as the environments, so they are skipped
17
+ // rather than treated as names.
17
18
  const markerKeys = new Set([
18
19
  '~k',
19
20
  '~r',
20
21
  '~l'
21
22
  ]);
22
- function getCronEnvironmentNames(environments) {
23
+ function getEnvironmentNames(environments) {
23
24
  return Object.keys(environments ?? {}).filter((key)=>!markerKeys.has(key));
24
25
  }
25
- export default getCronEnvironmentNames;
26
+ export default getEnvironmentNames;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowdefy/build",
3
- "version": "6.0.0",
3
+ "version": "6.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "",
6
6
  "homepage": "https://lowdefy.com",
@@ -46,71 +46,71 @@
46
46
  "dist/*"
47
47
  ],
48
48
  "dependencies": {
49
- "@lowdefy/ai-utils": "6.0.0",
50
- "@lowdefy/ajv": "6.0.0",
51
- "@lowdefy/block-utils": "6.0.0",
52
- "@lowdefy/blocks-basic": "6.0.0",
53
- "@lowdefy/blocks-loaders": "6.0.0",
54
- "@lowdefy/errors": "6.0.0",
55
- "@lowdefy/helpers": "6.0.0",
56
- "@lowdefy/node-utils": "6.0.0",
57
- "@lowdefy/nunjucks": "6.0.0",
58
- "@lowdefy/operators": "6.0.0",
59
- "@lowdefy/operators-js": "6.0.0",
49
+ "@lowdefy/ai-utils": "6.1.0",
50
+ "@lowdefy/ajv": "6.1.0",
51
+ "@lowdefy/block-utils": "6.1.0",
52
+ "@lowdefy/blocks-basic": "6.1.0",
53
+ "@lowdefy/blocks-loaders": "6.1.0",
54
+ "@lowdefy/errors": "6.1.0",
55
+ "@lowdefy/helpers": "6.1.0",
56
+ "@lowdefy/node-utils": "6.1.0",
57
+ "@lowdefy/nunjucks": "6.1.0",
58
+ "@lowdefy/operators": "6.1.0",
59
+ "@lowdefy/operators-js": "6.1.0",
60
60
  "ajv": "8.20.0",
61
61
  "json5": "2.2.3",
62
- "picomatch": "4.0.1",
62
+ "picomatch": "4.0.4",
63
63
  "semver": "7.7.4",
64
- "tar": "7.5.13",
64
+ "tar": "7.5.21",
65
65
  "yaml": "2.9.0",
66
66
  "yargs": "18.0.0"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@jest/globals": "28.1.3",
70
- "@lowdefy/actions-core": "6.0.0",
71
- "@lowdefy/actions-pdf-make": "6.0.0",
72
- "@lowdefy/blocks-aggrid": "6.0.0",
73
- "@lowdefy/blocks-antd": "6.0.0",
74
- "@lowdefy/blocks-antd-x": "6.0.0",
75
- "@lowdefy/blocks-diff": "6.0.0",
76
- "@lowdefy/blocks-echarts": "6.0.0",
77
- "@lowdefy/blocks-files": "6.0.0",
78
- "@lowdefy/blocks-google-maps": "6.0.0",
79
- "@lowdefy/blocks-markdown": "6.0.0",
80
- "@lowdefy/blocks-qr": "6.0.0",
81
- "@lowdefy/blocks-tiptap": "6.0.0",
82
- "@lowdefy/connection-ai-gateway": "6.0.0",
83
- "@lowdefy/connection-anthropic": "6.0.0",
84
- "@lowdefy/connection-axios-http": "6.0.0",
85
- "@lowdefy/connection-elasticsearch": "6.0.0",
86
- "@lowdefy/connection-google": "6.0.0",
87
- "@lowdefy/connection-google-sheets": "6.0.0",
88
- "@lowdefy/connection-knex": "6.0.0",
89
- "@lowdefy/connection-mcp": "6.0.0",
90
- "@lowdefy/connection-mongodb": "6.0.0",
91
- "@lowdefy/connection-openai": "6.0.0",
92
- "@lowdefy/connection-redis": "6.0.0",
93
- "@lowdefy/connection-sendgrid": "6.0.0",
94
- "@lowdefy/connection-smtp": "6.0.0",
95
- "@lowdefy/connection-stripe": "6.0.0",
96
- "@lowdefy/connection-test": "6.0.0",
97
- "@lowdefy/email-templates": "6.0.0",
98
- "@lowdefy/logger": "6.0.0",
99
- "@lowdefy/operators-change-case": "6.0.0",
100
- "@lowdefy/operators-dayjs": "6.0.0",
101
- "@lowdefy/operators-diff": "6.0.0",
102
- "@lowdefy/operators-jsonata": "6.0.0",
103
- "@lowdefy/operators-mql": "6.0.0",
104
- "@lowdefy/operators-nunjucks": "6.0.0",
105
- "@lowdefy/operators-uuid": "6.0.0",
106
- "@lowdefy/operators-yaml": "6.0.0",
107
- "@lowdefy/plugin-auth0": "6.0.0",
108
- "@lowdefy/plugin-aws": "6.0.0",
109
- "@lowdefy/plugin-azure": "6.0.0",
110
- "@lowdefy/plugin-csv": "6.0.0",
111
- "@lowdefy/plugin-gcp": "6.0.0",
112
- "@lowdefy/plugin-next-auth": "6.0.0",
113
- "@lowdefy/websockets-core": "6.0.0",
70
+ "@lowdefy/actions-core": "6.1.0",
71
+ "@lowdefy/actions-pdf-make": "6.1.0",
72
+ "@lowdefy/blocks-aggrid": "6.1.0",
73
+ "@lowdefy/blocks-antd": "6.1.0",
74
+ "@lowdefy/blocks-antd-x": "6.1.0",
75
+ "@lowdefy/blocks-diff": "6.1.0",
76
+ "@lowdefy/blocks-echarts": "6.1.0",
77
+ "@lowdefy/blocks-files": "6.1.0",
78
+ "@lowdefy/blocks-google-maps": "6.1.0",
79
+ "@lowdefy/blocks-markdown": "6.1.0",
80
+ "@lowdefy/blocks-qr": "6.1.0",
81
+ "@lowdefy/blocks-tiptap": "6.1.0",
82
+ "@lowdefy/connection-ai-gateway": "6.1.0",
83
+ "@lowdefy/connection-anthropic": "6.1.0",
84
+ "@lowdefy/connection-axios-http": "6.1.0",
85
+ "@lowdefy/connection-elasticsearch": "6.1.0",
86
+ "@lowdefy/connection-google": "6.1.0",
87
+ "@lowdefy/connection-google-sheets": "6.1.0",
88
+ "@lowdefy/connection-knex": "6.1.0",
89
+ "@lowdefy/connection-mcp": "6.1.0",
90
+ "@lowdefy/connection-mongodb": "6.1.0",
91
+ "@lowdefy/connection-openai": "6.1.0",
92
+ "@lowdefy/connection-redis": "6.1.0",
93
+ "@lowdefy/connection-sendgrid": "6.1.0",
94
+ "@lowdefy/connection-smtp": "6.1.0",
95
+ "@lowdefy/connection-stripe": "6.1.0",
96
+ "@lowdefy/connection-test": "6.1.0",
97
+ "@lowdefy/email-templates": "6.1.0",
98
+ "@lowdefy/logger": "6.1.0",
99
+ "@lowdefy/operators-change-case": "6.1.0",
100
+ "@lowdefy/operators-dayjs": "6.1.0",
101
+ "@lowdefy/operators-diff": "6.1.0",
102
+ "@lowdefy/operators-jsonata": "6.1.0",
103
+ "@lowdefy/operators-mql": "6.1.0",
104
+ "@lowdefy/operators-nunjucks": "6.1.0",
105
+ "@lowdefy/operators-uuid": "6.1.0",
106
+ "@lowdefy/operators-yaml": "6.1.0",
107
+ "@lowdefy/plugin-auth0": "6.1.0",
108
+ "@lowdefy/plugin-aws": "6.1.0",
109
+ "@lowdefy/plugin-azure": "6.1.0",
110
+ "@lowdefy/plugin-csv": "6.1.0",
111
+ "@lowdefy/plugin-gcp": "6.1.0",
112
+ "@lowdefy/plugin-next-auth": "6.1.0",
113
+ "@lowdefy/websockets-core": "6.1.0",
114
114
  "@swc/cli": "0.8.1",
115
115
  "@swc/core": "1.15.32",
116
116
  "@swc/jest": "0.2.39",
@@ -1,110 +0,0 @@
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 { ConfigError } from '@lowdefy/errors';
17
- import getCronEnvironmentNames from '../utils/getCronEnvironmentNames.js';
18
- // Environment names become a path segment (/api/cron-forward/<environment>/<endpointId>).
19
- const environmentNamePattern = /^[A-Za-z0-9\-_]+$/;
20
- function isAbsoluteHttpUrl(value) {
21
- try {
22
- const url = new URL(value);
23
- return url.protocol === 'http:' || url.protocol === 'https:';
24
- } catch {
25
- return false;
26
- }
27
- }
28
- // Returns true when the environment is forwarded to (has a url), false for the host environment.
29
- function validateCronEnvironment({ name, environment, configKey }) {
30
- if (name === 'default') {
31
- throw new ConfigError('Cron environment name "default" is reserved: it names the schedules every environment inherits.', {
32
- configKey
33
- });
34
- }
35
- if (!environmentNamePattern.test(name)) {
36
- throw new ConfigError(`Cron environment name "${name}" is invalid. Environment names must only contain A-Z, a-z, 0-9, "-" and "_".`, {
37
- configKey
38
- });
39
- }
40
- if (!type.isObject(environment)) {
41
- throw new ConfigError(`Cron environment "${name}" is not an object.`, {
42
- received: environment,
43
- configKey
44
- });
45
- }
46
- if (!type.isUndefined(environment.enabled) && !type.isBoolean(environment.enabled)) {
47
- throw new ConfigError(`Cron environment "${name}" enabled is not a boolean.`, {
48
- received: environment.enabled,
49
- configKey: environment['~k'] ?? configKey
50
- });
51
- }
52
- if (type.isUndefined(environment.url)) {
53
- if (!type.isUndefined(environment.secret)) {
54
- throw new ConfigError(`Cron environment "${name}" has a secret but no url. The environment without a url is the deployment that runs the crons and needs no secret.`, {
55
- configKey: environment['~k'] ?? configKey
56
- });
57
- }
58
- return false;
59
- }
60
- if (!type.isString(environment.url) || !isAbsoluteHttpUrl(environment.url)) {
61
- throw new ConfigError(`Cron environment "${name}" url is not an absolute http(s) URL, e.g. "https://staging.example.com".`, {
62
- received: environment.url,
63
- configKey: environment['~k'] ?? configKey
64
- });
65
- }
66
- if (!type.isString(environment.secret) || environment.secret === '') {
67
- throw new ConfigError(`Cron environment "${name}" has a url but no secret. Set secret to the Lowdefy secret name that holds the environment's CRON_SECRET.`, {
68
- received: environment.secret,
69
- configKey: environment['~k'] ?? configKey
70
- });
71
- }
72
- return true;
73
- }
74
- // Validates config.cron: the deployment environments scheduled endpoints run in. Exactly one
75
- // environment has no url — the deployment whose crons Vercel fires — and every other environment
76
- // is forwarded to from there, so it needs a url and the secret that authorizes the forwarded call.
77
- function validateCronConfig({ components }) {
78
- const cron = components.config.cron;
79
- if (type.isUndefined(cron)) return;
80
- const configKey = cron['~k'] ?? components.config['~k'];
81
- if (!type.isObject(cron)) {
82
- throw new ConfigError('lowdefy.config.cron is not an object.', {
83
- received: cron,
84
- configKey
85
- });
86
- }
87
- if (!type.isObject(cron.environments)) {
88
- throw new ConfigError('lowdefy.config.cron.environments is not an object.', {
89
- received: cron.environments,
90
- configKey
91
- });
92
- }
93
- const names = getCronEnvironmentNames(cron.environments);
94
- if (names.length === 0) {
95
- throw new ConfigError('lowdefy.config.cron.environments declares no environments.', {
96
- configKey
97
- });
98
- }
99
- const hosts = names.filter((name)=>!validateCronEnvironment({
100
- name,
101
- environment: cron.environments[name],
102
- configKey
103
- }));
104
- if (hosts.length !== 1) {
105
- throw new ConfigError(`Exactly one environment in lowdefy.config.cron.environments must have no url (the deployment that runs the crons). Received ${JSON.stringify(hosts)}.`, {
106
- configKey
107
- });
108
- }
109
- }
110
- export default validateCronConfig;