@aderis-erp/cli 1.0.14 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -8
- package/dist/commands/access-groups.d.ts +0 -1
- package/dist/commands/access-groups.js +22 -78
- package/dist/commands/account-transaction-allocations.d.ts +0 -1
- package/dist/commands/account-transaction-allocations.js +22 -78
- package/dist/commands/account-transactions.d.ts +0 -1
- package/dist/commands/account-transactions.js +28 -82
- package/dist/commands/accounts.d.ts +0 -1
- package/dist/commands/accounts.js +24 -80
- package/dist/commands/agent-platform.d.ts +0 -1
- package/dist/commands/agent-platform.js +24 -79
- package/dist/commands/analytics.d.ts +39 -0
- package/dist/commands/analytics.js +1113 -0
- package/dist/commands/{documents.d.ts → api-keys.d.ts} +1 -2
- package/dist/commands/api-keys.js +1117 -0
- package/dist/commands/audit-log.d.ts +0 -1
- package/dist/commands/audit-log.js +22 -78
- package/dist/commands/auth/login.d.ts +9 -0
- package/dist/commands/auth/login.js +83 -21
- package/dist/commands/auth/logout.d.ts +6 -0
- package/dist/commands/auth/logout.js +23 -6
- package/dist/commands/auth/status.js +46 -23
- package/dist/commands/auth/tenant.js +15 -9
- package/dist/commands/auth.d.ts +0 -1
- package/dist/commands/auth.js +37 -51
- package/dist/commands/bank-accounts.d.ts +0 -1
- package/dist/commands/bank-accounts.js +22 -78
- package/dist/commands/bank-integrations.d.ts +0 -1
- package/dist/commands/bank-integrations.js +22 -78
- package/dist/commands/business-partners.d.ts +1 -1
- package/dist/commands/business-partners.js +38 -84
- package/dist/commands/chat.d.ts +0 -1
- package/dist/commands/chat.js +22 -78
- package/dist/commands/config/add.d.ts +12 -0
- package/dist/commands/config/add.js +97 -17
- package/dist/commands/config/current.js +12 -4
- package/dist/commands/config/list.js +12 -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.d.ts +0 -1
- package/dist/commands/credit-card-accounts.js +22 -78
- package/dist/commands/delivery-notes.d.ts +0 -1
- package/dist/commands/delivery-notes.js +29 -84
- package/dist/commands/dunning-configs.d.ts +0 -1
- package/dist/commands/dunning-configs.js +22 -78
- package/dist/commands/dunning-reminders.d.ts +0 -1
- package/dist/commands/dunning-reminders.js +22 -78
- package/dist/commands/dunning-runs.d.ts +0 -1
- package/dist/commands/dunning-runs.js +22 -78
- package/dist/commands/email-transactions.d.ts +0 -1
- package/dist/commands/email-transactions.js +22 -78
- package/dist/commands/employees.d.ts +0 -1
- package/dist/commands/employees.js +24 -80
- package/dist/commands/entity-configurations.d.ts +0 -1
- package/dist/commands/entity-configurations.js +22 -78
- package/dist/commands/event-processor-mappings.d.ts +0 -1
- package/dist/commands/event-processor-mappings.js +22 -78
- package/dist/commands/{files-internal.d.ts → files.d.ts} +1 -2
- package/dist/commands/{files-internal.js → files.js} +40 -90
- package/dist/commands/health.d.ts +0 -1
- package/dist/commands/health.js +22 -78
- package/dist/commands/inbox.d.ts +0 -1
- package/dist/commands/inbox.js +22 -78
- package/dist/commands/integrations.d.ts +0 -1
- package/dist/commands/integrations.js +22 -78
- package/dist/commands/item-categories.d.ts +0 -1
- package/dist/commands/item-categories.js +22 -78
- package/dist/commands/items.d.ts +0 -1
- package/dist/commands/items.js +24 -80
- package/dist/commands/journal-lines.d.ts +0 -1
- package/dist/commands/journal-lines.js +22 -78
- package/dist/commands/journals.d.ts +1 -1
- package/dist/commands/journals.js +29 -81
- package/dist/commands/ledgers.d.ts +0 -1
- package/dist/commands/ledgers.js +26 -79
- package/dist/commands/nango-integrations.d.ts +39 -0
- package/dist/commands/nango-integrations.js +1115 -0
- package/dist/commands/office-locations.d.ts +0 -1
- package/dist/commands/office-locations.js +22 -78
- package/dist/commands/payment-methods.d.ts +0 -1
- package/dist/commands/payment-methods.js +22 -78
- package/dist/commands/payment-runs.d.ts +0 -1
- package/dist/commands/payment-runs.js +24 -79
- package/dist/commands/payment-terms.d.ts +0 -1
- package/dist/commands/payment-terms.js +22 -78
- package/dist/commands/payments.d.ts +0 -1
- package/dist/commands/payments.js +22 -78
- package/dist/commands/price-lists.d.ts +0 -1
- package/dist/commands/price-lists.js +22 -78
- package/dist/commands/processor-mappings.d.ts +0 -1
- package/dist/commands/processor-mappings.js +22 -78
- package/dist/commands/processors.d.ts +0 -1
- package/dist/commands/processors.js +22 -78
- package/dist/commands/purchase-order-types.d.ts +0 -1
- package/dist/commands/purchase-order-types.js +22 -78
- package/dist/commands/purchase-orders.d.ts +1 -1
- package/dist/commands/purchase-orders.js +35 -84
- package/dist/commands/reports.d.ts +0 -1
- package/dist/commands/reports.js +23 -79
- package/dist/commands/salary-types.d.ts +0 -1
- package/dist/commands/salary-types.js +22 -78
- package/dist/commands/sales-invoices.d.ts +0 -1
- package/dist/commands/sales-invoices.js +38 -89
- package/dist/commands/sales-orders.d.ts +0 -1
- package/dist/commands/sales-orders.js +26 -82
- package/dist/commands/saved-views.d.ts +0 -1
- package/dist/commands/saved-views.js +22 -78
- package/dist/commands/scheduled-processor-mappings.d.ts +0 -1
- package/dist/commands/scheduled-processor-mappings.js +22 -78
- package/dist/commands/schedules.d.ts +0 -1
- package/dist/commands/schedules.js +22 -78
- package/dist/commands/switch.js +14 -7
- package/dist/commands/tag-configurations.d.ts +39 -0
- package/dist/commands/{documents.js → tag-configurations.js} +40 -96
- package/dist/commands/tags.d.ts +0 -1
- package/dist/commands/tags.js +22 -78
- package/dist/commands/tax-codes.d.ts +0 -1
- package/dist/commands/tax-codes.js +22 -78
- package/dist/commands/tax-matrix.d.ts +0 -1
- package/dist/commands/tax-matrix.js +22 -78
- package/dist/commands/tenants.d.ts +0 -1
- package/dist/commands/tenants.js +24 -79
- package/dist/commands/text-templates.d.ts +0 -1
- package/dist/commands/text-templates.js +22 -78
- package/dist/commands/tools.d.ts +0 -1
- package/dist/commands/tools.js +22 -78
- package/dist/commands/vat-declarations.d.ts +1 -1
- package/dist/commands/vat-declarations.js +28 -79
- package/dist/commands/vendor-invoices.d.ts +0 -1
- package/dist/commands/vendor-invoices.js +31 -86
- package/dist/commands/webhooks.d.ts +0 -1
- package/dist/commands/webhooks.js +22 -78
- package/dist/commands/workflows.d.ts +0 -1
- package/dist/commands/workflows.js +22 -78
- package/dist/lib/api-client.js +8 -6
- package/dist/lib/auth/constants.d.ts +11 -0
- package/dist/lib/auth/constants.js +11 -0
- package/dist/lib/auth/errors.d.ts +17 -0
- package/dist/lib/auth/errors.js +22 -0
- package/dist/lib/auth/flow.d.ts +27 -0
- package/dist/lib/auth/flow.js +163 -0
- package/dist/lib/auth/guards.d.ts +5 -0
- package/dist/lib/auth/guards.js +14 -0
- package/dist/lib/auth/http.d.ts +16 -0
- package/dist/lib/auth/http.js +49 -0
- package/dist/lib/auth/index.d.ts +49 -0
- package/dist/lib/auth/index.js +217 -0
- package/dist/lib/auth/keycloak-provider.d.ts +75 -0
- package/dist/lib/auth/keycloak-provider.js +215 -0
- package/dist/lib/auth/pages.d.ts +25 -0
- package/dist/lib/auth/pages.js +123 -0
- package/dist/lib/auth/pkce.d.ts +11 -0
- package/dist/lib/auth/pkce.js +17 -0
- package/dist/lib/auth/tokens.d.ts +54 -0
- package/dist/lib/auth/tokens.js +104 -0
- package/dist/lib/auth/types.d.ts +57 -0
- package/dist/lib/auth/types.js +1 -0
- package/dist/lib/auth/validated-url.d.ts +6 -0
- package/dist/lib/auth/validated-url.js +53 -0
- package/dist/lib/base-api-command.js +6 -4
- package/dist/lib/config.d.ts +44 -4
- package/dist/lib/config.js +55 -19
- package/oclif.manifest.json +1181 -330
- package/package.json +3 -2
- package/dist/lib/auth.d.ts +0 -35
- package/dist/lib/auth.js +0 -566
|
@@ -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;
|
|
@@ -24,7 +24,7 @@ export default class EmailTransactions extends Command {
|
|
|
24
24
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
25
25
|
};
|
|
26
26
|
static flags = {
|
|
27
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
27
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
28
28
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
29
29
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
30
30
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -38,7 +38,7 @@ export default class EmailTransactions extends Command {
|
|
|
38
38
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
39
39
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
40
40
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
41
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
41
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
42
42
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
43
43
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
44
44
|
};
|
|
@@ -96,9 +96,9 @@ export default class EmailTransactions extends Command {
|
|
|
96
96
|
}
|
|
97
97
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
98
98
|
if (!context)
|
|
99
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
100
|
-
if (!context
|
|
101
|
-
this.error(
|
|
99
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
100
|
+
if (!hasCredentials(context))
|
|
101
|
+
this.error(missingCredentialsMessage(context));
|
|
102
102
|
const queryParams = {};
|
|
103
103
|
if (flags.page)
|
|
104
104
|
queryParams.page = flags.page;
|
|
@@ -110,6 +110,8 @@ export default class EmailTransactions extends Command {
|
|
|
110
110
|
queryParams.search = flags.search;
|
|
111
111
|
if (flags['sort-by'])
|
|
112
112
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
113
|
+
if (flags.fields)
|
|
114
|
+
queryParams.fields = flags.fields;
|
|
113
115
|
if (flags.query) {
|
|
114
116
|
try {
|
|
115
117
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -312,11 +314,6 @@ export default class EmailTransactions extends Command {
|
|
|
312
314
|
output = obj[arrayKeys[0]];
|
|
313
315
|
}
|
|
314
316
|
}
|
|
315
|
-
// Filter fields if --fields flag is provided
|
|
316
|
-
if (flags.fields) {
|
|
317
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
318
|
-
output = this.filterFields(output, fieldList);
|
|
319
|
-
}
|
|
320
317
|
// Sanitize output if requested
|
|
321
318
|
if (flags.sanitize) {
|
|
322
319
|
output = this.sanitizeOutput(output);
|
|
@@ -341,9 +338,9 @@ export default class EmailTransactions extends Command {
|
|
|
341
338
|
async runImport(flags) {
|
|
342
339
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
343
340
|
if (!context)
|
|
344
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
345
|
-
if (!context
|
|
346
|
-
this.error(
|
|
341
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
342
|
+
if (!hasCredentials(context))
|
|
343
|
+
this.error(missingCredentialsMessage(context));
|
|
347
344
|
// Get data from file, --data, or --set flags
|
|
348
345
|
let items = [];
|
|
349
346
|
if (flags.file) {
|
|
@@ -553,9 +550,9 @@ export default class EmailTransactions extends Command {
|
|
|
553
550
|
async runExport(flags) {
|
|
554
551
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
555
552
|
if (!context)
|
|
556
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
557
|
-
if (!context
|
|
558
|
-
this.error(
|
|
553
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
554
|
+
if (!hasCredentials(context))
|
|
555
|
+
this.error(missingCredentialsMessage(context));
|
|
559
556
|
const listEndpoint = ENDPOINTS['list'];
|
|
560
557
|
if (!listEndpoint)
|
|
561
558
|
this.error('Export requires a list endpoint');
|
|
@@ -571,6 +568,8 @@ export default class EmailTransactions extends Command {
|
|
|
571
568
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
572
569
|
if (flags.include)
|
|
573
570
|
baseParams.include = flags.include;
|
|
571
|
+
if (flags.fields)
|
|
572
|
+
baseParams.fields = flags.fields;
|
|
574
573
|
if (flags.query) {
|
|
575
574
|
try {
|
|
576
575
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -625,12 +624,7 @@ export default class EmailTransactions extends Command {
|
|
|
625
624
|
}
|
|
626
625
|
}
|
|
627
626
|
process.stderr.write(' done\n');
|
|
628
|
-
// Filter fields if specified
|
|
629
627
|
let output = allItems;
|
|
630
|
-
if (flags.fields) {
|
|
631
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
632
|
-
output = this.filterFields(allItems, fieldList);
|
|
633
|
-
}
|
|
634
628
|
// Sanitize output if requested
|
|
635
629
|
if (flags.sanitize) {
|
|
636
630
|
output = this.sanitizeOutput(output);
|
|
@@ -647,9 +641,9 @@ export default class EmailTransactions extends Command {
|
|
|
647
641
|
async runCamt053Import(flags) {
|
|
648
642
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
649
643
|
if (!context)
|
|
650
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
651
|
-
if (!context
|
|
652
|
-
this.error(
|
|
644
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
645
|
+
if (!hasCredentials(context))
|
|
646
|
+
this.error(missingCredentialsMessage(context));
|
|
653
647
|
if (!flags.file) {
|
|
654
648
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
655
649
|
}
|
|
@@ -737,9 +731,9 @@ export default class EmailTransactions extends Command {
|
|
|
737
731
|
}
|
|
738
732
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
739
733
|
if (!context)
|
|
740
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
741
|
-
if (!context
|
|
742
|
-
this.error(
|
|
734
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
735
|
+
if (!hasCredentials(context))
|
|
736
|
+
this.error(missingCredentialsMessage(context));
|
|
743
737
|
// Get data from file, --data, or --set flags
|
|
744
738
|
let items = [];
|
|
745
739
|
if (flags.file) {
|
|
@@ -959,56 +953,6 @@ export default class EmailTransactions extends Command {
|
|
|
959
953
|
return `\$${op}`;
|
|
960
954
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
961
955
|
}
|
|
962
|
-
filterFields(data, fields) {
|
|
963
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
964
|
-
const pick = (obj, keys) => {
|
|
965
|
-
// Group keys by their first segment so sibling sub-paths
|
|
966
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
967
|
-
// and don't clobber each other on merge.
|
|
968
|
-
const directKeys = new Set();
|
|
969
|
-
const nestedKeys = new Map();
|
|
970
|
-
for (const key of keys) {
|
|
971
|
-
if (key.split('.').some(isUnsafeKey))
|
|
972
|
-
continue;
|
|
973
|
-
if (key.includes('.')) {
|
|
974
|
-
const [first, ...rest] = key.split('.');
|
|
975
|
-
if (isUnsafeKey(first))
|
|
976
|
-
continue;
|
|
977
|
-
const list = nestedKeys.get(first);
|
|
978
|
-
if (list) {
|
|
979
|
-
list.push(rest.join('.'));
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
else {
|
|
986
|
-
directKeys.add(key);
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
const result = {};
|
|
990
|
-
for (const key of directKeys) {
|
|
991
|
-
if (key in obj)
|
|
992
|
-
result[key] = obj[key];
|
|
993
|
-
}
|
|
994
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
995
|
-
const val = obj[first];
|
|
996
|
-
if (!val || typeof val !== 'object')
|
|
997
|
-
continue;
|
|
998
|
-
if (Array.isArray(val)) {
|
|
999
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1000
|
-
}
|
|
1001
|
-
else {
|
|
1002
|
-
result[first] = pick(val, restKeys);
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
return result;
|
|
1006
|
-
};
|
|
1007
|
-
if (Array.isArray(data)) {
|
|
1008
|
-
return data.map(item => pick(item, fields));
|
|
1009
|
-
}
|
|
1010
|
-
return pick(data, fields);
|
|
1011
|
-
}
|
|
1012
956
|
sanitizeOutput(data) {
|
|
1013
957
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1014
958
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -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;
|
|
@@ -9,9 +9,9 @@ const NESTED_IMPORTS = ["salaries", "payments", "notes", "files", "salary-paymen
|
|
|
9
9
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "get-salaries", "create-salaries", "get-salaries-salaryId", "update-salaries", "delete-salaries", "get-payments", "create-payments", "get-payments-paymentId", "update-payments", "delete-payments", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-salary-payment-files", "create-salary-payment-files", "get-salary-payment-files", "update-salary-payment-files", "delete-salary-payment-files", "download-salary-payment-files"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
11
|
'list': { method: 'GET', path: '/v1/employees', summary: 'Get all employees with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes'] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
13
13
|
'get': { method: 'GET', path: '/v1/employees/{id}', summary: 'Get an employee by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes'] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
15
15
|
'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
16
|
'get-salaries': { method: 'GET', path: '/v1/employees/{id}/salaries', summary: 'Get all salaries for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
17
|
'create-salaries': { method: 'POST', path: '/v1/employees/{id}/salaries', summary: 'Add a salary configuration to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
@@ -56,7 +56,7 @@ export default class Employees extends Command {
|
|
|
56
56
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
57
57
|
};
|
|
58
58
|
static flags = {
|
|
59
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
59
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
60
60
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
61
61
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
62
62
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -74,7 +74,7 @@ export default class Employees extends Command {
|
|
|
74
74
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
75
75
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
76
76
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
77
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
77
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
78
78
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
79
79
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
80
80
|
};
|
|
@@ -132,9 +132,9 @@ export default class Employees extends Command {
|
|
|
132
132
|
}
|
|
133
133
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
134
134
|
if (!context)
|
|
135
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
136
|
-
if (!context
|
|
137
|
-
this.error(
|
|
135
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
136
|
+
if (!hasCredentials(context))
|
|
137
|
+
this.error(missingCredentialsMessage(context));
|
|
138
138
|
const queryParams = {};
|
|
139
139
|
if (flags.page)
|
|
140
140
|
queryParams.page = flags.page;
|
|
@@ -146,6 +146,8 @@ export default class Employees extends Command {
|
|
|
146
146
|
queryParams.search = flags.search;
|
|
147
147
|
if (flags['sort-by'])
|
|
148
148
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
149
|
+
if (flags.fields)
|
|
150
|
+
queryParams.fields = flags.fields;
|
|
149
151
|
if (flags.query) {
|
|
150
152
|
try {
|
|
151
153
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -348,11 +350,6 @@ export default class Employees extends Command {
|
|
|
348
350
|
output = obj[arrayKeys[0]];
|
|
349
351
|
}
|
|
350
352
|
}
|
|
351
|
-
// Filter fields if --fields flag is provided
|
|
352
|
-
if (flags.fields) {
|
|
353
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
354
|
-
output = this.filterFields(output, fieldList);
|
|
355
|
-
}
|
|
356
353
|
// Sanitize output if requested
|
|
357
354
|
if (flags.sanitize) {
|
|
358
355
|
output = this.sanitizeOutput(output);
|
|
@@ -377,9 +374,9 @@ export default class Employees extends Command {
|
|
|
377
374
|
async runImport(flags) {
|
|
378
375
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
379
376
|
if (!context)
|
|
380
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
381
|
-
if (!context
|
|
382
|
-
this.error(
|
|
377
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
378
|
+
if (!hasCredentials(context))
|
|
379
|
+
this.error(missingCredentialsMessage(context));
|
|
383
380
|
// Get data from file, --data, or --set flags
|
|
384
381
|
let items = [];
|
|
385
382
|
if (flags.file) {
|
|
@@ -589,9 +586,9 @@ export default class Employees extends Command {
|
|
|
589
586
|
async runExport(flags) {
|
|
590
587
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
591
588
|
if (!context)
|
|
592
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
593
|
-
if (!context
|
|
594
|
-
this.error(
|
|
589
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
590
|
+
if (!hasCredentials(context))
|
|
591
|
+
this.error(missingCredentialsMessage(context));
|
|
595
592
|
const listEndpoint = ENDPOINTS['list'];
|
|
596
593
|
if (!listEndpoint)
|
|
597
594
|
this.error('Export requires a list endpoint');
|
|
@@ -607,6 +604,8 @@ export default class Employees extends Command {
|
|
|
607
604
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
608
605
|
if (flags.include)
|
|
609
606
|
baseParams.include = flags.include;
|
|
607
|
+
if (flags.fields)
|
|
608
|
+
baseParams.fields = flags.fields;
|
|
610
609
|
if (flags.query) {
|
|
611
610
|
try {
|
|
612
611
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -661,12 +660,7 @@ export default class Employees extends Command {
|
|
|
661
660
|
}
|
|
662
661
|
}
|
|
663
662
|
process.stderr.write(' done\n');
|
|
664
|
-
// Filter fields if specified
|
|
665
663
|
let output = allItems;
|
|
666
|
-
if (flags.fields) {
|
|
667
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
668
|
-
output = this.filterFields(allItems, fieldList);
|
|
669
|
-
}
|
|
670
664
|
// Sanitize output if requested
|
|
671
665
|
if (flags.sanitize) {
|
|
672
666
|
output = this.sanitizeOutput(output);
|
|
@@ -683,9 +677,9 @@ export default class Employees extends Command {
|
|
|
683
677
|
async runCamt053Import(flags) {
|
|
684
678
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
685
679
|
if (!context)
|
|
686
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
687
|
-
if (!context
|
|
688
|
-
this.error(
|
|
680
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
681
|
+
if (!hasCredentials(context))
|
|
682
|
+
this.error(missingCredentialsMessage(context));
|
|
689
683
|
if (!flags.file) {
|
|
690
684
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
691
685
|
}
|
|
@@ -773,9 +767,9 @@ export default class Employees extends Command {
|
|
|
773
767
|
}
|
|
774
768
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
775
769
|
if (!context)
|
|
776
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
777
|
-
if (!context
|
|
778
|
-
this.error(
|
|
770
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
771
|
+
if (!hasCredentials(context))
|
|
772
|
+
this.error(missingCredentialsMessage(context));
|
|
779
773
|
// Get data from file, --data, or --set flags
|
|
780
774
|
let items = [];
|
|
781
775
|
if (flags.file) {
|
|
@@ -995,56 +989,6 @@ export default class Employees extends Command {
|
|
|
995
989
|
return `\$${op}`;
|
|
996
990
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
997
991
|
}
|
|
998
|
-
filterFields(data, fields) {
|
|
999
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
1000
|
-
const pick = (obj, keys) => {
|
|
1001
|
-
// Group keys by their first segment so sibling sub-paths
|
|
1002
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
1003
|
-
// and don't clobber each other on merge.
|
|
1004
|
-
const directKeys = new Set();
|
|
1005
|
-
const nestedKeys = new Map();
|
|
1006
|
-
for (const key of keys) {
|
|
1007
|
-
if (key.split('.').some(isUnsafeKey))
|
|
1008
|
-
continue;
|
|
1009
|
-
if (key.includes('.')) {
|
|
1010
|
-
const [first, ...rest] = key.split('.');
|
|
1011
|
-
if (isUnsafeKey(first))
|
|
1012
|
-
continue;
|
|
1013
|
-
const list = nestedKeys.get(first);
|
|
1014
|
-
if (list) {
|
|
1015
|
-
list.push(rest.join('.'));
|
|
1016
|
-
}
|
|
1017
|
-
else {
|
|
1018
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
else {
|
|
1022
|
-
directKeys.add(key);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
const result = {};
|
|
1026
|
-
for (const key of directKeys) {
|
|
1027
|
-
if (key in obj)
|
|
1028
|
-
result[key] = obj[key];
|
|
1029
|
-
}
|
|
1030
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1031
|
-
const val = obj[first];
|
|
1032
|
-
if (!val || typeof val !== 'object')
|
|
1033
|
-
continue;
|
|
1034
|
-
if (Array.isArray(val)) {
|
|
1035
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1036
|
-
}
|
|
1037
|
-
else {
|
|
1038
|
-
result[first] = pick(val, restKeys);
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
return result;
|
|
1042
|
-
};
|
|
1043
|
-
if (Array.isArray(data)) {
|
|
1044
|
-
return data.map(item => pick(item, fields));
|
|
1045
|
-
}
|
|
1046
|
-
return pick(data, fields);
|
|
1047
|
-
}
|
|
1048
992
|
sanitizeOutput(data) {
|
|
1049
993
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1050
994
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -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 = false;
|
|
@@ -20,7 +20,7 @@ export default class EntityConfigurations extends Command {
|
|
|
20
20
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
21
21
|
};
|
|
22
22
|
static flags = {
|
|
23
|
-
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)' }),
|
|
24
24
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
25
25
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
26
26
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -34,7 +34,7 @@ export default class EntityConfigurations extends Command {
|
|
|
34
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.' }),
|
|
35
35
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
36
36
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
37
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
37
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
38
38
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
39
39
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
40
40
|
};
|
|
@@ -92,9 +92,9 @@ export default class EntityConfigurations extends Command {
|
|
|
92
92
|
}
|
|
93
93
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
94
94
|
if (!context)
|
|
95
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
96
|
-
if (!context
|
|
97
|
-
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));
|
|
98
98
|
const queryParams = {};
|
|
99
99
|
if (flags.page)
|
|
100
100
|
queryParams.page = flags.page;
|
|
@@ -106,6 +106,8 @@ export default class EntityConfigurations extends Command {
|
|
|
106
106
|
queryParams.search = flags.search;
|
|
107
107
|
if (flags['sort-by'])
|
|
108
108
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
109
|
+
if (flags.fields)
|
|
110
|
+
queryParams.fields = flags.fields;
|
|
109
111
|
if (flags.query) {
|
|
110
112
|
try {
|
|
111
113
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -308,11 +310,6 @@ export default class EntityConfigurations extends Command {
|
|
|
308
310
|
output = obj[arrayKeys[0]];
|
|
309
311
|
}
|
|
310
312
|
}
|
|
311
|
-
// Filter fields if --fields flag is provided
|
|
312
|
-
if (flags.fields) {
|
|
313
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
314
|
-
output = this.filterFields(output, fieldList);
|
|
315
|
-
}
|
|
316
313
|
// Sanitize output if requested
|
|
317
314
|
if (flags.sanitize) {
|
|
318
315
|
output = this.sanitizeOutput(output);
|
|
@@ -337,9 +334,9 @@ export default class EntityConfigurations extends Command {
|
|
|
337
334
|
async runImport(flags) {
|
|
338
335
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
339
336
|
if (!context)
|
|
340
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
341
|
-
if (!context
|
|
342
|
-
this.error(
|
|
337
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
338
|
+
if (!hasCredentials(context))
|
|
339
|
+
this.error(missingCredentialsMessage(context));
|
|
343
340
|
// Get data from file, --data, or --set flags
|
|
344
341
|
let items = [];
|
|
345
342
|
if (flags.file) {
|
|
@@ -549,9 +546,9 @@ export default class EntityConfigurations extends Command {
|
|
|
549
546
|
async runExport(flags) {
|
|
550
547
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
551
548
|
if (!context)
|
|
552
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
553
|
-
if (!context
|
|
554
|
-
this.error(
|
|
549
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
550
|
+
if (!hasCredentials(context))
|
|
551
|
+
this.error(missingCredentialsMessage(context));
|
|
555
552
|
const listEndpoint = ENDPOINTS['list'];
|
|
556
553
|
if (!listEndpoint)
|
|
557
554
|
this.error('Export requires a list endpoint');
|
|
@@ -567,6 +564,8 @@ export default class EntityConfigurations extends Command {
|
|
|
567
564
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
568
565
|
if (flags.include)
|
|
569
566
|
baseParams.include = flags.include;
|
|
567
|
+
if (flags.fields)
|
|
568
|
+
baseParams.fields = flags.fields;
|
|
570
569
|
if (flags.query) {
|
|
571
570
|
try {
|
|
572
571
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -621,12 +620,7 @@ export default class EntityConfigurations extends Command {
|
|
|
621
620
|
}
|
|
622
621
|
}
|
|
623
622
|
process.stderr.write(' done\n');
|
|
624
|
-
// Filter fields if specified
|
|
625
623
|
let output = allItems;
|
|
626
|
-
if (flags.fields) {
|
|
627
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
628
|
-
output = this.filterFields(allItems, fieldList);
|
|
629
|
-
}
|
|
630
624
|
// Sanitize output if requested
|
|
631
625
|
if (flags.sanitize) {
|
|
632
626
|
output = this.sanitizeOutput(output);
|
|
@@ -643,9 +637,9 @@ export default class EntityConfigurations extends Command {
|
|
|
643
637
|
async runCamt053Import(flags) {
|
|
644
638
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
645
639
|
if (!context)
|
|
646
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
647
|
-
if (!context
|
|
648
|
-
this.error(
|
|
640
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
641
|
+
if (!hasCredentials(context))
|
|
642
|
+
this.error(missingCredentialsMessage(context));
|
|
649
643
|
if (!flags.file) {
|
|
650
644
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
651
645
|
}
|
|
@@ -733,9 +727,9 @@ export default class EntityConfigurations extends Command {
|
|
|
733
727
|
}
|
|
734
728
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
735
729
|
if (!context)
|
|
736
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
737
|
-
if (!context
|
|
738
|
-
this.error(
|
|
730
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
731
|
+
if (!hasCredentials(context))
|
|
732
|
+
this.error(missingCredentialsMessage(context));
|
|
739
733
|
// Get data from file, --data, or --set flags
|
|
740
734
|
let items = [];
|
|
741
735
|
if (flags.file) {
|
|
@@ -955,56 +949,6 @@ export default class EntityConfigurations extends Command {
|
|
|
955
949
|
return `\$${op}`;
|
|
956
950
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
957
951
|
}
|
|
958
|
-
filterFields(data, fields) {
|
|
959
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
960
|
-
const pick = (obj, keys) => {
|
|
961
|
-
// Group keys by their first segment so sibling sub-paths
|
|
962
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
963
|
-
// and don't clobber each other on merge.
|
|
964
|
-
const directKeys = new Set();
|
|
965
|
-
const nestedKeys = new Map();
|
|
966
|
-
for (const key of keys) {
|
|
967
|
-
if (key.split('.').some(isUnsafeKey))
|
|
968
|
-
continue;
|
|
969
|
-
if (key.includes('.')) {
|
|
970
|
-
const [first, ...rest] = key.split('.');
|
|
971
|
-
if (isUnsafeKey(first))
|
|
972
|
-
continue;
|
|
973
|
-
const list = nestedKeys.get(first);
|
|
974
|
-
if (list) {
|
|
975
|
-
list.push(rest.join('.'));
|
|
976
|
-
}
|
|
977
|
-
else {
|
|
978
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
directKeys.add(key);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
const result = {};
|
|
986
|
-
for (const key of directKeys) {
|
|
987
|
-
if (key in obj)
|
|
988
|
-
result[key] = obj[key];
|
|
989
|
-
}
|
|
990
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
991
|
-
const val = obj[first];
|
|
992
|
-
if (!val || typeof val !== 'object')
|
|
993
|
-
continue;
|
|
994
|
-
if (Array.isArray(val)) {
|
|
995
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
996
|
-
}
|
|
997
|
-
else {
|
|
998
|
-
result[first] = pick(val, restKeys);
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
return result;
|
|
1002
|
-
};
|
|
1003
|
-
if (Array.isArray(data)) {
|
|
1004
|
-
return data.map(item => pick(item, fields));
|
|
1005
|
-
}
|
|
1006
|
-
return pick(data, fields);
|
|
1007
|
-
}
|
|
1008
952
|
sanitizeOutput(data) {
|
|
1009
953
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1010
954
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|