@boltic/cli 1.0.37 → 1.0.38

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.
@@ -3,6 +3,7 @@ import FormData from "form-data";
3
3
  import fs from "fs";
4
4
  import https from "https";
5
5
  import { handleError } from "../helper/error.js";
6
+ import { getSecret } from "../helper/secure-storage.js";
6
7
  import { logApi } from "../helper/verbose.js";
7
8
 
8
9
  const getHttpsAgentForUrl = (baseUrl) => {
@@ -16,14 +17,39 @@ const getHttpsAgentForUrl = (baseUrl) => {
16
17
  ) {
17
18
  return new https.Agent({ rejectUnauthorized: false });
18
19
  }
19
- } catch (_) {
20
+ } catch {
20
21
  // ignore URL parse errors and fall back to default agent
21
22
  }
22
23
  return undefined;
23
24
  };
24
25
 
25
- const getIntegrationGroups = async (apiUrl, accountId, token, session) => {
26
- if (!token || !session || !accountId) {
26
+ const buildAuthHeaders = async (token, session) => {
27
+ const pat = await getSecret("pat");
28
+
29
+ // If PAT exists, prefer PAT-based auth and do not send bearer/session
30
+ if (pat && pat.trim()) {
31
+ return {
32
+ "x-boltic-token": pat.trim(),
33
+ };
34
+ }
35
+
36
+ // Fallback to existing Bearer + Cookie auth
37
+ const headers = {};
38
+ if (token) {
39
+ headers.Authorization = `Bearer ${token}`;
40
+ }
41
+ if (session) {
42
+ headers.Cookie = session;
43
+ }
44
+ return headers;
45
+ };
46
+
47
+ const ensureAuthenticatedOrExit = async (accountId, token, session) => {
48
+ const pat = await getSecret("pat");
49
+ const hasPatAuth = pat && pat.trim() && accountId;
50
+ const hasSessionAuth = token && session && accountId;
51
+
52
+ if (!hasPatAuth && !hasSessionAuth) {
27
53
  console.error(
28
54
  "\x1b[31mError:\x1b[0m Authentication credentials are required."
29
55
  );
@@ -31,7 +57,12 @@ const getIntegrationGroups = async (apiUrl, accountId, token, session) => {
31
57
  console.log("\x1b[32m$ boltic login\x1b[0m\n");
32
58
  process.exit(1); // Exit the CLI with an error code
33
59
  }
60
+ };
61
+
62
+ const getIntegrationGroups = async (apiUrl, accountId, token, session) => {
34
63
  try {
64
+ await ensureAuthenticatedOrExit(accountId, token, session);
65
+ const authHeaders = await buildAuthHeaders(token, session);
35
66
  const axiosOptions = {
36
67
  method: "get",
37
68
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integration-groups`,
@@ -41,8 +72,7 @@ const getIntegrationGroups = async (apiUrl, accountId, token, session) => {
41
72
  },
42
73
  headers: {
43
74
  "Content-Type": "application/json",
44
- Authorization: `Bearer ${token}`,
45
- Cookie: session,
75
+ ...authHeaders,
46
76
  },
47
77
  httpsAgent: getHttpsAgentForUrl(apiUrl),
48
78
  };
@@ -56,15 +86,9 @@ const getIntegrationGroups = async (apiUrl, accountId, token, session) => {
56
86
  };
57
87
 
58
88
  const listAllIntegrations = async (apiUrl, token, accountId, session) => {
59
- if (!token || !session || !accountId) {
60
- console.error(
61
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
62
- );
63
- console.log("\nšŸ”¹ Please log in first using:");
64
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
65
- process.exit(1); // Exit the CLI with an error code
66
- }
67
89
  try {
90
+ await ensureAuthenticatedOrExit(accountId, token, session);
91
+ const authHeaders = await buildAuthHeaders(token, session);
68
92
  const axiosOptions = {
69
93
  method: "get",
70
94
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integrations`,
@@ -74,8 +98,7 @@ const listAllIntegrations = async (apiUrl, token, accountId, session) => {
74
98
  },
75
99
  headers: {
76
100
  "Content-Type": "application/json",
77
- Authorization: `Bearer ${token}`,
78
- Cookie: session,
101
+ ...authHeaders,
79
102
  },
80
103
  httpsAgent: getHttpsAgentForUrl(apiUrl),
81
104
  };
@@ -95,23 +118,16 @@ const saveIntegration = async (
95
118
  session,
96
119
  integration
97
120
  ) => {
98
- if (!token || !session || !accountId) {
99
- console.error(
100
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
101
- );
102
- console.log("\nšŸ”¹ Please log in first using:");
103
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
104
- process.exit(1); // Exit the CLI with an error code
105
- }
106
121
  try {
122
+ await ensureAuthenticatedOrExit(accountId, token, session);
123
+ const authHeaders = await buildAuthHeaders(token, session);
107
124
  const response = await axios({
108
125
  method: "post",
109
126
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integrations`,
110
127
  data: integration,
111
128
  headers: {
112
129
  "Content-Type": "application/json",
113
- Authorization: `Bearer ${token}`,
114
- Cookie: session,
130
+ ...authHeaders,
115
131
  },
116
132
  httpsAgent: getHttpsAgentForUrl(apiUrl),
117
133
  });
@@ -122,24 +138,17 @@ const saveIntegration = async (
122
138
  };
123
139
 
124
140
  const editIntegration = async (apiUrl, token, accountId, session, payload) => {
125
- if (!token || !session || !accountId) {
126
- console.error(
127
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
128
- );
129
- console.log("\nšŸ”¹ Please log in first using:");
130
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
131
- process.exit(1); // Exit the CLI with an error code
132
- }
133
141
  const { id } = payload;
134
142
  try {
143
+ await ensureAuthenticatedOrExit(accountId, token, session);
144
+ const authHeaders = await buildAuthHeaders(token, session);
135
145
  const response = await axios({
136
146
  method: "post",
137
147
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integrations/${id}/edit`,
138
148
  data: payload,
139
149
  headers: {
140
150
  "Content-Type": "application/json",
141
- Authorization: `Bearer ${token}`,
142
- Cookie: session,
151
+ ...authHeaders,
143
152
  },
144
153
  httpsAgent: getHttpsAgentForUrl(apiUrl),
145
154
  });
@@ -157,15 +166,9 @@ const updateIntegration = async (
157
166
  session,
158
167
  integration
159
168
  ) => {
160
- if (!token || !session || !accountId) {
161
- console.error(
162
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
163
- );
164
- console.log("\nšŸ”¹ Please log in first using:");
165
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
166
- process.exit(1); // Exit the CLI with an error code
167
- }
168
169
  try {
170
+ await ensureAuthenticatedOrExit(accountId, token, session);
171
+ const authHeaders = await buildAuthHeaders(token, session);
169
172
  const { id, ...rest } = integration;
170
173
  const response = await axios({
171
174
  method: "patch",
@@ -173,8 +176,7 @@ const updateIntegration = async (
173
176
  data: rest,
174
177
  headers: {
175
178
  "Content-Type": "application/json",
176
- Authorization: `Bearer ${token}`,
177
- Cookie: session,
179
+ ...authHeaders,
178
180
  },
179
181
  httpsAgent: getHttpsAgentForUrl(apiUrl),
180
182
  });
@@ -191,23 +193,15 @@ const getIntegrationById = async (
191
193
  session,
192
194
  integrationId
193
195
  ) => {
194
- if (!token || !session || !accountId) {
195
- console.error(
196
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
197
- );
198
- console.log("\nšŸ”¹ Please log in first using:");
199
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
200
- process.exit(1); // Exit the CLI with an error code
201
- }
202
-
203
196
  try {
197
+ await ensureAuthenticatedOrExit(accountId, token, session);
198
+ const authHeaders = await buildAuthHeaders(token, session);
204
199
  const response = await axios({
205
200
  method: "get",
206
201
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integrations/${integrationId}`,
207
202
  headers: {
208
203
  "Content-Type": "application/json",
209
- Authorization: `Bearer ${token}`,
210
- Cookie: session,
204
+ ...authHeaders,
211
205
  },
212
206
  httpsAgent: getHttpsAgentForUrl(apiUrl),
213
207
  });
@@ -224,23 +218,15 @@ const getAuthenticationByIntegrationId = async (
224
218
  session,
225
219
  integrationId
226
220
  ) => {
227
- if (!token || !session || !accountId) {
228
- console.error(
229
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
230
- );
231
- console.log("\nšŸ”¹ Please log in first using:");
232
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
233
- process.exit(1); // Exit the CLI with an error code
234
- }
235
-
236
221
  try {
222
+ await ensureAuthenticatedOrExit(accountId, token, session);
223
+ const authHeaders = await buildAuthHeaders(token, session);
237
224
  const response = await axios({
238
225
  method: "get",
239
226
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}integrations/${integrationId}/authentication`,
240
227
  headers: {
241
228
  "Content-Type": "application/json",
242
- Authorization: `Bearer ${token}`,
243
- Cookie: session,
229
+ ...authHeaders,
244
230
  },
245
231
  httpsAgent: getHttpsAgentForUrl(apiUrl),
246
232
  });
@@ -290,22 +276,15 @@ const getConfigurationByIntegrationId = async (
290
276
  accountId,
291
277
  integrationId
292
278
  ) => {
293
- if (!token || !session || !accountId) {
294
- console.error(
295
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
296
- );
297
- console.log("\nšŸ”¹ Please log in first using:");
298
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
299
- process.exit(1); // Exit the CLI with an error code
300
- }
301
279
  try {
280
+ await ensureAuthenticatedOrExit(accountId, token, session);
281
+ const authHeaders = await buildAuthHeaders(token, session);
302
282
  const response = await axios({
303
283
  method: "get",
304
284
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}integrations/${integrationId}/configuration`,
305
285
  headers: {
306
286
  "Content-Type": "application/json",
307
- Authorization: `Bearer ${token}`,
308
- Cookie: session,
287
+ ...authHeaders,
309
288
  },
310
289
  httpsAgent: getHttpsAgentForUrl(apiUrl),
311
290
  });
@@ -322,23 +301,16 @@ const syncIntegration = async (
322
301
  session,
323
302
  integration
324
303
  ) => {
325
- if (!token || !session || !accountId) {
326
- console.error(
327
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
328
- );
329
- console.log("\nšŸ”¹ Please log in first using:");
330
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
331
- process.exit(1); // Exit the CLI with an error code
332
- }
333
304
  try {
305
+ await ensureAuthenticatedOrExit(accountId, token, session);
306
+ const authHeaders = await buildAuthHeaders(token, session);
334
307
  const response = await axios({
335
308
  method: "post",
336
309
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integrations/${integration.integration_id}/deploy`,
337
310
  data: integration,
338
311
  headers: {
339
312
  "Content-Type": "application/json",
340
- Authorization: `Bearer ${token}`,
341
- Cookie: session,
313
+ ...authHeaders,
342
314
  },
343
315
  httpsAgent: getHttpsAgentForUrl(apiUrl),
344
316
  });
@@ -355,15 +327,8 @@ const sendIntegrationForReview = async (
355
327
  session,
356
328
  integration
357
329
  ) => {
358
- if (!token || !session || !accountId) {
359
- console.error(
360
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
361
- );
362
- console.log("\nšŸ”¹ Please log in first using:");
363
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
364
- process.exit(1); // Exit the CLI with an error code
365
- }
366
330
  try {
331
+ await ensureAuthenticatedOrExit(accountId, token, session);
367
332
  const response = await axios({
368
333
  method: "post",
369
334
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integration-reviews`,
@@ -383,24 +348,16 @@ const sendIntegrationForReview = async (
383
348
 
384
349
  const purgeCache = async (apiUrl, token, accountId, session, integration) => {
385
350
  const { integration_id } = integration;
386
- if (!token || !session || !accountId) {
387
- console.error(
388
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
389
- );
390
- console.log("\nšŸ”¹ Please log in first using:");
391
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
392
- process.exit(1); // Exit the CLI with an error code
393
- }
394
-
395
351
  try {
352
+ await ensureAuthenticatedOrExit(accountId, token, session);
353
+ const authHeaders = await buildAuthHeaders(token, session);
396
354
  const response = await axios({
397
355
  method: "post",
398
356
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integrations/${integration_id}/cache`,
399
357
  data: {},
400
358
  headers: {
401
359
  "Content-Type": "application/json",
402
- Authorization: `Bearer ${token}`,
403
- Cookie: session,
360
+ ...authHeaders,
404
361
  },
405
362
  httpsAgent: getHttpsAgentForUrl(apiUrl),
406
363
  });
@@ -411,22 +368,15 @@ const purgeCache = async (apiUrl, token, accountId, session, integration) => {
411
368
  };
412
369
 
413
370
  const pullIntegration = async (apiUrl, token, accountId, session, id) => {
414
- if (!token || !session || !accountId) {
415
- console.error(
416
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
417
- );
418
- console.log("\nšŸ”¹ Please log in first using:");
419
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
420
- process.exit(1); // Exit the CLI with an error code
421
- }
422
371
  try {
372
+ await ensureAuthenticatedOrExit(accountId, token, session);
373
+ const authHeaders = await buildAuthHeaders(token, session);
423
374
  const response = await axios({
424
375
  method: "get",
425
376
  url: `${apiUrl}/service/panel/automation/v1.0/${accountId}/integrations/${id}/pull`,
426
377
  headers: {
427
378
  "Content-Type": "application/json",
428
- Authorization: `Bearer ${token}`,
429
- Cookie: session,
379
+ ...authHeaders,
430
380
  },
431
381
  httpsAgent: getHttpsAgentForUrl(apiUrl),
432
382
  });
@@ -444,20 +394,13 @@ const uploadFileToCloud = async (
444
394
  session,
445
395
  filePath
446
396
  ) => {
447
- if (!token || !session || !accountId) {
448
- console.error(
449
- "\x1b[31mError:\x1b[0m Authentication credentials are required."
450
- );
451
- console.log("\nšŸ”¹ Please log in first using:");
452
- console.log("\x1b[32m$ boltic login\x1b[0m\n");
453
- process.exit(1);
454
- }
455
-
456
397
  if (!fs.existsSync(filePath)) {
457
398
  throw new Error("File does not exist: " + filePath);
458
399
  }
459
400
 
460
401
  try {
402
+ await ensureAuthenticatedOrExit(accountId, token, session);
403
+ const authHeaders = await buildAuthHeaders(token, session);
461
404
  const form = new FormData();
462
405
  form.append("files", fs.createReadStream(filePath));
463
406
 
@@ -467,8 +410,7 @@ const uploadFileToCloud = async (
467
410
  {
468
411
  headers: {
469
412
  ...form.getHeaders(),
470
- Authorization: `Bearer ${token}`,
471
- Cookie: session,
413
+ ...authHeaders,
472
414
  },
473
415
  httpsAgent: getHttpsAgentForUrl(apiUrl),
474
416
  }
package/cli.js CHANGED
@@ -16,8 +16,15 @@ const createCLI = (consoleUrl, apiUrl, serviceName, env) => {
16
16
  const commands = {
17
17
  login: {
18
18
  description: "Authenticate the user and save access token",
19
- action: async () =>
20
- await AuthCommands.handleLogin(consoleUrl, apiUrl, env),
19
+ action: async (args) => {
20
+ // Support PAT-based login via flag: `boltic login --pat`
21
+ if (args.includes("--pat")) {
22
+ await AuthCommands.handlePatLogin();
23
+ return;
24
+ }
25
+
26
+ await AuthCommands.handleLogin(consoleUrl, apiUrl, env);
27
+ },
21
28
  },
22
29
  integration: {
23
30
  description: "Manage integrations (create, list)",
package/commands/login.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import open from "open";
3
+ import readline from "readline";
3
4
  import { v4 as uuidv4 } from "uuid";
4
5
  import { getCliBearerToken, getCliSession } from "../api/login.js";
5
6
  import { getCurrentEnv } from "../helper/env.js";
@@ -31,6 +32,21 @@ const execute = async (args) => {
31
32
  await commands[subCommand].action(args.slice(1));
32
33
  };
33
34
 
35
+ // Prompt user for input from the terminal
36
+ async function askQuestion(query) {
37
+ const rl = readline.createInterface({
38
+ input: process.stdin,
39
+ output: process.stdout,
40
+ });
41
+
42
+ return new Promise((resolve) => {
43
+ rl.question(query, (answer) => {
44
+ rl.close();
45
+ resolve(answer);
46
+ });
47
+ });
48
+ }
49
+
34
50
  // Show available login commands
35
51
  function showHelp() {
36
52
  console.log(chalk.cyan("\nLogin Commands:\n"));
@@ -161,6 +177,47 @@ async function handleLogin() {
161
177
  );
162
178
  }
163
179
 
180
+ // Handle PAT-based login command
181
+ async function handlePatLogin(patFromArg, accountIdFromArg) {
182
+ let pat = patFromArg;
183
+ let accountId = accountIdFromArg;
184
+
185
+ if (!pat) {
186
+ console.log(chalk.cyan("\nšŸ” Personal Access Token (PAT) login\n"));
187
+ pat = await askQuestion("Enter your PAT token: ");
188
+ }
189
+
190
+ if (!pat || !pat.trim()) {
191
+ console.log(chalk.red("\nāŒ PAT token cannot be empty.\n"));
192
+ return;
193
+ }
194
+
195
+ if (!accountId) {
196
+ accountId = await askQuestion("Enter your Account ID: ");
197
+ }
198
+
199
+ if (!accountId || !accountId.trim()) {
200
+ console.log(chalk.red("\nāŒ Account ID cannot be empty.\n"));
201
+ return;
202
+ }
203
+
204
+ try {
205
+ await storeSecret("pat", pat.trim());
206
+ await storeSecret("account_id", accountId.trim());
207
+ console.log(
208
+ chalk.green(
209
+ "\nāœ… PAT token and Account ID stored securely. They will be used for future organization-related requests.\n"
210
+ )
211
+ );
212
+ } catch (error) {
213
+ console.error(
214
+ chalk.red(
215
+ `\nāŒ Failed to store PAT credentials: ${error.message || error}\n`
216
+ )
217
+ );
218
+ }
219
+ }
220
+
164
221
  // Handle logout command
165
222
  async function handleLogout() {
166
223
  await deleteAllSecrets();
@@ -170,4 +227,4 @@ async function handleLogout() {
170
227
  );
171
228
  }
172
229
 
173
- export default { execute, handleLogin, handleLogout };
230
+ export default { execute, handleLogin, handlePatLogin, handleLogout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boltic/cli",
3
- "version": "1.0.37",
3
+ "version": "1.0.38",
4
4
  "description": "A powerful CLI tool for managing Boltic Workflow integrations - create, sync, test, and publish integrations with ease",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -218,6 +218,17 @@ async function getSvgFilePath() {
218
218
  if (pickedFile && fs.existsSync(pickedFile)) {
219
219
  return pickedFile;
220
220
  }
221
+
222
+ // Fallback: ask user to manually input the SVG path
223
+ const manualPath = await input({
224
+ message: "Enter the path to your SVG icon file:",
225
+ });
226
+
227
+ if (!manualPath || !fs.existsSync(manualPath)) {
228
+ return null;
229
+ }
230
+
231
+ return manualPath;
221
232
  }
222
233
 
223
234
  export { getSvgFilePath, pickSvgFile };