@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,65 @@
1
+ import { contextSlots } from "../../data/contextSlots.js";
2
+ import { getActiveContext } from "./contextStore.js";
3
+ let contextDisabled = false;
4
+ export function disableContext() {
5
+ contextDisabled = true;
6
+ }
7
+ export function hasActiveContext() {
8
+ if (contextDisabled)
9
+ return false;
10
+ return Object.keys(getActiveContext()).length > 0;
11
+ }
12
+ export function getContextCreateFields(collection) {
13
+ if (contextDisabled)
14
+ return {};
15
+ const active = getActiveContext();
16
+ const fields = {};
17
+ const col = collection.toLowerCase();
18
+ for (const slot of contextSlots) {
19
+ const entry = active[slot.slot];
20
+ if (!entry)
21
+ continue;
22
+ const fieldName = slot.injectAsCreateField[col];
23
+ if (fieldName) {
24
+ fields[fieldName] = entry.id;
25
+ }
26
+ }
27
+ return fields;
28
+ }
29
+ export function getContextFilterParams(collection) {
30
+ if (contextDisabled)
31
+ return {};
32
+ const active = getActiveContext();
33
+ const params = {};
34
+ const col = collection.toLowerCase();
35
+ for (const slot of contextSlots) {
36
+ const entry = active[slot.slot];
37
+ if (!entry)
38
+ continue;
39
+ const paramName = slot.injectAsFilterField[col];
40
+ if (paramName) {
41
+ params[paramName] = entry.id;
42
+ }
43
+ }
44
+ return params;
45
+ }
46
+ export function getContextSummary() {
47
+ if (contextDisabled)
48
+ return "";
49
+ const active = getActiveContext();
50
+ const entries = Object.entries(active);
51
+ if (entries.length === 0)
52
+ return "";
53
+ const lines = entries.map(([slot, entry]) => `- Active ${slot}: "${entry.name}" (${entry.collection}, ID: ${entry.id})`);
54
+ return `[Active context]\n${lines.join("\n")}`;
55
+ }
56
+ export function getContextForAI() {
57
+ if (contextDisabled)
58
+ return {};
59
+ const active = getActiveContext();
60
+ const result = {};
61
+ for (const [slot, entry] of Object.entries(active)) {
62
+ result[slot] = { id: entry.id, name: entry.name, collection: entry.collection };
63
+ }
64
+ return result;
65
+ }
@@ -0,0 +1,70 @@
1
+ import { apiCallHandler } from "../api/apiCallHandler.js";
2
+ import { getSlot, getChildSlots } from "../../data/contextSlots.js";
3
+ import { getContextEntry } from "./contextStore.js";
4
+ const OBJECT_ID_RE = /^[0-9a-fA-F]{24}$/;
5
+ export async function resolveEntity(slot, input) {
6
+ const slotDef = getSlot(slot);
7
+ if (!slotDef)
8
+ return [];
9
+ // Direct ID lookup
10
+ if (OBJECT_ID_RE.test(input)) {
11
+ try {
12
+ const res = await apiCallHandler(slotDef.module, `${slotDef.collection}/${input}`, "get", null, { fields: `_id,${slotDef.nameField}`, responseFormat: "json" });
13
+ if (res === null || res === void 0 ? void 0 : res.payload) {
14
+ const entity = Array.isArray(res.payload) ? res.payload[0] : res.payload;
15
+ if (entity === null || entity === void 0 ? void 0 : entity._id) {
16
+ return [{ id: entity._id, name: entity[slotDef.nameField] || entity._id }];
17
+ }
18
+ }
19
+ }
20
+ catch (_a) {
21
+ // Fall through to search
22
+ }
23
+ }
24
+ // Search by name
25
+ const params = {
26
+ q: input,
27
+ limit: 5,
28
+ responseFormat: "json",
29
+ fields: `_id,${slotDef.nameField}`,
30
+ };
31
+ // If parent context is active, filter by it
32
+ if (slotDef.parent) {
33
+ const parentEntry = getContextEntry(slotDef.parent);
34
+ if (parentEntry) {
35
+ const parentSlot = getSlot(slotDef.parent);
36
+ if (parentSlot) {
37
+ const filterField = parentSlot.injectAsFilterField[slotDef.collection];
38
+ if (filterField) {
39
+ params[filterField] = parentEntry.id;
40
+ }
41
+ }
42
+ }
43
+ }
44
+ try {
45
+ const res = await apiCallHandler(slotDef.module, slotDef.collection, "get", null, params);
46
+ if ((res === null || res === void 0 ? void 0 : res.payload) && Array.isArray(res.payload)) {
47
+ return res.payload.map((e) => ({
48
+ id: e._id,
49
+ name: e[slotDef.nameField] || e._id,
50
+ }));
51
+ }
52
+ }
53
+ catch (_b) {
54
+ // API error — return empty
55
+ }
56
+ return [];
57
+ }
58
+ export function validateHierarchy(slot) {
59
+ const slotDef = getSlot(slot);
60
+ if (!(slotDef === null || slotDef === void 0 ? void 0 : slotDef.parent))
61
+ return null;
62
+ const parentEntry = getContextEntry(slotDef.parent);
63
+ if (!parentEntry) {
64
+ return `Warning: Setting "${slot}" without parent "${slotDef.parent}" context. Results may not be scoped correctly.`;
65
+ }
66
+ return null;
67
+ }
68
+ export function getDependentSlots(slot) {
69
+ return getChildSlots(slot).map((s) => s.slot);
70
+ }
@@ -0,0 +1,46 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ const CONTEXT_PATH = path.join(os.homedir(), ".config", "ayoune", "context.json");
5
+ function ensureDir() {
6
+ const dir = path.dirname(CONTEXT_PATH);
7
+ if (!existsSync(dir)) {
8
+ mkdirSync(dir, { recursive: true });
9
+ }
10
+ }
11
+ export function loadContext() {
12
+ if (!existsSync(CONTEXT_PATH)) {
13
+ return { active: {} };
14
+ }
15
+ try {
16
+ const raw = readFileSync(CONTEXT_PATH, "utf-8");
17
+ return JSON.parse(raw);
18
+ }
19
+ catch (_a) {
20
+ return { active: {} };
21
+ }
22
+ }
23
+ export function saveContext(data) {
24
+ ensureDir();
25
+ writeFileSync(CONTEXT_PATH, JSON.stringify(data, null, 2), "utf-8");
26
+ }
27
+ export function getContextEntry(slot) {
28
+ const ctx = loadContext();
29
+ return ctx.active[slot];
30
+ }
31
+ export function setContextEntry(slot, entry) {
32
+ const ctx = loadContext();
33
+ ctx.active[slot] = entry;
34
+ saveContext(ctx);
35
+ }
36
+ export function unsetContextEntry(slot) {
37
+ const ctx = loadContext();
38
+ delete ctx.active[slot];
39
+ saveContext(ctx);
40
+ }
41
+ export function clearAllContext() {
42
+ saveContext({ active: {} });
43
+ }
44
+ export function getActiveContext() {
45
+ return loadContext().active;
46
+ }
@@ -0,0 +1,176 @@
1
+ import chalk from 'chalk';
2
+ import moment from 'moment';
3
+ import { addSpacesToCamelCase } from './addSpacesToCamelCase.js';
4
+ const SKIP_FIELDS = new Set(['__v', 'password', 'hash', 'salt']);
5
+ function isDateField(key, value) {
6
+ if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value))
7
+ return true;
8
+ if (key.endsWith('At') || key.endsWith('Date'))
9
+ return true;
10
+ return false;
11
+ }
12
+ function formatDate(value) {
13
+ const m = moment(value);
14
+ if (!m.isValid())
15
+ return String(value);
16
+ const formatted = m.format('YYYY-MM-DD HH:mm:ss');
17
+ const relative = m.fromNow();
18
+ return `${formatted} ${chalk.dim(`(${relative})`)}`;
19
+ }
20
+ function formatValue(key, value) {
21
+ if (value == null || value === '')
22
+ return '';
23
+ if (typeof value === 'boolean') {
24
+ return value ? chalk.green('yes') : chalk.red('no');
25
+ }
26
+ if (isDateField(key, value)) {
27
+ return formatDate(value);
28
+ }
29
+ if (typeof value === 'number') {
30
+ return String(value);
31
+ }
32
+ if (Array.isArray(value)) {
33
+ if (value.length === 0)
34
+ return '';
35
+ if (value.every((v) => typeof v !== 'object' || v === null)) {
36
+ return value.join(', ');
37
+ }
38
+ return '';
39
+ }
40
+ if (typeof value === 'object')
41
+ return '';
42
+ const str = String(value);
43
+ if ((key.endsWith('ID') || key.endsWith('Id') || key === '_id') && str.length > 10) {
44
+ return chalk.dim(str);
45
+ }
46
+ return str;
47
+ }
48
+ function getEntryName(obj) {
49
+ return (obj === null || obj === void 0 ? void 0 : obj.name) || (obj === null || obj === void 0 ? void 0 : obj.title) || (obj === null || obj === void 0 ? void 0 : obj.subject) || (obj === null || obj === void 0 ? void 0 : obj.originalname) || '';
50
+ }
51
+ function renderHeader(obj, ctx) {
52
+ const name = getEntryName(obj);
53
+ const contextParts = [];
54
+ if (ctx.module)
55
+ contextParts.push(ctx.module);
56
+ if (ctx.collection)
57
+ contextParts.push(ctx.collection);
58
+ if (ctx.id)
59
+ contextParts.push(ctx.id);
60
+ const contextLine = contextParts.join(chalk.dim(' · '));
61
+ const contentWidth = Math.max(name ? name.length : 0, contextLine ? contextParts.join(' · ').length : 0, 30);
62
+ const boxWidth = contentWidth + 4;
63
+ const lines = [];
64
+ lines.push(chalk.dim(`╭${'─'.repeat(boxWidth)}╮`));
65
+ if (name) {
66
+ lines.push(chalk.dim('│') + ` ${chalk.bold.white(name)}${' '.repeat(boxWidth - name.length - 2)}` + chalk.dim('│'));
67
+ }
68
+ if (contextLine) {
69
+ const plainLen = contextParts.join(' · ').length;
70
+ lines.push(chalk.dim('│') + ` ${chalk.dim(contextLine)}${' '.repeat(boxWidth - plainLen - 2)}` + chalk.dim('│'));
71
+ }
72
+ lines.push(chalk.dim(`╰${'─'.repeat(boxWidth)}╯`));
73
+ return lines.join('\n');
74
+ }
75
+ function collectFields(obj) {
76
+ const flat = [];
77
+ const nested = [];
78
+ const arrayOfObjects = [];
79
+ for (const [key, value] of Object.entries(obj)) {
80
+ if (SKIP_FIELDS.has(key) || value == null || value === '')
81
+ continue;
82
+ if (Array.isArray(value)) {
83
+ if (value.length === 0)
84
+ continue;
85
+ if (value.some((v) => typeof v === 'object' && v !== null)) {
86
+ arrayOfObjects.push([key, value]);
87
+ }
88
+ else {
89
+ flat.push([key, value]);
90
+ }
91
+ }
92
+ else if (typeof value === 'object' && !isDateField(key, value)) {
93
+ nested.push([key, value]);
94
+ }
95
+ else {
96
+ flat.push([key, value]);
97
+ }
98
+ }
99
+ return { flat, nested, arrayOfObjects };
100
+ }
101
+ function renderFields(fields, indent, labelWidth) {
102
+ const pad = ' '.repeat(indent);
103
+ const lines = [];
104
+ for (const [key, value] of fields) {
105
+ const formatted = formatValue(key, value);
106
+ if (!formatted)
107
+ continue;
108
+ const label = addSpacesToCamelCase(key);
109
+ lines.push(`${pad}${chalk.dim(label.padEnd(labelWidth))} ${chalk.white(formatted)}`);
110
+ }
111
+ return lines;
112
+ }
113
+ function getLabelWidth(fields) {
114
+ if (fields.length === 0)
115
+ return 16;
116
+ return Math.max(...fields.map(([k]) => addSpacesToCamelCase(k).length)) + 2;
117
+ }
118
+ function renderSection(title, obj, indent) {
119
+ const pad = ' '.repeat(indent);
120
+ const lines = [];
121
+ const { flat, nested, arrayOfObjects } = collectFields(obj);
122
+ lines.push('');
123
+ lines.push(`${pad}${chalk.dim('── ' + addSpacesToCamelCase(title) + ' ' + '─'.repeat(Math.max(0, 36 - title.length)))}`);
124
+ const labelWidth = getLabelWidth(flat);
125
+ lines.push(...renderFields(flat, indent + 2, labelWidth));
126
+ for (const [key, value] of nested) {
127
+ lines.push(...renderSection(key, value, indent + 2));
128
+ }
129
+ for (const [key, items] of arrayOfObjects) {
130
+ lines.push('');
131
+ lines.push(`${pad} ${chalk.dim('── ' + addSpacesToCamelCase(key) + ' ' + '─'.repeat(Math.max(0, 34 - key.length)))}`);
132
+ items.forEach((item, i) => {
133
+ if (typeof item === 'object' && item !== null) {
134
+ lines.push(`${pad} ${chalk.dim(`[${i + 1}]`)}`);
135
+ const itemFields = collectFields(item);
136
+ const itemLabelWidth = getLabelWidth(itemFields.flat);
137
+ lines.push(...renderFields(itemFields.flat, indent + 6, itemLabelWidth));
138
+ }
139
+ else {
140
+ lines.push(`${pad} ${chalk.dim(`[${i + 1}]`)} ${String(item)}`);
141
+ }
142
+ });
143
+ }
144
+ return lines;
145
+ }
146
+ export function formatDocument(obj, ctx = {}) {
147
+ if (!obj || typeof obj !== 'object')
148
+ return String(obj !== null && obj !== void 0 ? obj : '');
149
+ const lines = [];
150
+ lines.push('');
151
+ lines.push(renderHeader(obj, ctx));
152
+ const { flat, nested, arrayOfObjects } = collectFields(obj);
153
+ const labelWidth = getLabelWidth(flat);
154
+ lines.push('');
155
+ lines.push(...renderFields(flat, 2, labelWidth));
156
+ for (const [key, value] of nested) {
157
+ lines.push(...renderSection(key, value, 2));
158
+ }
159
+ for (const [key, items] of arrayOfObjects) {
160
+ lines.push('');
161
+ lines.push(` ${chalk.dim('── ' + addSpacesToCamelCase(key) + ' ' + '─'.repeat(Math.max(0, 36 - key.length)))}`);
162
+ items.forEach((item, i) => {
163
+ if (typeof item === 'object' && item !== null) {
164
+ lines.push(` ${chalk.dim(`[${i + 1}]`)}`);
165
+ const itemFields = collectFields(item);
166
+ const itemLabelWidth = getLabelWidth(itemFields.flat);
167
+ lines.push(...renderFields(itemFields.flat, 6, itemLabelWidth));
168
+ }
169
+ else {
170
+ lines.push(` ${chalk.dim(`[${i + 1}]`)} ${String(item)}`);
171
+ }
172
+ });
173
+ }
174
+ lines.push('');
175
+ return lines.join('\n');
176
+ }
@@ -0,0 +1,134 @@
1
+ import yaml from "js-yaml";
2
+ import jmespath from "jmespath";
3
+ /**
4
+ * Maps CLI response format to the API-compatible format.
5
+ * The API only supports json, yaml, csv — not table.
6
+ * Table formatting is done client-side from JSON data.
7
+ */
8
+ export function getApiResponseFormat(cliFormat) {
9
+ if (cliFormat === "table")
10
+ return "json";
11
+ return cliFormat;
12
+ }
13
+ function filterColumns(data, columns) {
14
+ const fields = columns.split(",").map((c) => c.trim());
15
+ if (Array.isArray(data)) {
16
+ return data.map((item) => {
17
+ const filtered = {};
18
+ for (const f of fields) {
19
+ if (item[f] !== undefined)
20
+ filtered[f] = item[f];
21
+ }
22
+ return filtered;
23
+ });
24
+ }
25
+ if (typeof data === "object" && data !== null) {
26
+ const filtered = {};
27
+ for (const f of fields) {
28
+ if (data[f] !== undefined)
29
+ filtered[f] = data[f];
30
+ }
31
+ return filtered;
32
+ }
33
+ return data;
34
+ }
35
+ export function handleResponseFormatOptions(opts, res) {
36
+ let plainResult;
37
+ let result;
38
+ let meta = {};
39
+ let content;
40
+ if (opts.responseFormat && opts.responseFormat === "yaml") {
41
+ // API returns YAML string when responseFormat=yaml, but locally-constructed
42
+ // responses (sync status, dry-run) are already objects — handle both
43
+ if (typeof res === "string") {
44
+ plainResult = yaml.load(res);
45
+ }
46
+ else {
47
+ plainResult = res;
48
+ }
49
+ // With hideMeta, API returns raw data (no {payload, meta} wrapper)
50
+ // Without hideMeta, API returns {payload, meta} wrapper
51
+ if (plainResult && plainResult.payload !== undefined) {
52
+ result = plainResult.payload;
53
+ meta = plainResult.meta || {};
54
+ }
55
+ else {
56
+ result = plainResult;
57
+ meta = {};
58
+ }
59
+ }
60
+ if (opts.responseFormat && opts.responseFormat === "csv") {
61
+ // API returns raw CSV string when responseFormat=csv — no {payload,meta} wrapper
62
+ if (typeof res === "string") {
63
+ plainResult = res;
64
+ result = res;
65
+ meta = {};
66
+ }
67
+ else {
68
+ plainResult = res;
69
+ result = res.payload;
70
+ meta = res.meta || {};
71
+ }
72
+ }
73
+ if (opts.responseFormat && opts.responseFormat === "table") {
74
+ plainResult = res;
75
+ if (res && res.payload !== undefined) {
76
+ result = res.payload;
77
+ meta = res.meta || {};
78
+ }
79
+ else if (Array.isArray(res)) {
80
+ result = res;
81
+ }
82
+ else {
83
+ result = res;
84
+ }
85
+ }
86
+ if (opts.responseFormat && opts.responseFormat === "json") {
87
+ plainResult = res;
88
+ if (res && res.payload !== undefined) {
89
+ result = res.payload;
90
+ meta = res.meta || {};
91
+ }
92
+ else if (Array.isArray(res)) {
93
+ result = res;
94
+ }
95
+ else {
96
+ result = res;
97
+ }
98
+ }
99
+ // Apply --columns filter
100
+ if (opts.columns && result) {
101
+ result = filterColumns(result, opts.columns);
102
+ }
103
+ // Apply --jq (JMESPath) filter
104
+ if (opts.jq && result) {
105
+ try {
106
+ result = jmespath.search(result, opts.jq);
107
+ }
108
+ catch (e) {
109
+ console.error(`JMESPath error: ${e.message}`);
110
+ }
111
+ }
112
+ // Generate content string after filtering
113
+ if (opts.responseFormat === "yaml") {
114
+ content = yaml.dump(result);
115
+ }
116
+ else if (opts.responseFormat === "csv") {
117
+ content = result;
118
+ }
119
+ else if (opts.responseFormat === "table") {
120
+ content = result;
121
+ }
122
+ else {
123
+ content = JSON.stringify(result, null, 4);
124
+ }
125
+ if (!opts.quiet) {
126
+ if (opts.responseFormat === "table") {
127
+ console.table(result);
128
+ }
129
+ else if (content !== undefined) {
130
+ console.log(content);
131
+ }
132
+ }
133
+ return { plainResult, result, meta, content };
134
+ }
@@ -0,0 +1,14 @@
1
+ //Initializes settings for system environment and inquirer
2
+ import inquirer from "inquirer";
3
+ import inquirerFuzzyPath from "inquirer-fuzzy-path";
4
+ import inquirerSearchList from "inquirer-search-list";
5
+ import inquirerFileTreeSelection from "inquirer-file-tree-selection-prompt";
6
+ import inquirerTableInput from "inquirer-table-input";
7
+ import InterruptedPrompt from "inquirer-interrupted-prompt";
8
+ export function initializeSettings() {
9
+ inquirer.registerPrompt("fuzzypath", inquirerFuzzyPath);
10
+ inquirer.registerPrompt("search-list", inquirerSearchList);
11
+ inquirer.registerPrompt("file-tree-selection", inquirerFileTreeSelection);
12
+ inquirer.registerPrompt("table-input", inquirerTableInput);
13
+ InterruptedPrompt.fromAll(inquirer);
14
+ }
@@ -0,0 +1,4 @@
1
+ import { LocalStorage } from "node-localstorage";
2
+ import path from "path";
3
+ import os from "os";
4
+ export const localStorage = new LocalStorage(path.join(os.homedir(), "aYOUne", "storage"));
@@ -0,0 +1,48 @@
1
+ import chalk from "chalk";
2
+ import figlet from "figlet";
3
+ export const BRAND_PURPLE = "#6B3FA0";
4
+ export const BRAND_BLUE = "#2B8DC6";
5
+ export const BRAND_PINK = "#E91E8C";
6
+ export function getLogo() {
7
+ try {
8
+ const raw = figlet.textSync("aYOUne", { font: "Slant" });
9
+ return colorizeByColumns(raw);
10
+ }
11
+ catch (_a) {
12
+ // Fallback: simple colored text
13
+ return ("\n " +
14
+ chalk.hex(BRAND_PURPLE).bold("a") +
15
+ chalk.hex(BRAND_BLUE).bold("YOU") +
16
+ chalk.hex(BRAND_PINK).bold("ne") +
17
+ "\n");
18
+ }
19
+ }
20
+ function colorizeByColumns(text) {
21
+ const lines = text.split("\n");
22
+ const colored = lines.map((line) => {
23
+ let result = "";
24
+ for (let i = 0; i < line.length; i++) {
25
+ const ch = line[i];
26
+ if (ch === " ") {
27
+ result += ch;
28
+ }
29
+ else if (i < 7) {
30
+ result += chalk.hex(BRAND_PURPLE)(ch);
31
+ }
32
+ else if (i < 26) {
33
+ result += chalk.hex(BRAND_BLUE)(ch);
34
+ }
35
+ else {
36
+ result += chalk.hex(BRAND_PINK)(ch);
37
+ }
38
+ }
39
+ return result;
40
+ });
41
+ return "\n" + colored.join("\n") + "\n";
42
+ }
43
+ export function getDescription() {
44
+ return (chalk.hex(BRAND_PURPLE)("a") +
45
+ chalk.hex(BRAND_BLUE)("YOU") +
46
+ chalk.hex(BRAND_PINK)("ne") +
47
+ chalk.dim(" — Business as a Service CLI"));
48
+ }
@@ -0,0 +1,27 @@
1
+ import { randomBytes } from "crypto";
2
+ /** Sync */
3
+ const randomString = (length, chars) => {
4
+ if (!chars) {
5
+ throw new Error("Argument 'chars' is undefined");
6
+ }
7
+ const charsLength = chars.length;
8
+ if (charsLength > 256) {
9
+ throw new Error("Argument 'chars' should not have more than 256 characters" +
10
+ ", otherwise unpredictability will be broken");
11
+ }
12
+ const _randomBytes = randomBytes(length);
13
+ let result = new Array(length);
14
+ let cursor = 0;
15
+ for (let i = 0; i < length; i++) {
16
+ cursor += _randomBytes[i];
17
+ result[i] = chars[cursor % charsLength];
18
+ }
19
+ return result.join("");
20
+ };
21
+ /** Sync */
22
+ export const randomAsciiString = (length = 32, alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") => {
23
+ if (typeof length === "undefined") {
24
+ length = 32;
25
+ }
26
+ return randomString(length, alphabet);
27
+ };
@@ -0,0 +1,7 @@
1
+ export function parseInteger(value, dummyPrevious) {
2
+ const parsedValue = parseInt(value, 10);
3
+ if (isNaN(parsedValue)) {
4
+ throw new Error("Not a number.");
5
+ }
6
+ return parsedValue;
7
+ }
@@ -0,0 +1,9 @@
1
+ import { spinner } from "../../index.js";
2
+ export function requireArg(value, name) {
3
+ if (value)
4
+ return true;
5
+ if (process.stdin.isTTY)
6
+ return false; // allow prompt to run
7
+ spinner.error({ text: `Missing required argument: ${name}` });
8
+ process.exit(1);
9
+ }
@@ -0,0 +1,36 @@
1
+ import { getModuleFromCollection } from "../models/getModuleFromCollection.js";
2
+ import { aYOUneModules } from "../../data/modules.js";
3
+ import { isSuperUser } from "./tokenPayload.js";
4
+ /**
5
+ * Resolves module and collection from CLI arguments.
6
+ * Supports both `ay list consumers` and `ay list crm consumers`.
7
+ * Blocks access to superuser-only modules for non-superusers.
8
+ *
9
+ * @param arg1 - Collection name, or module name if arg2 is provided
10
+ * @param arg2 - Collection name when arg1 is a module
11
+ */
12
+ export function resolveCollectionArgs(arg1, arg2) {
13
+ if (arg2) {
14
+ // ay list crm consumers → arg1=module, arg2=collection
15
+ enforceSuperUserAccess(arg1);
16
+ return { module: arg1, collection: arg2.toLowerCase() };
17
+ }
18
+ // Check if arg1 is a module name (user forgot the collection)
19
+ const isModule = aYOUneModules.some((mod) => mod.module === arg1.toLowerCase());
20
+ if (isModule) {
21
+ throw new Error(`"${arg1}" is a module name, not a collection. Use: ay <command> ${arg1} <collection>`);
22
+ }
23
+ // ay list consumers → lookup module from collection (throws if unknown)
24
+ const m = getModuleFromCollection(arg1.toLowerCase());
25
+ enforceSuperUserAccess(m.module);
26
+ return { module: m.module, collection: arg1.toLowerCase() };
27
+ }
28
+ /**
29
+ * Throws if the resolved module is superuser-only and the current user is not a superuser.
30
+ */
31
+ function enforceSuperUserAccess(module) {
32
+ const mod = aYOUneModules.find((m) => m.module === module.toLowerCase());
33
+ if ((mod === null || mod === void 0 ? void 0 : mod.superuserOnly) && !isSuperUser()) {
34
+ throw new Error(`Module "${module}" requires superuser access. Log in as a superuser to use this module.`);
35
+ }
36
+ }
@@ -0,0 +1,18 @@
1
+ import { EXIT_MISUSE } from "../exitCodes.js";
2
+ import { cliError } from "./cliError.js";
3
+ const VALID_FIELD_PATTERN = /^-?[a-zA-Z_][a-zA-Z0-9_.$]*$/;
4
+ /**
5
+ * Validates and sanitizes field names for MongoDB projections.
6
+ * Rejects MongoDB operators ($where, $function, etc.) and injection attempts.
7
+ * Accepts dot-notation paths (e.g., "address.city") and sort prefixes ("-createdAt").
8
+ */
9
+ export function sanitizeFields(fields) {
10
+ const fieldArray = Array.isArray(fields)
11
+ ? fields.flatMap((f) => f.split(",").map((s) => s.trim()))
12
+ : fields.split(",").map((s) => s.trim());
13
+ const invalid = fieldArray.filter((f) => !VALID_FIELD_PATTERN.test(f));
14
+ if (invalid.length > 0) {
15
+ cliError(`Invalid field name(s): ${invalid.join(", ")}. Field names must be alphanumeric (with dots for nested paths).`, EXIT_MISUSE, "invalid_fields");
16
+ }
17
+ return fieldArray;
18
+ }