cyberdesk 2.2.4 → 2.2.5

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/index.d.ts CHANGED
@@ -29,20 +29,38 @@ import { type MachineResponse, type MachinePoolUpdate, type PoolResponse, type P
29
29
  export * from './client/types.gen';
30
30
  export * from './client/sdk.gen';
31
31
  export * from './client/client.gen';
32
+ /**
33
+ * Client options for configuring retry behavior and other settings
34
+ */
35
+ export interface CyberdeskClientOptions {
36
+ /** Maximum number of retry attempts (default: 2, meaning 3 total attempts) */
37
+ maxRetries?: number;
38
+ /** Custom fetch implementation (for testing or advanced use cases) */
39
+ fetch?: typeof fetch;
40
+ }
32
41
  /**
33
42
  * Create a Cyberdesk API client
34
43
  *
35
44
  * @param apiKey - Your Cyberdesk API key
36
45
  * @param baseUrl - Optional API base URL (defaults to https://api.cyberdesk.io)
46
+ * @param options - Optional client configuration
47
+ * @param options.maxRetries - Maximum retry attempts for failed requests (default: 2)
37
48
  * @returns Configured client with all API endpoints
38
49
  *
39
50
  * @example
40
51
  * ```typescript
52
+ * // Basic usage
41
53
  * const client = createCyberdeskClient('your-api-key');
42
54
  * const machines = await client.machines.list();
55
+ *
56
+ * // With custom retry configuration
57
+ * const client = createCyberdeskClient('your-api-key', undefined, { maxRetries: 3 });
58
+ *
59
+ * // Disable retries
60
+ * const client = createCyberdeskClient('your-api-key', undefined, { maxRetries: 0 });
43
61
  * ```
44
62
  */
45
- export declare function createCyberdeskClient(apiKey: string, baseUrl?: string): {
63
+ export declare function createCyberdeskClient(apiKey: string, baseUrl?: string, options?: CyberdeskClientOptions): {
46
64
  machines: {
47
65
  /**
48
66
  * List machines with optional filtering
package/dist/index.js CHANGED
@@ -52,6 +52,146 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
52
52
  Object.defineProperty(exports, "__esModule", { value: true });
53
53
  exports.createCyberdeskClient = createCyberdeskClient;
54
54
  const client_fetch_1 = require("@hey-api/client-fetch");
55
+ // ============================================================================
56
+ // Retry Configuration (Stripe SDK-style)
57
+ // ============================================================================
58
+ /** Default number of retry attempts (2 retries = 3 total attempts, like Stripe) */
59
+ const DEFAULT_MAX_RETRIES = 2;
60
+ /** Initial retry delay in milliseconds */
61
+ const INITIAL_RETRY_DELAY_MS = 500;
62
+ /** Maximum retry delay in milliseconds */
63
+ const MAX_RETRY_DELAY_MS = 5000;
64
+ /** HTTP status codes that should trigger a retry */
65
+ const RETRYABLE_STATUS_CODES = new Set([
66
+ 408, // Request Timeout
67
+ 409, // Conflict (can be retried with idempotency)
68
+ 429, // Too Many Requests
69
+ 500, // Internal Server Error
70
+ 502, // Bad Gateway
71
+ 503, // Service Unavailable
72
+ 504, // Gateway Timeout
73
+ ]);
74
+ /**
75
+ * Determines if an error is a retryable network error
76
+ */
77
+ function isNetworkError(error) {
78
+ if (error instanceof TypeError) {
79
+ const message = error.message.toLowerCase();
80
+ return (message.includes('fetch') ||
81
+ message.includes('network') ||
82
+ message.includes('failed') ||
83
+ message.includes('aborted') ||
84
+ message.includes('timeout'));
85
+ }
86
+ // Handle AbortError
87
+ if (error instanceof DOMException && error.name === 'AbortError') {
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+ /**
93
+ * Determines if a response status code should trigger a retry
94
+ */
95
+ function shouldRetryResponse(response) {
96
+ return RETRYABLE_STATUS_CODES.has(response.status);
97
+ }
98
+ /**
99
+ * Calculate delay for exponential backoff with full jitter (Stripe-style)
100
+ *
101
+ * Formula: min(cap, random(0, base * 2^attempt))
102
+ * This provides better distribution than adding jitter to exponential backoff
103
+ */
104
+ function calculateRetryDelay(attempt, retryAfterMs) {
105
+ if (retryAfterMs && retryAfterMs > 0) {
106
+ // Respect server's Retry-After header, but cap it
107
+ return Math.min(retryAfterMs, MAX_RETRY_DELAY_MS);
108
+ }
109
+ // Full jitter exponential backoff
110
+ const exponentialDelay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attempt);
111
+ const maxDelay = Math.min(exponentialDelay, MAX_RETRY_DELAY_MS);
112
+ return Math.random() * maxDelay;
113
+ }
114
+ /**
115
+ * Parse Retry-After header value to milliseconds
116
+ */
117
+ function parseRetryAfter(response) {
118
+ const retryAfter = response.headers.get('Retry-After');
119
+ if (!retryAfter)
120
+ return undefined;
121
+ // Try parsing as seconds (integer)
122
+ const seconds = parseInt(retryAfter, 10);
123
+ if (!isNaN(seconds)) {
124
+ return seconds * 1000;
125
+ }
126
+ // Try parsing as HTTP date
127
+ const date = Date.parse(retryAfter);
128
+ if (!isNaN(date)) {
129
+ return Math.max(0, date - Date.now());
130
+ }
131
+ return undefined;
132
+ }
133
+ /**
134
+ * Sleep for a specified duration
135
+ */
136
+ function sleep(ms) {
137
+ return new Promise(resolve => setTimeout(resolve, ms));
138
+ }
139
+ /**
140
+ * Creates a fetch wrapper with automatic retry logic
141
+ *
142
+ * Implements Stripe-style retry behavior:
143
+ * - Retries on network errors (connection failures, timeouts)
144
+ * - Retries on 5xx server errors and 429 (rate limit)
145
+ * - Does NOT retry on 4xx client errors (except 408, 409, 429)
146
+ * - Uses exponential backoff with full jitter
147
+ * - Respects Retry-After headers
148
+ */
149
+ function createRetryFetch(maxRetries = DEFAULT_MAX_RETRIES) {
150
+ return function retryFetch(input, init) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ let lastError;
153
+ let lastResponse;
154
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
155
+ try {
156
+ // Use globalThis.fetch directly bound to avoid "Illegal invocation"
157
+ const response = yield globalThis.fetch(input, init);
158
+ // Success - return immediately
159
+ if (!shouldRetryResponse(response)) {
160
+ return response;
161
+ }
162
+ // Store response for potential retry
163
+ lastResponse = response;
164
+ // Don't retry on last attempt
165
+ if (attempt === maxRetries) {
166
+ return response;
167
+ }
168
+ // Calculate delay with Retry-After header support
169
+ const retryAfterMs = parseRetryAfter(response);
170
+ const delay = calculateRetryDelay(attempt, retryAfterMs);
171
+ yield sleep(delay);
172
+ }
173
+ catch (error) {
174
+ lastError = error;
175
+ // Only retry on network errors
176
+ if (!isNetworkError(error)) {
177
+ throw error;
178
+ }
179
+ // Don't retry on last attempt
180
+ if (attempt === maxRetries) {
181
+ throw error;
182
+ }
183
+ const delay = calculateRetryDelay(attempt);
184
+ yield sleep(delay);
185
+ }
186
+ }
187
+ // This should never be reached, but TypeScript needs it
188
+ if (lastResponse) {
189
+ return lastResponse;
190
+ }
191
+ throw lastError;
192
+ });
193
+ };
194
+ }
55
195
  // Import SDK methods from sdk.gen
56
196
  const sdk_gen_1 = require("./client/sdk.gen");
57
197
  // Export all generated types and methods for direct use
@@ -62,14 +202,18 @@ __exportStar(require("./client/client.gen"), exports);
62
202
  /** Default API base URL for Cyberdesk Cloud API */
63
203
  const DEFAULT_API_BASE_URL = "https://api.cyberdesk.io";
64
204
  /**
65
- * Create a configured HTTP client with authentication
205
+ * Create a configured HTTP client with authentication and automatic retries
66
206
  *
67
207
  * @internal
68
208
  * @param apiKey - Your Cyberdesk API key
69
209
  * @param baseUrl - API base URL
70
- * @returns Configured HTTP client
210
+ * @param options - Client configuration options
211
+ * @returns Configured HTTP client with retry logic
71
212
  */
72
- function createApiClient(apiKey, baseUrl = DEFAULT_API_BASE_URL) {
213
+ function createApiClient(apiKey, baseUrl = DEFAULT_API_BASE_URL, options = {}) {
214
+ const { maxRetries = DEFAULT_MAX_RETRIES, fetch: customFetch } = options;
215
+ // Use custom fetch if provided, otherwise create retry-enabled fetch
216
+ const fetchWithRetry = customFetch !== null && customFetch !== void 0 ? customFetch : createRetryFetch(maxRetries);
73
217
  return (0, client_fetch_1.createClient)({
74
218
  baseUrl,
75
219
  headers: {
@@ -77,6 +221,7 @@ function createApiClient(apiKey, baseUrl = DEFAULT_API_BASE_URL) {
77
221
  'Authorization': `Bearer ${apiKey}`,
78
222
  'Connection': 'keep-alive',
79
223
  },
224
+ fetch: fetchWithRetry,
80
225
  });
81
226
  }
82
227
  // Helpers
@@ -90,16 +235,25 @@ function toIsoUtc(value) {
90
235
  *
91
236
  * @param apiKey - Your Cyberdesk API key
92
237
  * @param baseUrl - Optional API base URL (defaults to https://api.cyberdesk.io)
238
+ * @param options - Optional client configuration
239
+ * @param options.maxRetries - Maximum retry attempts for failed requests (default: 2)
93
240
  * @returns Configured client with all API endpoints
94
241
  *
95
242
  * @example
96
243
  * ```typescript
244
+ * // Basic usage
97
245
  * const client = createCyberdeskClient('your-api-key');
98
246
  * const machines = await client.machines.list();
247
+ *
248
+ * // With custom retry configuration
249
+ * const client = createCyberdeskClient('your-api-key', undefined, { maxRetries: 3 });
250
+ *
251
+ * // Disable retries
252
+ * const client = createCyberdeskClient('your-api-key', undefined, { maxRetries: 0 });
99
253
  * ```
100
254
  */
101
- function createCyberdeskClient(apiKey, baseUrl) {
102
- const client = createApiClient(apiKey, baseUrl);
255
+ function createCyberdeskClient(apiKey, baseUrl, options) {
256
+ const client = createApiClient(apiKey, baseUrl, options);
103
257
  return {
104
258
  // Machine endpoints
105
259
  machines: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberdesk",
3
- "version": "2.2.4",
3
+ "version": "2.2.5",
4
4
  "description": "The official TypeScript SDK for Cyberdesk",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",