hetzner-robot-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.
package/dist/client.js ADDED
@@ -0,0 +1,656 @@
1
+ // ============================================================================
2
+ // Hetzner Robot API Client
3
+ // Base URL: https://robot-ws.your-server.de
4
+ // Auth: HTTP Basic Authentication
5
+ // ============================================================================
6
+ const BASE_URL = 'https://robot-ws.your-server.de';
7
+ export class HetznerRobotClient {
8
+ auth;
9
+ constructor(username, password) {
10
+ this.auth = Buffer.from(`${username}:${password}`).toString('base64');
11
+ }
12
+ async request(endpoint, options = {}) {
13
+ const url = `${BASE_URL}${endpoint}`;
14
+ const headers = {
15
+ Authorization: `Basic ${this.auth}`,
16
+ 'Content-Type': 'application/x-www-form-urlencoded',
17
+ Accept: 'application/json',
18
+ ...options.headers,
19
+ };
20
+ const response = await fetch(url, {
21
+ ...options,
22
+ headers,
23
+ });
24
+ if (!response.ok) {
25
+ let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
26
+ try {
27
+ const errorBody = await response.json();
28
+ if (errorBody.error) {
29
+ errorMessage = `${errorBody.error.code ?? 'ERROR'}: ${errorBody.error.message ?? 'Unknown error'}`;
30
+ }
31
+ }
32
+ catch {
33
+ // Use default error message
34
+ }
35
+ throw new Error(errorMessage);
36
+ }
37
+ // Handle 204 No Content
38
+ if (response.status === 204) {
39
+ return {};
40
+ }
41
+ return response.json();
42
+ }
43
+ encodeParams(params) {
44
+ const parts = [];
45
+ for (const [key, value] of Object.entries(params)) {
46
+ if (value === undefined)
47
+ continue;
48
+ if (Array.isArray(value)) {
49
+ for (const v of value) {
50
+ parts.push(`${encodeURIComponent(key)}[]=${encodeURIComponent(v)}`);
51
+ }
52
+ }
53
+ else {
54
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
55
+ }
56
+ }
57
+ return parts.join('&');
58
+ }
59
+ buildTrafficParams(trafficWarnings, trafficHourly, trafficDaily, trafficMonthly) {
60
+ return {
61
+ traffic_warnings: trafficWarnings,
62
+ traffic_hourly: trafficHourly,
63
+ traffic_daily: trafficDaily,
64
+ traffic_monthly: trafficMonthly,
65
+ };
66
+ }
67
+ // =========================================================================
68
+ // Server Management
69
+ // =========================================================================
70
+ async listServers() {
71
+ return this.request('/server');
72
+ }
73
+ async getServer(serverIpOrNumber) {
74
+ return this.request(`/server/${serverIpOrNumber}`);
75
+ }
76
+ async updateServerName(serverIpOrNumber, name) {
77
+ return this.request(`/server/${serverIpOrNumber}`, {
78
+ method: 'POST',
79
+ body: this.encodeParams({ server_name: name }),
80
+ });
81
+ }
82
+ // =========================================================================
83
+ // Cancellation
84
+ // =========================================================================
85
+ async getCancellation(serverIpOrNumber) {
86
+ return this.request(`/server/${serverIpOrNumber}/cancellation`);
87
+ }
88
+ async cancelServer(serverIpOrNumber, cancellationDate, cancellationReason) {
89
+ const params = {};
90
+ if (cancellationDate)
91
+ params.cancellation_date = cancellationDate;
92
+ if (cancellationReason)
93
+ params.cancellation_reason = cancellationReason;
94
+ return this.request(`/server/${serverIpOrNumber}/cancellation`, {
95
+ method: 'POST',
96
+ body: this.encodeParams(params),
97
+ });
98
+ }
99
+ async revokeCancellation(serverIpOrNumber) {
100
+ await this.request(`/server/${serverIpOrNumber}/cancellation`, {
101
+ method: 'DELETE',
102
+ });
103
+ }
104
+ // =========================================================================
105
+ // Reset
106
+ // =========================================================================
107
+ async listResetOptions() {
108
+ return this.request('/reset');
109
+ }
110
+ async getResetOptions(serverIpOrNumber) {
111
+ return this.request(`/reset/${serverIpOrNumber}`);
112
+ }
113
+ async resetServer(serverIpOrNumber, type = 'sw') {
114
+ return this.request(`/reset/${serverIpOrNumber}`, {
115
+ method: 'POST',
116
+ body: this.encodeParams({ type }),
117
+ });
118
+ }
119
+ // =========================================================================
120
+ // Boot Configuration
121
+ // =========================================================================
122
+ async getBootConfig(serverIpOrNumber) {
123
+ return this.request(`/boot/${serverIpOrNumber}`);
124
+ }
125
+ // Rescue System
126
+ async getRescue(serverIpOrNumber) {
127
+ return this.request(`/boot/${serverIpOrNumber}/rescue`);
128
+ }
129
+ async activateRescue(serverIpOrNumber, os, arch, authorizedKeys) {
130
+ const params = { os };
131
+ if (arch)
132
+ params.arch = arch;
133
+ if (authorizedKeys)
134
+ params.authorized_key = authorizedKeys;
135
+ return this.request(`/boot/${serverIpOrNumber}/rescue`, {
136
+ method: 'POST',
137
+ body: this.encodeParams(params),
138
+ });
139
+ }
140
+ async deactivateRescue(serverIpOrNumber) {
141
+ return this.request(`/boot/${serverIpOrNumber}/rescue`, {
142
+ method: 'DELETE',
143
+ });
144
+ }
145
+ async getLastRescue(serverIpOrNumber) {
146
+ return this.request(`/boot/${serverIpOrNumber}/rescue/last`);
147
+ }
148
+ // Linux Install
149
+ async getLinux(serverIpOrNumber) {
150
+ return this.request(`/boot/${serverIpOrNumber}/linux`);
151
+ }
152
+ async activateLinux(serverIpOrNumber, dist, arch, lang, authorizedKeys) {
153
+ const params = { dist };
154
+ if (arch)
155
+ params.arch = arch;
156
+ if (lang)
157
+ params.lang = lang;
158
+ if (authorizedKeys)
159
+ params.authorized_key = authorizedKeys;
160
+ return this.request(`/boot/${serverIpOrNumber}/linux`, {
161
+ method: 'POST',
162
+ body: this.encodeParams(params),
163
+ });
164
+ }
165
+ async deactivateLinux(serverIpOrNumber) {
166
+ return this.request(`/boot/${serverIpOrNumber}/linux`, {
167
+ method: 'DELETE',
168
+ });
169
+ }
170
+ async getLastLinux(serverIpOrNumber) {
171
+ return this.request(`/boot/${serverIpOrNumber}/linux/last`);
172
+ }
173
+ // VNC Install
174
+ async getVnc(serverIpOrNumber) {
175
+ return this.request(`/boot/${serverIpOrNumber}/vnc`);
176
+ }
177
+ async activateVnc(serverIpOrNumber, dist, arch, lang) {
178
+ const params = { dist };
179
+ if (arch)
180
+ params.arch = arch;
181
+ if (lang)
182
+ params.lang = lang;
183
+ return this.request(`/boot/${serverIpOrNumber}/vnc`, {
184
+ method: 'POST',
185
+ body: this.encodeParams(params),
186
+ });
187
+ }
188
+ async deactivateVnc(serverIpOrNumber) {
189
+ return this.request(`/boot/${serverIpOrNumber}/vnc`, {
190
+ method: 'DELETE',
191
+ });
192
+ }
193
+ // Windows Install
194
+ async getWindows(serverIpOrNumber) {
195
+ return this.request(`/boot/${serverIpOrNumber}/windows`);
196
+ }
197
+ async activateWindows(serverIpOrNumber, dist, lang) {
198
+ const params = { dist };
199
+ if (lang)
200
+ params.lang = lang;
201
+ return this.request(`/boot/${serverIpOrNumber}/windows`, {
202
+ method: 'POST',
203
+ body: this.encodeParams(params),
204
+ });
205
+ }
206
+ async deactivateWindows(serverIpOrNumber) {
207
+ return this.request(`/boot/${serverIpOrNumber}/windows`, {
208
+ method: 'DELETE',
209
+ });
210
+ }
211
+ // =========================================================================
212
+ // IP Management
213
+ // =========================================================================
214
+ async listIps() {
215
+ return this.request('/ip');
216
+ }
217
+ async getIp(ip) {
218
+ return this.request(`/ip/${ip}`);
219
+ }
220
+ async updateIp(ip, trafficWarnings, trafficHourly, trafficDaily, trafficMonthly) {
221
+ return this.request(`/ip/${ip}`, {
222
+ method: 'POST',
223
+ body: this.encodeParams(this.buildTrafficParams(trafficWarnings, trafficHourly, trafficDaily, trafficMonthly)),
224
+ });
225
+ }
226
+ async getIpMac(ip) {
227
+ return this.request(`/ip/${ip}/mac`);
228
+ }
229
+ async generateIpMac(ip) {
230
+ return this.request(`/ip/${ip}/mac`, {
231
+ method: 'PUT',
232
+ });
233
+ }
234
+ async deleteIpMac(ip) {
235
+ await this.request(`/ip/${ip}/mac`, {
236
+ method: 'DELETE',
237
+ });
238
+ }
239
+ // =========================================================================
240
+ // Subnet Management
241
+ // =========================================================================
242
+ async listSubnets() {
243
+ return this.request('/subnet');
244
+ }
245
+ async getSubnet(netIp) {
246
+ return this.request(`/subnet/${netIp}`);
247
+ }
248
+ async updateSubnet(netIp, trafficWarnings, trafficHourly, trafficDaily, trafficMonthly) {
249
+ return this.request(`/subnet/${netIp}`, {
250
+ method: 'POST',
251
+ body: this.encodeParams(this.buildTrafficParams(trafficWarnings, trafficHourly, trafficDaily, trafficMonthly)),
252
+ });
253
+ }
254
+ async getSubnetMac(netIp) {
255
+ return this.request(`/subnet/${netIp}/mac`);
256
+ }
257
+ async generateSubnetMac(netIp) {
258
+ return this.request(`/subnet/${netIp}/mac`, {
259
+ method: 'PUT',
260
+ });
261
+ }
262
+ async deleteSubnetMac(netIp) {
263
+ await this.request(`/subnet/${netIp}/mac`, {
264
+ method: 'DELETE',
265
+ });
266
+ }
267
+ // =========================================================================
268
+ // Failover
269
+ // =========================================================================
270
+ async listFailovers() {
271
+ return this.request('/failover');
272
+ }
273
+ async getFailover(failoverIp) {
274
+ return this.request(`/failover/${failoverIp}`);
275
+ }
276
+ async switchFailover(failoverIp, activeServerIp) {
277
+ return this.request(`/failover/${failoverIp}`, {
278
+ method: 'POST',
279
+ body: this.encodeParams({ active_server_ip: activeServerIp }),
280
+ });
281
+ }
282
+ async deleteFailoverRouting(failoverIp) {
283
+ await this.request(`/failover/${failoverIp}`, {
284
+ method: 'DELETE',
285
+ });
286
+ }
287
+ // =========================================================================
288
+ // Reverse DNS
289
+ // =========================================================================
290
+ async listRdns() {
291
+ return this.request('/rdns');
292
+ }
293
+ async getRdns(ip) {
294
+ return this.request(`/rdns/${ip}`);
295
+ }
296
+ async createRdns(ip, ptr) {
297
+ return this.request(`/rdns/${ip}`, {
298
+ method: 'PUT',
299
+ body: this.encodeParams({ ptr }),
300
+ });
301
+ }
302
+ async updateRdns(ip, ptr) {
303
+ return this.request(`/rdns/${ip}`, {
304
+ method: 'POST',
305
+ body: this.encodeParams({ ptr }),
306
+ });
307
+ }
308
+ async deleteRdns(ip) {
309
+ await this.request(`/rdns/${ip}`, {
310
+ method: 'DELETE',
311
+ });
312
+ }
313
+ // =========================================================================
314
+ // SSH Keys
315
+ // =========================================================================
316
+ async listSshKeys() {
317
+ return this.request('/key');
318
+ }
319
+ async getSshKey(fingerprint) {
320
+ return this.request(`/key/${fingerprint}`);
321
+ }
322
+ async createSshKey(name, data) {
323
+ return this.request('/key', {
324
+ method: 'POST',
325
+ body: this.encodeParams({ name, data }),
326
+ });
327
+ }
328
+ async updateSshKey(fingerprint, name) {
329
+ return this.request(`/key/${fingerprint}`, {
330
+ method: 'POST',
331
+ body: this.encodeParams({ name }),
332
+ });
333
+ }
334
+ async deleteSshKey(fingerprint) {
335
+ await this.request(`/key/${fingerprint}`, {
336
+ method: 'DELETE',
337
+ });
338
+ }
339
+ // =========================================================================
340
+ // Firewall
341
+ // =========================================================================
342
+ async getFirewall(serverIpOrNumber) {
343
+ return this.request(`/firewall/${serverIpOrNumber}`);
344
+ }
345
+ async updateFirewall(serverIpOrNumber, status, rules) {
346
+ const params = { status };
347
+ if (rules) {
348
+ params['rules[input]'] = JSON.stringify(rules.input);
349
+ }
350
+ return this.request(`/firewall/${serverIpOrNumber}`, {
351
+ method: 'POST',
352
+ body: this.encodeParams(params),
353
+ });
354
+ }
355
+ async deleteFirewall(serverIpOrNumber) {
356
+ await this.request(`/firewall/${serverIpOrNumber}`, {
357
+ method: 'DELETE',
358
+ });
359
+ }
360
+ // Firewall Templates
361
+ async listFirewallTemplates() {
362
+ return this.request('/firewall/template');
363
+ }
364
+ async getFirewallTemplate(templateId) {
365
+ return this.request(`/firewall/template/${templateId}`);
366
+ }
367
+ async createFirewallTemplate(name, filterIpv6, whitelistHos, isDefault, rules) {
368
+ const params = { name };
369
+ if (filterIpv6 !== undefined)
370
+ params.filter_ipv6 = filterIpv6;
371
+ if (whitelistHos !== undefined)
372
+ params.whitelist_hos = whitelistHos;
373
+ if (isDefault !== undefined)
374
+ params.is_default = isDefault;
375
+ if (rules)
376
+ params['rules[input]'] = JSON.stringify(rules.input);
377
+ return this.request('/firewall/template', {
378
+ method: 'POST',
379
+ body: this.encodeParams(params),
380
+ });
381
+ }
382
+ async updateFirewallTemplate(templateId, name, filterIpv6, whitelistHos, isDefault, rules) {
383
+ const params = {};
384
+ if (name)
385
+ params.name = name;
386
+ if (filterIpv6 !== undefined)
387
+ params.filter_ipv6 = filterIpv6;
388
+ if (whitelistHos !== undefined)
389
+ params.whitelist_hos = whitelistHos;
390
+ if (isDefault !== undefined)
391
+ params.is_default = isDefault;
392
+ if (rules)
393
+ params['rules[input]'] = JSON.stringify(rules.input);
394
+ return this.request(`/firewall/template/${templateId}`, {
395
+ method: 'POST',
396
+ body: this.encodeParams(params),
397
+ });
398
+ }
399
+ async deleteFirewallTemplate(templateId) {
400
+ await this.request(`/firewall/template/${templateId}`, {
401
+ method: 'DELETE',
402
+ });
403
+ }
404
+ // =========================================================================
405
+ // vSwitch
406
+ // =========================================================================
407
+ async listVSwitches() {
408
+ return this.request('/vswitch');
409
+ }
410
+ async getVSwitch(id) {
411
+ return this.request(`/vswitch/${id}`);
412
+ }
413
+ async createVSwitch(name, vlan) {
414
+ return this.request('/vswitch', {
415
+ method: 'POST',
416
+ body: this.encodeParams({ name, vlan }),
417
+ });
418
+ }
419
+ async updateVSwitch(id, name, vlan) {
420
+ const params = {};
421
+ if (name)
422
+ params.name = name;
423
+ if (vlan !== undefined)
424
+ params.vlan = vlan;
425
+ return this.request(`/vswitch/${id}`, {
426
+ method: 'POST',
427
+ body: this.encodeParams(params),
428
+ });
429
+ }
430
+ async deleteVSwitch(id, cancellationDate) {
431
+ const params = {};
432
+ if (cancellationDate)
433
+ params.cancellation_date = cancellationDate;
434
+ await this.request(`/vswitch/${id}`, {
435
+ method: 'DELETE',
436
+ body: this.encodeParams(params),
437
+ });
438
+ }
439
+ async addServerToVSwitch(vswitchId, serverIpOrNumber) {
440
+ return this.request(`/vswitch/${vswitchId}/server`, {
441
+ method: 'POST',
442
+ body: this.encodeParams({ server: String(serverIpOrNumber) }),
443
+ });
444
+ }
445
+ async removeServerFromVSwitch(vswitchId, serverIpOrNumber) {
446
+ await this.request(`/vswitch/${vswitchId}/server`, {
447
+ method: 'DELETE',
448
+ body: this.encodeParams({ server: String(serverIpOrNumber) }),
449
+ });
450
+ }
451
+ // =========================================================================
452
+ // Storage Box
453
+ // =========================================================================
454
+ async listStorageBoxes() {
455
+ return this.request('/storagebox');
456
+ }
457
+ async getStorageBox(id) {
458
+ return this.request(`/storagebox/${id}`);
459
+ }
460
+ async updateStorageBox(id, name, webdav, samba, ssh, externalReachability, zfs) {
461
+ const params = {};
462
+ if (name)
463
+ params.storagebox_name = name;
464
+ if (webdav !== undefined)
465
+ params.webdav = webdav;
466
+ if (samba !== undefined)
467
+ params.samba = samba;
468
+ if (ssh !== undefined)
469
+ params.ssh = ssh;
470
+ if (externalReachability !== undefined)
471
+ params.external_reachability = externalReachability;
472
+ if (zfs !== undefined)
473
+ params.zfs = zfs;
474
+ return this.request(`/storagebox/${id}`, {
475
+ method: 'POST',
476
+ body: this.encodeParams(params),
477
+ });
478
+ }
479
+ async resetStorageBoxPassword(id) {
480
+ return this.request(`/storagebox/${id}/password`, {
481
+ method: 'POST',
482
+ });
483
+ }
484
+ // Snapshots
485
+ async listStorageBoxSnapshots(id) {
486
+ return this.request(`/storagebox/${id}/snapshot`);
487
+ }
488
+ async createStorageBoxSnapshot(id) {
489
+ return this.request(`/storagebox/${id}/snapshot`, {
490
+ method: 'POST',
491
+ });
492
+ }
493
+ async deleteStorageBoxSnapshot(id, snapshotName) {
494
+ await this.request(`/storagebox/${id}/snapshot/${snapshotName}`, {
495
+ method: 'DELETE',
496
+ });
497
+ }
498
+ async revertStorageBoxSnapshot(id, snapshotName) {
499
+ await this.request(`/storagebox/${id}/snapshot/${snapshotName}/revert`, {
500
+ method: 'POST',
501
+ });
502
+ }
503
+ // Snapshot Plan
504
+ async getStorageBoxSnapshotPlan(id) {
505
+ return this.request(`/storagebox/${id}/snapshotplan`);
506
+ }
507
+ async updateStorageBoxSnapshotPlan(id, status, minute, hour, dayOfWeek, dayOfMonth, maxSnapshots) {
508
+ const params = { status };
509
+ if (minute !== undefined)
510
+ params.minute = minute;
511
+ if (hour !== undefined)
512
+ params.hour = hour;
513
+ if (dayOfWeek !== undefined)
514
+ params.day_of_week = dayOfWeek;
515
+ if (dayOfMonth !== undefined)
516
+ params.day_of_month = dayOfMonth;
517
+ if (maxSnapshots !== undefined)
518
+ params.max_snapshots = maxSnapshots;
519
+ return this.request(`/storagebox/${id}/snapshotplan`, {
520
+ method: 'POST',
521
+ body: this.encodeParams(params),
522
+ });
523
+ }
524
+ // Subaccounts
525
+ async listStorageBoxSubaccounts(id) {
526
+ return this.request(`/storagebox/${id}/subaccount`);
527
+ }
528
+ async createStorageBoxSubaccount(id, homedirectory, samba, ssh, externalReachability, webdav, readonly, comment) {
529
+ const params = { homedirectory };
530
+ if (samba !== undefined)
531
+ params.samba = samba;
532
+ if (ssh !== undefined)
533
+ params.ssh = ssh;
534
+ if (externalReachability !== undefined)
535
+ params.external_reachability = externalReachability;
536
+ if (webdav !== undefined)
537
+ params.webdav = webdav;
538
+ if (readonly !== undefined)
539
+ params.readonly = readonly;
540
+ if (comment)
541
+ params.comment = comment;
542
+ return this.request(`/storagebox/${id}/subaccount`, {
543
+ method: 'POST',
544
+ body: this.encodeParams(params),
545
+ });
546
+ }
547
+ async updateStorageBoxSubaccount(id, username, samba, ssh, externalReachability, webdav, readonly, comment) {
548
+ const params = {};
549
+ if (samba !== undefined)
550
+ params.samba = samba;
551
+ if (ssh !== undefined)
552
+ params.ssh = ssh;
553
+ if (externalReachability !== undefined)
554
+ params.external_reachability = externalReachability;
555
+ if (webdav !== undefined)
556
+ params.webdav = webdav;
557
+ if (readonly !== undefined)
558
+ params.readonly = readonly;
559
+ if (comment !== undefined)
560
+ params.comment = comment;
561
+ return this.request(`/storagebox/${id}/subaccount/${username}`, {
562
+ method: 'PUT',
563
+ body: this.encodeParams(params),
564
+ });
565
+ }
566
+ async deleteStorageBoxSubaccount(id, username) {
567
+ await this.request(`/storagebox/${id}/subaccount/${username}`, {
568
+ method: 'DELETE',
569
+ });
570
+ }
571
+ async resetStorageBoxSubaccountPassword(id, username) {
572
+ return this.request(`/storagebox/${id}/subaccount/${username}/password`, {
573
+ method: 'POST',
574
+ });
575
+ }
576
+ // =========================================================================
577
+ // Traffic
578
+ // =========================================================================
579
+ async getTraffic(ips, subnets, from, to, type = 'month') {
580
+ const params = {
581
+ type,
582
+ from,
583
+ to,
584
+ };
585
+ if (ips.length > 0)
586
+ params.ip = ips;
587
+ if (subnets.length > 0)
588
+ params.subnet = subnets;
589
+ return this.request('/traffic', {
590
+ method: 'POST',
591
+ body: this.encodeParams(params),
592
+ });
593
+ }
594
+ // =========================================================================
595
+ // Wake on LAN
596
+ // =========================================================================
597
+ async getWol(serverIpOrNumber) {
598
+ return this.request(`/wol/${serverIpOrNumber}`);
599
+ }
600
+ async sendWol(serverIpOrNumber) {
601
+ return this.request(`/wol/${serverIpOrNumber}`, {
602
+ method: 'POST',
603
+ });
604
+ }
605
+ // =========================================================================
606
+ // Server Ordering
607
+ // =========================================================================
608
+ async listServerProducts() {
609
+ return this.request('/order/server/product');
610
+ }
611
+ async listServerMarketProducts() {
612
+ return this.request('/order/server_market/product');
613
+ }
614
+ async listServerTransactions() {
615
+ return this.request('/order/server/transaction');
616
+ }
617
+ async getServerTransaction(transactionId) {
618
+ return this.request(`/order/server/transaction/${transactionId}`);
619
+ }
620
+ async orderServer(productId, authorizedKeys, password, dist, arch, lang, location, addons, test) {
621
+ const params = this.buildOrderParams(productId, authorizedKeys, password, dist, arch, lang, addons, test);
622
+ if (location)
623
+ params.location = location;
624
+ return this.request('/order/server/transaction', {
625
+ method: 'POST',
626
+ body: this.encodeParams(params),
627
+ });
628
+ }
629
+ async orderServerMarket(productId, authorizedKeys, password, dist, arch, lang, addons, test) {
630
+ const params = this.buildOrderParams(productId, authorizedKeys, password, dist, arch, lang, addons, test);
631
+ return this.request('/order/server_market/transaction', {
632
+ method: 'POST',
633
+ body: this.encodeParams(params),
634
+ });
635
+ }
636
+ buildOrderParams(productId, authorizedKeys, password, dist, arch, lang, addons, test) {
637
+ const params = {
638
+ product_id: productId,
639
+ };
640
+ if (authorizedKeys)
641
+ params.authorized_key = authorizedKeys;
642
+ if (password)
643
+ params.password = password;
644
+ if (dist)
645
+ params.dist = dist;
646
+ if (arch)
647
+ params.arch = arch;
648
+ if (lang)
649
+ params.lang = lang;
650
+ if (addons)
651
+ params.addon = addons;
652
+ if (test !== undefined)
653
+ params.test = test;
654
+ return params;
655
+ }
656
+ }
@@ -0,0 +1,41 @@
1
+ export interface Config {
2
+ user?: string;
3
+ password?: string;
4
+ }
5
+ /**
6
+ * Load configuration from file
7
+ */
8
+ export declare function loadConfig(): Config;
9
+ /**
10
+ * Save configuration to file
11
+ */
12
+ export declare function saveConfig(cfg: Config): void;
13
+ /**
14
+ * Clear saved configuration
15
+ */
16
+ export declare function clearConfig(): void;
17
+ /**
18
+ * Get credentials from environment variables, config file, or prompt
19
+ */
20
+ export declare function getCredentials(): {
21
+ user: string;
22
+ password: string;
23
+ } | null;
24
+ /**
25
+ * Check if credentials are configured
26
+ */
27
+ export declare function hasCredentials(): boolean;
28
+ /**
29
+ * Interactive login prompt
30
+ */
31
+ export declare function promptLogin(): Promise<{
32
+ user: string;
33
+ password: string;
34
+ }>;
35
+ /**
36
+ * Get credentials, prompting if necessary
37
+ */
38
+ export declare function requireCredentials(): Promise<{
39
+ user: string;
40
+ password: string;
41
+ }>;