@boltic/cli 1.0.4 → 1.0.6-beta.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.
@@ -19,7 +19,7 @@ const setEnvironment = async (environment) => {
19
19
 
20
20
  const getEnvironment = async (configData) => {
21
21
  try {
22
- return configData.environment || "uat";
22
+ return configData?.environment || "bolt";
23
23
  } catch (error) {
24
24
  handleError(error);
25
25
  }
package/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import fs from "fs";
3
+ import path from "path";
3
4
  import EnvironmentCommands from "./commands/env.js";
4
5
  import IntegrationCommands from "./commands/integration.js";
5
6
  import AuthCommands from "./commands/login.js";
@@ -73,8 +74,12 @@ const createCLI = (consoleUrl, apiUrl, serviceName, env) => {
73
74
  return;
74
75
  }
75
76
 
76
- // Check if user is authenticated for all commands except login and help
77
- if (command !== "login" && command !== "help") {
77
+ // Check if user is authenticated for all commands except login, help, and version
78
+ if (
79
+ command !== "login" &&
80
+ command !== "help" &&
81
+ command !== "version"
82
+ ) {
78
83
  const secrets = await getAllSecrets();
79
84
  const userData = secrets?.reduce(
80
85
  (acc, { account, password }) => {
@@ -101,9 +106,16 @@ const createCLI = (consoleUrl, apiUrl, serviceName, env) => {
101
106
  };
102
107
 
103
108
  async function showHelp(commands) {
104
- const packageJson = JSON.parse(
105
- fs.readFileSync(new URL("./package.json", import.meta.url))
106
- );
109
+ let packageJson;
110
+ try {
111
+ // Try to read package.json from current directory
112
+ packageJson = JSON.parse(
113
+ fs.readFileSync(path.join(process.cwd(), "package.json"))
114
+ );
115
+ } catch (error) {
116
+ // Fallback version if package.json not found
117
+ packageJson = { version: "1.0.0" };
118
+ }
107
119
  const version = packageJson.version;
108
120
 
109
121
  console.log(chalk.bold.yellow(`\nBoltic CLI Version: ${version}\n`));
@@ -127,9 +139,16 @@ async function handleEnvironment(args) {
127
139
  }
128
140
 
129
141
  async function showVersion() {
130
- const packageJson = JSON.parse(
131
- fs.readFileSync(new URL("./package.json", import.meta.url))
132
- );
142
+ let packageJson;
143
+ try {
144
+ // Try to read package.json from current directory
145
+ packageJson = JSON.parse(
146
+ fs.readFileSync(path.join(process.cwd(), "package.json"))
147
+ );
148
+ } catch (error) {
149
+ // Fallback version if package.json not found
150
+ packageJson = { version: "1.0.0" };
151
+ }
133
152
  const version = packageJson.version;
134
153
  console.log(`Boltic CLI Version: ${version}`);
135
154
  }
@@ -173,6 +173,21 @@ async function handleSync(args) {
173
173
  console.log(chalk.cyan(`\nSyncing integration: ${specContent.name}`));
174
174
 
175
175
  console.log("Validating schemas...");
176
+
177
+ // Validate resources
178
+ const { validateIntegrationSchemas } = await import(
179
+ "../helper/validation.js"
180
+ );
181
+ const validationResult = validateIntegrationSchemas(currentDir);
182
+ if (!validationResult.success) {
183
+ if (Array.isArray(validationResult.errors)) {
184
+ validationResult.errors.forEach((error) => {
185
+ console.error(chalk.red(`\n❌ ${error}`));
186
+ });
187
+ }
188
+ return;
189
+ }
190
+
176
191
  const schemas = await readSchemaFiles(currentDir);
177
192
  schemas.status = "draft";
178
193
 
@@ -256,6 +271,22 @@ async function handlePublish(args) {
256
271
  console.log(chalk.cyan(`\nSyncing integration: ${specContent.name}`));
257
272
 
258
273
  console.log("Validating schemas...");
274
+
275
+ // Validate resources
276
+ const { validateIntegrationSchemas } = await import(
277
+ "../helper/validation.js"
278
+ );
279
+ const validationResult = validateIntegrationSchemas(currentDir);
280
+ if (!validationResult.success) {
281
+ if (Array.isArray(validationResult.errors)) {
282
+ validationResult.errors.forEach((error) => {
283
+ console.error(chalk.red(`\n❌ ${error}`));
284
+ });
285
+ }
286
+
287
+ return;
288
+ }
289
+
259
290
  const schemas = await readSchemaFiles(currentDir);
260
291
  schemas.status = "draft";
261
292
 
package/helper/env.js CHANGED
@@ -6,8 +6,16 @@ import { getAllSecrets } from "./secure-storage.js";
6
6
  * @returns {Object} Environment configuration including apiUrl, token, session, and accountId
7
7
  */
8
8
  export const getCurrentEnv = async () => {
9
- const secrets = await getAllSecrets();
9
+ let secrets;
10
10
  let config;
11
+
12
+ try {
13
+ secrets = await getAllSecrets();
14
+ } catch (_) {
15
+ // If getAllSecrets fails, use default bolt environment
16
+ secrets = null;
17
+ }
18
+
11
19
  if (secrets && secrets.length > 0) {
12
20
  config = secrets.reduce((acc, { account, password }) => {
13
21
  acc[account] = password;
package/helper/folder.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import fs from "fs";
3
+ import isEmpty from "lodash.isempty";
3
4
  import path from "path";
4
5
  import {
5
6
  authentication,
@@ -48,30 +49,12 @@ export const createIntegrationFolderStructure = async (integration) => {
48
49
  "schemas/resources/resource1.json": JSON.stringify(resource1, null, 4),
49
50
  "schemas/authentication.json": JSON.stringify(authentication, null, 4),
50
51
  "schemas/base.json": JSON.stringify(base(name), null, 4),
51
- "schemas/webhook.json": JSON.stringify(webhook(name), null, 4),
52
+ ...(!isEmpty(trigger_type) && {
53
+ "schemas/webhook.json": JSON.stringify(webhook(name), null, 4),
54
+ }),
52
55
  "spec.json": JSON.stringify(spec, null, 4),
53
- "Authentication.mdx": `# ${name} Authentication
54
-
55
- Describe the authentication process for ${name} integration here.`,
56
- "Documentation.mdx": `# ${name} Documentation
57
-
58
- ${description}
59
-
60
- ## Overview
61
-
62
- Add integration overview here.
63
-
64
- ## Features
65
-
66
- - Feature 1
67
- - Feature 2
68
- - Feature 3
69
-
70
- ## Setup Guide
71
-
72
- 1. Step 1
73
- 2. Step 2
74
- 3. Step 3`,
56
+ "Authentication.mdx": `# ${name} Authentication`,
57
+ "Documentation.mdx": `# ${name} Documentation`,
75
58
  };
76
59
 
77
60
  // Create all files
@@ -0,0 +1,195 @@
1
+ import fs from "fs";
2
+ import isEmpty from "lodash.isempty";
3
+ import path from "path";
4
+
5
+ const readAndParseJson = (filePath, fileLabel, errors) => {
6
+ try {
7
+ const content = fs.readFileSync(filePath, "utf8");
8
+ if (!content.trim()) {
9
+ errors.add(`"${fileLabel}" is empty.`);
10
+ return null;
11
+ }
12
+ return JSON.parse(content);
13
+ } catch (e) {
14
+ errors.add(`Failed to read or parse "${fileLabel}": ${e.message}`);
15
+ return null;
16
+ }
17
+ };
18
+
19
+ const findResourceFieldsWithOptions = (schema) => {
20
+ const resourceFields = [];
21
+ if (Array.isArray(schema?.parameters)) {
22
+ schema.parameters.forEach((param) => {
23
+ if (
24
+ param.name === "resource" &&
25
+ Array.isArray(param.meta?.options)
26
+ ) {
27
+ resourceFields.push(
28
+ ...param.meta.options.map((opt) => opt.value)
29
+ );
30
+ }
31
+ });
32
+ }
33
+ return resourceFields;
34
+ };
35
+
36
+ const findOperationFieldsWithOptions = (schema) => {
37
+ const operationFields = [];
38
+ if (Array.isArray(schema?.parameters)) {
39
+ schema.parameters.forEach((param) => {
40
+ if (
41
+ param.name === "operation" &&
42
+ Array.isArray(param.meta?.options)
43
+ ) {
44
+ operationFields.push(
45
+ ...param.meta.options.map((opt) => opt.value)
46
+ );
47
+ }
48
+ });
49
+ }
50
+ return operationFields;
51
+ };
52
+
53
+ // ─────────────────────────────────────────────────────────────────────────────
54
+ // INDIVIDUAL VALIDATORS
55
+ // ─────────────────────────────────────────────────────────────────────────────
56
+
57
+ const validateDocumentation = (docPath, errors) => {
58
+ if (!fs.existsSync(docPath)) {
59
+ errors.add(`"Documentation.mdx" not found in the root directory.`);
60
+ }
61
+ };
62
+
63
+ const validateSpec = (specPath, errors) => {
64
+ if (!fs.existsSync(specPath)) {
65
+ errors.add(`"spec.json" not found in the root directory.`);
66
+ return null;
67
+ }
68
+ const spec = readAndParseJson(specPath, "spec.json", errors);
69
+ return spec;
70
+ };
71
+
72
+ const validateWebhook = (webhookPath, spec, errors) => {
73
+ const hasTrigger = spec && !isEmpty(spec.trigger_type);
74
+ const hasWebhook = fs.existsSync(webhookPath);
75
+
76
+ if (hasTrigger && !hasWebhook) {
77
+ errors.add(
78
+ `"webhook.json" not found, but trigger_type is defined in spec.json.`
79
+ );
80
+ }
81
+ if (!hasTrigger && hasWebhook) {
82
+ errors.add(
83
+ `"webhook.json" exists but trigger_type is not defined in spec.json.`
84
+ );
85
+ }
86
+ };
87
+
88
+ const validateBaseSchema = (baseSchemaPath, errors) => {
89
+ if (!fs.existsSync(baseSchemaPath)) {
90
+ errors.add(`"base.json" not found in the "schemas" directory.`);
91
+ return null;
92
+ }
93
+ return readAndParseJson(baseSchemaPath, "base.json", errors);
94
+ };
95
+
96
+ const validateResources = (resourcesDir, resourceFields, errors) => {
97
+ if (!fs.existsSync(resourcesDir)) {
98
+ errors.add(`"resources" directory not found in "schemas".`);
99
+ return;
100
+ }
101
+
102
+ const resourceFiles = fs
103
+ .readdirSync(resourcesDir)
104
+ .filter((f) => f.endsWith(".json"))
105
+ .map((f) => path.basename(f, ".json"));
106
+
107
+ // Check for missing resource files
108
+ resourceFields.forEach((field) => {
109
+ if (!resourceFiles.includes(field)) {
110
+ errors.add(`Resource file: "${field}.json" is missing.`);
111
+ }
112
+ });
113
+
114
+ // Validate each resource file
115
+ resourceFiles.forEach((resourceFile) => {
116
+ const filePath = path.join(resourcesDir, `${resourceFile}.json`);
117
+ const schema = readAndParseJson(
118
+ filePath,
119
+ `${resourceFile}.json`,
120
+ errors
121
+ );
122
+ if (!schema) return;
123
+
124
+ const operationFields = findOperationFieldsWithOptions(schema);
125
+
126
+ operationFields.forEach((operation) => {
127
+ const operationMethod = operation.split(".")[1];
128
+
129
+ if (!operationMethod) {
130
+ errors.add(
131
+ `Invalid format for operation "${operation}" in "${resourceFile}.json". Use "resource.operation".`
132
+ );
133
+ return;
134
+ }
135
+
136
+ const methodDef = schema[operationMethod];
137
+ if (!methodDef) {
138
+ errors.add(
139
+ `Operation "${operationMethod}" missing in "${resourceFile}.json".`
140
+ );
141
+ return;
142
+ }
143
+ if (!methodDef.parameters) {
144
+ errors.add(
145
+ `Operation "${operationMethod}" in "${resourceFile}.json" is missing parameters.`
146
+ );
147
+ }
148
+ if (!methodDef.definition) {
149
+ errors.add(
150
+ `Operation "${operationMethod}" in "${resourceFile}.json" is missing definition.`
151
+ );
152
+ }
153
+ });
154
+ });
155
+ };
156
+
157
+ // ─────────────────────────────────────────────────────────────────────────────
158
+ // MAIN FUNCTION
159
+ // ─────────────────────────────────────────────────────────────────────────────
160
+
161
+ export const validateIntegrationSchemas = (currentDir) => {
162
+ const errors = new Set();
163
+
164
+ // Define file paths
165
+ const paths = {
166
+ base: path.join(currentDir, "schemas", "base.json"),
167
+ resources: path.join(currentDir, "schemas", "resources"),
168
+ spec: path.join(currentDir, "spec.json"),
169
+ webhook: path.join(currentDir, "schemas", "webhook.json"),
170
+ documentation: path.join(currentDir, "Documentation.mdx"),
171
+ };
172
+
173
+ // Step-by-step validation
174
+ validateDocumentation(paths.documentation, errors);
175
+
176
+ const spec = validateSpec(paths.spec, errors);
177
+ validateWebhook(paths.webhook, spec, errors);
178
+
179
+ const baseSchema = validateBaseSchema(paths.base, errors);
180
+ const resourceFields = baseSchema
181
+ ? findResourceFieldsWithOptions(baseSchema)
182
+ : [];
183
+
184
+ validateResources(paths.resources, resourceFields, errors);
185
+
186
+ // Return results
187
+ if (errors.size > 0) {
188
+ return {
189
+ success: false,
190
+ errors: Array.from(errors),
191
+ };
192
+ }
193
+
194
+ return { success: true };
195
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boltic/cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.6-beta.0",
4
4
  "description": "A powerful CLI tool for managing Boltic Workflow integrations",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -51,6 +51,7 @@
51
51
  "husky": "^9.1.7",
52
52
  "jest": "^29.7.0",
53
53
  "lint-staged": "^15.4.3",
54
+ "lodash.isempty": "^4.4.0",
54
55
  "nodemon": "^3.1.9",
55
56
  "prettier": "^3.5.3"
56
57
  }