@ktmcp-cli/nordigen 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +11 -0
- package/.eslintrc.json +17 -0
- package/AGENT.md +480 -0
- package/CHANGELOG.md +69 -0
- package/CONTRIBUTING.md +198 -0
- package/EXAMPLES.md +561 -0
- package/INDEX.md +193 -0
- package/LICENSE +21 -0
- package/OPENCLAW.md +468 -0
- package/PROJECT.md +366 -0
- package/QUICKREF.md +231 -0
- package/README.md +424 -0
- package/SETUP.md +259 -0
- package/SUMMARY.md +419 -0
- package/banner.png +0 -0
- package/bin/nordigen.js +84 -0
- package/logo.png +0 -0
- package/package.json +40 -0
- package/scripts/quickstart.sh +110 -0
- package/src/commands/accounts.js +205 -0
- package/src/commands/agreements.js +241 -0
- package/src/commands/auth.js +86 -0
- package/src/commands/config.js +173 -0
- package/src/commands/institutions.js +181 -0
- package/src/commands/payments.js +228 -0
- package/src/commands/requisitions.js +239 -0
- package/src/lib/api.js +491 -0
- package/src/lib/auth.js +113 -0
- package/src/lib/config.js +145 -0
- package/src/lib/output.js +255 -0
- package/test/api.test.js +88 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Institution Commands
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Commands for browsing and searching financial institutions
|
|
5
|
+
* @module commands/institutions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { createClient } from '../lib/api.js';
|
|
12
|
+
import { ensureAuth } from '../lib/auth.js';
|
|
13
|
+
import {
|
|
14
|
+
printJSON,
|
|
15
|
+
printError,
|
|
16
|
+
printSection,
|
|
17
|
+
printRow,
|
|
18
|
+
truncate,
|
|
19
|
+
} from '../lib/output.js';
|
|
20
|
+
|
|
21
|
+
export const institutionsCommand = new Command('institutions')
|
|
22
|
+
.description('Browse and search financial institutions')
|
|
23
|
+
.alias('inst');
|
|
24
|
+
|
|
25
|
+
// List institutions
|
|
26
|
+
institutionsCommand
|
|
27
|
+
.command('list')
|
|
28
|
+
.description('List supported institutions')
|
|
29
|
+
.requiredOption('-c, --country <code>', 'ISO 3166 country code (e.g., GB, DE, FR)')
|
|
30
|
+
.option('--payments', 'Filter institutions supporting payments')
|
|
31
|
+
.option('--account-selection', 'Filter institutions supporting account selection')
|
|
32
|
+
.option('-j, --json', 'Output as JSON')
|
|
33
|
+
.action(async (options) => {
|
|
34
|
+
const spinner = ora('Fetching institutions...').start();
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
await ensureAuth();
|
|
38
|
+
const api = createClient();
|
|
39
|
+
|
|
40
|
+
const params = {};
|
|
41
|
+
if (options.payments) params.payments_enabled = true;
|
|
42
|
+
if (options.accountSelection) params.account_selection = true;
|
|
43
|
+
|
|
44
|
+
const institutions = await api.listInstitutions(options.country, params);
|
|
45
|
+
|
|
46
|
+
spinner.succeed(`Found ${institutions.length} institutions`);
|
|
47
|
+
|
|
48
|
+
if (options.json) {
|
|
49
|
+
printJSON(institutions);
|
|
50
|
+
} else {
|
|
51
|
+
printSection(`Institutions in ${options.country.toUpperCase()}`);
|
|
52
|
+
|
|
53
|
+
institutions.forEach((inst, index) => {
|
|
54
|
+
console.log(
|
|
55
|
+
chalk.cyan(`${(index + 1).toString().padStart(3)}.`),
|
|
56
|
+
chalk.bold(inst.name),
|
|
57
|
+
chalk.gray(`(${inst.id})`)
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (inst.bic) {
|
|
61
|
+
console.log(' BIC:', inst.bic);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const features = [];
|
|
65
|
+
if (inst.transaction_total_days) {
|
|
66
|
+
features.push(`${inst.transaction_total_days} days history`);
|
|
67
|
+
}
|
|
68
|
+
if (inst.payments_enabled) {
|
|
69
|
+
features.push('Payments');
|
|
70
|
+
}
|
|
71
|
+
if (inst.account_selection_supported) {
|
|
72
|
+
features.push('Account Selection');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (features.length > 0) {
|
|
76
|
+
console.log(' Features:', chalk.green(features.join(', ')));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log();
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
spinner.fail('Failed to fetch institutions');
|
|
84
|
+
printError(error.message, error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Get institution details
|
|
90
|
+
institutionsCommand
|
|
91
|
+
.command('get')
|
|
92
|
+
.description('Get institution details')
|
|
93
|
+
.argument('<institution-id>', 'Institution ID')
|
|
94
|
+
.option('-j, --json', 'Output as JSON')
|
|
95
|
+
.action(async (institutionId, options) => {
|
|
96
|
+
const spinner = ora('Fetching institution...').start();
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
await ensureAuth();
|
|
100
|
+
const api = createClient();
|
|
101
|
+
const institution = await api.getInstitution(institutionId);
|
|
102
|
+
|
|
103
|
+
spinner.succeed('Institution retrieved');
|
|
104
|
+
|
|
105
|
+
if (options.json) {
|
|
106
|
+
printJSON(institution);
|
|
107
|
+
} else {
|
|
108
|
+
printSection('Institution Details');
|
|
109
|
+
|
|
110
|
+
printRow('ID', institution.id);
|
|
111
|
+
printRow('Name', institution.name);
|
|
112
|
+
if (institution.bic) printRow('BIC', institution.bic);
|
|
113
|
+
if (institution.countries) printRow('Countries', institution.countries.join(', '));
|
|
114
|
+
if (institution.logo) printRow('Logo', institution.logo);
|
|
115
|
+
|
|
116
|
+
printSection('Features');
|
|
117
|
+
printRow('Transaction History', institution.transaction_total_days ? `${institution.transaction_total_days} days` : 'N/A');
|
|
118
|
+
printRow('Payments', institution.payments_enabled ? chalk.green('Supported') : chalk.gray('Not supported'));
|
|
119
|
+
printRow('Account Selection', institution.account_selection_supported ? chalk.green('Supported') : chalk.gray('Not supported'));
|
|
120
|
+
|
|
121
|
+
if (institution.supported_payments) {
|
|
122
|
+
printRow('Payment Types', institution.supported_payments.join(', '));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
spinner.fail('Failed to fetch institution');
|
|
127
|
+
printError(error.message, error);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Search institutions
|
|
133
|
+
institutionsCommand
|
|
134
|
+
.command('search')
|
|
135
|
+
.description('Search for institutions by name')
|
|
136
|
+
.argument('<query>', 'Search query')
|
|
137
|
+
.requiredOption('-c, --country <code>', 'ISO 3166 country code')
|
|
138
|
+
.option('-j, --json', 'Output as JSON')
|
|
139
|
+
.action(async (query, options) => {
|
|
140
|
+
const spinner = ora('Searching institutions...').start();
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
await ensureAuth();
|
|
144
|
+
const api = createClient();
|
|
145
|
+
const institutions = await api.listInstitutions(options.country);
|
|
146
|
+
|
|
147
|
+
// Filter by name
|
|
148
|
+
const results = institutions.filter((inst) =>
|
|
149
|
+
inst.name.toLowerCase().includes(query.toLowerCase())
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
spinner.succeed(`Found ${results.length} matching institutions`);
|
|
153
|
+
|
|
154
|
+
if (options.json) {
|
|
155
|
+
printJSON(results);
|
|
156
|
+
} else {
|
|
157
|
+
if (results.length === 0) {
|
|
158
|
+
console.log(chalk.yellow('No institutions found matching query'));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
printSection('Search Results');
|
|
163
|
+
|
|
164
|
+
results.forEach((inst, index) => {
|
|
165
|
+
console.log(
|
|
166
|
+
chalk.cyan(`${(index + 1).toString().padStart(3)}.`),
|
|
167
|
+
chalk.bold(inst.name),
|
|
168
|
+
chalk.gray(`(${inst.id})`)
|
|
169
|
+
);
|
|
170
|
+
if (inst.bic) {
|
|
171
|
+
console.log(' BIC:', inst.bic);
|
|
172
|
+
}
|
|
173
|
+
console.log();
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
spinner.fail('Search failed');
|
|
178
|
+
printError(error.message, error);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Commands
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Commands for managing payments and creditors
|
|
5
|
+
* @module commands/payments
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { createClient } from '../lib/api.js';
|
|
12
|
+
import { ensureAuth } from '../lib/auth.js';
|
|
13
|
+
import {
|
|
14
|
+
printJSON,
|
|
15
|
+
printSuccess,
|
|
16
|
+
printError,
|
|
17
|
+
printSection,
|
|
18
|
+
printRow,
|
|
19
|
+
formatStatus,
|
|
20
|
+
formatDateString,
|
|
21
|
+
} from '../lib/output.js';
|
|
22
|
+
|
|
23
|
+
export const paymentsCommand = new Command('payments')
|
|
24
|
+
.description('Manage payments and creditors')
|
|
25
|
+
.alias('pay');
|
|
26
|
+
|
|
27
|
+
// List payments
|
|
28
|
+
paymentsCommand
|
|
29
|
+
.command('list')
|
|
30
|
+
.description('List all payments')
|
|
31
|
+
.option('--limit <number>', 'Results per page', '100')
|
|
32
|
+
.option('--offset <number>', 'Pagination offset', '0')
|
|
33
|
+
.option('-j, --json', 'Output as JSON')
|
|
34
|
+
.action(async (options) => {
|
|
35
|
+
const spinner = ora('Fetching payments...').start();
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
await ensureAuth();
|
|
39
|
+
const api = createClient();
|
|
40
|
+
|
|
41
|
+
const params = {
|
|
42
|
+
limit: parseInt(options.limit),
|
|
43
|
+
offset: parseInt(options.offset),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const data = await api.listPayments(params);
|
|
47
|
+
|
|
48
|
+
spinner.succeed(`Found ${data.count || data.results?.length || 0} payments`);
|
|
49
|
+
|
|
50
|
+
if (options.json) {
|
|
51
|
+
printJSON(data);
|
|
52
|
+
} else {
|
|
53
|
+
const payments = data.results || [];
|
|
54
|
+
|
|
55
|
+
if (payments.length === 0) {
|
|
56
|
+
console.log(chalk.yellow('No payments found'));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
printSection('Payments');
|
|
61
|
+
|
|
62
|
+
payments.forEach((payment, index) => {
|
|
63
|
+
console.log(chalk.cyan(`${index + 1}.`), chalk.bold(payment.id));
|
|
64
|
+
console.log(' Status:', formatStatus(payment.status));
|
|
65
|
+
console.log(' Created:', formatDateString(payment.created));
|
|
66
|
+
|
|
67
|
+
if (payment.amount && payment.currency) {
|
|
68
|
+
console.log(' Amount:', `${payment.amount} ${payment.currency}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (data.next) {
|
|
75
|
+
console.log(chalk.gray('More results available. Use --offset to paginate.'));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
spinner.fail('Failed to fetch payments');
|
|
80
|
+
printError(error.message, error);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Get payment
|
|
86
|
+
paymentsCommand
|
|
87
|
+
.command('get')
|
|
88
|
+
.description('Get payment details')
|
|
89
|
+
.argument('<payment-id>', 'Payment UUID')
|
|
90
|
+
.option('-j, --json', 'Output as JSON')
|
|
91
|
+
.action(async (paymentId, options) => {
|
|
92
|
+
const spinner = ora('Fetching payment...').start();
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
await ensureAuth();
|
|
96
|
+
const api = createClient();
|
|
97
|
+
const payment = await api.getPayment(paymentId);
|
|
98
|
+
|
|
99
|
+
spinner.succeed('Payment retrieved');
|
|
100
|
+
|
|
101
|
+
if (options.json) {
|
|
102
|
+
printJSON(payment);
|
|
103
|
+
} else {
|
|
104
|
+
printSection('Payment Details');
|
|
105
|
+
printRow('Payment ID', payment.id);
|
|
106
|
+
printRow('Status', formatStatus(payment.status));
|
|
107
|
+
printRow('Created', formatDateString(payment.created));
|
|
108
|
+
|
|
109
|
+
if (payment.amount && payment.currency) {
|
|
110
|
+
printRow('Amount', `${payment.amount} ${payment.currency}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
spinner.fail('Failed to fetch payment');
|
|
115
|
+
printError(error.message, error);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Delete payment
|
|
121
|
+
paymentsCommand
|
|
122
|
+
.command('delete')
|
|
123
|
+
.description('Delete a periodic payment')
|
|
124
|
+
.argument('<payment-id>', 'Payment UUID')
|
|
125
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
126
|
+
.action(async (paymentId, options) => {
|
|
127
|
+
if (!options.yes) {
|
|
128
|
+
console.log(chalk.yellow('Warning: This will permanently delete the payment'));
|
|
129
|
+
console.log('Use --yes to confirm deletion');
|
|
130
|
+
process.exit(0);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const spinner = ora('Deleting payment...').start();
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
await ensureAuth();
|
|
137
|
+
const api = createClient();
|
|
138
|
+
await api.deletePayment(paymentId);
|
|
139
|
+
|
|
140
|
+
spinner.succeed('Payment deleted');
|
|
141
|
+
printSuccess('Payment deleted successfully');
|
|
142
|
+
} catch (error) {
|
|
143
|
+
spinner.fail('Failed to delete payment');
|
|
144
|
+
printError(error.message, error);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// List creditors
|
|
150
|
+
paymentsCommand
|
|
151
|
+
.command('creditors')
|
|
152
|
+
.description('List payment creditors')
|
|
153
|
+
.option('-j, --json', 'Output as JSON')
|
|
154
|
+
.action(async (options) => {
|
|
155
|
+
const spinner = ora('Fetching creditors...').start();
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
await ensureAuth();
|
|
159
|
+
const api = createClient();
|
|
160
|
+
const data = await api.listCreditors();
|
|
161
|
+
|
|
162
|
+
spinner.succeed(`Found ${data.count || data.results?.length || 0} creditors`);
|
|
163
|
+
|
|
164
|
+
if (options.json) {
|
|
165
|
+
printJSON(data);
|
|
166
|
+
} else {
|
|
167
|
+
const creditors = data.results || [];
|
|
168
|
+
|
|
169
|
+
if (creditors.length === 0) {
|
|
170
|
+
console.log(chalk.yellow('No creditors found'));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
printSection('Payment Creditors');
|
|
175
|
+
|
|
176
|
+
creditors.forEach((creditor, index) => {
|
|
177
|
+
console.log(chalk.cyan(`${index + 1}.`), chalk.bold(creditor.name || creditor.id));
|
|
178
|
+
console.log(' ID:', creditor.id);
|
|
179
|
+
|
|
180
|
+
if (creditor.account) {
|
|
181
|
+
console.log(' Account:', creditor.account);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
spinner.fail('Failed to fetch creditors');
|
|
189
|
+
printError(error.message, error);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Get payment fields
|
|
195
|
+
paymentsCommand
|
|
196
|
+
.command('fields')
|
|
197
|
+
.description('Get required payment fields for institution')
|
|
198
|
+
.argument('<institution-id>', 'Institution ID')
|
|
199
|
+
.option('-j, --json', 'Output as JSON')
|
|
200
|
+
.action(async (institutionId, options) => {
|
|
201
|
+
const spinner = ora('Fetching payment fields...').start();
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
await ensureAuth();
|
|
205
|
+
const api = createClient();
|
|
206
|
+
const fields = await api.getPaymentFields(institutionId);
|
|
207
|
+
|
|
208
|
+
spinner.succeed('Payment fields retrieved');
|
|
209
|
+
|
|
210
|
+
if (options.json) {
|
|
211
|
+
printJSON(fields);
|
|
212
|
+
} else {
|
|
213
|
+
printSection(`Required Payment Fields for ${institutionId}`);
|
|
214
|
+
|
|
215
|
+
if (Array.isArray(fields)) {
|
|
216
|
+
fields.forEach((field, index) => {
|
|
217
|
+
console.log(chalk.cyan(`${index + 1}.`), field);
|
|
218
|
+
});
|
|
219
|
+
} else {
|
|
220
|
+
console.log(chalk.yellow('No specific fields required'));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch (error) {
|
|
224
|
+
spinner.fail('Failed to fetch payment fields');
|
|
225
|
+
printError(error.message, error);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Requisition Commands
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Commands for managing account requisitions
|
|
5
|
+
* @module commands/requisitions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { createClient } from '../lib/api.js';
|
|
12
|
+
import { ensureAuth } from '../lib/auth.js';
|
|
13
|
+
import {
|
|
14
|
+
printJSON,
|
|
15
|
+
printSuccess,
|
|
16
|
+
printError,
|
|
17
|
+
printSection,
|
|
18
|
+
printRow,
|
|
19
|
+
formatDateString,
|
|
20
|
+
formatStatus,
|
|
21
|
+
} from '../lib/output.js';
|
|
22
|
+
|
|
23
|
+
export const requisitionsCommand = new Command('requisitions')
|
|
24
|
+
.description('Manage account requisitions')
|
|
25
|
+
.alias('req');
|
|
26
|
+
|
|
27
|
+
// List requisitions
|
|
28
|
+
requisitionsCommand
|
|
29
|
+
.command('list')
|
|
30
|
+
.description('List all requisitions')
|
|
31
|
+
.option('--limit <number>', 'Results per page', '100')
|
|
32
|
+
.option('--offset <number>', 'Pagination offset', '0')
|
|
33
|
+
.option('-j, --json', 'Output as JSON')
|
|
34
|
+
.action(async (options) => {
|
|
35
|
+
const spinner = ora('Fetching requisitions...').start();
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
await ensureAuth();
|
|
39
|
+
const api = createClient();
|
|
40
|
+
|
|
41
|
+
const params = {
|
|
42
|
+
limit: parseInt(options.limit),
|
|
43
|
+
offset: parseInt(options.offset),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const data = await api.listRequisitions(params);
|
|
47
|
+
|
|
48
|
+
spinner.succeed(`Found ${data.count || data.results?.length || 0} requisitions`);
|
|
49
|
+
|
|
50
|
+
if (options.json) {
|
|
51
|
+
printJSON(data);
|
|
52
|
+
} else {
|
|
53
|
+
const requisitions = data.results || [];
|
|
54
|
+
|
|
55
|
+
if (requisitions.length === 0) {
|
|
56
|
+
console.log(chalk.yellow('No requisitions found'));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
printSection('Requisitions');
|
|
61
|
+
|
|
62
|
+
requisitions.forEach((req, index) => {
|
|
63
|
+
console.log(chalk.cyan(`${index + 1}.`), chalk.bold(req.id));
|
|
64
|
+
console.log(' Status:', formatStatus(req.status));
|
|
65
|
+
console.log(' Institution:', req.institution_id);
|
|
66
|
+
console.log(' Created:', formatDateString(req.created));
|
|
67
|
+
|
|
68
|
+
if (req.reference) {
|
|
69
|
+
console.log(' Reference:', req.reference);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (req.accounts && req.accounts.length > 0) {
|
|
73
|
+
console.log(' Accounts:', req.accounts.join(', '));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (req.link) {
|
|
77
|
+
console.log(' Auth Link:', chalk.blue(req.link));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (data.next) {
|
|
84
|
+
console.log(chalk.gray('More results available. Use --offset to paginate.'));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} catch (error) {
|
|
88
|
+
spinner.fail('Failed to fetch requisitions');
|
|
89
|
+
printError(error.message, error);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Create requisition
|
|
95
|
+
requisitionsCommand
|
|
96
|
+
.command('create')
|
|
97
|
+
.description('Create a new requisition')
|
|
98
|
+
.requiredOption('-i, --institution-id <id>', 'Institution ID')
|
|
99
|
+
.requiredOption('-r, --redirect <url>', 'Redirect URL after authentication')
|
|
100
|
+
.option('--reference <ref>', 'Custom reference identifier')
|
|
101
|
+
.option('--agreement <id>', 'Agreement UUID')
|
|
102
|
+
.option('--language <code>', 'User language code (e.g., en, de, fr)')
|
|
103
|
+
.option('--account-selection', 'Enable account selection')
|
|
104
|
+
.option('--redirect-immediate', 'Redirect immediately after auth')
|
|
105
|
+
.option('-j, --json', 'Output as JSON')
|
|
106
|
+
.action(async (options) => {
|
|
107
|
+
const spinner = ora('Creating requisition...').start();
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
await ensureAuth();
|
|
111
|
+
const api = createClient();
|
|
112
|
+
|
|
113
|
+
const data = {
|
|
114
|
+
institution_id: options.institutionId,
|
|
115
|
+
redirect: options.redirect,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if (options.reference) data.reference = options.reference;
|
|
119
|
+
if (options.agreement) data.agreement = options.agreement;
|
|
120
|
+
if (options.language) data.user_language = options.language;
|
|
121
|
+
if (options.accountSelection) data.account_selection = true;
|
|
122
|
+
if (options.redirectImmediate) data.redirect_immediate = true;
|
|
123
|
+
|
|
124
|
+
const requisition = await api.createRequisition(data);
|
|
125
|
+
|
|
126
|
+
spinner.succeed('Requisition created');
|
|
127
|
+
|
|
128
|
+
if (options.json) {
|
|
129
|
+
printJSON(requisition);
|
|
130
|
+
} else {
|
|
131
|
+
printSection('Requisition Created');
|
|
132
|
+
printRow('Requisition ID', requisition.id);
|
|
133
|
+
printRow('Status', formatStatus(requisition.status));
|
|
134
|
+
printRow('Institution', requisition.institution_id);
|
|
135
|
+
|
|
136
|
+
if (requisition.reference) {
|
|
137
|
+
printRow('Reference', requisition.reference);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log();
|
|
141
|
+
printSuccess('Requisition created successfully');
|
|
142
|
+
|
|
143
|
+
if (requisition.link) {
|
|
144
|
+
console.log();
|
|
145
|
+
console.log(chalk.bold('Authentication Link:'));
|
|
146
|
+
console.log(chalk.blue(requisition.link));
|
|
147
|
+
console.log();
|
|
148
|
+
console.log(chalk.gray('Send this link to the end user to authorize access'));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
spinner.fail('Failed to create requisition');
|
|
153
|
+
printError(error.message, error);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Get requisition
|
|
159
|
+
requisitionsCommand
|
|
160
|
+
.command('get')
|
|
161
|
+
.description('Get requisition details')
|
|
162
|
+
.argument('<requisition-id>', 'Requisition UUID')
|
|
163
|
+
.option('-j, --json', 'Output as JSON')
|
|
164
|
+
.action(async (requisitionId, options) => {
|
|
165
|
+
const spinner = ora('Fetching requisition...').start();
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
await ensureAuth();
|
|
169
|
+
const api = createClient();
|
|
170
|
+
const requisition = await api.getRequisition(requisitionId);
|
|
171
|
+
|
|
172
|
+
spinner.succeed('Requisition retrieved');
|
|
173
|
+
|
|
174
|
+
if (options.json) {
|
|
175
|
+
printJSON(requisition);
|
|
176
|
+
} else {
|
|
177
|
+
printSection('Requisition Details');
|
|
178
|
+
printRow('Requisition ID', requisition.id);
|
|
179
|
+
printRow('Status', formatStatus(requisition.status));
|
|
180
|
+
printRow('Institution', requisition.institution_id);
|
|
181
|
+
printRow('Created', formatDateString(requisition.created));
|
|
182
|
+
|
|
183
|
+
if (requisition.reference) {
|
|
184
|
+
printRow('Reference', requisition.reference);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (requisition.agreement) {
|
|
188
|
+
printRow('Agreement', requisition.agreement);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (requisition.accounts && requisition.accounts.length > 0) {
|
|
192
|
+
console.log();
|
|
193
|
+
console.log(chalk.bold('Connected Accounts:'));
|
|
194
|
+
requisition.accounts.forEach((accountId, index) => {
|
|
195
|
+
console.log(chalk.cyan(` ${index + 1}.`), accountId);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (requisition.link) {
|
|
200
|
+
console.log();
|
|
201
|
+
console.log(chalk.bold('Authentication Link:'));
|
|
202
|
+
console.log(chalk.blue(requisition.link));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
spinner.fail('Failed to fetch requisition');
|
|
207
|
+
printError(error.message, error);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Delete requisition
|
|
213
|
+
requisitionsCommand
|
|
214
|
+
.command('delete')
|
|
215
|
+
.description('Delete a requisition')
|
|
216
|
+
.argument('<requisition-id>', 'Requisition UUID')
|
|
217
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
218
|
+
.action(async (requisitionId, options) => {
|
|
219
|
+
if (!options.yes) {
|
|
220
|
+
console.log(chalk.yellow('Warning: This will permanently delete the requisition'));
|
|
221
|
+
console.log('Use --yes to confirm deletion');
|
|
222
|
+
process.exit(0);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const spinner = ora('Deleting requisition...').start();
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
await ensureAuth();
|
|
229
|
+
const api = createClient();
|
|
230
|
+
await api.deleteRequisition(requisitionId);
|
|
231
|
+
|
|
232
|
+
spinner.succeed('Requisition deleted');
|
|
233
|
+
printSuccess('Requisition deleted successfully');
|
|
234
|
+
} catch (error) {
|
|
235
|
+
spinner.fail('Failed to delete requisition');
|
|
236
|
+
printError(error.message, error);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
});
|