@tolinax/ayoune-cli 2026.2.0 → 2026.2.2
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.
- package/data/defaultActions.js +9 -0
- package/data/modelsAndRights.js +3189 -0
- package/data/modules.js +111 -0
- package/data/operations.js +5 -0
- package/data/services.js +139 -0
- package/index.js +11 -0
- package/lib/api/apiCallHandler.js +68 -0
- package/lib/api/apiClient.js +100 -0
- package/lib/api/auditCallHandler.js +21 -0
- package/lib/api/decodeToken.js +4 -0
- package/lib/api/handleAPIError.js +59 -0
- package/lib/api/login.js +45 -0
- package/lib/commands/createActionsCommand.js +109 -0
- package/lib/commands/createAiCommand.js +188 -0
- package/lib/commands/createAliasCommand.js +106 -0
- package/lib/commands/createAuditCommand.js +49 -0
- package/lib/commands/createCompletionsCommand.js +136 -0
- package/lib/commands/createConfigCommand.js +208 -0
- package/lib/commands/createCopyCommand.js +39 -0
- package/lib/commands/createCreateCommand.js +50 -0
- package/lib/commands/createDeployCommand.js +666 -0
- package/lib/commands/createDescribeCommand.js +42 -0
- package/lib/commands/createEditCommand.js +43 -0
- package/lib/commands/createEventsCommand.js +60 -0
- package/lib/commands/createExecCommand.js +182 -0
- package/lib/commands/createGetCommand.js +47 -0
- package/lib/commands/createListCommand.js +49 -0
- package/lib/commands/createLoginCommand.js +18 -0
- package/lib/commands/createLogoutCommand.js +21 -0
- package/lib/commands/createModulesCommand.js +89 -0
- package/lib/commands/createMonitorCommand.js +283 -0
- package/lib/commands/createProgram.js +163 -0
- package/lib/commands/createServicesCommand.js +228 -0
- package/lib/commands/createStorageCommand.js +54 -0
- package/lib/commands/createStreamCommand.js +50 -0
- package/lib/commands/createWhoAmICommand.js +88 -0
- package/lib/exitCodes.js +6 -0
- package/lib/helpers/addSpacesToCamelCase.js +5 -0
- package/lib/helpers/config.js +6 -0
- package/lib/helpers/configLoader.js +60 -0
- package/lib/helpers/formatDocument.js +176 -0
- package/lib/helpers/handleResponseFormatOptions.js +85 -0
- package/lib/helpers/initializeSettings.js +14 -0
- package/lib/helpers/localStorage.js +4 -0
- package/lib/helpers/makeRandomToken.js +27 -0
- package/lib/helpers/parseInt.js +7 -0
- package/lib/helpers/requireArg.js +9 -0
- package/lib/helpers/saveFile.js +39 -0
- package/lib/models/getCollections.js +15 -0
- package/lib/models/getModelsInModules.js +13 -0
- package/lib/models/getModuleFromCollection.js +7 -0
- package/lib/operations/handleAuditOperation.js +22 -0
- package/lib/operations/handleCollectionOperation.js +91 -0
- package/lib/operations/handleCopySingleOperation.js +22 -0
- package/lib/operations/handleCreateSingleOperation.js +35 -0
- package/lib/operations/handleDeleteSingleOperation.js +14 -0
- package/lib/operations/handleDescribeSingleOperation.js +22 -0
- package/lib/operations/handleEditOperation.js +51 -0
- package/lib/operations/handleEditRawOperation.js +35 -0
- package/lib/operations/handleGetOperation.js +29 -0
- package/lib/operations/handleGetSingleOperation.js +20 -0
- package/lib/operations/handleListOperation.js +63 -0
- package/lib/operations/handleSingleAuditOperation.js +27 -0
- package/lib/prompts/promptAudits.js +15 -0
- package/lib/prompts/promptCollection.js +13 -0
- package/lib/prompts/promptCollectionInModule.js +13 -0
- package/lib/prompts/promptCollectionWithModule.js +15 -0
- package/lib/prompts/promptConfirm.js +12 -0
- package/lib/prompts/promptDefaultAction.js +13 -0
- package/lib/prompts/promptEntry.js +19 -0
- package/lib/prompts/promptFileName.js +12 -0
- package/lib/prompts/promptFilePath.js +18 -0
- package/lib/prompts/promptModule.js +19 -0
- package/lib/prompts/promptName.js +11 -0
- package/lib/prompts/promptOperation.js +13 -0
- package/lib/socket/customerSocketClient.js +13 -0
- package/lib/socket/socketClient.js +12 -0
- package/lib/types.js +1 -0
- package/package.json +2 -2
- package/README.md +0 -505
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Argument } from "commander";
|
|
2
|
+
import { getModuleFromCollection } from "../models/getModuleFromCollection.js";
|
|
3
|
+
import { handleDescribeSingleOperation } from "../operations/handleDescribeSingleOperation.js";
|
|
4
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
5
|
+
import { spinner } from "../../index.js";
|
|
6
|
+
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
7
|
+
export function createDescribeCommand(program) {
|
|
8
|
+
program
|
|
9
|
+
.command("describe")
|
|
10
|
+
.alias("d")
|
|
11
|
+
.description("Show detailed YAML description of an entry")
|
|
12
|
+
.addHelpText("after", `
|
|
13
|
+
Examples:
|
|
14
|
+
ay describe contacts 64a1b2c3d4e5 Describe a contact entry
|
|
15
|
+
ay d Describe last used entry`)
|
|
16
|
+
.addArgument(new Argument("[collection]", "The collection to use").default(localStorage.getItem("lastCollection"), `The last used collection (${localStorage.getItem("lastCollection")})`))
|
|
17
|
+
.addArgument(new Argument("[id]", "The ID of the entry to describe").default(localStorage.getItem("lastId"), `The last used id (${localStorage.getItem("lastId")})`))
|
|
18
|
+
.action(async (collection, id, options) => {
|
|
19
|
+
try {
|
|
20
|
+
if (!collection) {
|
|
21
|
+
spinner.error({ text: "Missing required argument: collection. Run a list or get command first, or provide it explicitly." });
|
|
22
|
+
process.exit(EXIT_MISUSE);
|
|
23
|
+
}
|
|
24
|
+
if (!id) {
|
|
25
|
+
spinner.error({ text: "Missing required argument: id. Provide an entry ID explicitly." });
|
|
26
|
+
process.exit(EXIT_MISUSE);
|
|
27
|
+
}
|
|
28
|
+
const opts = { ...program.opts(), ...options };
|
|
29
|
+
const module = getModuleFromCollection(collection);
|
|
30
|
+
localStorage.setItem("lastModule", module.module);
|
|
31
|
+
localStorage.setItem("lastCollection", collection);
|
|
32
|
+
localStorage.setItem("lastId", id);
|
|
33
|
+
await handleDescribeSingleOperation(module.module, collection, id, {
|
|
34
|
+
...opts,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
39
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Argument } from "commander";
|
|
2
|
+
import { getModuleFromCollection } from "../models/getModuleFromCollection.js";
|
|
3
|
+
import { handleGetSingleOperation } from "../operations/handleGetSingleOperation.js";
|
|
4
|
+
import { handleEditOperation } from "../operations/handleEditOperation.js";
|
|
5
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
6
|
+
import { spinner } from "../../index.js";
|
|
7
|
+
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
8
|
+
export function createEditCommand(program) {
|
|
9
|
+
program
|
|
10
|
+
.command("edit")
|
|
11
|
+
.alias("e")
|
|
12
|
+
.description("Edit an entry by ID in a collection")
|
|
13
|
+
.addHelpText("after", `
|
|
14
|
+
Examples:
|
|
15
|
+
ay edit contacts 64a1b2c3d4e5 Edit contact by ID
|
|
16
|
+
ay edit Edit last used entry`)
|
|
17
|
+
.addArgument(new Argument("[collection]", "The collection to use").default(localStorage.getItem("lastCollection"), `The last used collection (${localStorage.getItem("lastCollection")})`))
|
|
18
|
+
.addArgument(new Argument("[id]", "The ID of the entry to edit").default(localStorage.getItem("lastId"), `The last used id (${localStorage.getItem("lastId")})`))
|
|
19
|
+
.action(async (collection, id, options) => {
|
|
20
|
+
try {
|
|
21
|
+
if (!collection) {
|
|
22
|
+
spinner.error({ text: "Missing required argument: collection. Run a list or get command first, or provide it explicitly." });
|
|
23
|
+
process.exit(EXIT_MISUSE);
|
|
24
|
+
}
|
|
25
|
+
if (!id) {
|
|
26
|
+
spinner.error({ text: "Missing required argument: id. Provide an entry ID explicitly." });
|
|
27
|
+
process.exit(EXIT_MISUSE);
|
|
28
|
+
}
|
|
29
|
+
const opts = { ...program.opts(), ...options };
|
|
30
|
+
const module = getModuleFromCollection(collection);
|
|
31
|
+
localStorage.setItem("lastModule", module.module);
|
|
32
|
+
localStorage.setItem("lastCollection", collection);
|
|
33
|
+
localStorage.setItem("lastId", id);
|
|
34
|
+
let result = {};
|
|
35
|
+
result = await handleGetSingleOperation(module.module, collection, id, opts);
|
|
36
|
+
await handleEditOperation(module.module, collection, result.content);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
40
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Option } from "commander";
|
|
2
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
3
|
+
import { decodeToken } from "../api/decodeToken.js";
|
|
4
|
+
import { customerSocket } from "../socket/customerSocketClient.js";
|
|
5
|
+
import { spinner } from "../../index.js";
|
|
6
|
+
import yaml from "js-yaml";
|
|
7
|
+
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
8
|
+
export function createEventsCommand(program) {
|
|
9
|
+
program
|
|
10
|
+
.command("events")
|
|
11
|
+
.alias("sub")
|
|
12
|
+
.description("Subscribe to filtered events via WebSocket")
|
|
13
|
+
.addHelpText("after", `
|
|
14
|
+
Examples:
|
|
15
|
+
ay events Listen to all events
|
|
16
|
+
ay events -c sales -a create Filter by category and action
|
|
17
|
+
ay sub -f yaml -c crm Subscribe to CRM events as YAML`)
|
|
18
|
+
.addOption(new Option("-f, --format <format>", "Set the output format")
|
|
19
|
+
.choices(["json", "yaml", "table"])
|
|
20
|
+
.default("json"))
|
|
21
|
+
.addOption(new Option("-c, --category <category>", "Set the category to listen").default("*"))
|
|
22
|
+
.addOption(new Option("-a, --action <action>", "Set the action to listen").default("*"))
|
|
23
|
+
.addOption(new Option("-l, --label <label>", "Set the label to listen").default("*"))
|
|
24
|
+
.addOption(new Option("-V, --value <value>", "Set the value to listen").default("*"))
|
|
25
|
+
.action(async (options) => {
|
|
26
|
+
try {
|
|
27
|
+
const tokenPayload = decodeToken(localStorage.getItem("token"));
|
|
28
|
+
const user = tokenPayload.payload;
|
|
29
|
+
spinner.start({ text: `Starting stream with [${user._customerID}]` });
|
|
30
|
+
const socket = customerSocket(user);
|
|
31
|
+
spinner.update({ text: "Stream active" });
|
|
32
|
+
socket.on("event", (data) => {
|
|
33
|
+
if (options.category !== "*" && options.category !== data.category)
|
|
34
|
+
return;
|
|
35
|
+
if (options.action !== "*" && options.action !== data.action)
|
|
36
|
+
return;
|
|
37
|
+
if (options.label !== "*" && options.label !== data.label)
|
|
38
|
+
return;
|
|
39
|
+
if (options.value !== "*" && options.value !== data.value)
|
|
40
|
+
return;
|
|
41
|
+
spinner.update({
|
|
42
|
+
text: `Received [${data.category}.${data.action}.${data.label}.${data.value}]`,
|
|
43
|
+
});
|
|
44
|
+
if (options.format === "table") {
|
|
45
|
+
console.table(data.evt_data);
|
|
46
|
+
}
|
|
47
|
+
if (options.format === "yaml") {
|
|
48
|
+
console.log(yaml.dump(data.evt_data));
|
|
49
|
+
}
|
|
50
|
+
if (options.format === "json") {
|
|
51
|
+
console.log(JSON.stringify(data.evt_data, null, 2));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
57
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { api } from "../api/apiClient.js";
|
|
3
|
+
import { apiCallHandler } from "../api/apiCallHandler.js";
|
|
4
|
+
import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
|
|
5
|
+
import { saveFile } from "../helpers/saveFile.js";
|
|
6
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
7
|
+
import { spinner } from "../../index.js";
|
|
8
|
+
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
9
|
+
async function resolveAction(searchTerm) {
|
|
10
|
+
// Try exact operationId match first
|
|
11
|
+
const res = await apiCallHandler("config", "ayouneapiactions", "get", null, {
|
|
12
|
+
q: searchTerm,
|
|
13
|
+
limit: 50,
|
|
14
|
+
responseFormat: "json",
|
|
15
|
+
});
|
|
16
|
+
if (!(res === null || res === void 0 ? void 0 : res.payload) || !Array.isArray(res.payload) || res.payload.length === 0) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const actions = res.payload.filter((a) => !a.deprecated);
|
|
20
|
+
// Exact operationId match
|
|
21
|
+
const exact = actions.find((a) => a.operationId === searchTerm);
|
|
22
|
+
if (exact)
|
|
23
|
+
return mapAction(exact);
|
|
24
|
+
// Partial operationId match
|
|
25
|
+
const partial = actions.find((a) => { var _a; return (_a = a.operationId) === null || _a === void 0 ? void 0 : _a.includes(searchTerm); });
|
|
26
|
+
if (partial)
|
|
27
|
+
return mapAction(partial);
|
|
28
|
+
// If multiple results, return first match
|
|
29
|
+
if (actions.length > 0)
|
|
30
|
+
return mapAction(actions[0]);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function mapAction(a) {
|
|
34
|
+
return {
|
|
35
|
+
host: a.host || "",
|
|
36
|
+
endpoint: a.endpoint || "",
|
|
37
|
+
method: (a.method || "GET").toUpperCase(),
|
|
38
|
+
operationId: a.operationId || "",
|
|
39
|
+
nameSpace: a.nameSpace || "",
|
|
40
|
+
capability: a.capability || "",
|
|
41
|
+
params: a.params || [],
|
|
42
|
+
query: a.query || [],
|
|
43
|
+
description: a.shortDescription || a.description || "",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function buildUrl(endpoint, paramValues) {
|
|
47
|
+
let url = endpoint;
|
|
48
|
+
for (const [key, value] of Object.entries(paramValues)) {
|
|
49
|
+
url = url.replace(`:${key}`, encodeURIComponent(value));
|
|
50
|
+
}
|
|
51
|
+
return url;
|
|
52
|
+
}
|
|
53
|
+
export function createExecCommand(program) {
|
|
54
|
+
program
|
|
55
|
+
.command("exec <operationId>")
|
|
56
|
+
.alias("x")
|
|
57
|
+
.description("Execute any registered API action by operationId")
|
|
58
|
+
.addHelpText("after", `
|
|
59
|
+
Examples:
|
|
60
|
+
ay exec ayoune.ai.conversations.create.one --body '{"prompt":"Hello"}'
|
|
61
|
+
ay exec ayoune.crm.contacts.list
|
|
62
|
+
ay exec ayoune.pm.projects.create.one --body '{"subject":"Migration"}'
|
|
63
|
+
ay exec ayoune.ai.prompts.list -r table
|
|
64
|
+
ay exec ayoune.sale.orders.get.one --param id=507f1f77bcf86cd799439011`)
|
|
65
|
+
.option("--body <json>", "Request body as JSON string")
|
|
66
|
+
.option("--body-file <path>", "Read request body from file")
|
|
67
|
+
.option("--body-stdin", "Read request body from stdin (for piping)")
|
|
68
|
+
.option("--param <kv...>", "Path parameters as key=value pairs")
|
|
69
|
+
.option("--query <kv...>", "Query parameters as key=value pairs")
|
|
70
|
+
.action(async (operationId, options) => {
|
|
71
|
+
try {
|
|
72
|
+
const opts = { ...program.opts(), ...options };
|
|
73
|
+
spinner.start({ text: `Resolving action: ${operationId}`, color: "magenta" });
|
|
74
|
+
const action = await resolveAction(operationId);
|
|
75
|
+
if (!action) {
|
|
76
|
+
spinner.error({ text: `No API action found for: ${operationId}` });
|
|
77
|
+
process.exit(EXIT_MISUSE);
|
|
78
|
+
}
|
|
79
|
+
spinner.update({ text: `Executing: ${action.method} https://${action.host}${action.endpoint}` });
|
|
80
|
+
// Parse path params
|
|
81
|
+
const paramValues = {};
|
|
82
|
+
if (opts.param) {
|
|
83
|
+
for (const p of opts.param) {
|
|
84
|
+
const [key, ...rest] = p.split("=");
|
|
85
|
+
paramValues[key] = rest.join("=");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Parse query params
|
|
89
|
+
const queryParams = {
|
|
90
|
+
responseFormat: opts.responseFormat,
|
|
91
|
+
verbosity: opts.verbosity,
|
|
92
|
+
};
|
|
93
|
+
if (opts.hideMeta)
|
|
94
|
+
queryParams.hideMeta = "true";
|
|
95
|
+
if (opts.query) {
|
|
96
|
+
for (const q of opts.query) {
|
|
97
|
+
const [key, ...rest] = q.split("=");
|
|
98
|
+
queryParams[key] = rest.join("=");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Parse body
|
|
102
|
+
let body = null;
|
|
103
|
+
if (opts.body) {
|
|
104
|
+
try {
|
|
105
|
+
body = JSON.parse(opts.body);
|
|
106
|
+
}
|
|
107
|
+
catch (_a) {
|
|
108
|
+
spinner.error({ text: "Invalid JSON in --body" });
|
|
109
|
+
process.exit(EXIT_MISUSE);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (opts.bodyFile) {
|
|
113
|
+
const fs = await import("fs");
|
|
114
|
+
const content = fs.readFileSync(opts.bodyFile, "utf-8");
|
|
115
|
+
try {
|
|
116
|
+
body = JSON.parse(content);
|
|
117
|
+
}
|
|
118
|
+
catch (_b) {
|
|
119
|
+
spinner.error({ text: `Invalid JSON in file: ${opts.bodyFile}` });
|
|
120
|
+
process.exit(EXIT_MISUSE);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (opts.bodyStdin && !process.stdin.isTTY) {
|
|
124
|
+
const chunks = [];
|
|
125
|
+
for await (const chunk of process.stdin) {
|
|
126
|
+
chunks.push(chunk);
|
|
127
|
+
}
|
|
128
|
+
const stdinContent = Buffer.concat(chunks).toString("utf-8").trim();
|
|
129
|
+
if (stdinContent) {
|
|
130
|
+
try {
|
|
131
|
+
body = JSON.parse(stdinContent);
|
|
132
|
+
}
|
|
133
|
+
catch (_c) {
|
|
134
|
+
spinner.error({ text: "Invalid JSON from stdin" });
|
|
135
|
+
process.exit(EXIT_MISUSE);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Build final URL
|
|
140
|
+
const url = buildUrl(action.endpoint, paramValues);
|
|
141
|
+
const fullUrl = `https://${action.host}${url}`;
|
|
142
|
+
// Dry-run support
|
|
143
|
+
if (opts.dryRun && action.method !== "GET") {
|
|
144
|
+
spinner.stop();
|
|
145
|
+
console.error(chalk.yellow.bold("\n [DRY RUN] Request not sent:\n"));
|
|
146
|
+
console.error(` ${chalk.dim("Operation:")} ${chalk.cyan(action.operationId)}`);
|
|
147
|
+
console.error(` ${chalk.dim("Method:")} ${chalk.cyan(action.method)}`);
|
|
148
|
+
console.error(` ${chalk.dim("URL:")} ${chalk.cyan(fullUrl)}`);
|
|
149
|
+
if (body) {
|
|
150
|
+
console.error(` ${chalk.dim("Body:")} ${JSON.stringify(body, null, 2).split("\n").join("\n ")}`);
|
|
151
|
+
}
|
|
152
|
+
console.error();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// Execute the request directly against the service host
|
|
156
|
+
const response = await api({
|
|
157
|
+
baseURL: `https://${action.host}`,
|
|
158
|
+
method: action.method.toLowerCase(),
|
|
159
|
+
url,
|
|
160
|
+
data: body,
|
|
161
|
+
params: queryParams,
|
|
162
|
+
headers: {
|
|
163
|
+
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
const res = response.data;
|
|
167
|
+
const { plainResult, result, content } = handleResponseFormatOptions(opts, res);
|
|
168
|
+
const payloadCount = Array.isArray(res === null || res === void 0 ? void 0 : res.payload) ? res.payload.length : 1;
|
|
169
|
+
spinner.success({
|
|
170
|
+
text: `${action.method} ${action.operationId} — ${payloadCount} result(s)`,
|
|
171
|
+
});
|
|
172
|
+
spinner.stop();
|
|
173
|
+
if (opts.save) {
|
|
174
|
+
await saveFile("exec", opts, res);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (e) {
|
|
178
|
+
spinner.error({ text: e.message || "Failed to execute API action" });
|
|
179
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
2
|
+
import { promptCollectionWithModule } from "../prompts/promptCollectionWithModule.js";
|
|
3
|
+
import { getModuleFromCollection } from "../models/getModuleFromCollection.js";
|
|
4
|
+
import { saveFile } from "../helpers/saveFile.js";
|
|
5
|
+
import { handleGetOperation } from "../operations/handleGetOperation.js";
|
|
6
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
7
|
+
import { spinner } from "../../index.js";
|
|
8
|
+
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
9
|
+
export function createGetCommand(program) {
|
|
10
|
+
program
|
|
11
|
+
.command("get [collection]")
|
|
12
|
+
.alias("g")
|
|
13
|
+
.description("Retrieve entries from a collection with field selection")
|
|
14
|
+
.addHelpText("after", `
|
|
15
|
+
Examples:
|
|
16
|
+
ay get contacts Get contacts with default fields
|
|
17
|
+
ay get products -i name price Get only name and price fields
|
|
18
|
+
ay get orders -p 3 -l 10 -r csv Get orders page 3, 10 per page, as CSV`)
|
|
19
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
20
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 20)
|
|
21
|
+
.option("-f, --from <date>", "From date")
|
|
22
|
+
.option("-i, --fields <fields...>", "Fields to get")
|
|
23
|
+
.action(async (collection, options) => {
|
|
24
|
+
try {
|
|
25
|
+
const opts = { ...program.opts(), ...options };
|
|
26
|
+
if (!collection) {
|
|
27
|
+
if (!process.stdin.isTTY) {
|
|
28
|
+
spinner.error({ text: "Missing required argument: collection" });
|
|
29
|
+
process.exit(EXIT_MISUSE);
|
|
30
|
+
}
|
|
31
|
+
collection = await promptCollectionWithModule();
|
|
32
|
+
}
|
|
33
|
+
const module = getModuleFromCollection(collection);
|
|
34
|
+
localStorage.setItem("lastModule", module.module);
|
|
35
|
+
localStorage.setItem("lastCollection", collection);
|
|
36
|
+
let result = {};
|
|
37
|
+
result = await handleGetOperation(module.module, collection, opts);
|
|
38
|
+
if (opts.save) {
|
|
39
|
+
await saveFile("get", opts, result);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
44
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
2
|
+
import { promptCollectionWithModule } from "../prompts/promptCollectionWithModule.js";
|
|
3
|
+
import { getModuleFromCollection } from "../models/getModuleFromCollection.js";
|
|
4
|
+
import { handleListOperation } from "../operations/handleListOperation.js";
|
|
5
|
+
import { saveFile } from "../helpers/saveFile.js";
|
|
6
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
7
|
+
import { spinner } from "../../index.js";
|
|
8
|
+
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
9
|
+
export function createListCommand(program) {
|
|
10
|
+
program
|
|
11
|
+
.command("list [collection]")
|
|
12
|
+
.alias("l")
|
|
13
|
+
.description("List entries in a collection with pagination support")
|
|
14
|
+
.addHelpText("after", `
|
|
15
|
+
Examples:
|
|
16
|
+
ay list contacts List contacts (page 1, limit 20)
|
|
17
|
+
ay list products -p 2 -l 50 List products page 2, 50 per page
|
|
18
|
+
ay list orders -r yaml -s List orders as YAML and save to file
|
|
19
|
+
ay list contacts --all Fetch all pages
|
|
20
|
+
ay list contacts --jq '[].name' Extract just names using JMESPath`)
|
|
21
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
22
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 20)
|
|
23
|
+
.option("-f, --from <date>", "From date")
|
|
24
|
+
.option("-a, --all", "Fetch all pages automatically")
|
|
25
|
+
.action(async (collection, options) => {
|
|
26
|
+
try {
|
|
27
|
+
const opts = { ...program.opts(), ...options };
|
|
28
|
+
if (!collection) {
|
|
29
|
+
if (!process.stdin.isTTY) {
|
|
30
|
+
spinner.error({ text: "Missing required argument: collection" });
|
|
31
|
+
process.exit(EXIT_MISUSE);
|
|
32
|
+
}
|
|
33
|
+
collection = await promptCollectionWithModule();
|
|
34
|
+
}
|
|
35
|
+
const module = getModuleFromCollection(collection);
|
|
36
|
+
localStorage.setItem("lastModule", module.module);
|
|
37
|
+
localStorage.setItem("lastCollection", collection);
|
|
38
|
+
let result = {};
|
|
39
|
+
result = await handleListOperation(module.module, collection, opts);
|
|
40
|
+
if (opts.save) {
|
|
41
|
+
await saveFile("list", opts, result);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
46
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { login } from "../api/login.js";
|
|
2
|
+
import { spinner } from "../../index.js";
|
|
3
|
+
import { EXIT_AUTH_REQUIRED } from "../exitCodes.js";
|
|
4
|
+
export function createLoginCommand(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("login")
|
|
7
|
+
.alias("auth")
|
|
8
|
+
.description("Authenticate with your aYOUne account via browser")
|
|
9
|
+
.action(async () => {
|
|
10
|
+
try {
|
|
11
|
+
await login();
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
15
|
+
process.exit(EXIT_AUTH_REQUIRED);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
2
|
+
import { spinner } from "../../index.js";
|
|
3
|
+
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
4
|
+
export function createLogoutCommand(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("logout")
|
|
7
|
+
.alias("signout")
|
|
8
|
+
.description("Clear stored credentials and log out")
|
|
9
|
+
.action(async (options) => {
|
|
10
|
+
try {
|
|
11
|
+
spinner.start({ text: "Clearing credentials" });
|
|
12
|
+
localStorage.removeItem("token");
|
|
13
|
+
localStorage.removeItem("refreshToken");
|
|
14
|
+
spinner.success({ text: "Credentials cleared" });
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
18
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { promptModule } from "../prompts/promptModule.js";
|
|
2
|
+
import { promptCollectionInModule } from "../prompts/promptCollectionInModule.js";
|
|
3
|
+
import { promptOperation } from "../prompts/promptOperation.js";
|
|
4
|
+
import { handleListOperation } from "../operations/handleListOperation.js";
|
|
5
|
+
import { promptEntry } from "../prompts/promptEntry.js";
|
|
6
|
+
import { handleCollectionOperation } from "../operations/handleCollectionOperation.js";
|
|
7
|
+
import { localStorage } from "../helpers/localStorage.js";
|
|
8
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
9
|
+
import { handleGetOperation } from "../operations/handleGetOperation.js";
|
|
10
|
+
import { aYOUneModules } from "../../data/modules.js";
|
|
11
|
+
import { getModelsInModules } from "../models/getModelsInModules.js";
|
|
12
|
+
import { spinner } from "../../index.js";
|
|
13
|
+
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
14
|
+
function resolveModule(input) {
|
|
15
|
+
const lower = input.toLowerCase();
|
|
16
|
+
const match = aYOUneModules.find((m) => m.module === lower || m.label.toLowerCase() === lower);
|
|
17
|
+
return match ? match.module : null;
|
|
18
|
+
}
|
|
19
|
+
function resolveCollection(module, input) {
|
|
20
|
+
const lower = input.toLowerCase();
|
|
21
|
+
const collections = getModelsInModules(module);
|
|
22
|
+
const match = collections.find((c) => c.value === lower || c.name.toLowerCase() === lower);
|
|
23
|
+
return match ? match.value : null;
|
|
24
|
+
}
|
|
25
|
+
export function createModulesCommand(program) {
|
|
26
|
+
program
|
|
27
|
+
.command("modules [module] [collection]")
|
|
28
|
+
.alias("m")
|
|
29
|
+
.description("Browse modules, collections, and entries interactively")
|
|
30
|
+
.addHelpText("after", `
|
|
31
|
+
Examples:
|
|
32
|
+
ay modules Start interactive module browser
|
|
33
|
+
ay m Same using alias
|
|
34
|
+
ay m crm Jump straight to the CRM module
|
|
35
|
+
ay m crm consumers Jump to CRM consumers collection`)
|
|
36
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
37
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 20)
|
|
38
|
+
.option("-f, --from <date>", "From date")
|
|
39
|
+
.action(async (moduleArg, collectionArg, options) => {
|
|
40
|
+
try {
|
|
41
|
+
const opts = { ...program.opts(), ...options };
|
|
42
|
+
if (!process.stdin.isTTY) {
|
|
43
|
+
spinner.error({ text: "The modules command requires an interactive terminal" });
|
|
44
|
+
process.exit(EXIT_MISUSE);
|
|
45
|
+
}
|
|
46
|
+
let module;
|
|
47
|
+
if (moduleArg) {
|
|
48
|
+
const resolved = resolveModule(moduleArg);
|
|
49
|
+
if (!resolved) {
|
|
50
|
+
spinner.error({ text: `Unknown module: ${moduleArg}` });
|
|
51
|
+
process.exit(EXIT_MISUSE);
|
|
52
|
+
}
|
|
53
|
+
module = resolved;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
module = await promptModule();
|
|
57
|
+
}
|
|
58
|
+
let collection;
|
|
59
|
+
if (collectionArg) {
|
|
60
|
+
const resolved = resolveCollection(module, collectionArg);
|
|
61
|
+
if (!resolved) {
|
|
62
|
+
spinner.error({ text: `Unknown collection: ${collectionArg} in module ${module}` });
|
|
63
|
+
process.exit(EXIT_MISUSE);
|
|
64
|
+
}
|
|
65
|
+
collection = resolved;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
collection = await promptCollectionInModule(module);
|
|
69
|
+
}
|
|
70
|
+
const operation = await promptOperation();
|
|
71
|
+
localStorage.setItem("lastModule", module);
|
|
72
|
+
localStorage.setItem("lastCollection", collection);
|
|
73
|
+
let entry = "";
|
|
74
|
+
if (operation === "list") {
|
|
75
|
+
const { result } = await handleListOperation(module, collection, opts);
|
|
76
|
+
entry = await promptEntry(result);
|
|
77
|
+
}
|
|
78
|
+
if (operation === "get") {
|
|
79
|
+
const { result } = await handleGetOperation(module, collection, opts);
|
|
80
|
+
entry = await promptEntry(result);
|
|
81
|
+
}
|
|
82
|
+
await handleCollectionOperation(module, collection, entry, opts);
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
spinner.error({ text: e.message || "An unexpected error occurred" });
|
|
86
|
+
process.exit(EXIT_GENERAL_ERROR);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|