@aderis-erp/cli 1.0.13 → 1.0.15
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/dist/commands/access-groups.js +21 -21
- package/dist/commands/account-transaction-allocations.js +21 -21
- package/dist/commands/account-transactions.js +23 -23
- package/dist/commands/accounts.js +23 -23
- package/dist/commands/agent-platform.js +23 -22
- package/dist/commands/analytics.d.ts +40 -0
- package/dist/commands/{documents.js → analytics.js} +33 -43
- package/dist/commands/audit-log.js +24 -24
- package/dist/commands/auth/login.js +11 -2
- package/dist/commands/auth/logout.d.ts +2 -0
- package/dist/commands/auth/logout.js +19 -6
- package/dist/commands/auth/status.js +26 -12
- package/dist/commands/auth/tenant.js +12 -3
- package/dist/commands/auth.js +32 -17
- package/dist/commands/bank-accounts.js +21 -21
- package/dist/commands/bank-integrations.js +21 -21
- package/dist/commands/business-partners.js +29 -26
- package/dist/commands/chat.js +21 -21
- package/dist/commands/config/add.d.ts +9 -0
- package/dist/commands/config/add.js +64 -2
- package/dist/commands/config/current.js +9 -4
- package/dist/commands/config/list.js +9 -4
- package/dist/commands/config/set-api-key.d.ts +10 -0
- package/dist/commands/config/set-api-key.js +49 -0
- package/dist/commands/config/use.js +3 -4
- package/dist/commands/credit-card-accounts.js +21 -21
- package/dist/commands/delivery-notes.js +28 -25
- package/dist/commands/dunning-configs.js +21 -21
- package/dist/commands/dunning-reminders.js +21 -21
- package/dist/commands/dunning-runs.js +21 -21
- package/dist/commands/email-transactions.js +21 -21
- package/dist/commands/employees.js +23 -23
- package/dist/commands/entity-configurations.js +21 -21
- package/dist/commands/event-processor-mappings.js +21 -21
- package/dist/commands/{documents.d.ts → files.d.ts} +1 -1
- package/dist/commands/{files-internal.js → files.js} +39 -33
- package/dist/commands/health.js +21 -21
- package/dist/commands/inbox.d.ts +1 -0
- package/dist/commands/inbox.js +25 -23
- package/dist/commands/integrations.js +21 -21
- package/dist/commands/item-categories.js +21 -21
- package/dist/commands/items.js +23 -23
- package/dist/commands/journal-lines.js +21 -21
- package/dist/commands/journals.js +27 -24
- package/dist/commands/ledgers.js +25 -22
- package/dist/commands/office-locations.js +21 -21
- package/dist/commands/payment-methods.js +21 -21
- package/dist/commands/payment-runs.js +23 -22
- package/dist/commands/payment-terms.js +21 -21
- package/dist/commands/payments.js +21 -21
- package/dist/commands/price-lists.js +21 -21
- package/dist/commands/processor-mappings.js +21 -21
- package/dist/commands/processors.js +21 -21
- package/dist/commands/purchase-order-types.js +21 -21
- package/dist/commands/purchase-orders.d.ts +1 -0
- package/dist/commands/purchase-orders.js +32 -25
- package/dist/commands/reports.js +21 -21
- package/dist/commands/salary-types.js +21 -21
- package/dist/commands/sales-invoices.js +33 -31
- package/dist/commands/sales-orders.js +23 -23
- package/dist/commands/saved-views.js +21 -21
- package/dist/commands/scheduled-processor-mappings.d.ts +40 -0
- package/dist/commands/scheduled-processor-mappings.js +1178 -0
- package/dist/commands/schedules.js +21 -21
- package/dist/commands/switch.js +10 -3
- package/dist/commands/{files-internal.d.ts → tag-configurations.d.ts} +1 -1
- package/dist/commands/tag-configurations.js +1178 -0
- package/dist/commands/tags.js +21 -21
- package/dist/commands/tax-codes.js +21 -21
- package/dist/commands/tax-matrix.js +21 -21
- package/dist/commands/tenants.js +23 -23
- package/dist/commands/text-templates.js +21 -21
- package/dist/commands/tools.js +21 -21
- package/dist/commands/vat-declarations.js +21 -21
- package/dist/commands/vendor-invoices.js +25 -25
- package/dist/commands/webhooks.js +21 -21
- package/dist/commands/workflows.js +21 -21
- package/dist/lib/api-client.d.ts +8 -0
- package/dist/lib/api-client.js +31 -6
- package/dist/lib/auth.d.ts +8 -0
- package/dist/lib/auth.js +51 -7
- package/dist/lib/base-api-command.js +6 -4
- package/dist/lib/config.d.ts +31 -1
- package/dist/lib/config.js +31 -0
- package/oclif.manifest.json +1099 -443
- package/package.json +2 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Analytics extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: never[];
|
|
5
|
+
static args: {
|
|
6
|
+
action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
context: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
table: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
search: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
'sort-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
filter: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
};
|
|
28
|
+
run(): Promise<void>;
|
|
29
|
+
private runImport;
|
|
30
|
+
private runExport;
|
|
31
|
+
private runCamt053Import;
|
|
32
|
+
private runNestedImport;
|
|
33
|
+
private parseFilterValue;
|
|
34
|
+
private filterFields;
|
|
35
|
+
private sanitizeOutput;
|
|
36
|
+
private getColumns;
|
|
37
|
+
private getValue;
|
|
38
|
+
private printTable;
|
|
39
|
+
private printCsv;
|
|
40
|
+
}
|
|
@@ -1,36 +1,26 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
2
|
+
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
|
-
const HAS_IMPORT =
|
|
6
|
-
const HAS_EXPORT =
|
|
5
|
+
const HAS_IMPORT = false;
|
|
6
|
+
const HAS_EXPORT = false;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
|
-
const SUBCOMMANDS = [...["
|
|
9
|
+
const SUBCOMMANDS = [...["query", "views", "views-name"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/documents/{id}', summary: 'Patch an existing document', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['references', 'tags', 'files'] },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/documents/{id}', summary: 'Soft-delete (discard) a document', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
-
'reclassify': { method: 'POST', path: '/v1/documents/{id}/reclassify', summary: 'Reclassify a document to a new type', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'query': { method: 'POST', path: '/v1/analytics/query', summary: 'Run a structured aggregate query over a reporting view', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['measures', 'dimensions', 'filters', 'order'] },
|
|
12
|
+
'views': { method: 'GET', path: '/v1/analytics/views', summary: 'List the analytics views for discovery', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
+
'views-name': { method: 'GET', path: '/v1/analytics/views/{name}', summary: 'Describe one analytics view with full metadata', pathParams: ['name'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
14
|
};
|
|
18
|
-
export default class
|
|
19
|
-
static description = 'Manage
|
|
20
|
-
static examples = [
|
|
21
|
-
'<%= config.bin %> documents list',
|
|
22
|
-
'<%= config.bin %> documents get <id>',
|
|
23
|
-
'<%= config.bin %> documents create --data \'{...}\'',
|
|
24
|
-
'<%= config.bin %> documents update <id> --set field=value',
|
|
25
|
-
'<%= config.bin %> documents import --file data.json',
|
|
26
|
-
'<%= config.bin %> documents export --csv > documents.csv',
|
|
27
|
-
];
|
|
15
|
+
export default class Analytics extends Command {
|
|
16
|
+
static description = 'Manage analytics';
|
|
17
|
+
static examples = [];
|
|
28
18
|
static args = {
|
|
29
19
|
action: Args.string({ description: 'Action: ' + SUBCOMMANDS.join(', '), required: true }),
|
|
30
20
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
31
21
|
};
|
|
32
22
|
static flags = {
|
|
33
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
23
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
34
24
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
35
25
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
36
26
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -41,7 +31,7 @@ export default class Documents extends Command {
|
|
|
41
31
|
limit: Flags.string({ description: 'Items per page' }),
|
|
42
32
|
include: Flags.string({ description: 'Relations to include' }),
|
|
43
33
|
search: Flags.string({ description: 'Search term' }),
|
|
44
|
-
'sort-by': Flags.string({ description: 'Sort field' }),
|
|
34
|
+
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
45
35
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
46
36
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
47
37
|
fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
|
|
@@ -49,7 +39,7 @@ export default class Documents extends Command {
|
|
|
49
39
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
50
40
|
};
|
|
51
41
|
async run() {
|
|
52
|
-
const { args, flags } = await this.parse(
|
|
42
|
+
const { args, flags } = await this.parse(Analytics);
|
|
53
43
|
// Handle import action specially
|
|
54
44
|
if (args.action === 'import') {
|
|
55
45
|
if (!HAS_IMPORT)
|
|
@@ -90,7 +80,7 @@ export default class Documents extends Command {
|
|
|
90
80
|
// First path param always comes from positional argument
|
|
91
81
|
value = args.id;
|
|
92
82
|
if (!value)
|
|
93
|
-
this.error('Missing required argument: id. Usage: aderis
|
|
83
|
+
this.error('Missing required argument: id. Usage: aderis analytics <action> <id>');
|
|
94
84
|
}
|
|
95
85
|
else {
|
|
96
86
|
const flagName = param.replace(/\./g, '-').replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
|
|
@@ -102,9 +92,9 @@ export default class Documents extends Command {
|
|
|
102
92
|
}
|
|
103
93
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
104
94
|
if (!context)
|
|
105
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
106
|
-
if (!context
|
|
107
|
-
this.error(
|
|
95
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
96
|
+
if (!hasCredentials(context))
|
|
97
|
+
this.error(missingCredentialsMessage(context));
|
|
108
98
|
const queryParams = {};
|
|
109
99
|
if (flags.page)
|
|
110
100
|
queryParams.page = flags.page;
|
|
@@ -115,7 +105,7 @@ export default class Documents extends Command {
|
|
|
115
105
|
if (flags.search)
|
|
116
106
|
queryParams.search = flags.search;
|
|
117
107
|
if (flags['sort-by'])
|
|
118
|
-
queryParams.sortBy = flags['sort-by'];
|
|
108
|
+
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
119
109
|
if (flags.query) {
|
|
120
110
|
try {
|
|
121
111
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -347,9 +337,9 @@ export default class Documents extends Command {
|
|
|
347
337
|
async runImport(flags) {
|
|
348
338
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
349
339
|
if (!context)
|
|
350
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
351
|
-
if (!context
|
|
352
|
-
this.error(
|
|
340
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
341
|
+
if (!hasCredentials(context))
|
|
342
|
+
this.error(missingCredentialsMessage(context));
|
|
353
343
|
// Get data from file, --data, or --set flags
|
|
354
344
|
let items = [];
|
|
355
345
|
if (flags.file) {
|
|
@@ -559,9 +549,9 @@ export default class Documents extends Command {
|
|
|
559
549
|
async runExport(flags) {
|
|
560
550
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
561
551
|
if (!context)
|
|
562
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
563
|
-
if (!context
|
|
564
|
-
this.error(
|
|
552
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
553
|
+
if (!hasCredentials(context))
|
|
554
|
+
this.error(missingCredentialsMessage(context));
|
|
565
555
|
const listEndpoint = ENDPOINTS['list'];
|
|
566
556
|
if (!listEndpoint)
|
|
567
557
|
this.error('Export requires a list endpoint');
|
|
@@ -574,7 +564,7 @@ export default class Documents extends Command {
|
|
|
574
564
|
if (flags.search)
|
|
575
565
|
baseParams.search = flags.search;
|
|
576
566
|
if (flags['sort-by'])
|
|
577
|
-
baseParams.sortBy = flags['sort-by'];
|
|
567
|
+
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
578
568
|
if (flags.include)
|
|
579
569
|
baseParams.include = flags.include;
|
|
580
570
|
if (flags.query) {
|
|
@@ -653,9 +643,9 @@ export default class Documents extends Command {
|
|
|
653
643
|
async runCamt053Import(flags) {
|
|
654
644
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
655
645
|
if (!context)
|
|
656
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
657
|
-
if (!context
|
|
658
|
-
this.error(
|
|
646
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
647
|
+
if (!hasCredentials(context))
|
|
648
|
+
this.error(missingCredentialsMessage(context));
|
|
659
649
|
if (!flags.file) {
|
|
660
650
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
661
651
|
}
|
|
@@ -739,13 +729,13 @@ export default class Documents extends Command {
|
|
|
739
729
|
}
|
|
740
730
|
async runNestedImport(suffix, parentId, flags) {
|
|
741
731
|
if (!parentId) {
|
|
742
|
-
this.error(`Missing required argument: id. Usage: aderis
|
|
732
|
+
this.error(`Missing required argument: id. Usage: aderis analytics import-${suffix} <parent-id> --file data.json`);
|
|
743
733
|
}
|
|
744
734
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
745
735
|
if (!context)
|
|
746
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
747
|
-
if (!context
|
|
748
|
-
this.error(
|
|
736
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
737
|
+
if (!hasCredentials(context))
|
|
738
|
+
this.error(missingCredentialsMessage(context));
|
|
749
739
|
// Get data from file, --data, or --set flags
|
|
750
740
|
let items = [];
|
|
751
741
|
if (flags.file) {
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
2
|
+
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = false;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
|
-
const SUBCOMMANDS = [...["list", "
|
|
9
|
+
const SUBCOMMANDS = [...["list", "get"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
11
|
'list': { method: 'GET', path: '/v1/audit-logs', summary: 'Get audit log entries', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'
|
|
13
|
-
'find-workflow': { method: 'GET', path: '/v1/audit-logs/workflow/{workflowId}', summary: 'Get audit log entries for a specific workflow', pathParams: ['workflowId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
+
'get': { method: 'GET', path: '/v1/audit-logs/{id}', summary: 'Get a single audit log entry', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
13
|
};
|
|
15
14
|
export default class AuditLog extends Command {
|
|
16
15
|
static description = 'Manage audit log';
|
|
17
16
|
static examples = [
|
|
18
17
|
'<%= config.bin %> audit-log list',
|
|
18
|
+
'<%= config.bin %> audit-log get <id>',
|
|
19
19
|
'<%= config.bin %> audit-log export --csv > audit-log.csv',
|
|
20
20
|
];
|
|
21
21
|
static args = {
|
|
@@ -23,7 +23,7 @@ export default class AuditLog extends Command {
|
|
|
23
23
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
24
24
|
};
|
|
25
25
|
static flags = {
|
|
26
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
26
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
27
27
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
28
28
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
29
29
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -34,7 +34,7 @@ export default class AuditLog extends Command {
|
|
|
34
34
|
limit: Flags.string({ description: 'Items per page' }),
|
|
35
35
|
include: Flags.string({ description: 'Relations to include' }),
|
|
36
36
|
search: Flags.string({ description: 'Search term' }),
|
|
37
|
-
'sort-by': Flags.string({ description: 'Sort field' }),
|
|
37
|
+
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
38
38
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
39
39
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
40
40
|
fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
|
|
@@ -95,9 +95,9 @@ export default class AuditLog extends Command {
|
|
|
95
95
|
}
|
|
96
96
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
97
97
|
if (!context)
|
|
98
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
99
|
-
if (!context
|
|
100
|
-
this.error(
|
|
98
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
99
|
+
if (!hasCredentials(context))
|
|
100
|
+
this.error(missingCredentialsMessage(context));
|
|
101
101
|
const queryParams = {};
|
|
102
102
|
if (flags.page)
|
|
103
103
|
queryParams.page = flags.page;
|
|
@@ -108,7 +108,7 @@ export default class AuditLog extends Command {
|
|
|
108
108
|
if (flags.search)
|
|
109
109
|
queryParams.search = flags.search;
|
|
110
110
|
if (flags['sort-by'])
|
|
111
|
-
queryParams.sortBy = flags['sort-by'];
|
|
111
|
+
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
112
112
|
if (flags.query) {
|
|
113
113
|
try {
|
|
114
114
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -340,9 +340,9 @@ export default class AuditLog extends Command {
|
|
|
340
340
|
async runImport(flags) {
|
|
341
341
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
342
342
|
if (!context)
|
|
343
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
344
|
-
if (!context
|
|
345
|
-
this.error(
|
|
343
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
344
|
+
if (!hasCredentials(context))
|
|
345
|
+
this.error(missingCredentialsMessage(context));
|
|
346
346
|
// Get data from file, --data, or --set flags
|
|
347
347
|
let items = [];
|
|
348
348
|
if (flags.file) {
|
|
@@ -552,9 +552,9 @@ export default class AuditLog extends Command {
|
|
|
552
552
|
async runExport(flags) {
|
|
553
553
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
554
554
|
if (!context)
|
|
555
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
556
|
-
if (!context
|
|
557
|
-
this.error(
|
|
555
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
556
|
+
if (!hasCredentials(context))
|
|
557
|
+
this.error(missingCredentialsMessage(context));
|
|
558
558
|
const listEndpoint = ENDPOINTS['list'];
|
|
559
559
|
if (!listEndpoint)
|
|
560
560
|
this.error('Export requires a list endpoint');
|
|
@@ -567,7 +567,7 @@ export default class AuditLog extends Command {
|
|
|
567
567
|
if (flags.search)
|
|
568
568
|
baseParams.search = flags.search;
|
|
569
569
|
if (flags['sort-by'])
|
|
570
|
-
baseParams.sortBy = flags['sort-by'];
|
|
570
|
+
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
571
571
|
if (flags.include)
|
|
572
572
|
baseParams.include = flags.include;
|
|
573
573
|
if (flags.query) {
|
|
@@ -646,9 +646,9 @@ export default class AuditLog extends Command {
|
|
|
646
646
|
async runCamt053Import(flags) {
|
|
647
647
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
648
648
|
if (!context)
|
|
649
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
650
|
-
if (!context
|
|
651
|
-
this.error(
|
|
649
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
650
|
+
if (!hasCredentials(context))
|
|
651
|
+
this.error(missingCredentialsMessage(context));
|
|
652
652
|
if (!flags.file) {
|
|
653
653
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
654
654
|
}
|
|
@@ -736,9 +736,9 @@ export default class AuditLog extends Command {
|
|
|
736
736
|
}
|
|
737
737
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
738
738
|
if (!context)
|
|
739
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
740
|
-
if (!context
|
|
741
|
-
this.error(
|
|
739
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
740
|
+
if (!hasCredentials(context))
|
|
741
|
+
this.error(missingCredentialsMessage(context));
|
|
742
742
|
// Get data from file, --data, or --set flags
|
|
743
743
|
let items = [];
|
|
744
744
|
if (flags.file) {
|
|
@@ -2,7 +2,7 @@ import { input, select } from '@inquirer/prompts';
|
|
|
2
2
|
import { Command, Flags } from '@oclif/core';
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
import { login, testAuth } from '../../lib/auth.js';
|
|
5
|
-
import { addContext, DEFAULT_CLIENT_IDS, getContext, getCurrentContext, } from '../../lib/config.js';
|
|
5
|
+
import { addContext, DEFAULT_CLIENT_IDS, getAuthType, getContext, getCurrentContext, } from '../../lib/config.js';
|
|
6
6
|
export default class AuthLogin extends Command {
|
|
7
7
|
static description = 'Login to an Aderis environment using OAuth';
|
|
8
8
|
static examples = [
|
|
@@ -15,8 +15,10 @@ export default class AuthLogin extends Command {
|
|
|
15
15
|
description: 'OAuth client ID (uses default if not specified)',
|
|
16
16
|
}),
|
|
17
17
|
context: Flags.string({
|
|
18
|
+
aliases: ['config'],
|
|
18
19
|
char: 'c',
|
|
19
|
-
description: 'Context to login with
|
|
20
|
+
description: 'Context to login with, overriding the current context (alias: --config)',
|
|
21
|
+
env: 'ADERIS_CONTEXT',
|
|
20
22
|
}),
|
|
21
23
|
environment: Flags.string({
|
|
22
24
|
char: 'e',
|
|
@@ -51,6 +53,12 @@ export default class AuthLogin extends Command {
|
|
|
51
53
|
context = await this.createNewContext(flags);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
56
|
+
// API-key contexts have no browser flow; sending them through OAuth would
|
|
57
|
+
// fail deeper in with a less useful error.
|
|
58
|
+
if (getAuthType(context) === 'api_key') {
|
|
59
|
+
this.error(`Context "${context.name}" authenticates with an API key, so there is nothing to log in to.\n` +
|
|
60
|
+
`Set or rotate the key with: aderis config set-api-key --context ${context.name}`);
|
|
61
|
+
}
|
|
54
62
|
const spinner = ora(`Logging in to ${context.name} (${context.environment})...`).start();
|
|
55
63
|
try {
|
|
56
64
|
spinner.text = 'Waiting for browser authentication...';
|
|
@@ -104,6 +112,7 @@ export default class AuthLogin extends Command {
|
|
|
104
112
|
this.error(`No default client ID configured for ${environment} environment. Please provide --client-id`);
|
|
105
113
|
}
|
|
106
114
|
const context = {
|
|
115
|
+
auth_type: 'oauth2',
|
|
107
116
|
client_id: clientId,
|
|
108
117
|
environment,
|
|
109
118
|
name: contextName,
|
|
@@ -7,4 +7,6 @@ export default class AuthLogout extends Command {
|
|
|
7
7
|
context: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
8
|
};
|
|
9
9
|
run(): Promise<void>;
|
|
10
|
+
/** Drop whichever credential the context holds — OAuth tokens or an API key. */
|
|
11
|
+
private clearCredentials;
|
|
10
12
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import { clearTokens, getContext, getCurrentContext } from '../../lib/config.js';
|
|
2
|
+
import { clearApiKey, clearTokens, getAuthType, getContext, getCurrentContext, hasCredentials, } from '../../lib/config.js';
|
|
3
3
|
export default class AuthLogout extends Command {
|
|
4
4
|
static description = 'Logout from the current or specified context';
|
|
5
5
|
static examples = [
|
|
@@ -14,8 +14,10 @@ export default class AuthLogout extends Command {
|
|
|
14
14
|
description: 'Logout from all contexts',
|
|
15
15
|
}),
|
|
16
16
|
context: Flags.string({
|
|
17
|
+
aliases: ['config'],
|
|
17
18
|
char: 'c',
|
|
18
|
-
description: '
|
|
19
|
+
description: 'Context to logout from, overriding the current context (alias: --config)',
|
|
20
|
+
env: 'ADERIS_CONTEXT',
|
|
19
21
|
}),
|
|
20
22
|
};
|
|
21
23
|
async run() {
|
|
@@ -24,8 +26,8 @@ export default class AuthLogout extends Command {
|
|
|
24
26
|
if (flags.all) {
|
|
25
27
|
const contexts = listContexts();
|
|
26
28
|
for (const ctx of contexts) {
|
|
27
|
-
if (ctx
|
|
28
|
-
|
|
29
|
+
if (hasCredentials(ctx)) {
|
|
30
|
+
this.clearCredentials(ctx.name);
|
|
29
31
|
this.log(`Logged out from ${ctx.name}`);
|
|
30
32
|
}
|
|
31
33
|
}
|
|
@@ -48,11 +50,22 @@ export default class AuthLogout extends Command {
|
|
|
48
50
|
contextName = current.name;
|
|
49
51
|
}
|
|
50
52
|
const context = getContext(contextName);
|
|
51
|
-
if (!context
|
|
53
|
+
if (!context || !hasCredentials(context)) {
|
|
52
54
|
this.log(`Already logged out from ${contextName}`);
|
|
53
55
|
return;
|
|
54
56
|
}
|
|
57
|
+
this.clearCredentials(contextName);
|
|
58
|
+
this.log(getAuthType(context) === 'api_key'
|
|
59
|
+
? `Removed API key from ${contextName}`
|
|
60
|
+
: `Successfully logged out from ${contextName}`);
|
|
61
|
+
}
|
|
62
|
+
/** Drop whichever credential the context holds — OAuth tokens or an API key. */
|
|
63
|
+
clearCredentials(contextName) {
|
|
64
|
+
const context = getContext(contextName);
|
|
65
|
+
if (context && getAuthType(context) === 'api_key') {
|
|
66
|
+
clearApiKey(contextName);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
55
69
|
clearTokens(contextName);
|
|
56
|
-
this.log(`Successfully logged out from ${contextName}`);
|
|
57
70
|
}
|
|
58
71
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { testAuth } from '../../lib/auth.js';
|
|
3
|
-
import { getContext, getCurrentContext, listContexts } from '../../lib/config.js';
|
|
3
|
+
import { getAuthType, getContext, getCurrentContext, hasCredentials, listContexts, maskApiKey, missingCredentialsMessage, } from '../../lib/config.js';
|
|
4
4
|
export default class AuthStatus extends Command {
|
|
5
5
|
static description = 'Show authentication status for contexts';
|
|
6
6
|
static examples = [
|
|
@@ -15,8 +15,10 @@ export default class AuthStatus extends Command {
|
|
|
15
15
|
description: 'Show status for all contexts',
|
|
16
16
|
}),
|
|
17
17
|
context: Flags.string({
|
|
18
|
+
aliases: ['config'],
|
|
18
19
|
char: 'c',
|
|
19
|
-
description: '
|
|
20
|
+
description: 'Context to check, overriding the current context (alias: --config)',
|
|
21
|
+
env: 'ADERIS_CONTEXT',
|
|
20
22
|
}),
|
|
21
23
|
};
|
|
22
24
|
async run() {
|
|
@@ -56,7 +58,10 @@ export default class AuthStatus extends Command {
|
|
|
56
58
|
for (const ctx of contexts) {
|
|
57
59
|
const isCurrent = current?.name === ctx.name;
|
|
58
60
|
const prefix = isCurrent ? '* ' : ' ';
|
|
59
|
-
const
|
|
61
|
+
const isApiKey = getAuthType(ctx) === 'api_key';
|
|
62
|
+
const status = hasCredentials(ctx)
|
|
63
|
+
? (isApiKey ? '✓ api key set' : '✓ logged in')
|
|
64
|
+
: (isApiKey ? '✗ no api key' : '✗ not logged in');
|
|
60
65
|
this.log(`${prefix}${ctx.name} (${ctx.environment}) - ${status}`);
|
|
61
66
|
}
|
|
62
67
|
this.log('\n* = current context');
|
|
@@ -68,19 +73,28 @@ export default class AuthStatus extends Command {
|
|
|
68
73
|
this.error(`Context "${name}" not found.`);
|
|
69
74
|
}
|
|
70
75
|
const isCurrent = current?.name === name;
|
|
76
|
+
const authType = getAuthType(context);
|
|
71
77
|
this.log(`Context: ${context.name}${isCurrent ? ' (current)' : ''}`);
|
|
72
78
|
this.log(`Environment: ${context.environment}`);
|
|
73
|
-
this.log(`
|
|
74
|
-
if (
|
|
75
|
-
this.log(`
|
|
76
|
-
|
|
79
|
+
this.log(`Auth: ${authType === 'api_key' ? 'API key (x-api-key)' : 'oauth2'}`);
|
|
80
|
+
if (authType === 'oauth2') {
|
|
81
|
+
this.log(`Client ID: ${context.client_id ?? 'N/A'}`);
|
|
82
|
+
}
|
|
83
|
+
if (!hasCredentials(context)) {
|
|
84
|
+
this.log(`Status: ${authType === 'api_key' ? 'No API key set' : 'Not logged in'}`);
|
|
85
|
+
this.log(`\n${missingCredentialsMessage(context)}`);
|
|
77
86
|
return;
|
|
78
87
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.log(`
|
|
88
|
+
if (authType === 'api_key') {
|
|
89
|
+
this.log(`API key: ${maskApiKey(context.api_key)}`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.log(`Tenant ID: ${context.tenant_id || 'N/A'}`);
|
|
93
|
+
if (context.tokens?.expires_at) {
|
|
94
|
+
const expiresAt = new Date(context.tokens.expires_at);
|
|
95
|
+
const isExpired = expiresAt < new Date();
|
|
96
|
+
this.log(`Token expires: ${expiresAt.toLocaleString()}${isExpired ? ' (EXPIRED)' : ''}`);
|
|
97
|
+
}
|
|
84
98
|
}
|
|
85
99
|
if (detailed) {
|
|
86
100
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { select } from '@inquirer/prompts';
|
|
2
2
|
import { Args, Command, Flags } from '@oclif/core';
|
|
3
3
|
import { getCurrentTenant, listTenants, switchTenant } from '../../lib/auth.js';
|
|
4
|
-
import { getContext, getCurrentContext } from '../../lib/config.js';
|
|
4
|
+
import { getAuthType, getContext, getCurrentContext } from '../../lib/config.js';
|
|
5
5
|
export default class AuthTenant extends Command {
|
|
6
6
|
static args = {
|
|
7
7
|
action: Args.string({
|
|
@@ -23,8 +23,10 @@ export default class AuthTenant extends Command {
|
|
|
23
23
|
];
|
|
24
24
|
static flags = {
|
|
25
25
|
context: Flags.string({
|
|
26
|
+
aliases: ['config'],
|
|
26
27
|
char: 'c',
|
|
27
|
-
description: 'Context to use',
|
|
28
|
+
description: 'Context to use, overriding the current context (alias: --config)',
|
|
29
|
+
env: 'ADERIS_CONTEXT',
|
|
28
30
|
}),
|
|
29
31
|
json: Flags.boolean({
|
|
30
32
|
default: false,
|
|
@@ -38,7 +40,14 @@ export default class AuthTenant extends Command {
|
|
|
38
40
|
this.error('No context configured. Run: aderis auth login --new');
|
|
39
41
|
}
|
|
40
42
|
const context = getContext(contextName);
|
|
41
|
-
if (!context
|
|
43
|
+
if (!context) {
|
|
44
|
+
this.error(`Context "${contextName}" not found.`);
|
|
45
|
+
}
|
|
46
|
+
// API keys are issued per tenant, so there is nothing to list or switch.
|
|
47
|
+
if (getAuthType(context) === 'api_key') {
|
|
48
|
+
this.error(`Context "${contextName}" authenticates with an API key, which is already scoped to a single tenant. Tenant switching requires OAuth login.`);
|
|
49
|
+
}
|
|
50
|
+
if (!context.tokens) {
|
|
42
51
|
this.error('Not logged in. Run: aderis auth login');
|
|
43
52
|
}
|
|
44
53
|
const action = args.action || 'interactive';
|