@aderis-erp/cli 1.0.2 → 1.0.3
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/{processing-logs.d.ts → access-groups.d.ts} +1 -1
- package/dist/commands/{access-groups 2.js → access-groups.js} +30 -18
- package/dist/commands/account-transactions.d.ts +41 -0
- package/dist/commands/account-transactions.js +1032 -0
- package/dist/commands/accounts.d.ts +40 -0
- package/dist/commands/accounts.js +1024 -0
- package/dist/commands/agent-runs.d.ts +39 -0
- package/dist/commands/agent-runs.js +1013 -0
- package/dist/commands/{pubsub.d.ts → async-endpoints-internal.d.ts} +1 -1
- package/dist/commands/{pubsub.js → async-endpoints-internal.js} +37 -25
- package/dist/commands/audit-log.d.ts +39 -0
- package/dist/commands/{processing-logs.js → audit-log.js} +42 -28
- 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 +19 -0
- package/dist/commands/auth/tenant.js +184 -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 +1032 -0
- package/dist/commands/bank-integrations.js +30 -18
- package/dist/commands/business-partners---contacts.js +30 -18
- package/dist/commands/business-partners.js +30 -18
- 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.js +30 -18
- package/dist/commands/documents.js +30 -18
- package/dist/commands/dunning-configs.js +30 -18
- package/dist/commands/dunning-reminders.js +30 -18
- package/dist/commands/dunning-runs.js +30 -18
- package/dist/commands/employees.js +30 -18
- package/dist/commands/event-processor-mappings.js +30 -18
- package/dist/commands/files-internal.js +30 -18
- package/dist/commands/health.js +30 -18
- package/dist/commands/inbox.js +33 -19
- package/dist/commands/integrations.js +30 -18
- package/dist/commands/item-categories.js +30 -18
- package/dist/commands/items.js +30 -18
- package/dist/commands/journal-lines.js +30 -18
- package/dist/commands/journals.js +30 -18
- package/dist/commands/ledgers.js +30 -18
- package/dist/commands/office-locations.js +30 -18
- package/dist/commands/payment-method-ledger-mappings.js +30 -18
- package/dist/commands/payment-methods.js +30 -18
- package/dist/commands/payment-runs.js +30 -18
- package/dist/commands/payment-terms.js +30 -18
- package/dist/commands/price-lists.js +30 -18
- package/dist/commands/processor-mappings.js +30 -18
- package/dist/commands/processors.js +31 -19
- package/dist/commands/reconciliation.js +30 -18
- package/dist/commands/reports.js +30 -18
- package/dist/commands/salary-types.js +1018 -0
- package/dist/commands/sales-invoices.js +30 -18
- package/dist/commands/sales-orders.js +32 -19
- package/dist/commands/switch.d.ts +1 -0
- package/dist/commands/switch.js +58 -3
- package/dist/commands/tags.js +30 -18
- package/dist/commands/tax-codes.js +30 -18
- package/dist/commands/tax-matrix.js +30 -18
- package/dist/commands/tenants.js +30 -18
- package/dist/commands/text-templates.js +30 -18
- package/dist/commands/tools.js +30 -18
- package/dist/commands/vendor-invoices.js +33 -19
- package/dist/commands/webhooks.js +30 -18
- package/dist/commands/workflows.js +30 -18
- package/dist/index 2.js +1 -0
- package/dist/index.d 2.ts +1 -0
- package/dist/lib/auth.d.ts +16 -1
- package/dist/lib/auth.js +153 -45
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.js +6 -0
- package/oclif.manifest.json +2092 -669
- package/package.json +2 -2
|
@@ -834,32 +834,44 @@ export default class BankIntegrations extends Command {
|
|
|
834
834
|
filterFields(data, fields) {
|
|
835
835
|
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
836
836
|
const pick = (obj, keys) => {
|
|
837
|
-
|
|
837
|
+
// Group keys by their first segment so sibling sub-paths
|
|
838
|
+
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
839
|
+
// and don't clobber each other on merge.
|
|
840
|
+
const directKeys = new Set();
|
|
841
|
+
const nestedKeys = new Map();
|
|
838
842
|
for (const key of keys) {
|
|
839
843
|
if (key.split('.').some(isUnsafeKey))
|
|
840
844
|
continue;
|
|
841
845
|
if (key.includes('.')) {
|
|
842
|
-
// Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
|
|
843
846
|
const [first, ...rest] = key.split('.');
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
const existing = Array.isArray(result[first]) ? result[first] : [];
|
|
850
|
-
result[first] = val.map((item, i) => ({
|
|
851
|
-
...(existing[i] || {}),
|
|
852
|
-
...pick(item, [restKey]),
|
|
853
|
-
}));
|
|
854
|
-
}
|
|
855
|
-
else {
|
|
856
|
-
const nested = pick(val, [restKey]);
|
|
857
|
-
result[first] = { ...(result[first] || {}), ...nested };
|
|
858
|
-
}
|
|
847
|
+
if (isUnsafeKey(first))
|
|
848
|
+
continue;
|
|
849
|
+
const list = nestedKeys.get(first);
|
|
850
|
+
if (list) {
|
|
851
|
+
list.push(rest.join('.'));
|
|
859
852
|
}
|
|
853
|
+
else {
|
|
854
|
+
nestedKeys.set(first, [rest.join('.')]);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
else {
|
|
858
|
+
directKeys.add(key);
|
|
860
859
|
}
|
|
861
|
-
|
|
860
|
+
}
|
|
861
|
+
const result = {};
|
|
862
|
+
for (const key of directKeys) {
|
|
863
|
+
if (key in obj)
|
|
862
864
|
result[key] = obj[key];
|
|
865
|
+
}
|
|
866
|
+
for (const [first, restKeys] of nestedKeys) {
|
|
867
|
+
const val = obj[first];
|
|
868
|
+
if (!val || typeof val !== 'object')
|
|
869
|
+
continue;
|
|
870
|
+
if (Array.isArray(val)) {
|
|
871
|
+
result[first] = val.map(item => pick(item, restKeys));
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
result[first] = pick(val, restKeys);
|
|
863
875
|
}
|
|
864
876
|
}
|
|
865
877
|
return result;
|
|
@@ -819,32 +819,44 @@ export default class BusinessPartnersContacts extends Command {
|
|
|
819
819
|
filterFields(data, fields) {
|
|
820
820
|
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
821
821
|
const pick = (obj, keys) => {
|
|
822
|
-
|
|
822
|
+
// Group keys by their first segment so sibling sub-paths
|
|
823
|
+
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
824
|
+
// and don't clobber each other on merge.
|
|
825
|
+
const directKeys = new Set();
|
|
826
|
+
const nestedKeys = new Map();
|
|
823
827
|
for (const key of keys) {
|
|
824
828
|
if (key.split('.').some(isUnsafeKey))
|
|
825
829
|
continue;
|
|
826
830
|
if (key.includes('.')) {
|
|
827
|
-
// Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
|
|
828
831
|
const [first, ...rest] = key.split('.');
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const existing = Array.isArray(result[first]) ? result[first] : [];
|
|
835
|
-
result[first] = val.map((item, i) => ({
|
|
836
|
-
...(existing[i] || {}),
|
|
837
|
-
...pick(item, [restKey]),
|
|
838
|
-
}));
|
|
839
|
-
}
|
|
840
|
-
else {
|
|
841
|
-
const nested = pick(val, [restKey]);
|
|
842
|
-
result[first] = { ...(result[first] || {}), ...nested };
|
|
843
|
-
}
|
|
832
|
+
if (isUnsafeKey(first))
|
|
833
|
+
continue;
|
|
834
|
+
const list = nestedKeys.get(first);
|
|
835
|
+
if (list) {
|
|
836
|
+
list.push(rest.join('.'));
|
|
844
837
|
}
|
|
838
|
+
else {
|
|
839
|
+
nestedKeys.set(first, [rest.join('.')]);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
directKeys.add(key);
|
|
845
844
|
}
|
|
846
|
-
|
|
845
|
+
}
|
|
846
|
+
const result = {};
|
|
847
|
+
for (const key of directKeys) {
|
|
848
|
+
if (key in obj)
|
|
847
849
|
result[key] = obj[key];
|
|
850
|
+
}
|
|
851
|
+
for (const [first, restKeys] of nestedKeys) {
|
|
852
|
+
const val = obj[first];
|
|
853
|
+
if (!val || typeof val !== 'object')
|
|
854
|
+
continue;
|
|
855
|
+
if (Array.isArray(val)) {
|
|
856
|
+
result[first] = val.map(item => pick(item, restKeys));
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
result[first] = pick(val, restKeys);
|
|
848
860
|
}
|
|
849
861
|
}
|
|
850
862
|
return result;
|
|
@@ -825,32 +825,44 @@ export default class BusinessPartners extends Command {
|
|
|
825
825
|
filterFields(data, fields) {
|
|
826
826
|
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
827
827
|
const pick = (obj, keys) => {
|
|
828
|
-
|
|
828
|
+
// Group keys by their first segment so sibling sub-paths
|
|
829
|
+
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
830
|
+
// and don't clobber each other on merge.
|
|
831
|
+
const directKeys = new Set();
|
|
832
|
+
const nestedKeys = new Map();
|
|
829
833
|
for (const key of keys) {
|
|
830
834
|
if (key.split('.').some(isUnsafeKey))
|
|
831
835
|
continue;
|
|
832
836
|
if (key.includes('.')) {
|
|
833
|
-
// Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
|
|
834
837
|
const [first, ...rest] = key.split('.');
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
const existing = Array.isArray(result[first]) ? result[first] : [];
|
|
841
|
-
result[first] = val.map((item, i) => ({
|
|
842
|
-
...(existing[i] || {}),
|
|
843
|
-
...pick(item, [restKey]),
|
|
844
|
-
}));
|
|
845
|
-
}
|
|
846
|
-
else {
|
|
847
|
-
const nested = pick(val, [restKey]);
|
|
848
|
-
result[first] = { ...(result[first] || {}), ...nested };
|
|
849
|
-
}
|
|
838
|
+
if (isUnsafeKey(first))
|
|
839
|
+
continue;
|
|
840
|
+
const list = nestedKeys.get(first);
|
|
841
|
+
if (list) {
|
|
842
|
+
list.push(rest.join('.'));
|
|
850
843
|
}
|
|
844
|
+
else {
|
|
845
|
+
nestedKeys.set(first, [rest.join('.')]);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
directKeys.add(key);
|
|
851
850
|
}
|
|
852
|
-
|
|
851
|
+
}
|
|
852
|
+
const result = {};
|
|
853
|
+
for (const key of directKeys) {
|
|
854
|
+
if (key in obj)
|
|
853
855
|
result[key] = obj[key];
|
|
856
|
+
}
|
|
857
|
+
for (const [first, restKeys] of nestedKeys) {
|
|
858
|
+
const val = obj[first];
|
|
859
|
+
if (!val || typeof val !== 'object')
|
|
860
|
+
continue;
|
|
861
|
+
if (Array.isArray(val)) {
|
|
862
|
+
result[first] = val.map(item => pick(item, restKeys));
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
result[first] = pick(val, restKeys);
|
|
854
866
|
}
|
|
855
867
|
}
|
|
856
868
|
return result;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ConfigAdd extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
'client-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
'client-secret': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
environment: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { confirm, input, select } from '@inquirer/prompts';
|
|
2
|
+
import { Command, Flags } from '@oclif/core';
|
|
3
|
+
import { addContext, DEFAULT_CLIENT_IDS, getContext } from '../../lib/config.js';
|
|
4
|
+
export default class ConfigAdd extends Command {
|
|
5
|
+
static description = 'Add a new context configuration';
|
|
6
|
+
static examples = [
|
|
7
|
+
'<%= config.bin %> config add',
|
|
8
|
+
'<%= config.bin %> config add --name my-client --environment live',
|
|
9
|
+
'<%= config.bin %> config add --name dev-context --environment dev --client-id abc123',
|
|
10
|
+
];
|
|
11
|
+
static flags = {
|
|
12
|
+
'client-id': Flags.string({
|
|
13
|
+
description: 'OAuth client ID (uses default if not specified)',
|
|
14
|
+
}),
|
|
15
|
+
'client-secret': Flags.string({
|
|
16
|
+
description: 'OAuth client secret (optional, for confidential clients)',
|
|
17
|
+
}),
|
|
18
|
+
environment: Flags.string({
|
|
19
|
+
char: 'e',
|
|
20
|
+
description: 'Environment (dev, test, live)',
|
|
21
|
+
options: ['dev', 'test', 'live'],
|
|
22
|
+
}),
|
|
23
|
+
force: Flags.boolean({
|
|
24
|
+
char: 'f',
|
|
25
|
+
default: false,
|
|
26
|
+
description: 'Overwrite existing context without prompting',
|
|
27
|
+
}),
|
|
28
|
+
name: Flags.string({
|
|
29
|
+
char: 'n',
|
|
30
|
+
description: 'Context name',
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
async run() {
|
|
34
|
+
const { flags } = await this.parse(ConfigAdd);
|
|
35
|
+
// Get context name
|
|
36
|
+
let { name } = flags;
|
|
37
|
+
if (!name) {
|
|
38
|
+
name = await input({
|
|
39
|
+
message: 'Context name:',
|
|
40
|
+
validate(value) {
|
|
41
|
+
if (!value.trim())
|
|
42
|
+
return 'Context name is required';
|
|
43
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(value)) {
|
|
44
|
+
return 'Context name can only contain letters, numbers, hyphens, and underscores';
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Check if context already exists
|
|
51
|
+
const existing = getContext(name);
|
|
52
|
+
if (existing && !flags.force) {
|
|
53
|
+
const overwrite = await confirm({
|
|
54
|
+
default: false,
|
|
55
|
+
message: `Context "${name}" already exists. Overwrite?`,
|
|
56
|
+
});
|
|
57
|
+
if (!overwrite) {
|
|
58
|
+
this.log('Aborted.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Get environment
|
|
63
|
+
let environment = flags.environment;
|
|
64
|
+
if (!environment) {
|
|
65
|
+
environment = (await select({
|
|
66
|
+
choices: [
|
|
67
|
+
{ name: 'live (production)', value: 'live' },
|
|
68
|
+
{ name: 'test (staging)', value: 'test' },
|
|
69
|
+
{ name: 'dev (development)', value: 'dev' },
|
|
70
|
+
],
|
|
71
|
+
message: 'Environment:',
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
// Get client ID
|
|
75
|
+
let clientId = flags['client-id'];
|
|
76
|
+
if (!clientId) {
|
|
77
|
+
const defaultClientId = DEFAULT_CLIENT_IDS[environment];
|
|
78
|
+
if (defaultClientId) {
|
|
79
|
+
const useDefault = await confirm({
|
|
80
|
+
default: true,
|
|
81
|
+
message: `Use default client ID for ${environment}?`,
|
|
82
|
+
});
|
|
83
|
+
if (useDefault) {
|
|
84
|
+
clientId = defaultClientId;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!clientId) {
|
|
88
|
+
clientId = await input({
|
|
89
|
+
message: 'OAuth client ID:',
|
|
90
|
+
validate: (value) => (value.trim() ? true : 'Client ID is required'),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Get client secret (optional)
|
|
95
|
+
let clientSecret = flags['client-secret'];
|
|
96
|
+
if (!clientSecret && !flags.name) {
|
|
97
|
+
// Only prompt for secret in interactive mode
|
|
98
|
+
const hasSecret = await confirm({
|
|
99
|
+
default: false,
|
|
100
|
+
message: 'Do you have a client secret? (for confidential clients)',
|
|
101
|
+
});
|
|
102
|
+
if (hasSecret) {
|
|
103
|
+
clientSecret = await input({
|
|
104
|
+
message: 'OAuth client secret:',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Create the context
|
|
109
|
+
addContext({
|
|
110
|
+
client_id: clientId,
|
|
111
|
+
client_secret: clientSecret,
|
|
112
|
+
environment,
|
|
113
|
+
name,
|
|
114
|
+
});
|
|
115
|
+
this.log(`\nContext "${name}" created successfully.`);
|
|
116
|
+
this.log(`Environment: ${environment}`);
|
|
117
|
+
this.log(`Client ID: ${clientId}`);
|
|
118
|
+
this.log(`\nTo authenticate, run: aderis auth login`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ConfigCurrent extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { getCurrentContext } from '../../lib/config.js';
|
|
3
|
+
export default class ConfigCurrent extends Command {
|
|
4
|
+
static description = 'Show the current context';
|
|
5
|
+
static examples = ['<%= config.bin %> config current', '<%= config.bin %> config current --json'];
|
|
6
|
+
static flags = {
|
|
7
|
+
json: Flags.boolean({
|
|
8
|
+
default: false,
|
|
9
|
+
description: 'Output as JSON',
|
|
10
|
+
}),
|
|
11
|
+
};
|
|
12
|
+
async run() {
|
|
13
|
+
const { flags } = await this.parse(ConfigCurrent);
|
|
14
|
+
const context = getCurrentContext();
|
|
15
|
+
if (!context) {
|
|
16
|
+
if (flags.json) {
|
|
17
|
+
this.log(JSON.stringify({ current: null }, null, 2));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
this.log('No current context configured.');
|
|
21
|
+
this.log('Create one with: aderis auth login --new');
|
|
22
|
+
}
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (flags.json) {
|
|
26
|
+
this.log(JSON.stringify({
|
|
27
|
+
authenticated: Boolean(context.tokens),
|
|
28
|
+
client_id: context.client_id,
|
|
29
|
+
environment: context.environment,
|
|
30
|
+
name: context.name,
|
|
31
|
+
tenant_id: context.tenant_id,
|
|
32
|
+
}, null, 2));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.log(`Current context: ${context.name}`);
|
|
36
|
+
this.log(`Environment: ${context.environment}`);
|
|
37
|
+
this.log(`Client ID: ${context.client_id}`);
|
|
38
|
+
if (context.tenant_id) {
|
|
39
|
+
this.log(`Tenant ID: ${context.tenant_id}`);
|
|
40
|
+
}
|
|
41
|
+
this.log(`Authenticated: ${context.tokens ? 'Yes' : 'No'}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ConfigDelete extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { confirm, select } from '@inquirer/prompts';
|
|
2
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
3
|
+
import { deleteContext, getContext, getCurrentContext, listContexts } from '../../lib/config.js';
|
|
4
|
+
export default class ConfigDelete extends Command {
|
|
5
|
+
static args = {
|
|
6
|
+
name: Args.string({
|
|
7
|
+
description: 'Context name to delete',
|
|
8
|
+
required: false,
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
static description = 'Delete a configured context';
|
|
12
|
+
static examples = [
|
|
13
|
+
'<%= config.bin %> config delete my-client',
|
|
14
|
+
'<%= config.bin %> config delete my-client --force',
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
force: Flags.boolean({
|
|
18
|
+
char: 'f',
|
|
19
|
+
default: false,
|
|
20
|
+
description: 'Skip confirmation prompt',
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
const { args, flags } = await this.parse(ConfigDelete);
|
|
25
|
+
let contextName = args.name;
|
|
26
|
+
if (!contextName) {
|
|
27
|
+
const contexts = listContexts();
|
|
28
|
+
if (contexts.length === 0) {
|
|
29
|
+
this.error('No contexts configured.');
|
|
30
|
+
}
|
|
31
|
+
contextName = await select({
|
|
32
|
+
choices: contexts.map((c) => ({
|
|
33
|
+
name: `${c.name} (${c.environment})`,
|
|
34
|
+
value: c.name,
|
|
35
|
+
})),
|
|
36
|
+
message: 'Select a context to delete:',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const context = getContext(contextName);
|
|
40
|
+
if (!context) {
|
|
41
|
+
this.error(`Context "${contextName}" not found.`);
|
|
42
|
+
}
|
|
43
|
+
const current = getCurrentContext();
|
|
44
|
+
const isCurrent = current?.name === contextName;
|
|
45
|
+
if (!flags.force) {
|
|
46
|
+
const confirmed = await confirm({
|
|
47
|
+
default: false,
|
|
48
|
+
message: `Are you sure you want to delete context "${contextName}"?${isCurrent ? ' (This is your current context)' : ''}`,
|
|
49
|
+
});
|
|
50
|
+
if (!confirmed) {
|
|
51
|
+
this.log('Cancelled.');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
deleteContext(contextName);
|
|
56
|
+
this.log(`Context "${contextName}" deleted.`);
|
|
57
|
+
if (isCurrent) {
|
|
58
|
+
const newCurrent = getCurrentContext();
|
|
59
|
+
if (newCurrent) {
|
|
60
|
+
this.log(`Switched to context "${newCurrent.name}"`);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
this.log('\nNo contexts remaining. Create one with: aderis auth login --new');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { getCurrentContext, listContexts } from '../../lib/config.js';
|
|
3
|
+
export default class ConfigList extends Command {
|
|
4
|
+
static description = 'List all configured contexts';
|
|
5
|
+
static examples = ['<%= config.bin %> config list', '<%= config.bin %> config list --json'];
|
|
6
|
+
static flags = {
|
|
7
|
+
json: Flags.boolean({
|
|
8
|
+
default: false,
|
|
9
|
+
description: 'Output as JSON',
|
|
10
|
+
}),
|
|
11
|
+
};
|
|
12
|
+
async run() {
|
|
13
|
+
const { flags } = await this.parse(ConfigList);
|
|
14
|
+
const contexts = listContexts();
|
|
15
|
+
const current = getCurrentContext();
|
|
16
|
+
if (flags.json) {
|
|
17
|
+
this.log(JSON.stringify({
|
|
18
|
+
contexts: contexts.map((c) => ({
|
|
19
|
+
authenticated: Boolean(c.tokens),
|
|
20
|
+
client_id: c.client_id,
|
|
21
|
+
environment: c.environment,
|
|
22
|
+
name: c.name,
|
|
23
|
+
tenant_id: c.tenant_id,
|
|
24
|
+
})),
|
|
25
|
+
current: current?.name || null,
|
|
26
|
+
}, null, 2));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (contexts.length === 0) {
|
|
30
|
+
this.log('No contexts configured.');
|
|
31
|
+
this.log('\nCreate a new context with: aderis auth login --new');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.log('Configured contexts:\n');
|
|
35
|
+
for (const ctx of contexts) {
|
|
36
|
+
const isCurrent = current?.name === ctx.name;
|
|
37
|
+
const marker = isCurrent ? '*' : ' ';
|
|
38
|
+
const auth = ctx.tokens ? '✓' : '✗';
|
|
39
|
+
this.log(`${marker} ${ctx.name}`);
|
|
40
|
+
this.log(` Environment: ${ctx.environment}`);
|
|
41
|
+
this.log(` Client ID: ${ctx.client_id}`);
|
|
42
|
+
this.log(` Authenticated: ${auth}`);
|
|
43
|
+
if (ctx.tenant_id) {
|
|
44
|
+
this.log(` Tenant ID: ${ctx.tenant_id}`);
|
|
45
|
+
}
|
|
46
|
+
this.log('');
|
|
47
|
+
}
|
|
48
|
+
this.log('* = current context');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ConfigUse extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { select } from '@inquirer/prompts';
|
|
2
|
+
import { Args, Command } from '@oclif/core';
|
|
3
|
+
import { getContext, listContexts, setCurrentContext } from '../../lib/config.js';
|
|
4
|
+
export default class ConfigUse extends Command {
|
|
5
|
+
static args = {
|
|
6
|
+
name: Args.string({
|
|
7
|
+
description: 'Context name to switch to',
|
|
8
|
+
required: false,
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
static description = 'Switch to a different context';
|
|
12
|
+
static examples = ['<%= config.bin %> config use my-client', '<%= config.bin %> config use'];
|
|
13
|
+
async run() {
|
|
14
|
+
const { args } = await this.parse(ConfigUse);
|
|
15
|
+
let contextName = args.name;
|
|
16
|
+
if (!contextName) {
|
|
17
|
+
const contexts = listContexts();
|
|
18
|
+
if (contexts.length === 0) {
|
|
19
|
+
this.error('No contexts configured. Create one with: aderis auth login --new');
|
|
20
|
+
}
|
|
21
|
+
contextName = await select({
|
|
22
|
+
choices: contexts.map((c) => ({
|
|
23
|
+
name: `${c.name} (${c.environment})${c.tokens ? ' ✓' : ''}`,
|
|
24
|
+
value: c.name,
|
|
25
|
+
})),
|
|
26
|
+
message: 'Select a context:',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const context = getContext(contextName);
|
|
30
|
+
if (!context) {
|
|
31
|
+
this.error(`Context "${contextName}" not found.`);
|
|
32
|
+
}
|
|
33
|
+
setCurrentContext(contextName);
|
|
34
|
+
this.log(`Switched to context "${contextName}" (${context.environment})`);
|
|
35
|
+
if (!context.tokens) {
|
|
36
|
+
this.log(`\nNote: You are not logged in to this context.`);
|
|
37
|
+
this.log(`Run: aderis auth login`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -831,32 +831,44 @@ export default class CreditCardAccounts extends Command {
|
|
|
831
831
|
filterFields(data, fields) {
|
|
832
832
|
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
833
833
|
const pick = (obj, keys) => {
|
|
834
|
-
|
|
834
|
+
// Group keys by their first segment so sibling sub-paths
|
|
835
|
+
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
836
|
+
// and don't clobber each other on merge.
|
|
837
|
+
const directKeys = new Set();
|
|
838
|
+
const nestedKeys = new Map();
|
|
835
839
|
for (const key of keys) {
|
|
836
840
|
if (key.split('.').some(isUnsafeKey))
|
|
837
841
|
continue;
|
|
838
842
|
if (key.includes('.')) {
|
|
839
|
-
// Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
|
|
840
843
|
const [first, ...rest] = key.split('.');
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const existing = Array.isArray(result[first]) ? result[first] : [];
|
|
847
|
-
result[first] = val.map((item, i) => ({
|
|
848
|
-
...(existing[i] || {}),
|
|
849
|
-
...pick(item, [restKey]),
|
|
850
|
-
}));
|
|
851
|
-
}
|
|
852
|
-
else {
|
|
853
|
-
const nested = pick(val, [restKey]);
|
|
854
|
-
result[first] = { ...(result[first] || {}), ...nested };
|
|
855
|
-
}
|
|
844
|
+
if (isUnsafeKey(first))
|
|
845
|
+
continue;
|
|
846
|
+
const list = nestedKeys.get(first);
|
|
847
|
+
if (list) {
|
|
848
|
+
list.push(rest.join('.'));
|
|
856
849
|
}
|
|
850
|
+
else {
|
|
851
|
+
nestedKeys.set(first, [rest.join('.')]);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
directKeys.add(key);
|
|
857
856
|
}
|
|
858
|
-
|
|
857
|
+
}
|
|
858
|
+
const result = {};
|
|
859
|
+
for (const key of directKeys) {
|
|
860
|
+
if (key in obj)
|
|
859
861
|
result[key] = obj[key];
|
|
862
|
+
}
|
|
863
|
+
for (const [first, restKeys] of nestedKeys) {
|
|
864
|
+
const val = obj[first];
|
|
865
|
+
if (!val || typeof val !== 'object')
|
|
866
|
+
continue;
|
|
867
|
+
if (Array.isArray(val)) {
|
|
868
|
+
result[first] = val.map(item => pick(item, restKeys));
|
|
869
|
+
}
|
|
870
|
+
else {
|
|
871
|
+
result[first] = pick(val, restKeys);
|
|
860
872
|
}
|
|
861
873
|
}
|
|
862
874
|
return result;
|