opencode-puter-auth 1.0.39 → 1.0.42

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/README.md CHANGED
@@ -366,6 +366,9 @@ Create `~/.config/opencode/puter.json` for advanced settings:
366
366
  | `fallback_enabled` | `true` | Enable automatic model fallback on rate limits |
367
367
  | `fallback_models` | See below | Custom list of fallback models |
368
368
  | `fallback_cooldown_ms` | `60000` | Cooldown period for rate-limited models (1 min) |
369
+ | `account_rotation_enabled` | `true` | Enable automatic account rotation |
370
+ | `account_rotation_strategy` | `round-robin` | Strategy: `round-robin` or `least-recently-used` |
371
+ | `account_rotation_cooldown_ms` | `300000` | Cooldown for rate-limited accounts (5 min) |
369
372
 
370
373
  ## Automatic Model Fallback
371
374
 
@@ -435,6 +438,117 @@ const model = puter('claude-opus-4-5', { disableFallback: true });
435
438
  - Cooldown automatically expires, allowing the model to be retried
436
439
  - If all models (including fallbacks) are exhausted, the original error is thrown
437
440
 
441
+ ## Account Rotation (Multi-Account Support)
442
+
443
+ For even more resilience, you can configure multiple Puter accounts. When one account hits rate limits, the plugin automatically rotates to the next available account.
444
+
445
+ ### How It Works
446
+
447
+ 1. Add multiple Puter accounts using `puter-auth login`
448
+ 2. When the active account hits a rate limit, it goes into "cooldown"
449
+ 3. The plugin automatically switches to the next available account
450
+ 4. Your request continues without interruption
451
+ 5. Cooldown accounts become available again after the cooldown period
452
+
453
+ ### Adding Multiple Accounts
454
+
455
+ ```bash
456
+ # Add your first account
457
+ puter-auth login
458
+
459
+ # Add additional accounts (opens browser for each)
460
+ puter-auth login
461
+
462
+ # View all accounts
463
+ puter-auth status
464
+ ```
465
+
466
+ ### Rotation Strategies
467
+
468
+ The plugin supports two rotation strategies:
469
+
470
+ | Strategy | Description | Best For |
471
+ |----------|-------------|----------|
472
+ | `round-robin` (default) | Cycles through accounts in order | Even distribution |
473
+ | `least-recently-used` | Picks the account used longest ago | Maximizing cooldown recovery |
474
+
475
+ ### Configuration
476
+
477
+ In `~/.config/opencode/puter.json`:
478
+
479
+ ```json
480
+ {
481
+ "account_rotation_enabled": true,
482
+ "account_rotation_strategy": "round-robin",
483
+ "account_rotation_cooldown_ms": 300000
484
+ }
485
+ ```
486
+
487
+ | Option | Default | Description |
488
+ |--------|---------|-------------|
489
+ | `account_rotation_enabled` | `true` | Enable automatic account rotation |
490
+ | `account_rotation_strategy` | `round-robin` | Strategy: `round-robin` or `least-recently-used` |
491
+ | `account_rotation_cooldown_ms` | `300000` | Cooldown duration for rate-limited accounts (5 min) |
492
+
493
+ ### Cooldown Behavior
494
+
495
+ Account cooldowns use exponential backoff:
496
+ - First rate limit: 1x cooldown (5 minutes)
497
+ - Second consecutive: 2x cooldown (10 minutes)
498
+ - Third consecutive: 3x cooldown (15 minutes)
499
+ - Fourth+ consecutive: 4x cooldown (20 minutes max)
500
+
501
+ This prevents hammering accounts that are consistently being rate-limited.
502
+
503
+ ### Fallback vs Rotation
504
+
505
+ The plugin supports both **model fallback** and **account rotation**, and they work together:
506
+
507
+ | Feature | Model Fallback | Account Rotation |
508
+ |---------|---------------|------------------|
509
+ | **Scope** | Different models, same account | Same model, different accounts |
510
+ | **Use case** | Premium model unavailable | Account rate-limited |
511
+ | **Default cooldown** | 1 minute | 5 minutes |
512
+ | **Order of operations** | Tried first | Tried after fallback exhausted |
513
+
514
+ When a request fails:
515
+ 1. First, model fallback tries different models on the current account
516
+ 2. If all models fail, account rotation switches to a different account
517
+ 3. Model fallback then runs again on the new account
518
+
519
+ ### Programmatic Usage
520
+
521
+ ```typescript
522
+ import {
523
+ AccountRotationManager,
524
+ getGlobalAccountRotationManager,
525
+ AllAccountsOnCooldownError
526
+ } from 'opencode-puter-auth';
527
+
528
+ // Get the global rotation manager
529
+ const rotation = getGlobalAccountRotationManager(authManager, {
530
+ cooldownMs: 300000,
531
+ strategy: 'least-recently-used',
532
+ });
533
+
534
+ // Check current status
535
+ const summary = rotation.getSummary();
536
+ console.log(`${summary.availableAccounts}/${summary.totalAccounts} accounts available`);
537
+
538
+ // Handle rate limit errors
539
+ try {
540
+ await makeRequest();
541
+ } catch (error) {
542
+ const result = await rotation.handleRateLimitError(error);
543
+ if (result) {
544
+ console.log(`Rotated to account: ${result.account.username}`);
545
+ await makeRequest(); // Retry with new account
546
+ } else {
547
+ throw new AllAccountsOnCooldownError(rotation.getAccountStatuses());
548
+ }
549
+ }
550
+ ```
551
+
438
552
  ### Debug Logging
439
553
 
440
554
  When `debug: true` is set, the plugin outputs detailed logs with timestamps:
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Account Rotation Manager for opencode-puter-auth
3
+ *
4
+ * Provides automatic account rotation when rate limits are encountered.
5
+ * When an account returns a rate limit error (429/403), the manager:
6
+ * 1. Adds the account to a cooldown list
7
+ * 2. Switches to the next available account
8
+ * 3. Returns to the original account after cooldown expires
9
+ *
10
+ * This enables longer uninterrupted usage by cycling through multiple
11
+ * Puter accounts when individual accounts hit rate limits.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const rotation = new AccountRotationManager(authManager, {
16
+ * cooldownMs: 300000, // 5 minutes
17
+ * enabled: true,
18
+ * });
19
+ *
20
+ * // Get the next available account (respecting cooldowns)
21
+ * const account = await rotation.getNextAvailableAccount();
22
+ *
23
+ * // Mark an account as rate-limited
24
+ * rotation.addToCooldown('mihai_chindris', 'Rate limit exceeded');
25
+ * ```
26
+ */
27
+ import type { PuterAccount } from './types.js';
28
+ import type { Logger } from './logger.js';
29
+ /**
30
+ * Default cooldown duration for rate-limited accounts (5 minutes)
31
+ * Accounts typically need longer cooldown than models since Puter's
32
+ * account-level limits are stricter.
33
+ */
34
+ export declare const DEFAULT_ACCOUNT_COOLDOWN_MS = 300000;
35
+ /**
36
+ * Configuration options for AccountRotationManager
37
+ */
38
+ export interface AccountRotationOptions {
39
+ /** Cooldown duration in milliseconds (default: 5 minutes) */
40
+ cooldownMs?: number;
41
+ /** Whether account rotation is enabled (default: true) */
42
+ enabled?: boolean;
43
+ /** Strategy for selecting next account: 'round-robin' | 'least-recently-used' */
44
+ strategy?: 'round-robin' | 'least-recently-used';
45
+ }
46
+ /**
47
+ * Status of an individual account in the rotation pool
48
+ */
49
+ export interface AccountStatus {
50
+ /** Account username */
51
+ username: string;
52
+ /** Whether the account is currently on cooldown */
53
+ isOnCooldown: boolean;
54
+ /** Remaining cooldown time in ms (0 if not on cooldown) */
55
+ cooldownRemainingMs: number;
56
+ /** Reason for cooldown (if on cooldown) */
57
+ cooldownReason?: string;
58
+ /** When the account was last used (Unix timestamp) */
59
+ lastUsedAt?: number;
60
+ /** Number of times this account has been rate-limited */
61
+ rateLimitCount: number;
62
+ }
63
+ /**
64
+ * Result of account rotation attempt
65
+ */
66
+ export interface AccountRotationResult {
67
+ /** The account that was selected */
68
+ account: PuterAccount;
69
+ /** Whether this account was rotated to (vs. being the primary) */
70
+ wasRotated: boolean;
71
+ /** Username of the previous account (if rotated) */
72
+ previousUsername?: string;
73
+ /** Number of accounts currently on cooldown */
74
+ accountsOnCooldown: number;
75
+ /** Total accounts available */
76
+ totalAccounts: number;
77
+ }
78
+ /**
79
+ * Error thrown when all accounts are on cooldown
80
+ */
81
+ export declare class AllAccountsOnCooldownError extends Error {
82
+ readonly accountStatuses: AccountStatus[];
83
+ readonly nextAvailableIn: number;
84
+ constructor(statuses: AccountStatus[]);
85
+ }
86
+ /**
87
+ * Interface for the auth manager (to avoid circular dependency)
88
+ */
89
+ export interface IAuthManager {
90
+ getActiveAccount(): PuterAccount | null;
91
+ getAllAccounts(): PuterAccount[];
92
+ switchAccount(index: number): Promise<boolean>;
93
+ isAuthenticated(): boolean;
94
+ }
95
+ /**
96
+ * Manages automatic account rotation when rate limits are encountered.
97
+ *
98
+ * Works with PuterAuthManager to cycle through multiple accounts,
99
+ * ensuring uninterrupted service even when individual accounts
100
+ * hit their rate limits.
101
+ */
102
+ export declare class AccountRotationManager {
103
+ private authManager;
104
+ private cooldownMap;
105
+ private usageStats;
106
+ private cooldownMs;
107
+ private enabled;
108
+ private strategy;
109
+ private currentIndex;
110
+ private logger?;
111
+ /**
112
+ * Create a new AccountRotationManager
113
+ *
114
+ * @param authManager - The PuterAuthManager instance
115
+ * @param options - Configuration options
116
+ * @param logger - Optional logger for debugging
117
+ */
118
+ constructor(authManager: IAuthManager, options?: AccountRotationOptions, logger?: Logger);
119
+ /**
120
+ * Check if an account is currently on cooldown
121
+ *
122
+ * @param username - Account username to check
123
+ * @returns true if the account is on cooldown
124
+ */
125
+ isAccountOnCooldown(username: string): boolean;
126
+ /**
127
+ * Get remaining cooldown time for an account
128
+ *
129
+ * @param username - Account username to check
130
+ * @returns Remaining cooldown in ms, or 0 if not on cooldown
131
+ */
132
+ getCooldownRemaining(username: string): number;
133
+ /**
134
+ * Add an account to the cooldown list
135
+ *
136
+ * Each consecutive rate limit increases the cooldown duration
137
+ * exponentially (up to 4x base cooldown).
138
+ *
139
+ * @param username - Account username to add to cooldown
140
+ * @param reason - Reason for the cooldown
141
+ */
142
+ addToCooldown(username: string, reason: string): void;
143
+ /**
144
+ * Remove an account from cooldown (e.g., after successful request)
145
+ *
146
+ * @param username - Account username to remove from cooldown
147
+ */
148
+ removeFromCooldown(username: string): void;
149
+ /**
150
+ * Mark an account as recently used
151
+ *
152
+ * @param username - Account username that was used
153
+ */
154
+ markAsUsed(username: string): void;
155
+ /**
156
+ * Get status of all accounts
157
+ *
158
+ * @returns Array of account statuses
159
+ */
160
+ getAccountStatuses(): AccountStatus[];
161
+ /**
162
+ * Get list of available accounts (not on cooldown)
163
+ *
164
+ * @returns Array of available accounts
165
+ */
166
+ getAvailableAccounts(): PuterAccount[];
167
+ /**
168
+ * Get count of accounts currently on cooldown
169
+ *
170
+ * @returns Number of accounts on cooldown
171
+ */
172
+ getAccountsOnCooldownCount(): number;
173
+ /**
174
+ * Select the next account to use based on strategy
175
+ *
176
+ * @param availableAccounts - List of available accounts
177
+ * @returns The selected account
178
+ */
179
+ private selectNextAccount;
180
+ /**
181
+ * Get the next available account, potentially rotating from current
182
+ *
183
+ * If the current account is on cooldown or has been rate-limited,
184
+ * switches to the next available account.
185
+ *
186
+ * @returns Rotation result with the selected account
187
+ * @throws AllAccountsOnCooldownError if all accounts are on cooldown
188
+ */
189
+ getNextAvailableAccount(): Promise<AccountRotationResult>;
190
+ /**
191
+ * Handle a rate limit error by adding current account to cooldown
192
+ * and returning the next available account
193
+ *
194
+ * @param error - The rate limit error
195
+ * @returns Next available account, or null if all on cooldown
196
+ */
197
+ handleRateLimitError(error: Error): Promise<AccountRotationResult | null>;
198
+ /**
199
+ * Clear all cooldowns (useful for testing or manual reset)
200
+ */
201
+ clearCooldowns(): void;
202
+ /**
203
+ * Reset all statistics
204
+ */
205
+ resetStats(): void;
206
+ /**
207
+ * Update configuration
208
+ */
209
+ configure(options: Partial<AccountRotationOptions>): void;
210
+ /**
211
+ * Get current configuration
212
+ */
213
+ getConfig(): Required<AccountRotationOptions>;
214
+ /**
215
+ * Check if rotation is needed (current account on cooldown)
216
+ */
217
+ isRotationNeeded(): boolean;
218
+ /**
219
+ * Get a summary of the rotation state
220
+ */
221
+ getSummary(): {
222
+ enabled: boolean;
223
+ totalAccounts: number;
224
+ availableAccounts: number;
225
+ onCooldown: number;
226
+ currentAccount: string | null;
227
+ strategy: string;
228
+ };
229
+ }
230
+ /**
231
+ * Get the global AccountRotationManager instance
232
+ *
233
+ * @param authManager - The auth manager (required on first call)
234
+ * @param options - Configuration options
235
+ * @param logger - Optional logger
236
+ * @returns The global AccountRotationManager instance
237
+ */
238
+ export declare function getGlobalAccountRotationManager(authManager?: IAuthManager, options?: AccountRotationOptions, logger?: Logger): AccountRotationManager;
239
+ /**
240
+ * Reset the global AccountRotationManager (useful for testing)
241
+ */
242
+ export declare function resetGlobalAccountRotationManager(): void;
243
+ //# sourceMappingURL=account-rotation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-rotation.d.ts","sourceRoot":"","sources":["../src/account-rotation.ts"],"names":[],"mappings":"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"}