@tolinax/ayoune-cli 2026.3.0 → 2026.4.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.
Files changed (70) hide show
  1. package/data/contextSlots.js +189 -0
  2. package/data/modelsAndRights.js +56 -0
  3. package/data/modules.js +16 -0
  4. package/lib/api/apiCallHandler.js +6 -2
  5. package/lib/api/apiClient.js +9 -1
  6. package/lib/api/auditCallHandler.js +2 -2
  7. package/lib/api/handleAPIError.js +20 -18
  8. package/lib/api/login.js +3 -3
  9. package/lib/api/searchClient.js +119 -0
  10. package/lib/commands/createAccessCommand.js +126 -0
  11. package/lib/commands/createActionsCommand.js +40 -9
  12. package/lib/commands/createAiCommand.js +17 -17
  13. package/lib/commands/createAliasCommand.js +4 -6
  14. package/lib/commands/createAuditCommand.js +5 -9
  15. package/lib/commands/createBatchCommand.js +15 -28
  16. package/lib/commands/createCompletionsCommand.js +6 -3
  17. package/lib/commands/createConfigCommand.js +8 -14
  18. package/lib/commands/createContextCommand.js +163 -0
  19. package/lib/commands/createCopyCommand.js +4 -7
  20. package/lib/commands/createCreateCommand.js +4 -7
  21. package/lib/commands/createDeleteCommand.js +4 -6
  22. package/lib/commands/createDeployCommand.js +31 -55
  23. package/lib/commands/createDescribeCommand.js +12 -10
  24. package/lib/commands/createEditCommand.js +13 -8
  25. package/lib/commands/createEventsCommand.js +4 -4
  26. package/lib/commands/createExecCommand.js +65 -35
  27. package/lib/commands/createExportCommand.js +21 -24
  28. package/lib/commands/createGetCommand.js +13 -14
  29. package/lib/commands/createJobsCommand.js +8 -13
  30. package/lib/commands/createListCommand.js +13 -14
  31. package/lib/commands/createLoginCommand.js +16 -4
  32. package/lib/commands/createLogoutCommand.js +2 -2
  33. package/lib/commands/createModulesCommand.js +16 -19
  34. package/lib/commands/createMonitorCommand.js +9 -16
  35. package/lib/commands/createPermissionsCommand.js +10 -18
  36. package/lib/commands/createProgram.js +47 -21
  37. package/lib/commands/createSearchCommand.js +219 -69
  38. package/lib/commands/createSelfHostUpdateCommand.js +166 -0
  39. package/lib/commands/createServicesCommand.js +5 -8
  40. package/lib/commands/createSetupCommand.js +305 -0
  41. package/lib/commands/createStatusCommand.js +147 -0
  42. package/lib/commands/createStorageCommand.js +2 -3
  43. package/lib/commands/createStreamCommand.js +4 -4
  44. package/lib/commands/createSyncCommand.js +5 -8
  45. package/lib/commands/createTemplateCommand.js +9 -16
  46. package/lib/commands/createUpdateCommand.js +12 -15
  47. package/lib/commands/createUsersCommand.js +21 -31
  48. package/lib/commands/createWebhooksCommand.js +15 -22
  49. package/lib/commands/createWhoAmICommand.js +8 -6
  50. package/lib/helpers/cliError.js +24 -0
  51. package/lib/helpers/config.js +1 -0
  52. package/lib/helpers/configLoader.js +6 -0
  53. package/lib/helpers/contextInjector.js +65 -0
  54. package/lib/helpers/contextResolver.js +70 -0
  55. package/lib/helpers/contextStore.js +46 -0
  56. package/lib/helpers/handleResponseFormatOptions.js +59 -10
  57. package/lib/helpers/logo.js +48 -0
  58. package/lib/helpers/resolveCollectionArgs.js +36 -0
  59. package/lib/helpers/sanitizeFields.js +18 -0
  60. package/lib/helpers/secureStorage.js +72 -0
  61. package/lib/helpers/tokenPayload.js +21 -0
  62. package/lib/helpers/updateNotifier.js +49 -0
  63. package/lib/models/getModuleFromCollection.js +4 -1
  64. package/lib/operations/handleCopySingleOperation.js +10 -2
  65. package/lib/operations/handleCreateSingleOperation.js +3 -0
  66. package/lib/operations/handleDescribeSingleOperation.js +23 -0
  67. package/lib/operations/handleGetOperation.js +9 -3
  68. package/lib/operations/handleListOperation.js +14 -10
  69. package/lib/prompts/promptModule.js +9 -6
  70. package/package.json +163 -158
@@ -0,0 +1,305 @@
1
+ import chalk from "chalk";
2
+ import inquirer from "inquirer";
3
+ import { writeFile, mkdir } from "fs/promises";
4
+ import { existsSync } from "fs";
5
+ import path from "path";
6
+ import { spinner } from "../../index.js";
7
+ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
8
+ import { cliError } from "../helpers/cliError.js";
9
+ const AVAILABLE_MODULES = [
10
+ { name: "CRM", value: "crm", description: "Customer Relationship Management" },
11
+ { name: "Marketing", value: "marketing", description: "Marketing automation & campaigns" },
12
+ { name: "HR", value: "hr", description: "Human Resources" },
13
+ { name: "E-Commerce", value: "ecommerce", description: "Online shop & payments" },
14
+ { name: "Project Management", value: "pm", description: "Projects & tasks" },
15
+ { name: "DevOps", value: "devops", description: "Deployment & infrastructure" },
16
+ { name: "Accounting", value: "accounting", description: "Financial accounting" },
17
+ { name: "Automation", value: "automation", description: "Workflow automation" },
18
+ { name: "Support", value: "support", description: "Customer support & ticketing" },
19
+ { name: "Content", value: "content", description: "Content management" },
20
+ { name: "Communication", value: "communication", description: "Messaging & notifications" },
21
+ { name: "Reporting", value: "reporting", description: "Reports & analytics" },
22
+ { name: "Monitoring", value: "monitoring", description: "Platform monitoring" },
23
+ ];
24
+ function generateEnvFile(answers) {
25
+ const modules = answers.modules;
26
+ const lines = [
27
+ "# =============================================================================",
28
+ "# aYOUne Platform Configuration",
29
+ `# Generated by ay setup on ${new Date().toISOString()}`,
30
+ "# =============================================================================",
31
+ "",
32
+ "# -- Core --",
33
+ `NODE_ENV=production`,
34
+ `PORT=3000`,
35
+ "",
36
+ "# -- License --",
37
+ `AYOUNE_LICENSE_KEY=${answers.licenseKey}`,
38
+ "",
39
+ "# -- Database --",
40
+ `MONGO_CONNECTSTRING=${answers.mongoUri}`,
41
+ `MONGO_CONNECTSTRING_AGGREGATION=${answers.mongoUri}`,
42
+ "",
43
+ "# -- Redis --",
44
+ `JOB_REDIS_HOST=${answers.redisHost}`,
45
+ `JOB_REDIS_PORT=${answers.redisPort}`,
46
+ `JOB_REDIS_PASS=${answers.redisPass}`,
47
+ `CACHE_REDIS_HOST=${answers.redisHost}`,
48
+ `CACHE_REDIS_PORT=${answers.redisPort}`,
49
+ `CACHE_REDIS_PASS=${answers.redisPass}`,
50
+ "",
51
+ "# -- Security --",
52
+ `JWT_SECRET=${answers.jwtSecret}`,
53
+ `JWT_SIGN=${answers.jwtSecret}`,
54
+ `JWT_sign=${answers.jwtSecret}`,
55
+ `JWT_AUDIENCE=ayoune.app`,
56
+ `JWT_ISSUER=ayoune.app`,
57
+ `JWT_EXPIRATION=360000`,
58
+ `COOKIE_KEY=ayouneSession`,
59
+ `COOKIE_SECRET=${generateRandomString(32)}`,
60
+ `SALT_WORK_FACTOR=10`,
61
+ `SECURITY_ALGORITHM=aes-256-ctr`,
62
+ `SECURITY_HASH=${generateRandomString(32)}`,
63
+ "",
64
+ "# -- Email / SMTP --",
65
+ `SMTP_HOST=${answers.smtpHost}`,
66
+ `SMTP_PORT=${answers.smtpPort}`,
67
+ `SMTP_USER=${answers.smtpUser}`,
68
+ `SMTP_PASS=${answers.smtpPass}`,
69
+ `MAIL_HOST=${answers.smtpHost}`,
70
+ `MAIL_USER=${answers.smtpUser}`,
71
+ `MAIL_PASS=${answers.smtpPass}`,
72
+ "",
73
+ "# -- Domain --",
74
+ `frontendURL=https://${answers.domain}`,
75
+ `hostURL=https://api-v1.${answers.domain}`,
76
+ `authHost=https://auth.${answers.domain}`,
77
+ `apiHost=https://api.${answers.domain}`,
78
+ `apiConfig=https://config-api.${answers.domain}`,
79
+ `NOTIFIER=https://notifier.${answers.domain}`,
80
+ "",
81
+ "# -- Enabled Modules --",
82
+ `# Profiles: core,${modules.join(",")}`,
83
+ ];
84
+ // Add module-specific host URLs
85
+ for (const mod of modules) {
86
+ lines.push(`api${capitalize(mod)}=https://${mod}-api.${answers.domain}`);
87
+ }
88
+ lines.push("");
89
+ lines.push("# -- Monitoring --");
90
+ lines.push(`MONGO_PASSWORD=changeme`);
91
+ lines.push("");
92
+ return lines.join("\n");
93
+ }
94
+ function generateHelmValues(answers) {
95
+ const enabledModules = {};
96
+ for (const mod of AVAILABLE_MODULES) {
97
+ enabledModules[mod.value] = answers.modules.includes(mod.value);
98
+ }
99
+ const values = {
100
+ global: {
101
+ domain: answers.domain,
102
+ mongodb: { uri: answers.mongoUri },
103
+ redis: {
104
+ host: answers.redisHost,
105
+ port: parseInt(answers.redisPort),
106
+ password: answers.redisPass,
107
+ },
108
+ jwt: { secret: answers.jwtSecret },
109
+ smtp: {
110
+ host: answers.smtpHost,
111
+ port: parseInt(answers.smtpPort),
112
+ user: answers.smtpUser,
113
+ password: answers.smtpPass,
114
+ },
115
+ licenseKey: answers.licenseKey,
116
+ },
117
+ modules: enabledModules,
118
+ };
119
+ // Simple YAML serialization (avoid adding js-yaml dependency just for this)
120
+ return serializeYaml(values, 0);
121
+ }
122
+ function serializeYaml(obj, indent) {
123
+ const prefix = " ".repeat(indent);
124
+ const lines = [];
125
+ for (const [key, value] of Object.entries(obj)) {
126
+ if (value === null || value === undefined)
127
+ continue;
128
+ if (typeof value === "object" && !Array.isArray(value)) {
129
+ lines.push(`${prefix}${key}:`);
130
+ lines.push(serializeYaml(value, indent + 1));
131
+ }
132
+ else if (typeof value === "boolean") {
133
+ lines.push(`${prefix}${key}: ${value}`);
134
+ }
135
+ else if (typeof value === "number") {
136
+ lines.push(`${prefix}${key}: ${value}`);
137
+ }
138
+ else {
139
+ lines.push(`${prefix}${key}: "${value}"`);
140
+ }
141
+ }
142
+ return lines.join("\n");
143
+ }
144
+ function generateRandomString(length) {
145
+ const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
146
+ let result = "";
147
+ for (let i = 0; i < length; i++) {
148
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
149
+ }
150
+ return result;
151
+ }
152
+ function capitalize(s) {
153
+ return s.charAt(0).toUpperCase() + s.slice(1);
154
+ }
155
+ export function createSetupCommand(program) {
156
+ program
157
+ .command("setup")
158
+ .description("Interactive setup wizard for self-hosted aYOUne deployments")
159
+ .addHelpText("after", `
160
+ Examples:
161
+ ay setup Start interactive setup wizard
162
+ ay setup --output ./config Generate files in ./config directory`)
163
+ .option("-o, --output <dir>", "Output directory for generated files", ".")
164
+ .action(async (options) => {
165
+ try {
166
+ console.log(chalk.cyan.bold("\n aYOUne Self-Hosted Setup Wizard\n") +
167
+ chalk.dim(" This wizard will generate configuration files for your deployment.\n"));
168
+ const answers = await inquirer.prompt([
169
+ {
170
+ type: "list",
171
+ name: "deploymentMode",
172
+ message: "Deployment mode:",
173
+ choices: [
174
+ { name: "Docker Compose (single server)", value: "compose" },
175
+ { name: "Kubernetes (Helm chart)", value: "kubernetes" },
176
+ ],
177
+ },
178
+ {
179
+ type: "input",
180
+ name: "domain",
181
+ message: "Your domain (e.g. ayoune.example.com):",
182
+ validate: (v) => v.length > 0 || "Domain is required",
183
+ },
184
+ {
185
+ type: "input",
186
+ name: "mongoUri",
187
+ message: "MongoDB connection string:",
188
+ default: "mongodb://ayoune:changeme@mongodb:27017/ayoune?authSource=admin&retryWrites=true&w=majority",
189
+ },
190
+ {
191
+ type: "input",
192
+ name: "redisHost",
193
+ message: "Redis host:",
194
+ default: "redis",
195
+ },
196
+ {
197
+ type: "input",
198
+ name: "redisPort",
199
+ message: "Redis port:",
200
+ default: "6379",
201
+ },
202
+ {
203
+ type: "password",
204
+ name: "redisPass",
205
+ message: "Redis password:",
206
+ default: "",
207
+ },
208
+ {
209
+ type: "password",
210
+ name: "jwtSecret",
211
+ message: "JWT secret (leave blank to auto-generate):",
212
+ default: "",
213
+ },
214
+ {
215
+ type: "input",
216
+ name: "smtpHost",
217
+ message: "SMTP host:",
218
+ default: "smtp.example.com",
219
+ },
220
+ {
221
+ type: "input",
222
+ name: "smtpPort",
223
+ message: "SMTP port:",
224
+ default: "587",
225
+ },
226
+ {
227
+ type: "input",
228
+ name: "smtpUser",
229
+ message: "SMTP username:",
230
+ default: "",
231
+ },
232
+ {
233
+ type: "password",
234
+ name: "smtpPass",
235
+ message: "SMTP password:",
236
+ default: "",
237
+ },
238
+ {
239
+ type: "input",
240
+ name: "licenseKey",
241
+ message: "License key (leave blank for 14-day trial):",
242
+ default: "",
243
+ },
244
+ {
245
+ type: "checkbox",
246
+ name: "modules",
247
+ message: "Select modules to enable:",
248
+ choices: AVAILABLE_MODULES.map((m) => ({
249
+ name: `${m.name} — ${m.description}`,
250
+ value: m.value,
251
+ checked: ["crm"].includes(m.value),
252
+ })),
253
+ validate: (v) => v.length > 0 || "Select at least one module",
254
+ },
255
+ ]);
256
+ // Auto-generate JWT secret if not provided
257
+ if (!answers.jwtSecret) {
258
+ answers.jwtSecret = generateRandomString(64);
259
+ }
260
+ answers.outputDir = options.output;
261
+ spinner.start({ text: "Generating configuration files...", color: "cyan" });
262
+ const outputDir = path.resolve(answers.outputDir);
263
+ if (!existsSync(outputDir)) {
264
+ await mkdir(outputDir, { recursive: true });
265
+ }
266
+ // Generate .env
267
+ const envContent = generateEnvFile(answers);
268
+ const envPath = path.join(outputDir, ".env");
269
+ await writeFile(envPath, envContent, "utf-8");
270
+ if (answers.deploymentMode === "kubernetes") {
271
+ // Generate values.yaml for Helm
272
+ const valuesContent = generateHelmValues(answers);
273
+ const valuesPath = path.join(outputDir, "values.yaml");
274
+ await writeFile(valuesPath, valuesContent, "utf-8");
275
+ spinner.success({ text: "Configuration files generated!" });
276
+ spinner.stop();
277
+ console.log(chalk.green("\n Generated files:"));
278
+ console.log(chalk.dim(` ${envPath}`));
279
+ console.log(chalk.dim(` ${valuesPath}`));
280
+ console.log(chalk.cyan("\n Next steps:"));
281
+ console.log(chalk.dim(" 1. Review and adjust the generated files"));
282
+ console.log(chalk.dim(" 2. helm install ayoune tolinax/ayoune -f values.yaml"));
283
+ console.log(chalk.dim(" 3. ay status — verify all services are healthy\n"));
284
+ }
285
+ else {
286
+ spinner.success({ text: "Configuration files generated!" });
287
+ spinner.stop();
288
+ const profiles = ["core", ...answers.modules].join(",");
289
+ console.log(chalk.green("\n Generated files:"));
290
+ console.log(chalk.dim(` ${envPath}`));
291
+ console.log(chalk.cyan("\n Next steps:"));
292
+ console.log(chalk.dim(" 1. Review and adjust the .env file"));
293
+ console.log(chalk.dim(` 2. docker compose --profile ${profiles} up -d`));
294
+ console.log(chalk.dim(" 3. ay status — verify all services are healthy\n"));
295
+ }
296
+ if (!answers.licenseKey) {
297
+ console.log(chalk.yellow(" Note: Running in 14-day trial mode.") +
298
+ chalk.dim(" Set AYOUNE_LICENSE_KEY to activate your license.\n"));
299
+ }
300
+ }
301
+ catch (e) {
302
+ cliError(e.message || "Setup failed", EXIT_GENERAL_ERROR);
303
+ }
304
+ });
305
+ }
@@ -0,0 +1,147 @@
1
+ import chalk from "chalk";
2
+ import { spinner } from "../../index.js";
3
+ import { api, getModuleBaseUrl } from "../api/apiClient.js";
4
+ import { secureStorage } from "../helpers/secureStorage.js";
5
+ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
6
+ import { cliError } from "../helpers/cliError.js";
7
+ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
8
+ const CORE_SERVICES = [
9
+ { name: "config-api", module: "config", path: "healthz" },
10
+ { name: "auth", module: "auth", path: "healthz", customUrl: "auth" },
11
+ ];
12
+ const MODULE_SERVICES = {
13
+ crm: [{ name: "crm-api", module: "crm", path: "healthz" }],
14
+ marketing: [{ name: "marketing-api", module: "marketing", path: "healthz" }],
15
+ hr: [{ name: "hr-api", module: "hr", path: "healthz" }],
16
+ ecommerce: [{ name: "ecommerce-api", module: "ecommerce", path: "healthz" }],
17
+ pm: [{ name: "pm-api", module: "pm", path: "healthz" }],
18
+ devops: [{ name: "devops-api", module: "devops", path: "healthz" }],
19
+ accounting: [{ name: "accounting-api", module: "accounting", path: "healthz" }],
20
+ automation: [{ name: "automation-api", module: "automation", path: "healthz" }],
21
+ support: [{ name: "support-api", module: "support", path: "healthz" }],
22
+ reporting: [{ name: "reporting-api", module: "reporting", path: "healthz" }],
23
+ monitoring: [{ name: "monitoring-api", module: "monitoring", path: "healthz" }],
24
+ };
25
+ async function checkService(name, module, healthPath) {
26
+ var _a;
27
+ const baseUrl = getModuleBaseUrl(module);
28
+ const start = Date.now();
29
+ try {
30
+ // Use api client directly to avoid handleAPIError calling process.exit()
31
+ const response = await api({
32
+ baseURL: baseUrl,
33
+ method: "get",
34
+ url: healthPath,
35
+ timeout: 10000,
36
+ headers: {
37
+ Authorization: `Bearer ${secureStorage.getItem("token") || ""}`,
38
+ },
39
+ });
40
+ const responseTime = Date.now() - start;
41
+ const res = response.data;
42
+ return {
43
+ service: name,
44
+ url: baseUrl,
45
+ status: "healthy",
46
+ responseTime,
47
+ version: (res === null || res === void 0 ? void 0 : res.version) || ((_a = res === null || res === void 0 ? void 0 : res.payload) === null || _a === void 0 ? void 0 : _a.version) || undefined,
48
+ };
49
+ }
50
+ catch (e) {
51
+ const responseTime = Date.now() - start;
52
+ if (e.response) {
53
+ return {
54
+ service: name,
55
+ url: baseUrl,
56
+ status: "unhealthy",
57
+ responseTime,
58
+ error: `HTTP ${e.response.status}`,
59
+ };
60
+ }
61
+ return {
62
+ service: name,
63
+ url: baseUrl,
64
+ status: "unreachable",
65
+ responseTime,
66
+ error: e.message || "Connection failed",
67
+ };
68
+ }
69
+ }
70
+ export function createStatusCommand(program) {
71
+ program
72
+ .command("status")
73
+ .description("Check health status of aYOUne platform services")
74
+ .addHelpText("after", `
75
+ Examples:
76
+ ay status Check all reachable services
77
+ ay status --module crm Check only CRM services
78
+ ay status -r json Output as JSON (for scripting)
79
+ ay status -r table Output as table`)
80
+ .option("--module <name>", "Check only a specific module")
81
+ .action(async (options) => {
82
+ try {
83
+ const opts = { ...program.opts(), ...options };
84
+ spinner.start({ text: "Checking platform health...", color: "cyan" });
85
+ const servicesToCheck = [];
86
+ // Always check core
87
+ servicesToCheck.push(...CORE_SERVICES);
88
+ if (opts.module) {
89
+ const moduleServices = MODULE_SERVICES[opts.module];
90
+ if (moduleServices) {
91
+ servicesToCheck.push(...moduleServices);
92
+ }
93
+ else {
94
+ cliError(`Unknown module: ${opts.module}`, EXIT_GENERAL_ERROR);
95
+ }
96
+ }
97
+ else {
98
+ // Check all known modules
99
+ for (const services of Object.values(MODULE_SERVICES)) {
100
+ servicesToCheck.push(...services);
101
+ }
102
+ }
103
+ // Check services concurrently
104
+ const results = await Promise.all(servicesToCheck.map((svc) => checkService(svc.name, svc.module, svc.path)));
105
+ spinner.stop();
106
+ const healthy = results.filter((r) => r.status === "healthy").length;
107
+ const unhealthy = results.filter((r) => r.status === "unhealthy").length;
108
+ const unreachable = results.filter((r) => r.status === "unreachable").length;
109
+ // Format output based on response format
110
+ if (opts.responseFormat === "json") {
111
+ const output = {
112
+ payload: results,
113
+ meta: {
114
+ total: results.length,
115
+ healthy,
116
+ unhealthy,
117
+ unreachable,
118
+ checkedAt: new Date().toISOString(),
119
+ },
120
+ };
121
+ handleResponseFormatOptions(opts, output);
122
+ }
123
+ else {
124
+ // Pretty terminal output
125
+ console.log(chalk.cyan.bold("\n aYOUne Platform Status\n"));
126
+ for (const result of results) {
127
+ const icon = result.status === "healthy" ? chalk.green("●") : result.status === "unhealthy" ? chalk.yellow("●") : chalk.red("●");
128
+ const time = result.responseTime ? chalk.dim(` (${result.responseTime}ms)`) : "";
129
+ const ver = result.version ? chalk.dim(` v${result.version}`) : "";
130
+ const err = result.error ? chalk.red(` — ${result.error}`) : "";
131
+ console.log(` ${icon} ${chalk.white(result.service)}${ver}${time}${err}`);
132
+ }
133
+ console.log("");
134
+ console.log(` ${chalk.green(healthy + " healthy")}` +
135
+ (unhealthy > 0 ? ` ${chalk.yellow(unhealthy + " unhealthy")}` : "") +
136
+ (unreachable > 0 ? ` ${chalk.red(unreachable + " unreachable")}` : ""));
137
+ console.log("");
138
+ }
139
+ if (unhealthy > 0 || unreachable > 0) {
140
+ process.exit(EXIT_GENERAL_ERROR);
141
+ }
142
+ }
143
+ catch (e) {
144
+ cliError(e.message || "Status check failed", EXIT_GENERAL_ERROR);
145
+ }
146
+ });
147
+ }
@@ -1,8 +1,8 @@
1
1
  import chalk from "chalk";
2
2
  import { localStorage } from "../helpers/localStorage.js";
3
3
  import { loadConfig } from "../helpers/configLoader.js";
4
- import { spinner } from "../../index.js";
5
4
  import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
5
+ import { cliError } from "../helpers/cliError.js";
6
6
  const REDACT_KEYS = new Set(["token", "refreshToken"]);
7
7
  function redact(value) {
8
8
  if (value.length <= 8)
@@ -47,8 +47,7 @@ export function createStorageCommand(program) {
47
47
  console.log();
48
48
  }
49
49
  catch (e) {
50
- spinner.error({ text: e.message || "An unexpected error occurred" });
51
- process.exit(EXIT_GENERAL_ERROR);
50
+ cliError(e.message || "An unexpected error occurred", EXIT_GENERAL_ERROR);
52
51
  }
53
52
  });
54
53
  }
@@ -1,10 +1,11 @@
1
1
  import { Option } from "commander";
2
- import { localStorage } from "../helpers/localStorage.js";
2
+ import { secureStorage } from "../helpers/secureStorage.js";
3
3
  import { decodeToken } from "../api/decodeToken.js";
4
4
  import { customerSocket } from "../socket/customerSocketClient.js";
5
5
  import { spinner } from "../../index.js";
6
6
  import yaml from "js-yaml";
7
7
  import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
8
+ import { cliError } from "../helpers/cliError.js";
8
9
  export function createStreamCommand(program) {
9
10
  program
10
11
  .command("stream")
@@ -23,7 +24,7 @@ Examples:
23
24
  .default("default"))
24
25
  .action(async (options) => {
25
26
  try {
26
- const tokenPayload = decodeToken(localStorage.getItem("token"));
27
+ const tokenPayload = decodeToken(secureStorage.getItem("token"));
27
28
  const user = tokenPayload.payload;
28
29
  console.log(`Starting stream with [${user._customerID}]`);
29
30
  spinner.start({ text: `Starting stream with [${user._customerID}]` });
@@ -43,8 +44,7 @@ Examples:
43
44
  });
44
45
  }
45
46
  catch (e) {
46
- spinner.error({ text: e.message || "An unexpected error occurred" });
47
- process.exit(EXIT_GENERAL_ERROR);
47
+ cliError(e.message || "An unexpected error occurred", EXIT_GENERAL_ERROR);
48
48
  }
49
49
  });
50
50
  }
@@ -2,6 +2,7 @@ import { apiCallHandler } from "../api/apiCallHandler.js";
2
2
  import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
3
3
  import { spinner } from "../../index.js";
4
4
  import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
5
+ import { cliError } from "../helpers/cliError.js";
5
6
  export function createSyncCommand(program) {
6
7
  const sync = program
7
8
  .command("sync")
@@ -63,8 +64,7 @@ Examples:
63
64
  }
64
65
  }
65
66
  catch (e) {
66
- spinner.error({ text: e.message || "Repository sync failed" });
67
- process.exit(EXIT_GENERAL_ERROR);
67
+ cliError(e.message || "Repository sync failed", EXIT_GENERAL_ERROR);
68
68
  }
69
69
  });
70
70
  // ay sync clusters
@@ -104,8 +104,7 @@ Examples:
104
104
  }
105
105
  }
106
106
  catch (e) {
107
- spinner.error({ text: e.message || "Cluster sync failed" });
108
- process.exit(EXIT_GENERAL_ERROR);
107
+ cliError(e.message || "Cluster sync failed", EXIT_GENERAL_ERROR);
109
108
  }
110
109
  });
111
110
  // ay sync pipelines
@@ -131,8 +130,7 @@ Examples:
131
130
  spinner.stop();
132
131
  }
133
132
  catch (e) {
134
- spinner.error({ text: e.message || "Pipeline sync failed" });
135
- process.exit(EXIT_GENERAL_ERROR);
133
+ cliError(e.message || "Pipeline sync failed", EXIT_GENERAL_ERROR);
136
134
  }
137
135
  });
138
136
  // ay sync status
@@ -170,8 +168,7 @@ Examples:
170
168
  spinner.stop();
171
169
  }
172
170
  catch (e) {
173
- spinner.error({ text: e.message || "Failed to get sync status" });
174
- process.exit(EXIT_GENERAL_ERROR);
171
+ cliError(e.message || "Failed to get sync status", EXIT_GENERAL_ERROR);
175
172
  }
176
173
  });
177
174
  }
@@ -3,6 +3,7 @@ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOpti
3
3
  import { saveFile } from "../helpers/saveFile.js";
4
4
  import { spinner } from "../../index.js";
5
5
  import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
6
+ import { cliError } from "../helpers/cliError.js";
6
7
  export function createTemplateCommand(program) {
7
8
  const tmpl = program
8
9
  .command("templates")
@@ -42,8 +43,7 @@ export function createTemplateCommand(program) {
42
43
  await saveFile("email-templates", opts, res);
43
44
  }
44
45
  catch (e) {
45
- spinner.error({ text: e.message || "Failed to list email templates" });
46
- process.exit(EXIT_GENERAL_ERROR);
46
+ cliError(e.message || "Failed to list email templates", EXIT_GENERAL_ERROR);
47
47
  }
48
48
  });
49
49
  // ay templates email get <id>
@@ -63,8 +63,7 @@ export function createTemplateCommand(program) {
63
63
  spinner.stop();
64
64
  }
65
65
  catch (e) {
66
- spinner.error({ text: e.message || "Failed to get email template" });
67
- process.exit(EXIT_GENERAL_ERROR);
66
+ cliError(e.message || "Failed to get email template", EXIT_GENERAL_ERROR);
68
67
  }
69
68
  });
70
69
  // ── NOTIFICATION TEMPLATES ─────────────────────────────
@@ -98,8 +97,7 @@ export function createTemplateCommand(program) {
98
97
  await saveFile("notification-templates", opts, res);
99
98
  }
100
99
  catch (e) {
101
- spinner.error({ text: e.message || "Failed to list notification templates" });
102
- process.exit(EXIT_GENERAL_ERROR);
100
+ cliError(e.message || "Failed to list notification templates", EXIT_GENERAL_ERROR);
103
101
  }
104
102
  });
105
103
  // ay templates notification get <id>
@@ -119,8 +117,7 @@ export function createTemplateCommand(program) {
119
117
  spinner.stop();
120
118
  }
121
119
  catch (e) {
122
- spinner.error({ text: e.message || "Failed to get notification template" });
123
- process.exit(EXIT_GENERAL_ERROR);
120
+ cliError(e.message || "Failed to get notification template", EXIT_GENERAL_ERROR);
124
121
  }
125
122
  });
126
123
  // ── REPORT TEMPLATES ───────────────────────────────────
@@ -151,8 +148,7 @@ export function createTemplateCommand(program) {
151
148
  await saveFile("report-templates", opts, res);
152
149
  }
153
150
  catch (e) {
154
- spinner.error({ text: e.message || "Failed to list report templates" });
155
- process.exit(EXIT_GENERAL_ERROR);
151
+ cliError(e.message || "Failed to list report templates", EXIT_GENERAL_ERROR);
156
152
  }
157
153
  });
158
154
  // ── STORE TEMPLATES ────────────────────────────────────
@@ -192,8 +188,7 @@ export function createTemplateCommand(program) {
192
188
  await saveFile("store-templates", opts, res);
193
189
  }
194
190
  catch (e) {
195
- spinner.error({ text: e.message || "Failed to list store templates" });
196
- process.exit(EXIT_GENERAL_ERROR);
191
+ cliError(e.message || "Failed to list store templates", EXIT_GENERAL_ERROR);
197
192
  }
198
193
  });
199
194
  // ay templates store get <id>
@@ -213,8 +208,7 @@ export function createTemplateCommand(program) {
213
208
  spinner.stop();
214
209
  }
215
210
  catch (e) {
216
- spinner.error({ text: e.message || "Failed to get store template" });
217
- process.exit(EXIT_GENERAL_ERROR);
211
+ cliError(e.message || "Failed to get store template", EXIT_GENERAL_ERROR);
218
212
  }
219
213
  });
220
214
  // ay templates store install <id>
@@ -231,8 +225,7 @@ export function createTemplateCommand(program) {
231
225
  spinner.stop();
232
226
  }
233
227
  catch (e) {
234
- spinner.error({ text: e.message || "Failed to install template" });
235
- process.exit(EXIT_GENERAL_ERROR);
228
+ cliError(e.message || "Failed to install template", EXIT_GENERAL_ERROR);
236
229
  }
237
230
  });
238
231
  }