@ebowwa/hetzner 0.1.0 → 0.2.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/errors.js CHANGED
@@ -1,6 +1,30 @@
1
+ "use strict";
1
2
  /**
2
3
  * Hetzner Cloud API error types and utilities
3
4
  */
5
+ var __extends = (this && this.__extends) || (function () {
6
+ var extendStatics = function (d, b) {
7
+ extendStatics = Object.setPrototypeOf ||
8
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
9
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
10
+ return extendStatics(d, b);
11
+ };
12
+ return function (d, b) {
13
+ if (typeof b !== "function" && b !== null)
14
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
15
+ extendStatics(d, b);
16
+ function __() { this.constructor = d; }
17
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
18
+ };
19
+ })();
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.HetznerTimeoutError = exports.HetznerActionError = exports.HetznerServiceError = exports.HetznerConflictError = exports.HetznerInvalidInputError = exports.HetznerResourceLimitError = exports.HetznerResourceLockedError = exports.HetznerRateLimitError = exports.HetznerNotFoundError = exports.HetznerForbiddenError = exports.HetznerUnauthorizedError = exports.HetznerAPIError = exports.HetznerErrorCode = void 0;
22
+ exports.createHetznerError = createHetznerError;
23
+ exports.isRetryableError = isRetryableError;
24
+ exports.isRateLimitError = isRateLimitError;
25
+ exports.isResourceLockedError = isResourceLockedError;
26
+ exports.calculateRetryDelay = calculateRetryDelay;
27
+ exports.defaultErrorHandler = defaultErrorHandler;
4
28
  // ============================================================================
5
29
  // Error Codes
6
30
  // ============================================================================
@@ -8,7 +32,7 @@
8
32
  * Hetzner API error codes
9
33
  * @see https://docs.hetzner.cloud/#errors
10
34
  */
11
- export var HetznerErrorCode;
35
+ var HetznerErrorCode;
12
36
  (function (HetznerErrorCode) {
13
37
  // Authentication errors
14
38
  HetznerErrorCode["Unauthorized"] = "unauthorized";
@@ -40,162 +64,212 @@ export var HetznerErrorCode;
40
64
  // Certificate errors
41
65
  HetznerErrorCode["CertificateValidationFailed"] = "certificate_validation_failed";
42
66
  HetznerErrorCode["CertificatePending"] = "certificate_pending";
43
- })(HetznerErrorCode || (HetznerErrorCode = {}));
67
+ })(HetznerErrorCode || (exports.HetznerErrorCode = HetznerErrorCode = {}));
44
68
  // ============================================================================
45
69
  // Error Classes
46
70
  // ============================================================================
47
71
  /**
48
72
  * Base Hetzner API error
49
73
  */
50
- export class HetznerAPIError extends Error {
51
- code;
52
- details;
53
- constructor(message, code, details) {
54
- super(message);
55
- this.code = code;
56
- this.details = details;
57
- this.name = "HetznerAPIError";
74
+ var HetznerAPIError = /** @class */ (function (_super) {
75
+ __extends(HetznerAPIError, _super);
76
+ function HetznerAPIError(message, code, details) {
77
+ var _this = _super.call(this, message) || this;
78
+ _this.code = code;
79
+ _this.details = details;
80
+ _this.name = "HetznerAPIError";
81
+ return _this;
58
82
  }
59
- }
83
+ return HetznerAPIError;
84
+ }(Error));
85
+ exports.HetznerAPIError = HetznerAPIError;
60
86
  /**
61
87
  * Authentication error (401)
62
88
  */
63
- export class HetznerUnauthorizedError extends HetznerAPIError {
64
- constructor(message = "Unauthorized: Invalid API token") {
65
- super(message, HetznerErrorCode.Unauthorized);
66
- this.name = "HetznerUnauthorizedError";
89
+ var HetznerUnauthorizedError = /** @class */ (function (_super) {
90
+ __extends(HetznerUnauthorizedError, _super);
91
+ function HetznerUnauthorizedError(message) {
92
+ if (message === void 0) { message = "Unauthorized: Invalid API token"; }
93
+ var _this = _super.call(this, message, HetznerErrorCode.Unauthorized) || this;
94
+ _this.name = "HetznerUnauthorizedError";
95
+ return _this;
67
96
  }
68
- }
97
+ return HetznerUnauthorizedError;
98
+ }(HetznerAPIError));
99
+ exports.HetznerUnauthorizedError = HetznerUnauthorizedError;
69
100
  /**
70
101
  * Forbidden error (403)
71
102
  */
72
- export class HetznerForbiddenError extends HetznerAPIError {
73
- constructor(message = "Forbidden: Insufficient permissions") {
74
- super(message, HetznerErrorCode.Forbidden);
75
- this.name = "HetznerForbiddenError";
103
+ var HetznerForbiddenError = /** @class */ (function (_super) {
104
+ __extends(HetznerForbiddenError, _super);
105
+ function HetznerForbiddenError(message) {
106
+ if (message === void 0) { message = "Forbidden: Insufficient permissions"; }
107
+ var _this = _super.call(this, message, HetznerErrorCode.Forbidden) || this;
108
+ _this.name = "HetznerForbiddenError";
109
+ return _this;
76
110
  }
77
- }
111
+ return HetznerForbiddenError;
112
+ }(HetznerAPIError));
113
+ exports.HetznerForbiddenError = HetznerForbiddenError;
78
114
  /**
79
115
  * Resource not found error (404)
80
116
  */
81
- export class HetznerNotFoundError extends HetznerAPIError {
82
- constructor(resource, id) {
83
- super(`${resource} with ID ${id} not found`, HetznerErrorCode.NotFound, { resource, id });
84
- this.name = "HetznerNotFoundError";
117
+ var HetznerNotFoundError = /** @class */ (function (_super) {
118
+ __extends(HetznerNotFoundError, _super);
119
+ function HetznerNotFoundError(resource, id) {
120
+ var _this = _super.call(this, "".concat(resource, " with ID ").concat(id, " not found"), HetznerErrorCode.NotFound, { resource: resource, id: id }) || this;
121
+ _this.name = "HetznerNotFoundError";
122
+ return _this;
85
123
  }
86
- }
124
+ return HetznerNotFoundError;
125
+ }(HetznerAPIError));
126
+ exports.HetznerNotFoundError = HetznerNotFoundError;
87
127
  /**
88
128
  * Rate limit exceeded error (429)
89
129
  */
90
- export class HetznerRateLimitError extends HetznerAPIError {
91
- rateLimitInfo;
92
- constructor(message = "Rate limit exceeded", rateLimitInfo) {
93
- super(message, HetznerErrorCode.RateLimitExceeded, rateLimitInfo);
94
- this.rateLimitInfo = rateLimitInfo;
95
- this.name = "HetznerRateLimitError";
130
+ var HetznerRateLimitError = /** @class */ (function (_super) {
131
+ __extends(HetznerRateLimitError, _super);
132
+ function HetznerRateLimitError(message, rateLimitInfo) {
133
+ if (message === void 0) { message = "Rate limit exceeded"; }
134
+ var _this = _super.call(this, message, HetznerErrorCode.RateLimitExceeded, rateLimitInfo) || this;
135
+ _this.rateLimitInfo = rateLimitInfo;
136
+ _this.name = "HetznerRateLimitError";
137
+ return _this;
96
138
  }
97
- /**
98
- * Get the number of milliseconds until the rate limit resets
99
- */
100
- get resetInMs() {
101
- if (!this.rateLimitInfo)
102
- return 60000; // Default to 1 minute
103
- return Math.max(0, this.rateLimitInfo.reset * 1000 - Date.now());
104
- }
105
- /**
106
- * Get a human-readable reset time
107
- */
108
- get resetTime() {
109
- if (!this.rateLimitInfo)
110
- return "unknown";
111
- return new Date(this.rateLimitInfo.reset * 1000).toISOString();
112
- }
113
- }
139
+ Object.defineProperty(HetznerRateLimitError.prototype, "resetInMs", {
140
+ /**
141
+ * Get the number of milliseconds until the rate limit resets
142
+ */
143
+ get: function () {
144
+ if (!this.rateLimitInfo)
145
+ return 60000; // Default to 1 minute
146
+ return Math.max(0, this.rateLimitInfo.reset * 1000 - Date.now());
147
+ },
148
+ enumerable: false,
149
+ configurable: true
150
+ });
151
+ Object.defineProperty(HetznerRateLimitError.prototype, "resetTime", {
152
+ /**
153
+ * Get a human-readable reset time
154
+ */
155
+ get: function () {
156
+ if (!this.rateLimitInfo)
157
+ return "unknown";
158
+ return new Date(this.rateLimitInfo.reset * 1000).toISOString();
159
+ },
160
+ enumerable: false,
161
+ configurable: true
162
+ });
163
+ return HetznerRateLimitError;
164
+ }(HetznerAPIError));
165
+ exports.HetznerRateLimitError = HetznerRateLimitError;
114
166
  /**
115
167
  * Resource locked error
116
168
  */
117
- export class HetznerResourceLockedError extends HetznerAPIError {
118
- actionInProgress;
119
- constructor(resource, id, actionInProgress) {
120
- super(`${resource} ${id} is locked${actionInProgress ? ` by ${actionInProgress}` : ""}`, HetznerErrorCode.ResourceLocked, { resource, id, actionInProgress });
121
- this.actionInProgress = actionInProgress;
122
- this.name = "HetznerResourceLockedError";
169
+ var HetznerResourceLockedError = /** @class */ (function (_super) {
170
+ __extends(HetznerResourceLockedError, _super);
171
+ function HetznerResourceLockedError(resource, id, actionInProgress) {
172
+ var _this = _super.call(this, "".concat(resource, " ").concat(id, " is locked").concat(actionInProgress ? " by ".concat(actionInProgress) : ""), HetznerErrorCode.ResourceLocked, { resource: resource, id: id, actionInProgress: actionInProgress }) || this;
173
+ _this.actionInProgress = actionInProgress;
174
+ _this.name = "HetznerResourceLockedError";
175
+ return _this;
123
176
  }
124
- }
177
+ return HetznerResourceLockedError;
178
+ }(HetznerAPIError));
179
+ exports.HetznerResourceLockedError = HetznerResourceLockedError;
125
180
  /**
126
181
  * Resource limit exceeded error
127
182
  */
128
- export class HetznerResourceLimitError extends HetznerAPIError {
129
- constructor(resource, limit) {
130
- super(`Resource limit exceeded: ${resource} (limit: ${limit})`, HetznerErrorCode.ResourceLimitExceeded, { resource, limit });
131
- this.name = "HetznerResourceLimitError";
183
+ var HetznerResourceLimitError = /** @class */ (function (_super) {
184
+ __extends(HetznerResourceLimitError, _super);
185
+ function HetznerResourceLimitError(resource, limit) {
186
+ var _this = _super.call(this, "Resource limit exceeded: ".concat(resource, " (limit: ").concat(limit, ")"), HetznerErrorCode.ResourceLimitExceeded, { resource: resource, limit: limit }) || this;
187
+ _this.name = "HetznerResourceLimitError";
188
+ return _this;
132
189
  }
133
- }
190
+ return HetznerResourceLimitError;
191
+ }(HetznerAPIError));
192
+ exports.HetznerResourceLimitError = HetznerResourceLimitError;
134
193
  /**
135
194
  * Invalid input error
136
195
  */
137
- export class HetznerInvalidInputError extends HetznerAPIError {
138
- fields;
139
- constructor(message, fields) {
140
- super(message, HetznerErrorCode.InvalidInput, { fields });
141
- this.fields = fields;
142
- this.name = "HetznerInvalidInputError";
196
+ var HetznerInvalidInputError = /** @class */ (function (_super) {
197
+ __extends(HetznerInvalidInputError, _super);
198
+ function HetznerInvalidInputError(message, fields) {
199
+ var _this = _super.call(this, message, HetznerErrorCode.InvalidInput, { fields: fields }) || this;
200
+ _this.fields = fields;
201
+ _this.name = "HetznerInvalidInputError";
202
+ return _this;
143
203
  }
144
- }
204
+ return HetznerInvalidInputError;
205
+ }(HetznerAPIError));
206
+ exports.HetznerInvalidInputError = HetznerInvalidInputError;
145
207
  /**
146
208
  * Conflict error
147
209
  */
148
- export class HetznerConflictError extends HetznerAPIError {
149
- constructor(message, details) {
150
- super(message, HetznerErrorCode.Conflict, details);
151
- this.name = "HetznerConflictError";
210
+ var HetznerConflictError = /** @class */ (function (_super) {
211
+ __extends(HetznerConflictError, _super);
212
+ function HetznerConflictError(message, details) {
213
+ var _this = _super.call(this, message, HetznerErrorCode.Conflict, details) || this;
214
+ _this.name = "HetznerConflictError";
215
+ return _this;
152
216
  }
153
- }
217
+ return HetznerConflictError;
218
+ }(HetznerAPIError));
219
+ exports.HetznerConflictError = HetznerConflictError;
154
220
  /**
155
221
  * Service error (5xx)
156
222
  */
157
- export class HetznerServiceError extends HetznerAPIError {
158
- statusCode;
159
- constructor(message, statusCode) {
160
- super(message, HetznerErrorCode.ServiceError, { statusCode });
161
- this.statusCode = statusCode;
162
- this.name = "HetznerServiceError";
223
+ var HetznerServiceError = /** @class */ (function (_super) {
224
+ __extends(HetznerServiceError, _super);
225
+ function HetznerServiceError(message, statusCode) {
226
+ var _this = _super.call(this, message, HetznerErrorCode.ServiceError, { statusCode: statusCode }) || this;
227
+ _this.statusCode = statusCode;
228
+ _this.name = "HetznerServiceError";
229
+ return _this;
163
230
  }
164
- }
231
+ return HetznerServiceError;
232
+ }(HetznerAPIError));
233
+ exports.HetznerServiceError = HetznerServiceError;
165
234
  /**
166
235
  * Action failed error
167
236
  */
168
- export class HetznerActionError extends HetznerAPIError {
169
- actionError;
170
- actionId;
171
- constructor(actionError, actionId) {
172
- super(`Action ${actionId} failed: ${actionError.code} - ${actionError.message}`, actionError.code, { actionError, actionId });
173
- this.actionError = actionError;
174
- this.actionId = actionId;
175
- this.name = "HetznerActionError";
237
+ var HetznerActionError = /** @class */ (function (_super) {
238
+ __extends(HetznerActionError, _super);
239
+ function HetznerActionError(actionError, actionId) {
240
+ var _this = _super.call(this, "Action ".concat(actionId, " failed: ").concat(actionError.code, " - ").concat(actionError.message), actionError.code, { actionError: actionError, actionId: actionId }) || this;
241
+ _this.actionError = actionError;
242
+ _this.actionId = actionId;
243
+ _this.name = "HetznerActionError";
244
+ return _this;
176
245
  }
177
- }
246
+ return HetznerActionError;
247
+ }(HetznerAPIError));
248
+ exports.HetznerActionError = HetznerActionError;
178
249
  /**
179
250
  * Timeout error for action polling
180
251
  */
181
- export class HetznerTimeoutError extends HetznerAPIError {
182
- lastProgress;
183
- constructor(actionId, timeout, lastProgress) {
184
- super(`Action ${actionId} timed out after ${timeout}ms (last progress: ${lastProgress}%)`, "timeout", { actionId, timeout, lastProgress });
185
- this.lastProgress = lastProgress;
186
- this.name = "HetznerTimeoutError";
252
+ var HetznerTimeoutError = /** @class */ (function (_super) {
253
+ __extends(HetznerTimeoutError, _super);
254
+ function HetznerTimeoutError(actionId, timeout, lastProgress) {
255
+ var _this = _super.call(this, "Action ".concat(actionId, " timed out after ").concat(timeout, "ms (last progress: ").concat(lastProgress, "%)"), "timeout", { actionId: actionId, timeout: timeout, lastProgress: lastProgress }) || this;
256
+ _this.lastProgress = lastProgress;
257
+ _this.name = "HetznerTimeoutError";
258
+ return _this;
187
259
  }
188
- }
260
+ return HetznerTimeoutError;
261
+ }(HetznerAPIError));
262
+ exports.HetznerTimeoutError = HetznerTimeoutError;
189
263
  // ============================================================================
190
264
  // Error Factory
191
265
  // ============================================================================
192
266
  /**
193
267
  * Parse Hetzner API error response and create appropriate error
194
268
  */
195
- export function createHetznerError(statusCode, body) {
196
- const error = body.error;
269
+ function createHetznerError(statusCode, body) {
270
+ var error = body.error;
197
271
  if (!error) {
198
- return new HetznerServiceError(`HTTP ${statusCode}: ${JSON.stringify(body)}`, statusCode);
272
+ return new HetznerServiceError("HTTP ".concat(statusCode, ": ").concat(JSON.stringify(body)), statusCode);
199
273
  }
200
274
  switch (statusCode) {
201
275
  case 401:
@@ -226,7 +300,7 @@ export function createHetznerError(statusCode, body) {
226
300
  /**
227
301
  * Check if an error is retryable
228
302
  */
229
- export function isRetryableError(error) {
303
+ function isRetryableError(error) {
230
304
  if (error instanceof HetznerRateLimitError)
231
305
  return true;
232
306
  if (error instanceof HetznerResourceLockedError)
@@ -240,31 +314,32 @@ export function isRetryableError(error) {
240
314
  /**
241
315
  * Check if an error is a rate limit error
242
316
  */
243
- export function isRateLimitError(error) {
317
+ function isRateLimitError(error) {
244
318
  return error instanceof HetznerRateLimitError;
245
319
  }
246
320
  /**
247
321
  * Check if an error is a resource locked error
248
322
  */
249
- export function isResourceLockedError(error) {
323
+ function isResourceLockedError(error) {
250
324
  return error instanceof HetznerResourceLockedError;
251
325
  }
252
326
  /**
253
327
  * Calculate retry delay with exponential backoff
254
328
  */
255
- export function calculateRetryDelay(attempt, baseDelay = 1000, maxDelay = 60000) {
256
- const delay = baseDelay * Math.pow(2, attempt);
329
+ function calculateRetryDelay(attempt, baseDelay, maxDelay) {
330
+ if (baseDelay === void 0) { baseDelay = 1000; }
331
+ if (maxDelay === void 0) { maxDelay = 60000; }
332
+ var delay = baseDelay * Math.pow(2, attempt);
257
333
  // Add jitter (±25%)
258
- const jitter = delay * 0.25 * (Math.random() * 2 - 1);
334
+ var jitter = delay * 0.25 * (Math.random() * 2 - 1);
259
335
  return Math.min(maxDelay, delay + jitter);
260
336
  }
261
337
  /**
262
338
  * Default error handler that logs to console
263
339
  */
264
- export function defaultErrorHandler(error) {
265
- console.error(`[Hetzner API Error] ${error.name}: ${error.message}`);
340
+ function defaultErrorHandler(error) {
341
+ console.error("[Hetzner API Error] ".concat(error.name, ": ").concat(error.message));
266
342
  if (error.details) {
267
343
  console.error("Details:", error.details);
268
344
  }
269
345
  }
270
- //# sourceMappingURL=errors.js.map
package/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Hetzner Cloud API client
3
4
  * For server-side use only (requires API token)
@@ -6,23 +7,67 @@
6
7
  * - Certificate actions: https://docs.hetzner.cloud/reference/cloud#certificate-actions
7
8
  * - DNS operations
8
9
  */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
22
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.ACTION_TIMEOUTS = exports.createProgressLogger = exports.waitForRateLimitReset = exports.formatRateLimitStatus = exports.isRateLimitLow = exports.parseRateLimitHeaders = exports.waitForActionAdaptive = exports.getAdaptivePollInterval = exports.getPollInterval = exports.getActionDescription = exports.formatActionProgress = exports.isActionError = exports.isActionSuccess = exports.isActionRunning = exports.getActionTimeout = exports.batchCheckActions = exports.waitForMultipleActionsWithLimit = exports.waitForMultipleActions = exports.waitForAction = exports.HETZNER_API_BASE = exports.resolveApiToken = exports.isAuthenticated = exports.getTokenFromCLI = exports.SSHKeyOperations = exports.ActionOperations = exports.VolumeOperations = exports.ServerOperations = exports.HetznerClient = void 0;
9
26
  // Core exports
10
- export { HetznerClient } from "./client.js";
11
- export { ServerOperations } from "./servers.js";
12
- export { ActionOperations } from "./actions.js";
13
- export { SSHKeyOperations } from "./ssh-keys.js";
27
+ var client_js_1 = require("./client.js");
28
+ Object.defineProperty(exports, "HetznerClient", { enumerable: true, get: function () { return client_js_1.HetznerClient; } });
29
+ var servers_js_1 = require("./servers.js");
30
+ Object.defineProperty(exports, "ServerOperations", { enumerable: true, get: function () { return servers_js_1.ServerOperations; } });
31
+ var volumes_js_1 = require("./volumes.js");
32
+ Object.defineProperty(exports, "VolumeOperations", { enumerable: true, get: function () { return volumes_js_1.VolumeOperations; } });
33
+ var actions_js_1 = require("./actions.js");
34
+ Object.defineProperty(exports, "ActionOperations", { enumerable: true, get: function () { return actions_js_1.ActionOperations; } });
35
+ var ssh_keys_js_1 = require("./ssh-keys.js");
36
+ Object.defineProperty(exports, "SSHKeyOperations", { enumerable: true, get: function () { return ssh_keys_js_1.SSHKeyOperations; } });
14
37
  // Auth
15
- export { getTokenFromCLI, isAuthenticated, resolveApiToken } from "./auth.js";
38
+ var auth_js_1 = require("./auth.js");
39
+ Object.defineProperty(exports, "getTokenFromCLI", { enumerable: true, get: function () { return auth_js_1.getTokenFromCLI; } });
40
+ Object.defineProperty(exports, "isAuthenticated", { enumerable: true, get: function () { return auth_js_1.isAuthenticated; } });
41
+ Object.defineProperty(exports, "resolveApiToken", { enumerable: true, get: function () { return auth_js_1.resolveApiToken; } });
16
42
  // Config
17
- export { HETZNER_API_BASE } from "./config.js";
43
+ var config_js_1 = require("./config.js");
44
+ Object.defineProperty(exports, "HETZNER_API_BASE", { enumerable: true, get: function () { return config_js_1.HETZNER_API_BASE; } });
18
45
  // Types
19
- export * from "./types.js";
46
+ __exportStar(require("./types.js"), exports);
20
47
  // Schemas
21
- export * from "./schemas.js";
48
+ __exportStar(require("./schemas.js"), exports);
22
49
  // Errors
23
- export * from "./errors.js";
50
+ __exportStar(require("./errors.js"), exports);
24
51
  // Action utilities
25
- export { waitForAction, waitForMultipleActions, waitForMultipleActionsWithLimit, batchCheckActions, getActionTimeout, isActionRunning, isActionSuccess, isActionError, formatActionProgress, getActionDescription, getPollInterval, getAdaptivePollInterval, waitForActionAdaptive, parseRateLimitHeaders, isRateLimitLow, formatRateLimitStatus, waitForRateLimitReset, createProgressLogger, ACTION_TIMEOUTS, } from "./actions.js";
52
+ var actions_js_2 = require("./actions.js");
53
+ Object.defineProperty(exports, "waitForAction", { enumerable: true, get: function () { return actions_js_2.waitForAction; } });
54
+ Object.defineProperty(exports, "waitForMultipleActions", { enumerable: true, get: function () { return actions_js_2.waitForMultipleActions; } });
55
+ Object.defineProperty(exports, "waitForMultipleActionsWithLimit", { enumerable: true, get: function () { return actions_js_2.waitForMultipleActionsWithLimit; } });
56
+ Object.defineProperty(exports, "batchCheckActions", { enumerable: true, get: function () { return actions_js_2.batchCheckActions; } });
57
+ Object.defineProperty(exports, "getActionTimeout", { enumerable: true, get: function () { return actions_js_2.getActionTimeout; } });
58
+ Object.defineProperty(exports, "isActionRunning", { enumerable: true, get: function () { return actions_js_2.isActionRunning; } });
59
+ Object.defineProperty(exports, "isActionSuccess", { enumerable: true, get: function () { return actions_js_2.isActionSuccess; } });
60
+ Object.defineProperty(exports, "isActionError", { enumerable: true, get: function () { return actions_js_2.isActionError; } });
61
+ Object.defineProperty(exports, "formatActionProgress", { enumerable: true, get: function () { return actions_js_2.formatActionProgress; } });
62
+ Object.defineProperty(exports, "getActionDescription", { enumerable: true, get: function () { return actions_js_2.getActionDescription; } });
63
+ Object.defineProperty(exports, "getPollInterval", { enumerable: true, get: function () { return actions_js_2.getPollInterval; } });
64
+ Object.defineProperty(exports, "getAdaptivePollInterval", { enumerable: true, get: function () { return actions_js_2.getAdaptivePollInterval; } });
65
+ Object.defineProperty(exports, "waitForActionAdaptive", { enumerable: true, get: function () { return actions_js_2.waitForActionAdaptive; } });
66
+ Object.defineProperty(exports, "parseRateLimitHeaders", { enumerable: true, get: function () { return actions_js_2.parseRateLimitHeaders; } });
67
+ Object.defineProperty(exports, "isRateLimitLow", { enumerable: true, get: function () { return actions_js_2.isRateLimitLow; } });
68
+ Object.defineProperty(exports, "formatRateLimitStatus", { enumerable: true, get: function () { return actions_js_2.formatRateLimitStatus; } });
69
+ Object.defineProperty(exports, "waitForRateLimitReset", { enumerable: true, get: function () { return actions_js_2.waitForRateLimitReset; } });
70
+ Object.defineProperty(exports, "createProgressLogger", { enumerable: true, get: function () { return actions_js_2.createProgressLogger; } });
71
+ Object.defineProperty(exports, "ACTION_TIMEOUTS", { enumerable: true, get: function () { return actions_js_2.ACTION_TIMEOUTS; } });
26
72
  // Bootstrap security modules
27
- export * from "./bootstrap/index.js";
28
- //# sourceMappingURL=index.js.map
73
+ __exportStar(require("./bootstrap/index.js"), exports);
package/index.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  // Core exports
11
11
  export { HetznerClient } from "./client.js";
12
12
  export { ServerOperations } from "./servers.js";
13
+ export { VolumeOperations } from "./volumes.js";
13
14
  export { ActionOperations } from "./actions.js";
14
15
  export { SSHKeyOperations } from "./ssh-keys.js";
15
16
 
@@ -53,3 +54,6 @@ export {
53
54
 
54
55
  // Bootstrap security modules
55
56
  export * from "./bootstrap/index.js";
57
+
58
+ // Onboarding (Phase 2: post-boot configuration)
59
+ export * from "./onboarding/index.js";
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Doppler Onboarding
3
+ *
4
+ * Configure Doppler CLI service token on remote servers.
5
+ * This enables doppler run to inject secrets into processes.
6
+ */
7
+
8
+ import type { SSHOptions } from "@ebowwa/terminal/types";
9
+
10
+ export interface DopplerConfig {
11
+ token: string;
12
+ project?: string;
13
+ config?: string;
14
+ }
15
+
16
+ /**
17
+ * Configure Doppler on a remote server
18
+ *
19
+ * @param host - Server IP or hostname
20
+ * @param config - Doppler configuration
21
+ * @param sshOptions - SSH options
22
+ * @returns Success status
23
+ */
24
+ export async function onboardDoppler(
25
+ host: string,
26
+ config: DopplerConfig,
27
+ sshOptions: Partial<SSHOptions> = {}
28
+ ): Promise<{ success: boolean; message: string }> {
29
+ const { execSSH } = await import("@ebowwa/terminal/client");
30
+
31
+ const { token, project = "seed", config: dopplerConfig = "prd" } = config;
32
+
33
+ try {
34
+ // Step 1: Configure Doppler service token
35
+ const configureCmd = [
36
+ `doppler configure set token ${token}`,
37
+ `doppler configure set project ${project}`,
38
+ `doppler configure set config ${dopplerConfig}`,
39
+ ].join(" && ");
40
+
41
+ await execSSH(configureCmd, {
42
+ host,
43
+ user: "root",
44
+ ...sshOptions
45
+ });
46
+
47
+ // Step 2: Verify configuration by fetching a secret
48
+ const verifyCmd = `doppler secrets get --config ${dopplerConfig} --project ${project} --json 2>/dev/null | head -5`;
49
+
50
+ await execSSH(verifyCmd, {
51
+ host,
52
+ user: "root",
53
+ timeout: 10000,
54
+ ...sshOptions
55
+ });
56
+
57
+ return {
58
+ success: true,
59
+ message: `Doppler configured for project ${project}/${dopplerConfig}`
60
+ };
61
+ } catch (error) {
62
+ return {
63
+ success: false,
64
+ message: `Doppler configuration failed: ${error instanceof Error ? error.message : String(error)}`
65
+ };
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Check Doppler status on a remote server
71
+ *
72
+ * @param host - Server IP or hostname
73
+ * @param sshOptions - SSH options
74
+ * @returns Doppler status
75
+ */
76
+ export async function checkDopplerStatus(
77
+ host: string,
78
+ sshOptions: Partial<SSHOptions> = {}
79
+ ): Promise<{ configured: boolean; project?: string; config?: string; message: string }> {
80
+ const { execSSH } = await import("@ebowwa/terminal/client");
81
+
82
+ try {
83
+ // Check if doppler is configured
84
+ const checkCmd = `
85
+ doppler configure get project 2>/dev/null || echo "NOT_CONFIGURED"
86
+ doppler configure get config 2>/dev/null || echo "NOT_CONFIGURED"
87
+ `;
88
+
89
+ const result = await execSSH(checkCmd, {
90
+ host,
91
+ user: "root",
92
+ timeout: 5000,
93
+ ...sshOptions
94
+ });
95
+
96
+ const lines = result.trim().split("\n");
97
+ const project = lines[0]?.trim() || "";
98
+ const config = lines[1]?.trim() || "";
99
+
100
+ const configured = project !== "NOT_CONFIGURED" && config !== "NOT_CONFIGURED";
101
+
102
+ return {
103
+ configured,
104
+ project: configured ? project : undefined,
105
+ config: configured ? config : undefined,
106
+ message: configured
107
+ ? `Doppler configured: ${project}/${config}`
108
+ : "Doppler not configured"
109
+ };
110
+ } catch (error) {
111
+ return {
112
+ configured: false,
113
+ message: `Could not check Doppler status: ${error instanceof Error ? error.message : String(error)}`
114
+ };
115
+ }
116
+ }