wedos-cli 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.
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Czech locale utilities for WEDOS CLI
3
+ */
4
+
5
+ const TIMEZONE = 'Europe/Prague';
6
+
7
+ /**
8
+ * Format date in Czech format (DD.MM.YYYY)
9
+ */
10
+ export function formatDate(date) {
11
+ if (!date) return '-';
12
+
13
+ const d = typeof date === 'string' ? new Date(date) : date;
14
+ if (isNaN(d.getTime())) {
15
+ // Try parsing YYYY-MM-DD format
16
+ if (typeof date === 'string' && date.match(/^\d{4}-\d{2}-\d{2}/)) {
17
+ const [year, month, day] = date.split(/[-T]/);
18
+ return `${day}.${month}.${year}`;
19
+ }
20
+ return date; // Return as-is if can't parse
21
+ }
22
+
23
+ return d.toLocaleDateString('cs-CZ', { timeZone: TIMEZONE });
24
+ }
25
+
26
+ /**
27
+ * Format datetime in Czech format (DD.MM.YYYY HH:mm)
28
+ */
29
+ export function formatDateTime(date) {
30
+ if (!date) return '-';
31
+
32
+ const d = typeof date === 'string' ? new Date(date) : date;
33
+ if (isNaN(d.getTime())) return date;
34
+
35
+ return d.toLocaleString('cs-CZ', {
36
+ timeZone: TIMEZONE,
37
+ day: '2-digit',
38
+ month: '2-digit',
39
+ year: 'numeric',
40
+ hour: '2-digit',
41
+ minute: '2-digit'
42
+ });
43
+ }
44
+
45
+ /**
46
+ * Format timestamp to Czech datetime
47
+ */
48
+ export function formatTimestamp(timestamp) {
49
+ if (!timestamp) return '-';
50
+ const d = new Date(timestamp * 1000);
51
+ return formatDateTime(d);
52
+ }
53
+
54
+ /**
55
+ * Get current time in Prague timezone
56
+ */
57
+ export function getPragueTime() {
58
+ return new Date().toLocaleString('cs-CZ', { timeZone: TIMEZONE });
59
+ }
60
+
61
+ /**
62
+ * Response code translations
63
+ */
64
+ export const RESPONSE_MESSAGES = {
65
+ 1000: 'OK',
66
+ 1001: 'Čeká na zpracování (asynchronní operace)',
67
+ 1300: 'Žádné čekající notifikace',
68
+ 2000: 'Chyba parsování požadavku',
69
+ 2009: 'Neplatný požadavek - prázdný požadavek',
70
+ 2051: 'Přístup z této IP adresy není povolen',
71
+ 2201: 'Nepodporovaná TLD',
72
+ 2202: 'Neplatný název domény',
73
+ 2203: 'Neplatná perioda',
74
+ 3002: 'Nedostatečný kredit',
75
+ 3201: 'Doména je již zaregistrována',
76
+ 3204: 'Doména je v karanténě',
77
+ 3205: 'Doména je rezervována',
78
+ 3206: 'Doména je blokována',
79
+ 3209: 'Nepodařilo se odeslat AUTH-ID',
80
+ 3217: 'Připojení k registru selhalo',
81
+ 3218: 'Transfer není možný',
82
+ 3222: 'Nepodařilo se získat informace o doméně',
83
+ 3229: 'Chyba při načítání kontaktu',
84
+ 3231: 'Kontakt již existuje',
85
+ 3238: 'Chyba autorizace',
86
+ 3305: 'Doména je uzamčena pro úpravy',
87
+ 5001: 'Interní chyba serveru',
88
+ };
89
+
90
+ /**
91
+ * Status translations
92
+ */
93
+ export const STATUS_LABELS = {
94
+ active: 'aktivní',
95
+ expired: 'expirovaná',
96
+ deleted: 'smazaná',
97
+ pending: 'čekající',
98
+ available: 'volná',
99
+ registered: 'zaregistrovaná',
100
+ quarantine: 'karanténa',
101
+ reserved: 'rezervovaná',
102
+ blocked: 'blokovaná',
103
+ unknown: 'neznámý',
104
+ };
105
+
106
+ /**
107
+ * Get Czech status label
108
+ */
109
+ export function getStatusLabel(status) {
110
+ if (!status) return STATUS_LABELS.unknown;
111
+ return STATUS_LABELS[status.toLowerCase()] || status;
112
+ }
@@ -0,0 +1,191 @@
1
+ import chalk from 'chalk';
2
+ import boxen from 'boxen';
3
+ import { getConfig } from './config.js';
4
+ import { isSuccess } from './wapi.js';
5
+ import { formatDate, formatDateTime, RESPONSE_MESSAGES, getStatusLabel } from './locale.js';
6
+ import {
7
+ createTable,
8
+ printApiStatus,
9
+ printDomainCard,
10
+ printDomainCheck,
11
+ printSuccessBox,
12
+ printErrorBox,
13
+ printInfoBox,
14
+ printWarningBox,
15
+ printHeader,
16
+ formatDnsType,
17
+ wedosGradient,
18
+ } from './ui.js';
19
+
20
+ /**
21
+ * Format API response for output
22
+ */
23
+ export function formatResponse(response, options = {}) {
24
+ const config = getConfig();
25
+ const format = options.format || config.outputFormat;
26
+
27
+ if (format === 'json') {
28
+ console.log(JSON.stringify(response, null, 2));
29
+ return;
30
+ }
31
+
32
+ const code = parseInt(response.code);
33
+ const success = isSuccess(code);
34
+ const message = RESPONSE_MESSAGES[code] || response.result || (success ? 'OK' : 'Chyba');
35
+
36
+ printApiStatus(code, message, response.svTRID);
37
+
38
+ if (response.data && Object.keys(response.data).length > 0) {
39
+ formatData(response.data, options);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Format data object for display
45
+ */
46
+ export function formatData(data, options = {}) {
47
+ const config = getConfig();
48
+ const format = options.format || config.outputFormat;
49
+
50
+ if (format === 'json') {
51
+ console.log(JSON.stringify(data, null, 2));
52
+ return;
53
+ }
54
+
55
+ // Handle array of domains
56
+ if (data.domain && Array.isArray(data.domain)) {
57
+ printHeader('Seznam domén', '🌐');
58
+
59
+ const table = createTable(['Doména', 'Stav', 'Expirace', 'Vlastník']);
60
+
61
+ for (const domain of data.domain) {
62
+ table.push([
63
+ chalk.white.bold(domain.name || '-'),
64
+ formatStatusBadge(domain.status),
65
+ formatDate(domain.expiration),
66
+ domain.owner || '-',
67
+ ]);
68
+ }
69
+
70
+ console.log(table.toString());
71
+ console.log(chalk.gray(`\n 📊 Celkem: ${data.domain.length} doména(y)`));
72
+ return;
73
+ }
74
+
75
+ // Handle single domain info
76
+ if (data.name && (data.status || data.expiration)) {
77
+ printDomainCard(data);
78
+ return;
79
+ }
80
+
81
+ // Handle DNS records
82
+ if (data.row) {
83
+ const records = Array.isArray(data.row) ? data.row : [data.row];
84
+ printHeader('DNS záznamy', '📋');
85
+
86
+ const table = createTable(['ID', 'Název', 'Typ', 'TTL', 'Data']);
87
+
88
+ for (const row of records) {
89
+ table.push([
90
+ chalk.gray(row.ID || row.id || '-'),
91
+ chalk.white(row.name || '@'),
92
+ formatDnsType(row.rdtype || row.type),
93
+ chalk.yellow(row.ttl || '-'),
94
+ truncate(row.rdata || '-', 45),
95
+ ]);
96
+ }
97
+
98
+ console.log(table.toString());
99
+ console.log(chalk.gray(`\n 📊 Celkem: ${records.length} záznam(ů)`));
100
+ return;
101
+ }
102
+
103
+ // Handle domain check results (multiple domains)
104
+ if (typeof data === 'object' && !Array.isArray(data)) {
105
+ // Check if this looks like domain availability data
106
+ const firstValue = Object.values(data)[0];
107
+ if (firstValue && typeof firstValue === 'object' && 'avail' in firstValue) {
108
+ printHeader('Dostupnost domén', '🔍');
109
+ console.log('');
110
+
111
+ for (const [domain, info] of Object.entries(data)) {
112
+ const available = info.avail === '1' || info.avail === 1;
113
+ printDomainCheck(domain, available, info.reason);
114
+ }
115
+ console.log('');
116
+ return;
117
+ }
118
+
119
+ // Generic object display
120
+ console.log('');
121
+ for (const [key, value] of Object.entries(data)) {
122
+ if (typeof value === 'object' && value !== null) {
123
+ console.log(chalk.cyan.bold(` ${key}:`));
124
+ for (const [k, v] of Object.entries(value)) {
125
+ console.log(` ${chalk.gray(k)}: ${chalk.white(v)}`);
126
+ }
127
+ } else {
128
+ console.log(` ${chalk.cyan(key)}: ${chalk.white(value)}`);
129
+ }
130
+ }
131
+ }
132
+ }
133
+
134
+ function formatStatusBadge(status) {
135
+ const statusConfig = {
136
+ active: { bg: 'bgGreen', fg: 'black', label: ' AKTIVNÍ ' },
137
+ expired: { bg: 'bgRed', fg: 'white', label: ' EXPIROVANÁ ' },
138
+ deleted: { bg: 'bgGray', fg: 'white', label: ' SMAZANÁ ' },
139
+ pending: { bg: 'bgYellow', fg: 'black', label: ' ČEKAJÍCÍ ' },
140
+ };
141
+
142
+ const config = statusConfig[status?.toLowerCase()] || { bg: 'bgWhite', fg: 'black', label: ` ${status || '?'} ` };
143
+ return chalk[config.bg][config.fg](config.label);
144
+ }
145
+
146
+ function truncate(str, len) {
147
+ if (!str) return '-';
148
+ return str.length > len ? str.substring(0, len - 3) + '...' : str;
149
+ }
150
+
151
+ /**
152
+ * Print error
153
+ */
154
+ export function printError(error) {
155
+ const message = error.message || error;
156
+ const czechMessage = RESPONSE_MESSAGES[error.code] || message;
157
+ printErrorBox(czechMessage);
158
+ }
159
+
160
+ /**
161
+ * Print success
162
+ */
163
+ export function printSuccess(message) {
164
+ console.log(chalk.green(` ✓ ${message}`));
165
+ }
166
+
167
+ /**
168
+ * Print info
169
+ */
170
+ export function printInfo(message) {
171
+ console.log(chalk.cyan(` ℹ ${message}`));
172
+ }
173
+
174
+ /**
175
+ * Print warning
176
+ */
177
+ export function printWarning(message) {
178
+ console.log(chalk.yellow(` ⚠ ${message}`));
179
+ }
180
+
181
+ // Re-export UI components for direct use
182
+ export {
183
+ printSuccessBox,
184
+ printErrorBox,
185
+ printInfoBox,
186
+ printWarningBox,
187
+ printHeader,
188
+ createTable,
189
+ printDomainCard,
190
+ printDomainCheck,
191
+ };
package/src/lib/ui.js ADDED
@@ -0,0 +1,263 @@
1
+ import chalk from 'chalk';
2
+ import boxen from 'boxen';
3
+ import gradient from 'gradient-string';
4
+ import figlet from 'figlet';
5
+ import Table from 'cli-table3';
6
+
7
+ // Custom gradient for WEDOS brand colors (blue/cyan theme)
8
+ const wedosGradient = gradient(['#0066cc', '#00ccff', '#00ffcc']);
9
+ const successGradient = gradient(['#00cc66', '#00ff99']);
10
+ const errorGradient = gradient(['#ff3366', '#ff6699']);
11
+ const warningGradient = gradient(['#ffcc00', '#ff9900']);
12
+
13
+ /**
14
+ * Print WEDOS CLI banner
15
+ */
16
+ export function printBanner() {
17
+ const banner = figlet.textSync('WEDOS', {
18
+ font: 'Small',
19
+ horizontalLayout: 'default',
20
+ });
21
+
22
+ console.log('');
23
+ console.log(wedosGradient(banner));
24
+ console.log(chalk.gray(' ─────────────────────────────────────'));
25
+ console.log(chalk.gray(' CLI pro správu domén a DNS │ v1.0.0'));
26
+ console.log('');
27
+ }
28
+
29
+ /**
30
+ * Print a styled header
31
+ */
32
+ export function printHeader(text, icon = '◆') {
33
+ const line = '─'.repeat(Math.max(40, text.length + 4));
34
+ console.log('');
35
+ console.log(wedosGradient(`${icon} ${text}`));
36
+ console.log(chalk.gray(line));
37
+ }
38
+
39
+ /**
40
+ * Print success box
41
+ */
42
+ export function printSuccessBox(title, content = null) {
43
+ const message = content ? `${title}\n\n${chalk.gray(content)}` : title;
44
+ console.log('');
45
+ console.log(boxen(successGradient('✓ ') + chalk.green(message), {
46
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
47
+ borderStyle: 'round',
48
+ borderColor: 'green',
49
+ }));
50
+ }
51
+
52
+ /**
53
+ * Print error box
54
+ */
55
+ export function printErrorBox(title, content = null) {
56
+ const message = content ? `${title}\n\n${chalk.gray(content)}` : title;
57
+ console.log('');
58
+ console.log(boxen(errorGradient('✗ ') + chalk.red(message), {
59
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
60
+ borderStyle: 'round',
61
+ borderColor: 'red',
62
+ }));
63
+ }
64
+
65
+ /**
66
+ * Print info box
67
+ */
68
+ export function printInfoBox(title, content = null) {
69
+ const message = content ? `${title}\n\n${chalk.white(content)}` : title;
70
+ console.log('');
71
+ console.log(boxen(wedosGradient('ℹ ') + chalk.cyan(message), {
72
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
73
+ borderStyle: 'round',
74
+ borderColor: 'cyan',
75
+ }));
76
+ }
77
+
78
+ /**
79
+ * Print warning box
80
+ */
81
+ export function printWarningBox(title, content = null) {
82
+ const message = content ? `${title}\n\n${chalk.gray(content)}` : title;
83
+ console.log('');
84
+ console.log(boxen(warningGradient('⚠ ') + chalk.yellow(message), {
85
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
86
+ borderStyle: 'round',
87
+ borderColor: 'yellow',
88
+ }));
89
+ }
90
+
91
+ /**
92
+ * Create a styled table
93
+ */
94
+ export function createTable(headers, options = {}) {
95
+ const styledHeaders = headers.map(h => chalk.cyan.bold(h));
96
+
97
+ return new Table({
98
+ head: styledHeaders,
99
+ chars: {
100
+ 'top': '─', 'top-mid': '┬', 'top-left': '╭', 'top-right': '╮',
101
+ 'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '╰', 'bottom-right': '╯',
102
+ 'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼',
103
+ 'right': '│', 'right-mid': '┤', 'middle': '│'
104
+ },
105
+ style: {
106
+ head: [],
107
+ border: ['gray'],
108
+ ...options.style
109
+ },
110
+ ...options
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Print domain availability result
116
+ */
117
+ export function printDomainCheck(domain, available, reason = null) {
118
+ const icon = available ? chalk.green('●') : chalk.red('●');
119
+ const status = available ? chalk.green.bold('VOLNÁ') : chalk.red.bold('OBSAZENÁ');
120
+ const domainStyled = chalk.white.bold(domain);
121
+
122
+ let line = ` ${icon} ${domainStyled} → ${status}`;
123
+ if (reason && !available) {
124
+ line += chalk.gray(` (${reason})`);
125
+ }
126
+ console.log(line);
127
+ }
128
+
129
+ /**
130
+ * Print key-value pair
131
+ */
132
+ export function printKeyValue(key, value, indent = 2) {
133
+ const spaces = ' '.repeat(indent);
134
+ console.log(`${spaces}${chalk.cyan(key + ':')} ${chalk.white(value || '-')}`);
135
+ }
136
+
137
+ /**
138
+ * Print section divider
139
+ */
140
+ export function printDivider(char = '─', length = 50) {
141
+ console.log(chalk.gray(char.repeat(length)));
142
+ }
143
+
144
+ /**
145
+ * Print domain info card
146
+ */
147
+ export function printDomainCard(domain) {
148
+ const statusColors = {
149
+ active: chalk.green,
150
+ expired: chalk.red,
151
+ deleted: chalk.gray,
152
+ pending: chalk.yellow,
153
+ };
154
+
155
+ const statusFn = statusColors[domain.status?.toLowerCase()] || chalk.white;
156
+ const statusIcon = domain.status?.toLowerCase() === 'active' ? '●' : '○';
157
+
158
+ const content = [
159
+ `${chalk.cyan.bold('Doména:')} ${chalk.white.bold(domain.name)}`,
160
+ `${chalk.cyan.bold('Stav:')} ${statusFn(statusIcon + ' ' + (domain.status || 'neznámý'))}`,
161
+ `${chalk.cyan.bold('Expirace:')} ${chalk.white(domain.expiration || '-')}`,
162
+ domain.owner ? `${chalk.cyan.bold('Vlastník:')} ${chalk.white(domain.owner)}` : null,
163
+ domain.nsset ? `${chalk.cyan.bold('NSSET:')} ${chalk.white(domain.nsset)}` : null,
164
+ ].filter(Boolean).join('\n');
165
+
166
+ console.log('');
167
+ console.log(boxen(content, {
168
+ padding: 1,
169
+ borderStyle: 'round',
170
+ borderColor: domain.status?.toLowerCase() === 'active' ? 'green' : 'yellow',
171
+ title: '🌐 Detail domény',
172
+ titleAlignment: 'center',
173
+ }));
174
+ }
175
+
176
+ /**
177
+ * Print DNS record row with nice formatting
178
+ */
179
+ export function formatDnsType(type) {
180
+ const typeColors = {
181
+ 'A': chalk.green,
182
+ 'AAAA': chalk.green,
183
+ 'CNAME': chalk.blue,
184
+ 'MX': chalk.magenta,
185
+ 'TXT': chalk.yellow,
186
+ 'NS': chalk.cyan,
187
+ 'SOA': chalk.gray,
188
+ 'SRV': chalk.red,
189
+ 'CAA': chalk.white,
190
+ };
191
+
192
+ const colorFn = typeColors[type?.toUpperCase()] || chalk.white;
193
+ return colorFn.bold(type || '-');
194
+ }
195
+
196
+ /**
197
+ * Print config card
198
+ */
199
+ export function printConfigCard(config) {
200
+ const content = [
201
+ `${chalk.cyan('👤 Uživatel:')} ${config.username || chalk.gray('nenastaveno')}`,
202
+ `${chalk.cyan('🔑 Heslo:')} ${config.password ? '••••••••' : chalk.gray('nenastaveno')}`,
203
+ `${chalk.cyan('🧪 Test režim:')} ${config.testMode ? chalk.yellow('AKTIVNÍ') : chalk.green('vypnutý')}`,
204
+ `${chalk.cyan('🌐 Výchozí NSSET:')} ${config.defaultNsset || 'WEDOS'}`,
205
+ `${chalk.cyan('📇 Výchozí kontakt:')} ${config.defaultContact || chalk.gray('nenastaveno')}`,
206
+ ].join('\n');
207
+
208
+ console.log('');
209
+ console.log(boxen(content, {
210
+ padding: 1,
211
+ borderStyle: 'round',
212
+ borderColor: 'cyan',
213
+ title: '⚙️ Konfigurace',
214
+ titleAlignment: 'center',
215
+ }));
216
+ }
217
+
218
+ /**
219
+ * Print API response status
220
+ */
221
+ export function printApiStatus(code, message, transactionId = null) {
222
+ const isSuccess = code >= 1000 && code < 2000;
223
+ const icon = isSuccess ? chalk.green('✓') : chalk.red('✗');
224
+ const statusColor = isSuccess ? chalk.green : chalk.red;
225
+
226
+ console.log('');
227
+ console.log(`${icon} ${statusColor.bold(message)}`);
228
+ console.log(chalk.gray(` Kód: ${code}${transactionId ? ` │ TX: ${transactionId}` : ''}`));
229
+ }
230
+
231
+ /**
232
+ * Print welcome message for config init
233
+ */
234
+ export function printWelcome() {
235
+ printBanner();
236
+
237
+ console.log(boxen(
238
+ chalk.white('Vítej v WEDOS CLI! Pro začátek potřebuji\ntvoje přihlašovací údaje k WAPI.\n\n') +
239
+ chalk.gray('💡 WAPI heslo nastavíš na:\n') +
240
+ chalk.cyan.underline(' https://client.wedos.com/client/wapi.html'),
241
+ {
242
+ padding: 1,
243
+ borderStyle: 'round',
244
+ borderColor: 'cyan',
245
+ title: '🚀 Nastavení',
246
+ titleAlignment: 'center',
247
+ }
248
+ ));
249
+ console.log('');
250
+ }
251
+
252
+ /**
253
+ * Print help footer
254
+ */
255
+ export function printHelpFooter() {
256
+ console.log('');
257
+ console.log(chalk.gray('─'.repeat(50)));
258
+ console.log(chalk.gray(' 📖 Dokumentace: ') + chalk.cyan('wedos <příkaz> --help'));
259
+ console.log(chalk.gray(' 🐛 Problémy: ') + chalk.cyan('https://github.com/...'));
260
+ console.log('');
261
+ }
262
+
263
+ export { wedosGradient, successGradient, errorGradient, warningGradient };