@aderis-erp/cli 1.0.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.
- package/README.md +244 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/commands/access-groups.d.ts +39 -0
- package/dist/commands/access-groups.js +1004 -0
- package/dist/commands/account-statement-runs.d.ts +40 -0
- package/dist/commands/account-statement-runs.js +1004 -0
- package/dist/commands/account-transactions.d.ts +41 -0
- package/dist/commands/account-transactions.js +1020 -0
- package/dist/commands/accounts.d.ts +40 -0
- package/dist/commands/accounts.js +1012 -0
- package/dist/commands/agent-runs.d.ts +39 -0
- package/dist/commands/agent-runs.js +1001 -0
- package/dist/commands/audit-log.d.ts +39 -0
- package/dist/commands/audit-log.js +1000 -0
- package/dist/commands/auth/login.d.ts +14 -0
- package/dist/commands/auth/login.js +116 -0
- package/dist/commands/auth/logout.d.ts +10 -0
- package/dist/commands/auth/logout.js +58 -0
- package/dist/commands/auth/status.d.ts +12 -0
- package/dist/commands/auth/status.js +101 -0
- package/dist/commands/auth/tenant.d.ts +18 -0
- package/dist/commands/auth/tenant.js +168 -0
- package/dist/commands/auth.d.ts +37 -0
- package/dist/commands/auth.js +871 -0
- package/dist/commands/bank-accounts.d.ts +41 -0
- package/dist/commands/bank-accounts.js +1020 -0
- package/dist/commands/bank-integrations.d.ts +39 -0
- package/dist/commands/bank-integrations.js +1011 -0
- package/dist/commands/bank-statements.d.ts +40 -0
- package/dist/commands/bank-statements.js +998 -0
- package/dist/commands/business-partners---contacts.d.ts +41 -0
- package/dist/commands/business-partners---contacts.js +1006 -0
- package/dist/commands/business-partners.d.ts +40 -0
- package/dist/commands/business-partners.js +1012 -0
- package/dist/commands/config/add.d.ts +13 -0
- package/dist/commands/config/add.js +120 -0
- package/dist/commands/config/current.d.ts +9 -0
- package/dist/commands/config/current.js +43 -0
- package/dist/commands/config/delete.d.ts +12 -0
- package/dist/commands/config/delete.js +67 -0
- package/dist/commands/config/list.d.ts +9 -0
- package/dist/commands/config/list.js +50 -0
- package/dist/commands/config/use.d.ts +9 -0
- package/dist/commands/config/use.js +40 -0
- package/dist/commands/credit-card-accounts.d.ts +41 -0
- package/dist/commands/credit-card-accounts.js +1018 -0
- package/dist/commands/documents.d.ts +39 -0
- package/dist/commands/documents.js +1005 -0
- package/dist/commands/dunning-configs.d.ts +39 -0
- package/dist/commands/dunning-configs.js +1006 -0
- package/dist/commands/dunning-reminders.d.ts +39 -0
- package/dist/commands/dunning-reminders.js +1007 -0
- package/dist/commands/dunning-runs.d.ts +39 -0
- package/dist/commands/dunning-runs.js +995 -0
- package/dist/commands/employees.d.ts +43 -0
- package/dist/commands/employees.js +1037 -0
- package/dist/commands/event-processor-mappings.d.ts +39 -0
- package/dist/commands/event-processor-mappings.js +1005 -0
- package/dist/commands/files-internal.d.ts +39 -0
- package/dist/commands/files-internal.js +1007 -0
- package/dist/commands/health.d.ts +39 -0
- package/dist/commands/health.js +1001 -0
- package/dist/commands/inbox.d.ts +39 -0
- package/dist/commands/inbox.js +997 -0
- package/dist/commands/integrations.d.ts +40 -0
- package/dist/commands/integrations.js +1001 -0
- package/dist/commands/item-categories.d.ts +39 -0
- package/dist/commands/item-categories.js +1006 -0
- package/dist/commands/items.d.ts +39 -0
- package/dist/commands/items.js +1006 -0
- package/dist/commands/journal-lines.d.ts +39 -0
- package/dist/commands/journal-lines.js +998 -0
- package/dist/commands/journals.d.ts +41 -0
- package/dist/commands/journals.js +1022 -0
- package/dist/commands/ledgers.d.ts +41 -0
- package/dist/commands/ledgers.js +1019 -0
- package/dist/commands/office-locations.d.ts +39 -0
- package/dist/commands/office-locations.js +1006 -0
- package/dist/commands/payment-method-ledger-mappings.d.ts +40 -0
- package/dist/commands/payment-method-ledger-mappings.js +1000 -0
- package/dist/commands/payment-methods.d.ts +39 -0
- package/dist/commands/payment-methods.js +1006 -0
- package/dist/commands/payment-runs.d.ts +41 -0
- package/dist/commands/payment-runs.js +1021 -0
- package/dist/commands/payment-terms.d.ts +39 -0
- package/dist/commands/payment-terms.js +1007 -0
- package/dist/commands/price-lists.d.ts +40 -0
- package/dist/commands/price-lists.js +1012 -0
- package/dist/commands/processing-logs.d.ts +39 -0
- package/dist/commands/processing-logs.js +997 -0
- package/dist/commands/processor-mappings.d.ts +39 -0
- package/dist/commands/processor-mappings.js +1004 -0
- package/dist/commands/processors.d.ts +39 -0
- package/dist/commands/processors.js +1010 -0
- package/dist/commands/reconciliation.d.ts +39 -0
- package/dist/commands/reconciliation.js +1003 -0
- package/dist/commands/reports.d.ts +39 -0
- package/dist/commands/reports.js +996 -0
- package/dist/commands/salary-types.d.ts +39 -0
- package/dist/commands/salary-types.js +1006 -0
- package/dist/commands/sales-invoices.d.ts +42 -0
- package/dist/commands/sales-invoices.js +1033 -0
- package/dist/commands/sales-orders.d.ts +42 -0
- package/dist/commands/sales-orders.js +1030 -0
- package/dist/commands/switch.d.ts +6 -0
- package/dist/commands/switch.js +41 -0
- package/dist/commands/tags.d.ts +39 -0
- package/dist/commands/tags.js +1006 -0
- package/dist/commands/tax-codes.d.ts +39 -0
- package/dist/commands/tax-codes.js +1009 -0
- package/dist/commands/tax-matrix.d.ts +39 -0
- package/dist/commands/tax-matrix.js +1006 -0
- package/dist/commands/tenants.d.ts +39 -0
- package/dist/commands/tenants.js +1006 -0
- package/dist/commands/text-templates.d.ts +39 -0
- package/dist/commands/text-templates.js +1006 -0
- package/dist/commands/tools.d.ts +39 -0
- package/dist/commands/tools.js +999 -0
- package/dist/commands/vendor-invoices.d.ts +43 -0
- package/dist/commands/vendor-invoices.js +1037 -0
- package/dist/commands/webhooks.d.ts +39 -0
- package/dist/commands/webhooks.js +1008 -0
- package/dist/commands/workflows.d.ts +39 -0
- package/dist/commands/workflows.js +1000 -0
- package/dist/hooks/command-not-found.d.ts +3 -0
- package/dist/hooks/command-not-found.js +57 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/api-client.d.ts +40 -0
- package/dist/lib/api-client.js +120 -0
- package/dist/lib/auth.d.ts +20 -0
- package/dist/lib/auth.js +431 -0
- package/dist/lib/base-api-command.d.ts +19 -0
- package/dist/lib/base-api-command.js +173 -0
- package/dist/lib/config.d.ts +40 -0
- package/dist/lib/config.js +113 -0
- package/dist/lib/openapi.d.ts +82 -0
- package/dist/lib/openapi.js +100 -0
- package/oclif.manifest.json +9040 -0
- package/package.json +91 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export type OutputFormat = 'json' | 'table' | 'yaml';
|
|
3
|
+
export declare abstract class BaseApiCommand extends Command {
|
|
4
|
+
static globalFlags: {
|
|
5
|
+
context: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
protected contextName?: string;
|
|
10
|
+
protected outputFormat: OutputFormat;
|
|
11
|
+
protected quiet: boolean;
|
|
12
|
+
protected executeApiCall(method: string, path: string, options?: {
|
|
13
|
+
data?: unknown;
|
|
14
|
+
params?: Record<string, unknown>;
|
|
15
|
+
}): Promise<unknown>;
|
|
16
|
+
protected formatOutput(data: unknown): void;
|
|
17
|
+
protected init(): Promise<void>;
|
|
18
|
+
protected printTable(data: unknown): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { ApiError, apiRequest } from './api-client.js';
|
|
3
|
+
import { getCurrentContext } from './config.js';
|
|
4
|
+
export class BaseApiCommand extends Command {
|
|
5
|
+
static globalFlags = {
|
|
6
|
+
context: Flags.string({
|
|
7
|
+
char: 'c',
|
|
8
|
+
description: 'Context to use (defaults to current context)',
|
|
9
|
+
}),
|
|
10
|
+
output: Flags.string({
|
|
11
|
+
char: 'o',
|
|
12
|
+
default: 'json',
|
|
13
|
+
description: 'Output format',
|
|
14
|
+
options: ['json', 'table', 'yaml'],
|
|
15
|
+
}),
|
|
16
|
+
quiet: Flags.boolean({
|
|
17
|
+
char: 'q',
|
|
18
|
+
default: false,
|
|
19
|
+
description: 'Only output the result, no headers or formatting',
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
contextName;
|
|
23
|
+
outputFormat = 'json';
|
|
24
|
+
quiet = false;
|
|
25
|
+
async executeApiCall(method, path, options = {}) {
|
|
26
|
+
try {
|
|
27
|
+
const response = await apiRequest(method, path, {
|
|
28
|
+
...options,
|
|
29
|
+
contextName: this.contextName,
|
|
30
|
+
});
|
|
31
|
+
return response.data;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof ApiError) {
|
|
35
|
+
this.error(`API Error (${error.status}): ${error.message}`);
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
formatOutput(data) {
|
|
41
|
+
switch (this.outputFormat) {
|
|
42
|
+
case 'json': {
|
|
43
|
+
this.log(JSON.stringify(data, null, this.quiet ? 0 : 2));
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case 'table': {
|
|
47
|
+
this.printTable(data);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'yaml': {
|
|
51
|
+
// Simple YAML output
|
|
52
|
+
this.log(toYaml(data));
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
// No default
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async init() {
|
|
59
|
+
await super.init();
|
|
60
|
+
const { flags } = await this.parse(this.constructor);
|
|
61
|
+
this.contextName = flags.context;
|
|
62
|
+
this.outputFormat = (flags.output || 'json');
|
|
63
|
+
this.quiet = flags.quiet || false;
|
|
64
|
+
// Verify we have a valid context
|
|
65
|
+
const context = this.contextName ? (await import('./config.js')).getContext(this.contextName) : getCurrentContext();
|
|
66
|
+
if (!context) {
|
|
67
|
+
this.error('No context configured. Run: aderis auth login --new');
|
|
68
|
+
}
|
|
69
|
+
if (!context.tokens) {
|
|
70
|
+
this.error(`Not logged in to context "${context.name}". Run: aderis auth login`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
printTable(data) {
|
|
74
|
+
if (Array.isArray(data)) {
|
|
75
|
+
if (data.length === 0) {
|
|
76
|
+
this.log('No results');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Get columns from first item
|
|
80
|
+
const firstItem = data[0];
|
|
81
|
+
if (typeof firstItem === 'object' && firstItem !== null) {
|
|
82
|
+
const columns = Object.keys(firstItem).slice(0, 8); // Limit columns for readability
|
|
83
|
+
const header = columns.join('\t');
|
|
84
|
+
this.log(header);
|
|
85
|
+
this.log('-'.repeat(header.length));
|
|
86
|
+
for (const item of data) {
|
|
87
|
+
const row = columns.map((col) => formatValue(item[col])).join('\t');
|
|
88
|
+
this.log(row);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
for (const item of data) {
|
|
93
|
+
this.log(String(item));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (typeof data === 'object' && data !== null) {
|
|
98
|
+
// Handle paginated responses
|
|
99
|
+
const obj = data;
|
|
100
|
+
if (Array.isArray(obj.data)) {
|
|
101
|
+
this.printTable(obj.data);
|
|
102
|
+
if (obj.meta && typeof obj.meta === 'object') {
|
|
103
|
+
const meta = obj.meta;
|
|
104
|
+
this.log(`\nPage ${meta.currentPage}/${meta.totalPages} (${meta.totalItems} total items)`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
109
|
+
this.log(`${key}: ${formatValue(value)}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this.log(String(data));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function formatValue(value) {
|
|
119
|
+
if (value === null || value === undefined)
|
|
120
|
+
return '-';
|
|
121
|
+
if (typeof value === 'object') {
|
|
122
|
+
if (Array.isArray(value))
|
|
123
|
+
return `[${value.length} items]`;
|
|
124
|
+
return '{...}';
|
|
125
|
+
}
|
|
126
|
+
const str = String(value);
|
|
127
|
+
return str.length > 50 ? str.slice(0, 47) + '...' : str;
|
|
128
|
+
}
|
|
129
|
+
function toYaml(obj, indent = 0) {
|
|
130
|
+
const spaces = ' '.repeat(indent);
|
|
131
|
+
if (obj === null || obj === undefined) {
|
|
132
|
+
return `${spaces}null`;
|
|
133
|
+
}
|
|
134
|
+
if (typeof obj === 'string') {
|
|
135
|
+
if (obj.includes('\n')) {
|
|
136
|
+
return `${spaces}|\n${obj
|
|
137
|
+
.split('\n')
|
|
138
|
+
.map((line) => spaces + ' ' + line)
|
|
139
|
+
.join('\n')}`;
|
|
140
|
+
}
|
|
141
|
+
return obj.includes(':') || obj.includes('#') ? `"${obj}"` : obj;
|
|
142
|
+
}
|
|
143
|
+
if (typeof obj === 'number' || typeof obj === 'boolean') {
|
|
144
|
+
return String(obj);
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(obj)) {
|
|
147
|
+
if (obj.length === 0)
|
|
148
|
+
return '[]';
|
|
149
|
+
return obj
|
|
150
|
+
.map((item) => {
|
|
151
|
+
const formatted = toYaml(item, indent + 1);
|
|
152
|
+
if (typeof item === 'object' && item !== null) {
|
|
153
|
+
return `${spaces}- ${formatted.trim()}`;
|
|
154
|
+
}
|
|
155
|
+
return `${spaces}- ${formatted}`;
|
|
156
|
+
})
|
|
157
|
+
.join('\n');
|
|
158
|
+
}
|
|
159
|
+
if (typeof obj === 'object') {
|
|
160
|
+
const entries = Object.entries(obj);
|
|
161
|
+
if (entries.length === 0)
|
|
162
|
+
return '{}';
|
|
163
|
+
return entries
|
|
164
|
+
.map(([key, value]) => {
|
|
165
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
166
|
+
return `${spaces}${key}:\n${toYaml(value, indent + 1)}`;
|
|
167
|
+
}
|
|
168
|
+
return `${spaces}${key}: ${toYaml(value, indent)}`;
|
|
169
|
+
})
|
|
170
|
+
.join('\n');
|
|
171
|
+
}
|
|
172
|
+
return String(obj);
|
|
173
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
export type Environment = 'dev' | 'live' | 'test';
|
|
3
|
+
export interface BaseUrls {
|
|
4
|
+
api: string;
|
|
5
|
+
auth: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const BASE_URLS: Record<Environment, BaseUrls>;
|
|
8
|
+
export declare const DEFAULT_CLIENT_IDS: Record<Environment, string>;
|
|
9
|
+
export interface TokenData {
|
|
10
|
+
access_token: string;
|
|
11
|
+
expires_at?: number;
|
|
12
|
+
refresh_token?: string;
|
|
13
|
+
tenant_id?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Context {
|
|
16
|
+
client_id: string;
|
|
17
|
+
client_secret?: string;
|
|
18
|
+
environment: Environment;
|
|
19
|
+
name: string;
|
|
20
|
+
tenant_id?: string;
|
|
21
|
+
tokens?: TokenData;
|
|
22
|
+
}
|
|
23
|
+
export interface ConfigSchema {
|
|
24
|
+
contexts: Record<string, Context>;
|
|
25
|
+
current_context: null | string;
|
|
26
|
+
}
|
|
27
|
+
declare const config: Conf<ConfigSchema>;
|
|
28
|
+
export declare function getConfig(): ConfigSchema;
|
|
29
|
+
export declare function getCurrentContext(): Context | null;
|
|
30
|
+
export declare function setCurrentContext(name: string): void;
|
|
31
|
+
export declare function listContexts(): Context[];
|
|
32
|
+
export declare function getContext(name: string): Context | null;
|
|
33
|
+
export declare function addContext(context: Context): void;
|
|
34
|
+
export declare function updateContext(name: string, updates: Partial<Context>): void;
|
|
35
|
+
export declare function deleteContext(name: string): void;
|
|
36
|
+
export declare function saveTokens(contextName: string, tokens: TokenData): void;
|
|
37
|
+
export declare function getTokens(contextName: string): null | TokenData;
|
|
38
|
+
export declare function clearTokens(contextName: string): void;
|
|
39
|
+
export declare function getBaseUrls(environment: Environment): BaseUrls;
|
|
40
|
+
export { config };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
export const BASE_URLS = {
|
|
6
|
+
dev: {
|
|
7
|
+
api: 'https://api-dev.aderis.com',
|
|
8
|
+
auth: 'https://auth-dev.aderis.com',
|
|
9
|
+
},
|
|
10
|
+
live: {
|
|
11
|
+
api: 'https://api.aderis.com',
|
|
12
|
+
auth: 'https://auth.aderis.com',
|
|
13
|
+
},
|
|
14
|
+
test: {
|
|
15
|
+
api: 'https://api-test.aderis.com',
|
|
16
|
+
auth: 'https://auth-test.aderis.com',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
// Default OAuth client IDs per environment (public clients, no secret required)
|
|
20
|
+
export const DEFAULT_CLIENT_IDS = {
|
|
21
|
+
dev: '74fd96f8-cf4b-49d8-b713-2a121ea22910',
|
|
22
|
+
live: '970d9568-84c9-4613-b966-30d7e1d93828',
|
|
23
|
+
test: '', // TODO: Add test client ID
|
|
24
|
+
};
|
|
25
|
+
const CONFIG_DIR = path.join(os.homedir(), '.aderis');
|
|
26
|
+
// Ensure config directory exists
|
|
27
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
28
|
+
fs.mkdirSync(CONFIG_DIR, { mode: 0o700, recursive: true });
|
|
29
|
+
}
|
|
30
|
+
const config = new Conf({
|
|
31
|
+
configName: 'config',
|
|
32
|
+
cwd: CONFIG_DIR,
|
|
33
|
+
defaults: {
|
|
34
|
+
contexts: {},
|
|
35
|
+
current_context: null,
|
|
36
|
+
},
|
|
37
|
+
projectName: 'aderis',
|
|
38
|
+
});
|
|
39
|
+
export function getConfig() {
|
|
40
|
+
return {
|
|
41
|
+
contexts: config.get('contexts'),
|
|
42
|
+
current_context: config.get('current_context'),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function getCurrentContext() {
|
|
46
|
+
const currentName = config.get('current_context');
|
|
47
|
+
if (!currentName)
|
|
48
|
+
return null;
|
|
49
|
+
const contexts = config.get('contexts');
|
|
50
|
+
return contexts[currentName] || null;
|
|
51
|
+
}
|
|
52
|
+
export function setCurrentContext(name) {
|
|
53
|
+
const contexts = config.get('contexts');
|
|
54
|
+
if (!contexts[name]) {
|
|
55
|
+
throw new Error(`Context "${name}" does not exist`);
|
|
56
|
+
}
|
|
57
|
+
config.set('current_context', name);
|
|
58
|
+
}
|
|
59
|
+
export function listContexts() {
|
|
60
|
+
const contexts = config.get('contexts');
|
|
61
|
+
return Object.values(contexts);
|
|
62
|
+
}
|
|
63
|
+
export function getContext(name) {
|
|
64
|
+
const contexts = config.get('contexts');
|
|
65
|
+
return contexts[name] || null;
|
|
66
|
+
}
|
|
67
|
+
export function addContext(context) {
|
|
68
|
+
const contexts = config.get('contexts');
|
|
69
|
+
contexts[context.name] = context;
|
|
70
|
+
config.set('contexts', contexts);
|
|
71
|
+
// If this is the first context, set it as current
|
|
72
|
+
if (!config.get('current_context')) {
|
|
73
|
+
config.set('current_context', context.name);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function updateContext(name, updates) {
|
|
77
|
+
const contexts = config.get('contexts');
|
|
78
|
+
if (!contexts[name]) {
|
|
79
|
+
throw new Error(`Context "${name}" does not exist`);
|
|
80
|
+
}
|
|
81
|
+
contexts[name] = { ...contexts[name], ...updates };
|
|
82
|
+
config.set('contexts', contexts);
|
|
83
|
+
}
|
|
84
|
+
export function deleteContext(name) {
|
|
85
|
+
const contexts = config.get('contexts');
|
|
86
|
+
if (!contexts[name]) {
|
|
87
|
+
throw new Error(`Context "${name}" does not exist`);
|
|
88
|
+
}
|
|
89
|
+
delete contexts[name];
|
|
90
|
+
config.set('contexts', contexts);
|
|
91
|
+
// If we deleted the current context, clear it
|
|
92
|
+
if (config.get('current_context') === name) {
|
|
93
|
+
const remaining = Object.keys(contexts);
|
|
94
|
+
config.set('current_context', remaining.length > 0 ? remaining[0] : null);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function saveTokens(contextName, tokens) {
|
|
98
|
+
updateContext(contextName, {
|
|
99
|
+
tenant_id: tokens.tenant_id,
|
|
100
|
+
tokens,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export function getTokens(contextName) {
|
|
104
|
+
const context = getContext(contextName);
|
|
105
|
+
return context?.tokens || null;
|
|
106
|
+
}
|
|
107
|
+
export function clearTokens(contextName) {
|
|
108
|
+
updateContext(contextName, { tokens: undefined });
|
|
109
|
+
}
|
|
110
|
+
export function getBaseUrls(environment) {
|
|
111
|
+
return BASE_URLS[environment];
|
|
112
|
+
}
|
|
113
|
+
export { config };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export interface OpenApiParameter {
|
|
2
|
+
description?: string;
|
|
3
|
+
in: 'body' | 'header' | 'path' | 'query';
|
|
4
|
+
name: string;
|
|
5
|
+
required?: boolean;
|
|
6
|
+
schema?: {
|
|
7
|
+
default?: unknown;
|
|
8
|
+
enum?: string[];
|
|
9
|
+
example?: unknown;
|
|
10
|
+
items?: {
|
|
11
|
+
enum?: string[];
|
|
12
|
+
type?: string;
|
|
13
|
+
};
|
|
14
|
+
type?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface OpenApiRequestBody {
|
|
18
|
+
content?: {
|
|
19
|
+
'application/json'?: {
|
|
20
|
+
schema?: {
|
|
21
|
+
$ref?: string;
|
|
22
|
+
properties?: Record<string, unknown>;
|
|
23
|
+
type?: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
required?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface OpenApiOperation {
|
|
30
|
+
description?: string;
|
|
31
|
+
operationId: string;
|
|
32
|
+
parameters?: OpenApiParameter[];
|
|
33
|
+
requestBody?: OpenApiRequestBody;
|
|
34
|
+
responses?: Record<string, {
|
|
35
|
+
content?: Record<string, {
|
|
36
|
+
schema?: Record<string, unknown>;
|
|
37
|
+
}>;
|
|
38
|
+
description?: string;
|
|
39
|
+
}>;
|
|
40
|
+
security?: Array<Record<string, unknown>>;
|
|
41
|
+
summary?: string;
|
|
42
|
+
tags?: string[];
|
|
43
|
+
}
|
|
44
|
+
export interface OpenApiPath {
|
|
45
|
+
delete?: OpenApiOperation;
|
|
46
|
+
get?: OpenApiOperation;
|
|
47
|
+
patch?: OpenApiOperation;
|
|
48
|
+
post?: OpenApiOperation;
|
|
49
|
+
put?: OpenApiOperation;
|
|
50
|
+
}
|
|
51
|
+
export interface OpenApiSpec {
|
|
52
|
+
components?: {
|
|
53
|
+
schemas?: Record<string, unknown>;
|
|
54
|
+
};
|
|
55
|
+
info: {
|
|
56
|
+
description?: string;
|
|
57
|
+
title: string;
|
|
58
|
+
version: string;
|
|
59
|
+
};
|
|
60
|
+
openapi: string;
|
|
61
|
+
paths: Record<string, OpenApiPath>;
|
|
62
|
+
}
|
|
63
|
+
export interface ParsedEndpoint {
|
|
64
|
+
description?: string;
|
|
65
|
+
hasRequestBody: boolean;
|
|
66
|
+
method: 'delete' | 'get' | 'patch' | 'post' | 'put';
|
|
67
|
+
operationId: string;
|
|
68
|
+
path: string;
|
|
69
|
+
pathParams: OpenApiParameter[];
|
|
70
|
+
queryParams: OpenApiParameter[];
|
|
71
|
+
requestBodyRequired: boolean;
|
|
72
|
+
requestBodySchema?: string;
|
|
73
|
+
summary: string;
|
|
74
|
+
tag: string;
|
|
75
|
+
}
|
|
76
|
+
export declare function loadOpenApiSpec(specPath: string): OpenApiSpec;
|
|
77
|
+
export declare function parseEndpoints(spec: OpenApiSpec): ParsedEndpoint[];
|
|
78
|
+
export declare function normalizeTag(tag: string): string;
|
|
79
|
+
export declare function groupEndpointsByTag(endpoints: ParsedEndpoint[]): Map<string, ParsedEndpoint[]>;
|
|
80
|
+
export declare function getCommandName(endpoint: ParsedEndpoint): string;
|
|
81
|
+
export declare function generateFlagName(param: OpenApiParameter): string;
|
|
82
|
+
export declare function getSchemaDefinition(spec: OpenApiSpec, schemaName: string): null | Record<string, unknown>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
export function loadOpenApiSpec(specPath) {
|
|
3
|
+
const content = fs.readFileSync(specPath, 'utf8');
|
|
4
|
+
return JSON.parse(content);
|
|
5
|
+
}
|
|
6
|
+
export function parseEndpoints(spec) {
|
|
7
|
+
const endpoints = [];
|
|
8
|
+
const methods = ['get', 'post', 'put', 'patch', 'delete'];
|
|
9
|
+
for (const [pathStr, pathObj] of Object.entries(spec.paths)) {
|
|
10
|
+
for (const method of methods) {
|
|
11
|
+
const operation = pathObj[method];
|
|
12
|
+
if (!operation)
|
|
13
|
+
continue;
|
|
14
|
+
const params = operation.parameters || [];
|
|
15
|
+
const pathParams = params.filter((p) => p.in === 'path');
|
|
16
|
+
const queryParams = params.filter((p) => p.in === 'query');
|
|
17
|
+
const hasRequestBody = Boolean(operation.requestBody?.content?.['application/json']);
|
|
18
|
+
const requestBodySchema = operation.requestBody?.content?.['application/json']?.schema?.$ref;
|
|
19
|
+
endpoints.push({
|
|
20
|
+
description: operation.description,
|
|
21
|
+
hasRequestBody,
|
|
22
|
+
method,
|
|
23
|
+
operationId: operation.operationId,
|
|
24
|
+
path: pathStr,
|
|
25
|
+
pathParams,
|
|
26
|
+
queryParams,
|
|
27
|
+
requestBodyRequired: Boolean(operation.requestBody?.required),
|
|
28
|
+
requestBodySchema: requestBodySchema?.replace('#/components/schemas/', ''),
|
|
29
|
+
summary: operation.summary || `${method.toUpperCase()} ${pathStr}`,
|
|
30
|
+
tag: normalizeTag(operation.tags?.[0] || 'misc'),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return endpoints;
|
|
35
|
+
}
|
|
36
|
+
export function normalizeTag(tag) {
|
|
37
|
+
return tag
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
.replaceAll(/\s+/g, '-')
|
|
40
|
+
.replaceAll(/[^a-z0-9-]/g, '');
|
|
41
|
+
}
|
|
42
|
+
export function groupEndpointsByTag(endpoints) {
|
|
43
|
+
const groups = new Map();
|
|
44
|
+
for (const endpoint of endpoints) {
|
|
45
|
+
const existing = groups.get(endpoint.tag) || [];
|
|
46
|
+
existing.push(endpoint);
|
|
47
|
+
groups.set(endpoint.tag, existing);
|
|
48
|
+
}
|
|
49
|
+
return groups;
|
|
50
|
+
}
|
|
51
|
+
export function getCommandName(endpoint) {
|
|
52
|
+
// Extract action from operationId like "AccountsController_findAll_v1" -> "list"
|
|
53
|
+
// or "AccountsController_create_v1" -> "create"
|
|
54
|
+
const { operationId } = endpoint;
|
|
55
|
+
// Common mappings
|
|
56
|
+
const actionMap = {
|
|
57
|
+
approve: 'approve',
|
|
58
|
+
cancel: 'cancel',
|
|
59
|
+
copy: 'copy',
|
|
60
|
+
create: 'create',
|
|
61
|
+
delete: 'delete',
|
|
62
|
+
findAll: 'list',
|
|
63
|
+
findOne: 'get',
|
|
64
|
+
import: 'import',
|
|
65
|
+
pay: 'pay',
|
|
66
|
+
post: 'post',
|
|
67
|
+
remove: 'delete',
|
|
68
|
+
replace: 'replace',
|
|
69
|
+
resend: 'resend',
|
|
70
|
+
send: 'send',
|
|
71
|
+
update: 'update',
|
|
72
|
+
validate: 'validate',
|
|
73
|
+
};
|
|
74
|
+
for (const [key, value] of Object.entries(actionMap)) {
|
|
75
|
+
if (operationId.toLowerCase().includes(key.toLowerCase())) {
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Fallback: use method
|
|
80
|
+
const methodMap = {
|
|
81
|
+
delete: 'delete',
|
|
82
|
+
get: 'get',
|
|
83
|
+
patch: 'update',
|
|
84
|
+
post: 'create',
|
|
85
|
+
put: 'update',
|
|
86
|
+
};
|
|
87
|
+
return methodMap[endpoint.method] || endpoint.method;
|
|
88
|
+
}
|
|
89
|
+
export function generateFlagName(param) {
|
|
90
|
+
// Convert parameter name to kebab-case flag
|
|
91
|
+
return param.name
|
|
92
|
+
.replaceAll('.', '-')
|
|
93
|
+
.replaceAll(/([A-Z])/g, '-$1')
|
|
94
|
+
.toLowerCase()
|
|
95
|
+
.replace(/^-/, '')
|
|
96
|
+
.replaceAll(/--+/g, '-');
|
|
97
|
+
}
|
|
98
|
+
export function getSchemaDefinition(spec, schemaName) {
|
|
99
|
+
return spec.components?.schemas?.[schemaName] || null;
|
|
100
|
+
}
|