@tolinax/ayoune-cli 2026.3.1 → 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 (107) hide show
  1. package/data/contextSlots.js +189 -0
  2. package/data/defaultActions.js +9 -0
  3. package/data/modelsAndRights.js +3245 -0
  4. package/data/modules.js +127 -0
  5. package/data/operations.js +5 -0
  6. package/data/services.js +139 -0
  7. package/index.js +11 -0
  8. package/lib/api/apiCallHandler.js +72 -0
  9. package/lib/api/apiClient.js +108 -0
  10. package/lib/api/auditCallHandler.js +21 -0
  11. package/lib/api/decodeToken.js +4 -0
  12. package/lib/api/handleAPIError.js +61 -0
  13. package/lib/api/login.js +45 -0
  14. package/lib/api/searchClient.js +119 -0
  15. package/lib/commands/createAccessCommand.js +126 -0
  16. package/lib/commands/createActionsCommand.js +140 -0
  17. package/lib/commands/createAiCommand.js +188 -0
  18. package/lib/commands/createAliasCommand.js +104 -0
  19. package/lib/commands/createAuditCommand.js +45 -0
  20. package/lib/commands/createBatchCommand.js +291 -0
  21. package/lib/commands/createCompletionsCommand.js +172 -0
  22. package/lib/commands/createConfigCommand.js +202 -0
  23. package/lib/commands/createContextCommand.js +163 -0
  24. package/lib/commands/createCopyCommand.js +36 -0
  25. package/lib/commands/createCreateCommand.js +47 -0
  26. package/lib/commands/createDeleteCommand.js +96 -0
  27. package/lib/commands/createDeployCommand.js +642 -0
  28. package/lib/commands/createDescribeCommand.js +44 -0
  29. package/lib/commands/createEditCommand.js +48 -0
  30. package/lib/commands/createEventsCommand.js +60 -0
  31. package/lib/commands/createExecCommand.js +212 -0
  32. package/lib/commands/createExportCommand.js +216 -0
  33. package/lib/commands/createGetCommand.js +46 -0
  34. package/lib/commands/createJobsCommand.js +163 -0
  35. package/lib/commands/createListCommand.js +48 -0
  36. package/lib/commands/createLoginCommand.js +30 -0
  37. package/lib/commands/createLogoutCommand.js +21 -0
  38. package/lib/commands/createModulesCommand.js +147 -0
  39. package/lib/commands/createMonitorCommand.js +276 -0
  40. package/lib/commands/createPermissionsCommand.js +233 -0
  41. package/lib/commands/createProgram.js +211 -0
  42. package/lib/commands/createSearchCommand.js +251 -0
  43. package/lib/commands/createSelfHostUpdateCommand.js +166 -0
  44. package/lib/commands/createServicesCommand.js +225 -0
  45. package/lib/commands/createSetupCommand.js +305 -0
  46. package/lib/commands/createStatusCommand.js +147 -0
  47. package/lib/commands/createStorageCommand.js +53 -0
  48. package/lib/commands/createStreamCommand.js +50 -0
  49. package/lib/commands/createSyncCommand.js +174 -0
  50. package/lib/commands/createTemplateCommand.js +231 -0
  51. package/lib/commands/createUpdateCommand.js +112 -0
  52. package/lib/commands/createUsersCommand.js +275 -0
  53. package/lib/commands/createWebhooksCommand.js +149 -0
  54. package/lib/commands/createWhoAmICommand.js +90 -0
  55. package/lib/exitCodes.js +6 -0
  56. package/lib/helpers/addSpacesToCamelCase.js +5 -0
  57. package/lib/helpers/cliError.js +24 -0
  58. package/lib/helpers/config.js +7 -0
  59. package/lib/helpers/configLoader.js +66 -0
  60. package/lib/helpers/contextInjector.js +65 -0
  61. package/lib/helpers/contextResolver.js +70 -0
  62. package/lib/helpers/contextStore.js +46 -0
  63. package/lib/helpers/formatDocument.js +176 -0
  64. package/lib/helpers/handleResponseFormatOptions.js +134 -0
  65. package/lib/helpers/initializeSettings.js +14 -0
  66. package/lib/helpers/localStorage.js +4 -0
  67. package/lib/helpers/logo.js +48 -0
  68. package/lib/helpers/makeRandomToken.js +27 -0
  69. package/lib/helpers/parseInt.js +7 -0
  70. package/lib/helpers/requireArg.js +9 -0
  71. package/lib/helpers/resolveCollectionArgs.js +36 -0
  72. package/lib/helpers/sanitizeFields.js +18 -0
  73. package/lib/helpers/saveFile.js +39 -0
  74. package/lib/helpers/secureStorage.js +72 -0
  75. package/lib/helpers/tokenPayload.js +21 -0
  76. package/lib/helpers/updateNotifier.js +49 -0
  77. package/lib/models/getCollections.js +15 -0
  78. package/lib/models/getModelsInModules.js +13 -0
  79. package/lib/models/getModuleFromCollection.js +10 -0
  80. package/lib/operations/handleAuditOperation.js +22 -0
  81. package/lib/operations/handleCollectionOperation.js +91 -0
  82. package/lib/operations/handleCopySingleOperation.js +30 -0
  83. package/lib/operations/handleCreateSingleOperation.js +38 -0
  84. package/lib/operations/handleDeleteSingleOperation.js +14 -0
  85. package/lib/operations/handleDescribeSingleOperation.js +45 -0
  86. package/lib/operations/handleEditOperation.js +51 -0
  87. package/lib/operations/handleEditRawOperation.js +35 -0
  88. package/lib/operations/handleGetOperation.js +35 -0
  89. package/lib/operations/handleGetSingleOperation.js +20 -0
  90. package/lib/operations/handleListOperation.js +67 -0
  91. package/lib/operations/handleSingleAuditOperation.js +27 -0
  92. package/lib/prompts/promptAudits.js +15 -0
  93. package/lib/prompts/promptCollection.js +13 -0
  94. package/lib/prompts/promptCollectionInModule.js +13 -0
  95. package/lib/prompts/promptCollectionWithModule.js +15 -0
  96. package/lib/prompts/promptConfirm.js +12 -0
  97. package/lib/prompts/promptDefaultAction.js +13 -0
  98. package/lib/prompts/promptEntry.js +19 -0
  99. package/lib/prompts/promptFileName.js +12 -0
  100. package/lib/prompts/promptFilePath.js +18 -0
  101. package/lib/prompts/promptModule.js +22 -0
  102. package/lib/prompts/promptName.js +11 -0
  103. package/lib/prompts/promptOperation.js +13 -0
  104. package/lib/socket/customerSocketClient.js +13 -0
  105. package/lib/socket/socketClient.js +12 -0
  106. package/lib/types.js +1 -0
  107. package/package.json +13 -10
@@ -0,0 +1,127 @@
1
+ const aYOUneModules = [
2
+ {
3
+ label: "Artificial Intelligence",
4
+ module: "ai",
5
+ host: "ai.ayoune.app",
6
+ },
7
+ {
8
+ label: "Asset store",
9
+ module: "assetstore",
10
+ host: "assetstore.ayoune.app",
11
+ },
12
+ {
13
+ label: "Customer Relationship Management",
14
+ module: "crm",
15
+ host: "crm.ayoune.app",
16
+ },
17
+ {
18
+ label: "Project management",
19
+ module: "pm",
20
+ host: "pm.ayoune.app",
21
+ },
22
+ {
23
+ label: "Content management system",
24
+ module: "cms",
25
+ host: "cms.ayoune.app",
26
+ },
27
+ {
28
+ label: "Marketing",
29
+ module: "marketing",
30
+ host: "marketing.ayoune.app",
31
+ },
32
+ {
33
+ label: "Automation",
34
+ module: "automation",
35
+ host: "automation.ayoune.app",
36
+ },
37
+ { label: "Sale", module: "sale", host: "sale.ayoune.app" },
38
+ {
39
+ label: "Product information management",
40
+ module: "pim",
41
+ host: "pim.ayoune.app",
42
+ },
43
+ { label: "Hub", module: "hub", host: "hub.ayoune.app" },
44
+ {
45
+ label: "Human Resources",
46
+ module: "hr",
47
+ host: "hr.ayoune.app",
48
+ },
49
+ {
50
+ label: "Service Desk",
51
+ module: "service",
52
+ host: "service.ayoune.app",
53
+ },
54
+ {
55
+ label: "Purchase",
56
+ module: "purchase",
57
+ host: "purchase.ayoune.app",
58
+ },
59
+ {
60
+ label: "Accounting",
61
+ module: "accounting",
62
+ host: "accounting.ayoune.app",
63
+ },
64
+ {
65
+ label: "E Commerce",
66
+ module: "ecommerce",
67
+ host: "ecommerce.ayoune.app",
68
+ },
69
+ {
70
+ label: "Monitoring",
71
+ module: "monitoring",
72
+ host: "monitoring.ayoune.app",
73
+ },
74
+ {
75
+ label: "Research",
76
+ module: "research",
77
+ host: "research.ayoune.app",
78
+ },
79
+ {
80
+ label: "Production",
81
+ module: "production",
82
+ host: "production.ayoune.app",
83
+ },
84
+ {
85
+ label: "Affiliate",
86
+ module: "affiliate",
87
+ host: "affiliate.ayoune.app",
88
+ },
89
+ {
90
+ label: "Reporting",
91
+ module: "reporting",
92
+ host: "reporting.ayoune.app",
93
+ },
94
+ {
95
+ label: "Export",
96
+ module: "export",
97
+ host: "export.ayoune.app",
98
+ },
99
+ {
100
+ label: "Configuration",
101
+ module: "config",
102
+ host: "config.ayoune.app",
103
+ },
104
+ {
105
+ label: "Audit",
106
+ module: "audit",
107
+ host: "audit.ayoune.app",
108
+ },
109
+ {
110
+ label: "DevOps",
111
+ module: "devops",
112
+ host: "devops.ayoune.app",
113
+ },
114
+ {
115
+ label: "Sync",
116
+ module: "sync",
117
+ host: "sync.ayoune.app",
118
+ },
119
+ {
120
+ label: "System (Superuser)",
121
+ module: "su",
122
+ host: "api-v1.ayoune.app",
123
+ superuserOnly: true,
124
+ },
125
+ ];
126
+ export default aYOUneModules;
127
+ export { aYOUneModules };
@@ -0,0 +1,5 @@
1
+ const operations = [
2
+ 'list',
3
+ 'get',
4
+ ];
5
+ export { operations };
@@ -0,0 +1,139 @@
1
+ const aYOUneServices = [
2
+ {
3
+ label: "Barcodes",
4
+ module: "global",
5
+ host: "bc.ayoune.app",
6
+ },
7
+ {
8
+ label: "Aggregation",
9
+ module: "global",
10
+ host: "aggregation.ayoune.app",
11
+ },
12
+ {
13
+ label: "Browser Automations",
14
+ module: "automation",
15
+ host: "browser-automations.ayoune.app",
16
+ },
17
+ {
18
+ label: "Datatables",
19
+ module: "global",
20
+ host: "datatables.ayoune.app",
21
+ },
22
+ {
23
+ label: "Exports",
24
+ module: "exports",
25
+ host: "exports.ayoune.app",
26
+ },
27
+ {
28
+ label: "Middleware",
29
+ module: "global",
30
+ host: "mw.ayoune.app",
31
+ },
32
+ {
33
+ label: "Replacer",
34
+ module: "global",
35
+ host: "replacer.ayoune.app",
36
+ },
37
+ {
38
+ label: "Services",
39
+ module: "services",
40
+ host: "services.ayoune.app",
41
+ },
42
+ {
43
+ label: "Endpoints",
44
+ module: "global",
45
+ host: "endpoints.ayoune.app",
46
+ },
47
+ {
48
+ label: "Gists",
49
+ module: "pm",
50
+ host: "gists.ayoune.app",
51
+ },
52
+ {
53
+ label: "Text to Speech",
54
+ module: "global",
55
+ host: "tts.ayoune.app",
56
+ },
57
+ {
58
+ label: "Statistics",
59
+ module: "metrics",
60
+ host: "stats.ayoune.app",
61
+ },
62
+ {
63
+ label: "Statistics",
64
+ module: "stats",
65
+ host: "stats.ayoune.app",
66
+ },
67
+ {
68
+ label: "Video Generation",
69
+ module: "cms",
70
+ host: "video-generation.ayoune.app",
71
+ },
72
+ {
73
+ label: "Image Generation",
74
+ module: "cms",
75
+ host: "image-generation.ayoune.app",
76
+ },
77
+ {
78
+ label: "Text Generation",
79
+ module: "text",
80
+ host: "text-generation.ayoune.app",
81
+ },
82
+ {
83
+ label: "Serp Html Archive",
84
+ module: "research",
85
+ host: "serp-html-archive.ayoune.app",
86
+ },
87
+ {
88
+ label: "Config files",
89
+ module: "global",
90
+ host: "configs.ayoune.app",
91
+ },
92
+ {
93
+ label: "GraphQl",
94
+ module: "global",
95
+ host: "graph.ayoune.app",
96
+ },
97
+ {
98
+ label: "Dynamic Content",
99
+ module: "cms",
100
+ host: "dc.ayoune.app",
101
+ },
102
+ {
103
+ label: "Media",
104
+ module: "cms",
105
+ host: "media.ayoune.app",
106
+ },
107
+ {
108
+ label: "Text Spinner",
109
+ module: "cms",
110
+ host: "spinner.ayoune.app",
111
+ },
112
+ {
113
+ label: "Content Snippets",
114
+ module: "cms",
115
+ host: "snippets.ayoune.app",
116
+ },
117
+ {
118
+ label: "Downloads",
119
+ module: "cms",
120
+ host: "downloads.ayoune.app",
121
+ },
122
+ {
123
+ label: "Scripts",
124
+ module: "global",
125
+ host: "scripts.ayoune.app",
126
+ },
127
+ {
128
+ label: "Downloads",
129
+ module: "cms",
130
+ host: "downloads.ayoune.app",
131
+ },
132
+ {
133
+ label: "Documents",
134
+ module: "crm",
135
+ host: "documents.ayoune.app",
136
+ },
137
+ ];
138
+ export default aYOUneServices;
139
+ export { aYOUneServices };
package/index.js ADDED
@@ -0,0 +1,11 @@
1
+ #! /usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { createSpinner } from "nanospinner";
4
+ import { initializeSettings } from "./lib/helpers/initializeSettings.js";
5
+ import { createProgram } from "./lib/commands/createProgram.js";
6
+ //Create new command instance
7
+ const program = new Command();
8
+ initializeSettings();
9
+ //Setup spinner - output to stderr so stdout stays clean for piping
10
+ export const spinner = createSpinner("Getting data...", { stream: process.stderr });
11
+ createProgram(program);
@@ -0,0 +1,72 @@
1
+ import { api, getModuleBaseUrl } from "./apiClient.js";
2
+ import chalk from "chalk";
3
+ import * as process from "process";
4
+ import { secureStorage } from "../helpers/secureStorage.js";
5
+ import { handleAPIError } from "./handleAPIError.js";
6
+ import { login } from "./login.js";
7
+ import { spinner } from "../../index.js";
8
+ let dryRunEnabled = false;
9
+ export function enableDryRun() {
10
+ dryRunEnabled = true;
11
+ }
12
+ function cleanParams(params) {
13
+ const cleaned = {};
14
+ for (const [key, value] of Object.entries(params)) {
15
+ if (value === undefined || value === null || value === false || value === "")
16
+ continue;
17
+ cleaned[key] = value;
18
+ }
19
+ // The API only supports json, yaml, csv — table is formatted client-side from JSON
20
+ if (cleaned.responseFormat === "table") {
21
+ cleaned.responseFormat = "json";
22
+ }
23
+ const version = process.env.AYOUNE_VERSION;
24
+ if (version) {
25
+ cleaned.ref = `ayoune-cli@${version}`;
26
+ }
27
+ return cleaned;
28
+ }
29
+ function getToken() {
30
+ return secureStorage.getItem("token") || process.env.AYOUNE_TOKEN || "";
31
+ }
32
+ const makeRequest = (module, url, method, data, params) => api({
33
+ baseURL: getModuleBaseUrl(module),
34
+ method,
35
+ url,
36
+ data,
37
+ params: cleanParams(params),
38
+ headers: {
39
+ Authorization: `Bearer ${getToken()}`,
40
+ },
41
+ });
42
+ export const apiCallHandler = async (module, url, method = "get", data = null, params = {}) => {
43
+ var _a;
44
+ // Dry-run: show what would happen for mutating requests
45
+ if (dryRunEnabled && method !== "get") {
46
+ const baseUrl = getModuleBaseUrl(module);
47
+ const fullUrl = `${baseUrl}/${url}`.replace(/\/+/g, "/").replace(":/", "://");
48
+ spinner.stop();
49
+ console.error(chalk.yellow.bold("\n [DRY RUN] Request not sent:\n"));
50
+ console.error(` ${chalk.dim("Method:")} ${chalk.cyan(method.toUpperCase())}`);
51
+ console.error(` ${chalk.dim("URL:")} ${chalk.cyan(fullUrl)}`);
52
+ if (data) {
53
+ console.error(` ${chalk.dim("Body:")} ${JSON.stringify(data, null, 2).split("\n").join("\n ")}`);
54
+ }
55
+ console.error();
56
+ return { payload: null, meta: { responseTime: 0, message: "Dry run - no request sent" } };
57
+ }
58
+ try {
59
+ const response = await makeRequest(module, url, method, data, params);
60
+ return response.data;
61
+ }
62
+ catch (error) {
63
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401) {
64
+ spinner.stop();
65
+ spinner.error({ text: "Session expired. Re-authenticating..." });
66
+ await login();
67
+ const response = await makeRequest(module, url, method, data, params);
68
+ return response.data;
69
+ }
70
+ handleAPIError(error);
71
+ }
72
+ };
@@ -0,0 +1,108 @@
1
+ import axios from "axios";
2
+ import https from "https";
3
+ import chalk from "chalk";
4
+ import axiosRetry from "axios-retry";
5
+ import { config } from "../helpers/config.js";
6
+ const httpsAgent = new https.Agent({ rejectUnauthorized: false });
7
+ let debugEnabled = false;
8
+ export function enableDebug() {
9
+ debugEnabled = true;
10
+ }
11
+ function debugLog(prefix, ...args) {
12
+ if (!debugEnabled)
13
+ return;
14
+ console.error(chalk.dim(` [debug] ${prefix}`), ...args);
15
+ }
16
+ const api = axios.create({
17
+ timeout: 30000,
18
+ httpsAgent,
19
+ });
20
+ const audit = axios.create({
21
+ baseURL: config.auditUrl,
22
+ httpsAgent,
23
+ });
24
+ // Modules that don't follow the standard {module}-api.ayoune.app pattern
25
+ const MODULE_HOST_OVERRIDES = {
26
+ su: "https://api-v1.ayoune.app/api/su",
27
+ logs: "https://monitoring-api.ayoune.app",
28
+ general: "https://api-v1.ayoune.app/api/general",
29
+ usersettings: "https://api-v1.ayoune.app/api/usersettings",
30
+ auth: "https://auth.ayoune.app",
31
+ };
32
+ export function getModuleBaseUrl(module) {
33
+ return MODULE_HOST_OVERRIDES[module] || `https://${module}-api.ayoune.app`;
34
+ }
35
+ function addDebugInterceptors(instance) {
36
+ instance.interceptors.request.use((req) => {
37
+ var _a, _b, _c;
38
+ const url = `${req.baseURL || ""}/${req.url || ""}`.replace(/\/+/g, "/").replace(":/", "://");
39
+ debugLog(`${chalk.yellow((_a = req.method) === null || _a === void 0 ? void 0 : _a.toUpperCase())} ${chalk.cyan(url)}`);
40
+ if (req.params && Object.keys(req.params).length) {
41
+ debugLog("params:", JSON.stringify(req.params));
42
+ }
43
+ if (req.data) {
44
+ debugLog("body:", JSON.stringify(req.data).substring(0, 200));
45
+ }
46
+ const auth = ((_b = req.headers) === null || _b === void 0 ? void 0 : _b.Authorization) || ((_c = req.headers) === null || _c === void 0 ? void 0 : _c.authorization);
47
+ if (auth) {
48
+ const token = String(auth);
49
+ debugLog("auth:", token.substring(0, 15) + "..." + token.substring(token.length - 10));
50
+ }
51
+ return req;
52
+ });
53
+ instance.interceptors.response.use((res) => {
54
+ var _a, _b;
55
+ const meta = (_a = res.data) === null || _a === void 0 ? void 0 : _a.meta;
56
+ const total = (_b = meta === null || meta === void 0 ? void 0 : meta.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries;
57
+ const time = meta === null || meta === void 0 ? void 0 : meta.responseTime;
58
+ debugLog(`${chalk.green(res.status)} ${res.statusText}` +
59
+ (time ? ` ${chalk.dim(`(${time}ms)`)}` : "") +
60
+ (total !== undefined ? ` ${chalk.dim(`[${total} entries]`)}` : ""));
61
+ if (res.data) {
62
+ const body = JSON.stringify(res.data);
63
+ debugLog("response:", body.length > 500 ? body.substring(0, 500) + "..." : body);
64
+ }
65
+ return res;
66
+ }, (err) => {
67
+ if (err.response) {
68
+ debugLog(`${chalk.red(err.response.status)} ${err.response.statusText}`);
69
+ if (err.response.data) {
70
+ debugLog("response:", JSON.stringify(err.response.data).substring(0, 500));
71
+ }
72
+ }
73
+ else {
74
+ debugLog(chalk.red(`network error: ${err.message}`));
75
+ }
76
+ return Promise.reject(err);
77
+ });
78
+ }
79
+ addDebugInterceptors(api);
80
+ addDebugInterceptors(audit);
81
+ const retryConfig = {
82
+ retries: 3,
83
+ retryDelay: (retryCount, error) => {
84
+ var _a, _b;
85
+ // Respect Retry-After header for 429 responses
86
+ const retryAfter = (_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.headers) === null || _b === void 0 ? void 0 : _b["retry-after"];
87
+ if (retryAfter) {
88
+ const seconds = parseInt(retryAfter, 10);
89
+ if (!isNaN(seconds)) {
90
+ debugLog(chalk.yellow(`Rate limited. Retrying in ${seconds}s...`));
91
+ return seconds * 1000;
92
+ }
93
+ }
94
+ // Exponential backoff: 1s, 2s, 4s
95
+ const delay = Math.pow(2, retryCount - 1) * 1000;
96
+ debugLog(chalk.yellow(`Retrying in ${delay / 1000}s (attempt ${retryCount}/3)...`));
97
+ return delay;
98
+ },
99
+ retryCondition: (error) => {
100
+ var _a;
101
+ // Retry on network errors, 5xx, and 429 (rate limit)
102
+ return axiosRetry.isNetworkOrIdempotentRequestError(error)
103
+ || ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429;
104
+ },
105
+ };
106
+ axiosRetry(api, retryConfig);
107
+ axiosRetry(audit, retryConfig);
108
+ export { api, audit };
@@ -0,0 +1,21 @@
1
+ import { audit } from "./apiClient.js";
2
+ import * as process from "process";
3
+ import { secureStorage } from "../helpers/secureStorage.js";
4
+ import { handleAPIError } from "./handleAPIError.js";
5
+ export const auditCallHandler = async (url, method = "get", data = null, params = {}) => {
6
+ try {
7
+ const response = await audit({
8
+ method,
9
+ url,
10
+ data,
11
+ params: { ...params, ref: `ayoune-cli@${process.env.AYOUNE_VERSION}` },
12
+ headers: {
13
+ Authorization: `Bearer ${secureStorage.getItem("token")}`,
14
+ },
15
+ });
16
+ return response.data;
17
+ }
18
+ catch (error) {
19
+ handleAPIError(error);
20
+ }
21
+ };
@@ -0,0 +1,4 @@
1
+ import { decode } from "jsonwebtoken";
2
+ export const decodeToken = (token) => {
3
+ return decode(token, { json: true, complete: true });
4
+ };
@@ -0,0 +1,61 @@
1
+ import { spinner } from "../../index.js";
2
+ import { EXIT_GENERAL_ERROR, EXIT_AUTH_REQUIRED, EXIT_PERMISSION_DENIED, } from "../exitCodes.js";
3
+ import { isJsonErrorsEnabled } from "../helpers/cliError.js";
4
+ function emitJsonError(code, type, message, details) {
5
+ if (isJsonErrorsEnabled()) {
6
+ const err = { error: type, code, message, ...(details ? { details } : {}) };
7
+ console.error(JSON.stringify(err));
8
+ }
9
+ process.exit(code);
10
+ }
11
+ export function handleAPIError(error) {
12
+ var _a, _b, _c, _d;
13
+ const jsonErrors = isJsonErrorsEnabled();
14
+ const apiError = error.response;
15
+ const requestConfig = error.config;
16
+ const method = ((requestConfig === null || requestConfig === void 0 ? void 0 : requestConfig.method) || "GET").toUpperCase();
17
+ const fullUrl = requestConfig
18
+ ? `${requestConfig.baseURL || ""}/${requestConfig.url || ""}`.replace(/\/+/g, "/").replace(":/", "://")
19
+ : "unknown";
20
+ if (!apiError) {
21
+ if (!jsonErrors) {
22
+ spinner.error({ text: `Network error: ${error.message}` });
23
+ console.error(` Request: ${method} ${fullUrl}`);
24
+ }
25
+ emitJsonError(EXIT_GENERAL_ERROR, "network_error", error.message, { method, url: fullUrl });
26
+ }
27
+ const serverMessage = ((_b = (_a = apiError.data) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.message) || apiError.statusText;
28
+ if (apiError.status === 400) {
29
+ if (!jsonErrors) {
30
+ spinner.error({ text: `Bad Request: ${serverMessage}` });
31
+ console.error(` Request: ${method} ${fullUrl}`);
32
+ }
33
+ emitJsonError(EXIT_GENERAL_ERROR, "bad_request", serverMessage, { method, url: fullUrl, status: 400 });
34
+ }
35
+ if (apiError.status === 401) {
36
+ if (!jsonErrors)
37
+ spinner.error({ text: "Session expired. Please run: ay login" });
38
+ emitJsonError(EXIT_AUTH_REQUIRED, "auth_required", "Session expired", { status: 401 });
39
+ }
40
+ if (apiError.status === 403) {
41
+ const rights = ((_d = (_c = apiError.data) === null || _c === void 0 ? void 0 : _c.meta) === null || _d === void 0 ? void 0 : _d.requiredRights) || [];
42
+ if (!jsonErrors) {
43
+ spinner.error({
44
+ text: `Forbidden. Required rights: [${rights.join(", ")}]`,
45
+ });
46
+ console.error(` Request: ${method} ${fullUrl}`);
47
+ }
48
+ emitJsonError(EXIT_PERMISSION_DENIED, "permission_denied", "Forbidden", { method, url: fullUrl, status: 403, requiredRights: rights });
49
+ }
50
+ if (!jsonErrors) {
51
+ spinner.error({
52
+ text: `Error ${apiError.status}: ${serverMessage}`,
53
+ });
54
+ console.error(` Request: ${method} ${fullUrl}`);
55
+ if (apiError.data && typeof apiError.data === "object") {
56
+ const debugInfo = apiError.data.meta || apiError.data;
57
+ console.error(` Response: ${JSON.stringify(debugInfo)}`);
58
+ }
59
+ }
60
+ emitJsonError(EXIT_GENERAL_ERROR, "api_error", serverMessage, { method, url: fullUrl, status: apiError.status });
61
+ }
@@ -0,0 +1,45 @@
1
+ import { socket } from "../socket/socketClient.js";
2
+ import { randomAsciiString } from "../helpers/makeRandomToken.js";
3
+ import { spinner } from "../../index.js";
4
+ import { secureStorage } from "../helpers/secureStorage.js";
5
+ import { config } from "../helpers/config.js";
6
+ import chalk from "chalk";
7
+ function terminalLink(text, url) {
8
+ // OSC 8 hyperlink escape sequence - supported by most modern terminals
9
+ return `\u001B]8;;${url}\u0007${text}\u001B]8;;\u0007`;
10
+ }
11
+ export const login = async () => {
12
+ spinner.start({ text: "Waiting for login\n" });
13
+ const token = randomAsciiString();
14
+ const url = `${config.loginUrl}/ayoune?cli=${token}`;
15
+ const clickable = terminalLink(chalk.cyan.underline(url), url);
16
+ console.log();
17
+ console.log(` ${chalk.dim("Open this URL to authenticate:")}`);
18
+ console.log(` ${clickable}`);
19
+ console.log();
20
+ const credentials = await waitForCredentials(token);
21
+ return credentials;
22
+ };
23
+ const waitForCredentials = async (token) => {
24
+ return new Promise(function (resolve, reject) {
25
+ const _socket = socket(token);
26
+ _socket.on("join:cli:confirmed", async (data) => {
27
+ spinner.update({ text: `Session active` });
28
+ });
29
+ _socket.on("cli-token", async (data) => {
30
+ spinner.success({ text: `Received auth credentials` });
31
+ secureStorage.setItem("token", data.token);
32
+ secureStorage.setItem("refreshToken", data.refreshToken);
33
+ _socket.disconnect();
34
+ resolve(data);
35
+ });
36
+ _socket.on("connect_error", async (err) => {
37
+ spinner.error({ text: err.message });
38
+ _socket.disconnect();
39
+ reject(err);
40
+ });
41
+ _socket.on("connect", async () => {
42
+ spinner.update({ text: "Tunnel established. Waiting for credentials" });
43
+ });
44
+ });
45
+ };