@aderis-erp/cli 1.0.14 → 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.
Files changed (83) hide show
  1. package/dist/commands/access-groups.js +17 -17
  2. package/dist/commands/account-transaction-allocations.js +17 -17
  3. package/dist/commands/account-transactions.js +19 -19
  4. package/dist/commands/accounts.js +19 -19
  5. package/dist/commands/agent-platform.js +19 -18
  6. package/dist/commands/analytics.d.ts +40 -0
  7. package/dist/commands/{documents.js → analytics.js} +29 -39
  8. package/dist/commands/audit-log.js +17 -17
  9. package/dist/commands/auth/login.js +11 -2
  10. package/dist/commands/auth/logout.d.ts +2 -0
  11. package/dist/commands/auth/logout.js +19 -6
  12. package/dist/commands/auth/status.js +26 -12
  13. package/dist/commands/auth/tenant.js +12 -3
  14. package/dist/commands/auth.js +32 -17
  15. package/dist/commands/bank-accounts.js +17 -17
  16. package/dist/commands/bank-integrations.js +17 -17
  17. package/dist/commands/business-partners.js +25 -22
  18. package/dist/commands/chat.js +17 -17
  19. package/dist/commands/config/add.d.ts +9 -0
  20. package/dist/commands/config/add.js +64 -2
  21. package/dist/commands/config/current.js +9 -4
  22. package/dist/commands/config/list.js +9 -4
  23. package/dist/commands/config/set-api-key.d.ts +10 -0
  24. package/dist/commands/config/set-api-key.js +49 -0
  25. package/dist/commands/config/use.js +3 -4
  26. package/dist/commands/credit-card-accounts.js +17 -17
  27. package/dist/commands/delivery-notes.js +22 -21
  28. package/dist/commands/dunning-configs.js +17 -17
  29. package/dist/commands/dunning-reminders.js +17 -17
  30. package/dist/commands/dunning-runs.js +17 -17
  31. package/dist/commands/email-transactions.js +17 -17
  32. package/dist/commands/employees.js +19 -19
  33. package/dist/commands/entity-configurations.js +17 -17
  34. package/dist/commands/event-processor-mappings.js +17 -17
  35. package/dist/commands/{documents.d.ts → files.d.ts} +1 -1
  36. package/dist/commands/{files-internal.js → files.js} +35 -29
  37. package/dist/commands/health.js +17 -17
  38. package/dist/commands/inbox.js +17 -17
  39. package/dist/commands/integrations.js +17 -17
  40. package/dist/commands/item-categories.js +17 -17
  41. package/dist/commands/items.js +19 -19
  42. package/dist/commands/journal-lines.js +17 -17
  43. package/dist/commands/journals.js +21 -20
  44. package/dist/commands/ledgers.js +21 -18
  45. package/dist/commands/office-locations.js +17 -17
  46. package/dist/commands/payment-methods.js +17 -17
  47. package/dist/commands/payment-runs.js +19 -18
  48. package/dist/commands/payment-terms.js +17 -17
  49. package/dist/commands/payments.js +17 -17
  50. package/dist/commands/price-lists.js +17 -17
  51. package/dist/commands/processor-mappings.js +17 -17
  52. package/dist/commands/processors.js +17 -17
  53. package/dist/commands/purchase-order-types.js +17 -17
  54. package/dist/commands/purchase-orders.d.ts +1 -0
  55. package/dist/commands/purchase-orders.js +28 -21
  56. package/dist/commands/reports.js +17 -17
  57. package/dist/commands/salary-types.js +17 -17
  58. package/dist/commands/sales-invoices.js +27 -25
  59. package/dist/commands/sales-orders.js +19 -19
  60. package/dist/commands/saved-views.js +17 -17
  61. package/dist/commands/scheduled-processor-mappings.js +17 -17
  62. package/dist/commands/schedules.js +17 -17
  63. package/dist/commands/switch.js +10 -3
  64. package/dist/commands/{files-internal.d.ts → tag-configurations.d.ts} +1 -1
  65. package/dist/commands/tag-configurations.js +1178 -0
  66. package/dist/commands/tags.js +17 -17
  67. package/dist/commands/tax-codes.js +17 -17
  68. package/dist/commands/tax-matrix.js +17 -17
  69. package/dist/commands/tenants.js +17 -17
  70. package/dist/commands/text-templates.js +17 -17
  71. package/dist/commands/tools.js +17 -17
  72. package/dist/commands/vat-declarations.js +17 -17
  73. package/dist/commands/vendor-invoices.js +21 -21
  74. package/dist/commands/webhooks.js +17 -17
  75. package/dist/commands/workflows.js +17 -17
  76. package/dist/lib/api-client.js +11 -6
  77. package/dist/lib/auth.d.ts +8 -0
  78. package/dist/lib/auth.js +51 -7
  79. package/dist/lib/base-api-command.js +6 -4
  80. package/dist/lib/config.d.ts +31 -1
  81. package/dist/lib/config.js +31 -0
  82. package/oclif.manifest.json +729 -247
  83. package/package.json +2 -2
@@ -1,36 +1,26 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
2
  import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.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 = true;
6
- const HAS_EXPORT = true;
5
+ const HAS_IMPORT = false;
6
+ const HAS_EXPORT = false;
7
7
  const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = [];
9
- const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "reclassify"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["query", "views", "views-name"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
- 'list': { method: 'GET', path: '/v1/documents', summary: 'List documents (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/documents', summary: 'Create a new document (letterbox)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['references', 'tags', 'files'] },
13
- 'get': { method: 'GET', path: '/v1/documents/{id}', summary: 'Get a document, optionally with related data via include', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
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 Documents extends Command {
19
- static description = 'Manage documents';
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)' }),
@@ -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(Documents);
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 documents <action> <id>');
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.tokens)
107
- this.error('Not logged in. Run: aderis auth login');
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;
@@ -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.tokens)
352
- this.error('Not logged in. Run: aderis auth login');
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.tokens)
564
- this.error('Not logged in. Run: aderis auth login');
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');
@@ -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.tokens)
658
- this.error('Not logged in. Run: aderis auth login');
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 documents import-${suffix} <parent-id> --file data.json`);
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.tokens)
748
- this.error('Not logged in. Run: aderis auth login');
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,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
2
  import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.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;
@@ -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)' }),
@@ -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.tokens)
100
- this.error('Not logged in. Run: aderis auth login');
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;
@@ -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.tokens)
345
- this.error('Not logged in. Run: aderis auth login');
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.tokens)
557
- this.error('Not logged in. Run: aderis auth login');
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');
@@ -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.tokens)
651
- this.error('Not logged in. Run: aderis auth login');
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.tokens)
741
- this.error('Not logged in. Run: aderis auth login');
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 (uses current context if not specified)',
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: 'Specific context to logout from',
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.tokens) {
28
- clearTokens(ctx.name);
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?.tokens) {
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: 'Specific context to check',
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 status = ctx.tokens ? '✓ logged in' : '✗ not logged in';
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(`Client ID: ${context.client_id}`);
74
- if (!context.tokens) {
75
- this.log(`Status: Not logged in`);
76
- this.log(`\nRun: aderis auth login${isCurrent ? '' : ` --context ${name}`}`);
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
- this.log(`Tenant ID: ${context.tenant_id || 'N/A'}`);
80
- if (context.tokens.expires_at) {
81
- const expiresAt = new Date(context.tokens.expires_at);
82
- const isExpired = expiresAt < new Date();
83
- this.log(`Token expires: ${expiresAt.toLocaleString()}${isExpired ? ' (EXPIRED)' : ''}`);
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?.tokens) {
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';
@@ -1,6 +1,6 @@
1
1
  import { Args, Command, Flags } from '@oclif/core';
2
2
  import { ApiError, apiRequest } from '../lib/api-client.js';
3
- import { getContext, getCurrentContext } from '../lib/config.js';
3
+ import { getContext, getCurrentContext, 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 = false;
@@ -40,7 +40,12 @@ export default class Auth extends Command {
40
40
  static description = 'Manage auth';
41
41
  static examples = [];
42
42
  static flags = {
43
- context: Flags.string({ char: 'c', description: 'Context to use' }),
43
+ context: Flags.string({
44
+ aliases: ['config'],
45
+ char: 'c',
46
+ description: 'Context to use for this command, overriding the current context (alias: --config)',
47
+ env: 'ADERIS_CONTEXT',
48
+ }),
44
49
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
45
50
  data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
46
51
  fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
@@ -96,9 +101,11 @@ export default class Auth extends Command {
96
101
  this.error(`Unknown action: ${args.action}. Available: ${SUBCOMMANDS.join(', ')}`);
97
102
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
98
103
  if (!context)
99
- this.error('No context configured. Run: aderis auth login --new');
100
- if (!context.tokens)
101
- this.error('Not logged in. Run: aderis auth login');
104
+ this.error(flags.context
105
+ ? `Context "${flags.context}" not found. List contexts with: aderis config list`
106
+ : 'No context configured. Run: aderis auth login --new');
107
+ if (!hasCredentials(context))
108
+ this.error(missingCredentialsMessage(context));
102
109
  let apiPath = endpoint.path;
103
110
  for (const param of endpoint.pathParams) {
104
111
  let value;
@@ -359,9 +366,11 @@ export default class Auth extends Command {
359
366
  async runCamt053Import(flags) {
360
367
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
361
368
  if (!context)
362
- this.error('No context configured. Run: aderis auth login --new');
363
- if (!context.tokens)
364
- this.error('Not logged in. Run: aderis auth login');
369
+ this.error(flags.context
370
+ ? `Context "${flags.context}" not found. List contexts with: aderis config list`
371
+ : 'No context configured. Run: aderis auth login --new');
372
+ if (!hasCredentials(context))
373
+ this.error(missingCredentialsMessage(context));
365
374
  if (!flags.file) {
366
375
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
367
376
  }
@@ -446,9 +455,11 @@ export default class Auth extends Command {
446
455
  async runExport(flags) {
447
456
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
448
457
  if (!context)
449
- this.error('No context configured. Run: aderis auth login --new');
450
- if (!context.tokens)
451
- this.error('Not logged in. Run: aderis auth login');
458
+ this.error(flags.context
459
+ ? `Context "${flags.context}" not found. List contexts with: aderis config list`
460
+ : 'No context configured. Run: aderis auth login --new');
461
+ if (!hasCredentials(context))
462
+ this.error(missingCredentialsMessage(context));
452
463
  const listEndpoint = ENDPOINTS.list;
453
464
  if (!listEndpoint)
454
465
  this.error('Export requires a list endpoint');
@@ -522,9 +533,11 @@ export default class Auth extends Command {
522
533
  async runImport(flags) {
523
534
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
524
535
  if (!context)
525
- this.error('No context configured. Run: aderis auth login --new');
526
- if (!context.tokens)
527
- this.error('Not logged in. Run: aderis auth login');
536
+ this.error(flags.context
537
+ ? `Context "${flags.context}" not found. List contexts with: aderis config list`
538
+ : 'No context configured. Run: aderis auth login --new');
539
+ if (!hasCredentials(context))
540
+ this.error(missingCredentialsMessage(context));
528
541
  // Get data from file, --data, or --set flags
529
542
  let items = [];
530
543
  if (flags.file) {
@@ -676,9 +689,11 @@ export default class Auth extends Command {
676
689
  }
677
690
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
678
691
  if (!context)
679
- this.error('No context configured. Run: aderis auth login --new');
680
- if (!context.tokens)
681
- this.error('Not logged in. Run: aderis auth login');
692
+ this.error(flags.context
693
+ ? `Context "${flags.context}" not found. List contexts with: aderis config list`
694
+ : 'No context configured. Run: aderis auth login --new');
695
+ if (!hasCredentials(context))
696
+ this.error(missingCredentialsMessage(context));
682
697
  // Get data from file, --data, or --set flags
683
698
  let items = [];
684
699
  if (flags.file) {
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
2
  import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.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 = true;
6
6
  const HAS_EXPORT = true;
@@ -41,7 +41,7 @@ export default class BankAccounts extends Command {
41
41
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
42
42
  };
43
43
  static flags = {
44
- context: Flags.string({ char: 'c', description: 'Context to use' }),
44
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
45
45
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
46
46
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
47
47
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -115,9 +115,9 @@ export default class BankAccounts extends Command {
115
115
  }
116
116
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
117
117
  if (!context)
118
- this.error('No context configured. Run: aderis auth login --new');
119
- if (!context.tokens)
120
- this.error('Not logged in. Run: aderis auth login');
118
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
119
+ if (!hasCredentials(context))
120
+ this.error(missingCredentialsMessage(context));
121
121
  const queryParams = {};
122
122
  if (flags.page)
123
123
  queryParams.page = flags.page;
@@ -360,9 +360,9 @@ export default class BankAccounts extends Command {
360
360
  async runImport(flags) {
361
361
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
362
362
  if (!context)
363
- this.error('No context configured. Run: aderis auth login --new');
364
- if (!context.tokens)
365
- this.error('Not logged in. Run: aderis auth login');
363
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
364
+ if (!hasCredentials(context))
365
+ this.error(missingCredentialsMessage(context));
366
366
  // Get data from file, --data, or --set flags
367
367
  let items = [];
368
368
  if (flags.file) {
@@ -572,9 +572,9 @@ export default class BankAccounts extends Command {
572
572
  async runExport(flags) {
573
573
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
574
574
  if (!context)
575
- this.error('No context configured. Run: aderis auth login --new');
576
- if (!context.tokens)
577
- this.error('Not logged in. Run: aderis auth login');
575
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
576
+ if (!hasCredentials(context))
577
+ this.error(missingCredentialsMessage(context));
578
578
  const listEndpoint = ENDPOINTS['list'];
579
579
  if (!listEndpoint)
580
580
  this.error('Export requires a list endpoint');
@@ -666,9 +666,9 @@ export default class BankAccounts extends Command {
666
666
  async runCamt053Import(flags) {
667
667
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
668
668
  if (!context)
669
- this.error('No context configured. Run: aderis auth login --new');
670
- if (!context.tokens)
671
- this.error('Not logged in. Run: aderis auth login');
669
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
670
+ if (!hasCredentials(context))
671
+ this.error(missingCredentialsMessage(context));
672
672
  if (!flags.file) {
673
673
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
674
674
  }
@@ -756,9 +756,9 @@ export default class BankAccounts extends Command {
756
756
  }
757
757
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
758
758
  if (!context)
759
- this.error('No context configured. Run: aderis auth login --new');
760
- if (!context.tokens)
761
- this.error('Not logged in. Run: aderis auth login');
759
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
760
+ if (!hasCredentials(context))
761
+ this.error(missingCredentialsMessage(context));
762
762
  // Get data from file, --data, or --set flags
763
763
  let items = [];
764
764
  if (flags.file) {