@tolinax/ayoune-cli 2026.3.1 → 2026.5.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 +217 -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 +160 -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 +50 -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,276 @@
1
+ import { apiCallHandler } from "../api/apiCallHandler.js";
2
+ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
3
+ import { saveFile } from "../helpers/saveFile.js";
4
+ import { spinner } from "../../index.js";
5
+ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
6
+ import { cliError } from "../helpers/cliError.js";
7
+ export function createMonitorCommand(program) {
8
+ const monitor = program
9
+ .command("monitor")
10
+ .alias("mon")
11
+ .description("Monitor platform activity, logs, and alerts");
12
+ // ay monitor logs [type]
13
+ monitor
14
+ .command("logs [type]")
15
+ .description("List recent platform logs (api, error, mail, ai, trigger, ...)")
16
+ .addHelpText("after", `
17
+ Log types: api, error, mail, ai, trigger, doi, export, sms, whatsapp, production, setup, state, shop, score, sensor, stock, soi, reward, merge, download, post, webreceiver, work, computingentitieslogs, consumerapi, accessterminal, googleads
18
+
19
+ Examples:
20
+ ay monitor logs error List recent error logs
21
+ ay monitor logs api -l 10 List last 10 API logs
22
+ ay monitor logs ai -r table List AI logs in table format`)
23
+ .option("-l, --limit <number>", "Limit results", parseInt, 25)
24
+ .option("-p, --page <number>", "Page number", parseInt, 1)
25
+ .option("--sort <field>", "Sort by field", "-createdAt")
26
+ .action(async (type, options) => {
27
+ var _a, _b, _c;
28
+ try {
29
+ const opts = { ...program.opts(), ...options };
30
+ const logType = type || "api";
31
+ const collectionMap = {
32
+ api: "apilogs",
33
+ error: "errorlogs",
34
+ mail: "maillogs",
35
+ ai: "ailogs",
36
+ trigger: "triggerlogs",
37
+ doi: "doilogs",
38
+ export: "exportlogs",
39
+ sms: "smslogs",
40
+ whatsapp: "whatsapplogs",
41
+ production: "productionlogs",
42
+ setup: "setuplogs",
43
+ state: "statelogs",
44
+ shop: "shoplogs",
45
+ score: "scorelogs",
46
+ sensor: "sensorlogs",
47
+ stock: "stocklogs",
48
+ soi: "soilogs",
49
+ reward: "rewardlogs",
50
+ merge: "mergelogs",
51
+ download: "downloadlogs",
52
+ post: "postlogs",
53
+ webreceiver: "webreceiverlogs",
54
+ work: "worklogs",
55
+ consumerapi: "consumerapilogs",
56
+ accessterminal: "accessterminallogs",
57
+ googleads: "adwordslogs",
58
+ computing: "computingentitieslogs",
59
+ };
60
+ const collection = collectionMap[logType] || `${logType}logs`;
61
+ spinner.start({ text: `Fetching ${logType} logs...`, color: "magenta" });
62
+ const res = await apiCallHandler("logs", collection, "get", null, {
63
+ page: opts.page,
64
+ limit: opts.limit,
65
+ sort: opts.sort,
66
+ responseFormat: opts.responseFormat,
67
+ verbosity: opts.verbosity,
68
+ hideMeta: opts.hideMeta,
69
+ });
70
+ handleResponseFormatOptions(opts, res);
71
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
72
+ spinner.success({ text: `Found ${total} ${logType} log entries` });
73
+ spinner.stop();
74
+ if (opts.save)
75
+ await saveFile(`monitor-logs-${logType}`, opts, res);
76
+ }
77
+ catch (e) {
78
+ cliError(e.message || "Failed to fetch logs", EXIT_GENERAL_ERROR);
79
+ }
80
+ });
81
+ // ay monitor alerts — command group
82
+ const alerts = monitor
83
+ .command("alerts")
84
+ .description("Manage platform alerts (list, acknowledge, resolve)");
85
+ // ay monitor alerts list
86
+ alerts
87
+ .command("list")
88
+ .alias("ls")
89
+ .description("List active alerts")
90
+ .addHelpText("after", `
91
+ Examples:
92
+ ay monitor alerts list List all active alerts
93
+ ay monitor alerts list --severity critical Show critical alerts only
94
+ ay monitor alerts list --type pod_crash Filter by alert type
95
+ ay monitor alerts list --status acknowledged Show acknowledged alerts`)
96
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
97
+ .option("-p, --page <number>", "Page number", parseInt, 1)
98
+ .option("--severity <level>", "Filter: info, warning, critical")
99
+ .option("--type <type>", "Filter: pod_crash, oom_killed, image_pull_error, deployment_failed, pipeline_failed, cluster_unreachable, high_restart_count, custom")
100
+ .option("--status <status>", "Filter: active, acknowledged, resolved", "active")
101
+ .action(async (options) => {
102
+ var _a, _b, _c;
103
+ try {
104
+ const opts = { ...program.opts(), ...options };
105
+ spinner.start({ text: "Fetching alerts...", color: "magenta" });
106
+ const params = {
107
+ page: opts.page,
108
+ limit: opts.limit,
109
+ responseFormat: opts.responseFormat,
110
+ verbosity: opts.verbosity,
111
+ hideMeta: opts.hideMeta,
112
+ };
113
+ if (opts.severity)
114
+ params.severity = opts.severity;
115
+ if (opts.type)
116
+ params.type = opts.type;
117
+ if (opts.status)
118
+ params.status = opts.status;
119
+ const res = await apiCallHandler("devops", "alerts", "get", null, params);
120
+ handleResponseFormatOptions(opts, res);
121
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
122
+ spinner.success({ text: `Found ${total} alerts` });
123
+ spinner.stop();
124
+ if (opts.save)
125
+ await saveFile("monitor-alerts", opts, res);
126
+ }
127
+ catch (e) {
128
+ cliError(e.message || "Failed to fetch alerts", EXIT_GENERAL_ERROR);
129
+ }
130
+ });
131
+ // ay monitor alerts ack <id>
132
+ alerts
133
+ .command("ack <id>")
134
+ .alias("acknowledge")
135
+ .description("Acknowledge an alert")
136
+ .action(async (id, options) => {
137
+ try {
138
+ const opts = { ...program.opts(), ...options };
139
+ spinner.start({ text: `Acknowledging alert ${id}...`, color: "magenta" });
140
+ const res = await apiCallHandler("devops", `alerts/${id}/acknowledge`, "put", null, {
141
+ responseFormat: opts.responseFormat,
142
+ });
143
+ handleResponseFormatOptions(opts, res);
144
+ spinner.success({ text: `Alert ${id} acknowledged` });
145
+ spinner.stop();
146
+ }
147
+ catch (e) {
148
+ cliError(e.message || "Failed to acknowledge alert", EXIT_GENERAL_ERROR);
149
+ }
150
+ });
151
+ // ay monitor alerts resolve <id>
152
+ alerts
153
+ .command("resolve <id>")
154
+ .description("Resolve an alert")
155
+ .action(async (id, options) => {
156
+ try {
157
+ const opts = { ...program.opts(), ...options };
158
+ spinner.start({ text: `Resolving alert ${id}...`, color: "magenta" });
159
+ const res = await apiCallHandler("devops", `alerts/${id}/resolve`, "put", null, {
160
+ responseFormat: opts.responseFormat,
161
+ });
162
+ handleResponseFormatOptions(opts, res);
163
+ spinner.success({ text: `Alert ${id} resolved` });
164
+ spinner.stop();
165
+ }
166
+ catch (e) {
167
+ cliError(e.message || "Failed to resolve alert", EXIT_GENERAL_ERROR);
168
+ }
169
+ });
170
+ // ay monitor sessions
171
+ monitor
172
+ .command("sessions")
173
+ .description("List active user sessions")
174
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
175
+ .action(async (options) => {
176
+ var _a, _b, _c;
177
+ try {
178
+ const opts = { ...program.opts(), ...options };
179
+ spinner.start({ text: "Fetching active sessions...", color: "magenta" });
180
+ const res = await apiCallHandler("monitoring", "sessions", "get", null, {
181
+ limit: opts.limit,
182
+ responseFormat: opts.responseFormat,
183
+ verbosity: opts.verbosity,
184
+ });
185
+ handleResponseFormatOptions(opts, res);
186
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
187
+ spinner.success({ text: `Found ${total} active sessions` });
188
+ spinner.stop();
189
+ if (opts.save)
190
+ await saveFile("monitor-sessions", opts, res);
191
+ }
192
+ catch (e) {
193
+ cliError(e.message || "Failed to fetch sessions", EXIT_GENERAL_ERROR);
194
+ }
195
+ });
196
+ // ay monitor checks
197
+ monitor
198
+ .command("checks")
199
+ .description("List monitoring checks and their results")
200
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
201
+ .action(async (options) => {
202
+ var _a, _b, _c;
203
+ try {
204
+ const opts = { ...program.opts(), ...options };
205
+ spinner.start({ text: "Fetching monitoring checks...", color: "magenta" });
206
+ const res = await apiCallHandler("monitoring", "checks", "get", null, {
207
+ limit: opts.limit,
208
+ responseFormat: opts.responseFormat,
209
+ verbosity: opts.verbosity,
210
+ });
211
+ handleResponseFormatOptions(opts, res);
212
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
213
+ spinner.success({ text: `Found ${total} monitoring checks` });
214
+ spinner.stop();
215
+ if (opts.save)
216
+ await saveFile("monitor-checks", opts, res);
217
+ }
218
+ catch (e) {
219
+ cliError(e.message || "Failed to fetch checks", EXIT_GENERAL_ERROR);
220
+ }
221
+ });
222
+ // ay monitor activeusers
223
+ monitor
224
+ .command("activeusers")
225
+ .alias("users")
226
+ .description("Show currently active users on the platform")
227
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
228
+ .action(async (options) => {
229
+ var _a, _b, _c;
230
+ try {
231
+ const opts = { ...program.opts(), ...options };
232
+ spinner.start({ text: "Fetching active users...", color: "magenta" });
233
+ const res = await apiCallHandler("monitoring", "activeusers", "get", null, {
234
+ limit: opts.limit,
235
+ responseFormat: opts.responseFormat,
236
+ verbosity: opts.verbosity,
237
+ });
238
+ handleResponseFormatOptions(opts, res);
239
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
240
+ spinner.success({ text: `${total} active users` });
241
+ spinner.stop();
242
+ if (opts.save)
243
+ await saveFile("monitor-activeusers", opts, res);
244
+ }
245
+ catch (e) {
246
+ cliError(e.message || "Failed to fetch active users", EXIT_GENERAL_ERROR);
247
+ }
248
+ });
249
+ // ay monitor pagestats
250
+ monitor
251
+ .command("pagestats")
252
+ .alias("pages")
253
+ .description("View page view statistics")
254
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
255
+ .action(async (options) => {
256
+ var _a, _b, _c;
257
+ try {
258
+ const opts = { ...program.opts(), ...options };
259
+ spinner.start({ text: "Fetching page statistics...", color: "magenta" });
260
+ const res = await apiCallHandler("monitoring", "pagestats", "get", null, {
261
+ limit: opts.limit,
262
+ responseFormat: opts.responseFormat,
263
+ verbosity: opts.verbosity,
264
+ });
265
+ handleResponseFormatOptions(opts, res);
266
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
267
+ spinner.success({ text: `Found ${total} page stat entries` });
268
+ spinner.stop();
269
+ if (opts.save)
270
+ await saveFile("monitor-pagestats", opts, res);
271
+ }
272
+ catch (e) {
273
+ cliError(e.message || "Failed to fetch page stats", EXIT_GENERAL_ERROR);
274
+ }
275
+ });
276
+ }
@@ -0,0 +1,233 @@
1
+ import { apiCallHandler } from "../api/apiCallHandler.js";
2
+ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
3
+ import { saveFile } from "../helpers/saveFile.js";
4
+ import { spinner } from "../../index.js";
5
+ import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
6
+ import { cliError } from "../helpers/cliError.js";
7
+ export function createPermissionsCommand(program) {
8
+ const perms = program
9
+ .command("permissions")
10
+ .alias("perms")
11
+ .description("Manage permissions, access requests, and user rights");
12
+ // ── PERMISSION REQUESTS ────────────────────────────────
13
+ const requests = perms
14
+ .command("requests")
15
+ .alias("req")
16
+ .description("Manage permission requests");
17
+ // ay permissions requests list
18
+ requests
19
+ .command("list")
20
+ .alias("ls")
21
+ .description("List permission requests")
22
+ .option("--status <status>", "Filter by status (pending, approved, rejected)")
23
+ .option("-l, --limit <number>", "Limit results", parseInt, 25)
24
+ .option("-p, --page <number>", "Page number", parseInt, 1)
25
+ .action(async (options) => {
26
+ var _a, _b, _c;
27
+ try {
28
+ const opts = { ...program.opts(), ...options };
29
+ spinner.start({ text: "Fetching permission requests...", color: "magenta" });
30
+ const params = {
31
+ page: opts.page,
32
+ limit: opts.limit,
33
+ responseFormat: opts.responseFormat,
34
+ verbosity: opts.verbosity,
35
+ };
36
+ if (opts.status)
37
+ params.status = opts.status;
38
+ const res = await apiCallHandler("config", "permissionrequests", "get", null, params);
39
+ handleResponseFormatOptions(opts, res);
40
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
41
+ spinner.success({ text: `Found ${total} permission requests` });
42
+ spinner.stop();
43
+ if (opts.save)
44
+ await saveFile("permission-requests", opts, res);
45
+ }
46
+ catch (e) {
47
+ cliError(e.message || "Failed to list permission requests", EXIT_GENERAL_ERROR);
48
+ }
49
+ });
50
+ // ay permissions requests approve <id>
51
+ requests
52
+ .command("approve <id>")
53
+ .description("Approve a permission request")
54
+ .action(async (id, options) => {
55
+ try {
56
+ const opts = { ...program.opts(), ...options };
57
+ spinner.start({ text: `Approving request ${id}...`, color: "magenta" });
58
+ const res = await apiCallHandler("config", "permissionrequests", "put", { _id: id, status: "approved" }, { responseFormat: opts.responseFormat });
59
+ handleResponseFormatOptions(opts, res);
60
+ spinner.success({ text: `Permission request ${id} approved` });
61
+ spinner.stop();
62
+ }
63
+ catch (e) {
64
+ cliError(e.message || "Failed to approve request", EXIT_GENERAL_ERROR);
65
+ }
66
+ });
67
+ // ay permissions requests reject <id>
68
+ requests
69
+ .command("reject <id>")
70
+ .description("Reject a permission request")
71
+ .option("--reason <reason>", "Reason for rejection")
72
+ .action(async (id, options) => {
73
+ try {
74
+ const opts = { ...program.opts(), ...options };
75
+ spinner.start({ text: `Rejecting request ${id}...`, color: "magenta" });
76
+ const body = { _id: id, status: "rejected" };
77
+ if (opts.reason)
78
+ body.reason = opts.reason;
79
+ const res = await apiCallHandler("config", "permissionrequests", "put", body, { responseFormat: opts.responseFormat });
80
+ handleResponseFormatOptions(opts, res);
81
+ spinner.success({ text: `Permission request ${id} rejected` });
82
+ spinner.stop();
83
+ }
84
+ catch (e) {
85
+ cliError(e.message || "Failed to reject request", EXIT_GENERAL_ERROR);
86
+ }
87
+ });
88
+ // ay permissions requests create
89
+ requests
90
+ .command("create")
91
+ .description("Create a new permission request")
92
+ .option("--body <json>", "Request definition as JSON")
93
+ .option("--right <right>", "Right to request (e.g. crm.contacts.edit)")
94
+ .option("--reason <reason>", "Reason for the request")
95
+ .action(async (options) => {
96
+ try {
97
+ const opts = { ...program.opts(), ...options };
98
+ let body = null;
99
+ if (opts.body) {
100
+ try {
101
+ body = JSON.parse(opts.body);
102
+ }
103
+ catch (_a) {
104
+ cliError("Invalid JSON in --body", EXIT_MISUSE);
105
+ }
106
+ }
107
+ else if (opts.right) {
108
+ body = { right: opts.right };
109
+ if (opts.reason)
110
+ body.reason = opts.reason;
111
+ }
112
+ if (!body) {
113
+ cliError("Provide request via --body or --right", EXIT_MISUSE);
114
+ }
115
+ spinner.start({ text: "Creating permission request...", color: "magenta" });
116
+ const res = await apiCallHandler("config", "permissionrequests", "post", body, {
117
+ responseFormat: opts.responseFormat,
118
+ });
119
+ handleResponseFormatOptions(opts, res);
120
+ spinner.success({ text: "Permission request created" });
121
+ spinner.stop();
122
+ }
123
+ catch (e) {
124
+ cliError(e.message || "Failed to create permission request", EXIT_GENERAL_ERROR);
125
+ }
126
+ });
127
+ // ── USER RIGHTS ────────────────────────────────────────
128
+ const rights = perms
129
+ .command("rights")
130
+ .description("View and manage user rights");
131
+ // ay permissions rights list
132
+ rights
133
+ .command("list")
134
+ .alias("ls")
135
+ .description("List user rights / permission assignments")
136
+ .option("--userId <id>", "Filter by user ID")
137
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
138
+ .option("-p, --page <number>", "Page number", parseInt, 1)
139
+ .action(async (options) => {
140
+ var _a, _b, _c;
141
+ try {
142
+ const opts = { ...program.opts(), ...options };
143
+ spinner.start({ text: "Fetching user rights...", color: "magenta" });
144
+ const params = {
145
+ page: opts.page,
146
+ limit: opts.limit,
147
+ responseFormat: opts.responseFormat,
148
+ verbosity: opts.verbosity,
149
+ };
150
+ if (opts.userId)
151
+ params.userId = opts.userId;
152
+ const res = await apiCallHandler("config", "userrights", "get", null, params);
153
+ handleResponseFormatOptions(opts, res);
154
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
155
+ spinner.success({ text: `Found ${total} user right assignments` });
156
+ spinner.stop();
157
+ if (opts.save)
158
+ await saveFile("user-rights", opts, res);
159
+ }
160
+ catch (e) {
161
+ cliError(e.message || "Failed to list user rights", EXIT_GENERAL_ERROR);
162
+ }
163
+ });
164
+ // ay permissions rights get <id>
165
+ rights
166
+ .command("get <id>")
167
+ .description("Get user right details")
168
+ .action(async (id, options) => {
169
+ try {
170
+ const opts = { ...program.opts(), ...options };
171
+ spinner.start({ text: `Fetching right ${id}...`, color: "magenta" });
172
+ const res = await apiCallHandler("config", `userrights/${id}`, "get", null, {
173
+ responseFormat: opts.responseFormat,
174
+ verbosity: opts.verbosity,
175
+ });
176
+ handleResponseFormatOptions(opts, res);
177
+ spinner.success({ text: `Right ${id} loaded` });
178
+ spinner.stop();
179
+ }
180
+ catch (e) {
181
+ cliError(e.message || "Failed to get user right", EXIT_GENERAL_ERROR);
182
+ }
183
+ });
184
+ // ── AUDIT (ENHANCED) ──────────────────────────────────
185
+ perms
186
+ .command("audit")
187
+ .description("Audit permission changes and access logs")
188
+ .addHelpText("after", `
189
+ Examples:
190
+ ay permissions audit --action delete --days 30
191
+ ay permissions audit --userId abc123 --collection contacts
192
+ ay permissions audit --action create --days 7 --save`)
193
+ .option("--userId <id>", "Filter by user ID")
194
+ .option("--action <action>", "Filter by action (create, update, delete, login)")
195
+ .option("--collection <name>", "Filter by collection")
196
+ .option("--days <number>", "Show entries from last N days", parseInt, 7)
197
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
198
+ .option("-p, --page <number>", "Page number", parseInt, 1)
199
+ .action(async (options) => {
200
+ var _a, _b, _c;
201
+ try {
202
+ const opts = { ...program.opts(), ...options };
203
+ spinner.start({ text: "Fetching audit logs...", color: "magenta" });
204
+ const params = {
205
+ page: opts.page,
206
+ limit: opts.limit,
207
+ responseFormat: opts.responseFormat,
208
+ verbosity: opts.verbosity,
209
+ };
210
+ if (opts.userId)
211
+ params.userId = opts.userId;
212
+ if (opts.action)
213
+ params.action = opts.action;
214
+ if (opts.collection)
215
+ params.collection = opts.collection;
216
+ if (opts.days) {
217
+ const fromDate = new Date();
218
+ fromDate.setDate(fromDate.getDate() - opts.days);
219
+ params.from = fromDate.toISOString();
220
+ }
221
+ const res = await apiCallHandler("general", "auditlogs", "get", null, params);
222
+ handleResponseFormatOptions(opts, res);
223
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
224
+ spinner.success({ text: `Found ${total} audit entries (last ${opts.days} days)` });
225
+ spinner.stop();
226
+ if (opts.save)
227
+ await saveFile("permissions-audit", opts, res);
228
+ }
229
+ catch (e) {
230
+ cliError(e.message || "Failed to fetch audit logs", EXIT_GENERAL_ERROR);
231
+ }
232
+ });
233
+ }