opencode-puter-auth 1.0.1 → 1.0.2
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 +3 -3
- package/dist/client.d.ts +71 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +159 -66
- package/dist/client.js.map +1 -1
- package/dist/retry.d.ts +103 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +175 -0
- package/dist/retry.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# opencode-puter-auth
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/opencode-puter-auth)
|
|
4
|
-
[](https://github.com/Mihai-Codes/opencode-puter-auth/actions/workflows/ci.yml)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://ko-fi.com/chindrismihai)
|
|
7
7
|
|
|
@@ -49,7 +49,7 @@ https://raw.githubusercontent.com/Mihai-Codes/opencode-puter-auth/main/README.md
|
|
|
49
49
|
|
|
50
50
|
```json
|
|
51
51
|
{
|
|
52
|
-
"plugin": ["opencode-puter-auth
|
|
52
|
+
"plugin": ["opencode-puter-auth"]
|
|
53
53
|
}
|
|
54
54
|
```
|
|
55
55
|
|
|
@@ -65,7 +65,7 @@ opencode auth login
|
|
|
65
65
|
```json
|
|
66
66
|
{
|
|
67
67
|
"$schema": "https://opencode.ai/config.json",
|
|
68
|
-
"plugin": ["opencode-puter-auth
|
|
68
|
+
"plugin": ["opencode-puter-auth"],
|
|
69
69
|
"provider": {
|
|
70
70
|
"puter": {
|
|
71
71
|
"models": {
|
package/dist/client.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Puter API Client
|
|
3
3
|
*
|
|
4
|
-
* Handles all communication with Puter.com's AI API
|
|
4
|
+
* Handles all communication with Puter.com's AI API.
|
|
5
|
+
* Includes automatic retry with exponential backoff for transient failures.
|
|
5
6
|
*/
|
|
6
7
|
import type { PuterChatMessage, PuterChatOptions, PuterChatResponse, PuterChatStreamChunk, PuterModelInfo, PuterConfig } from './types.js';
|
|
7
8
|
export declare class PuterClient {
|
|
8
9
|
private authToken;
|
|
9
10
|
private config;
|
|
11
|
+
private debug;
|
|
10
12
|
constructor(authToken: string, config?: Partial<PuterConfig>);
|
|
11
13
|
/**
|
|
12
14
|
* Get the API base URL
|
|
@@ -16,20 +18,66 @@ export declare class PuterClient {
|
|
|
16
18
|
* Get the request timeout
|
|
17
19
|
*/
|
|
18
20
|
private get timeout();
|
|
21
|
+
/**
|
|
22
|
+
* Get retry options from config
|
|
23
|
+
*/
|
|
24
|
+
private get retryOptions();
|
|
19
25
|
/**
|
|
20
26
|
* Update the auth token
|
|
21
27
|
*/
|
|
22
28
|
setAuthToken(token: string): void;
|
|
23
29
|
/**
|
|
24
30
|
* Send a chat completion request (non-streaming)
|
|
31
|
+
*
|
|
32
|
+
* Automatically retries on transient failures (rate limits, server errors)
|
|
33
|
+
* using exponential backoff with jitter.
|
|
34
|
+
*
|
|
35
|
+
* @param messages - Array of chat messages
|
|
36
|
+
* @param options - Chat options (model, temperature, etc.)
|
|
37
|
+
* @returns Chat response with assistant message
|
|
38
|
+
* @throws Error if request fails after all retries
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const response = await client.chat([
|
|
43
|
+
* { role: 'user', content: 'Hello!' }
|
|
44
|
+
* ], { model: 'claude-opus-4-5' });
|
|
45
|
+
* console.log(response.message.content);
|
|
46
|
+
* ```
|
|
25
47
|
*/
|
|
26
48
|
chat(messages: PuterChatMessage[], options?: PuterChatOptions): Promise<PuterChatResponse>;
|
|
27
49
|
/**
|
|
28
50
|
* Send a streaming chat completion request
|
|
51
|
+
*
|
|
52
|
+
* Returns an async generator that yields chunks as they arrive.
|
|
53
|
+
* The initial connection is retried on transient failures.
|
|
54
|
+
*
|
|
55
|
+
* @param messages - Array of chat messages
|
|
56
|
+
* @param options - Chat options (model, temperature, etc.)
|
|
57
|
+
* @yields Chat stream chunks with text, reasoning, or tool calls
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* for await (const chunk of client.chatStream([
|
|
62
|
+
* { role: 'user', content: 'Tell me a story' }
|
|
63
|
+
* ])) {
|
|
64
|
+
* if (chunk.text) process.stdout.write(chunk.text);
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
29
67
|
*/
|
|
30
68
|
chatStream(messages: PuterChatMessage[], options?: PuterChatOptions): AsyncGenerator<PuterChatStreamChunk>;
|
|
31
69
|
/**
|
|
32
|
-
* List available models
|
|
70
|
+
* List available models from Puter API
|
|
71
|
+
*
|
|
72
|
+
* Falls back to a default model list if the API is unavailable.
|
|
73
|
+
*
|
|
74
|
+
* @returns Array of available model information
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const models = await client.listModels();
|
|
79
|
+
* models.forEach(m => console.log(`${m.id}: ${m.name}`));
|
|
80
|
+
* ```
|
|
33
81
|
*/
|
|
34
82
|
listModels(): Promise<PuterModelInfo[]>;
|
|
35
83
|
/**
|
|
@@ -38,10 +86,30 @@ export declare class PuterClient {
|
|
|
38
86
|
private getDefaultModels;
|
|
39
87
|
/**
|
|
40
88
|
* Make a generic API request to the drivers endpoint
|
|
89
|
+
*
|
|
90
|
+
* Includes automatic retry with exponential backoff for transient failures.
|
|
91
|
+
*
|
|
92
|
+
* @param method - API method to call
|
|
93
|
+
* @param args - Arguments to pass to the method
|
|
94
|
+
* @returns API response
|
|
95
|
+
* @throws Error if request fails after all retries
|
|
41
96
|
*/
|
|
42
97
|
private makeRequest;
|
|
43
98
|
/**
|
|
44
|
-
* Test the connection and auth token
|
|
99
|
+
* Test the connection and auth token validity
|
|
100
|
+
*
|
|
101
|
+
* Makes a minimal API call to verify the token works.
|
|
102
|
+
*
|
|
103
|
+
* @returns true if connection is successful, false otherwise
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* if (await client.testConnection()) {
|
|
108
|
+
* console.log('Connected to Puter!');
|
|
109
|
+
* } else {
|
|
110
|
+
* console.log('Connection failed');
|
|
111
|
+
* }
|
|
112
|
+
* ```
|
|
45
113
|
*/
|
|
46
114
|
testConnection(): Promise<boolean>;
|
|
47
115
|
}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACZ,MAAM,YAAY,CAAC;AAQpB,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,KAAK,CAAU;gBAEX,SAAS,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM;IAMhE;;OAEG;IACH,OAAO,KAAK,MAAM,GAEjB;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;IAED;;OAEG;IACH,OAAO,KAAK,YAAY,GAUvB;IAED;;OAEG;IACI,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIxC;;;;;;;;;;;;;;;;;;OAkBG;IACU,IAAI,CACf,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IAa7B;;;;;;;;;;;;;;;;;;OAkBG;IACW,UAAU,CACtB,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,OAAO,GAAE,gBAAqB,GAC7B,cAAc,CAAC,oBAAoB,CAAC;IAoFvC;;;;;;;;;;;;OAYG;IACU,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IA0BpD;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;;;;;;;OASG;YACW,WAAW;IAqCzB;;;;;;;;;;;;;;;OAeG;IACU,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAWhD"}
|
package/dist/client.js
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Puter API Client
|
|
3
3
|
*
|
|
4
|
-
* Handles all communication with Puter.com's AI API
|
|
4
|
+
* Handles all communication with Puter.com's AI API.
|
|
5
|
+
* Includes automatic retry with exponential backoff for transient failures.
|
|
5
6
|
*/
|
|
7
|
+
import { withRetry } from './retry.js';
|
|
6
8
|
const DEFAULT_API_URL = 'https://api.puter.com';
|
|
7
9
|
const DEFAULT_TIMEOUT = 120000;
|
|
10
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
11
|
+
const DEFAULT_RETRY_DELAY = 1000;
|
|
8
12
|
export class PuterClient {
|
|
9
13
|
authToken;
|
|
10
14
|
config;
|
|
15
|
+
debug;
|
|
11
16
|
constructor(authToken, config = {}) {
|
|
12
17
|
this.authToken = authToken;
|
|
13
18
|
this.config = config;
|
|
19
|
+
this.debug = config.debug ?? false;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* Get the API base URL
|
|
@@ -24,6 +30,20 @@ export class PuterClient {
|
|
|
24
30
|
get timeout() {
|
|
25
31
|
return this.config.api_timeout_ms || DEFAULT_TIMEOUT;
|
|
26
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Get retry options from config
|
|
35
|
+
*/
|
|
36
|
+
get retryOptions() {
|
|
37
|
+
return {
|
|
38
|
+
maxRetries: this.config.max_retries ?? DEFAULT_MAX_RETRIES,
|
|
39
|
+
initialDelay: this.config.retry_delay_ms ?? DEFAULT_RETRY_DELAY,
|
|
40
|
+
onRetry: this.debug
|
|
41
|
+
? (attempt, error, delay) => {
|
|
42
|
+
console.warn(`[PuterClient] Retry ${attempt}: ${error.message} (waiting ${delay}ms)`);
|
|
43
|
+
}
|
|
44
|
+
: undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
27
47
|
/**
|
|
28
48
|
* Update the auth token
|
|
29
49
|
*/
|
|
@@ -32,6 +52,22 @@ export class PuterClient {
|
|
|
32
52
|
}
|
|
33
53
|
/**
|
|
34
54
|
* Send a chat completion request (non-streaming)
|
|
55
|
+
*
|
|
56
|
+
* Automatically retries on transient failures (rate limits, server errors)
|
|
57
|
+
* using exponential backoff with jitter.
|
|
58
|
+
*
|
|
59
|
+
* @param messages - Array of chat messages
|
|
60
|
+
* @param options - Chat options (model, temperature, etc.)
|
|
61
|
+
* @returns Chat response with assistant message
|
|
62
|
+
* @throws Error if request fails after all retries
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const response = await client.chat([
|
|
67
|
+
* { role: 'user', content: 'Hello!' }
|
|
68
|
+
* ], { model: 'claude-opus-4-5' });
|
|
69
|
+
* console.log(response.message.content);
|
|
70
|
+
* ```
|
|
35
71
|
*/
|
|
36
72
|
async chat(messages, options = {}) {
|
|
37
73
|
const response = await this.makeRequest('complete', {
|
|
@@ -46,36 +82,56 @@ export class PuterClient {
|
|
|
46
82
|
}
|
|
47
83
|
/**
|
|
48
84
|
* Send a streaming chat completion request
|
|
85
|
+
*
|
|
86
|
+
* Returns an async generator that yields chunks as they arrive.
|
|
87
|
+
* The initial connection is retried on transient failures.
|
|
88
|
+
*
|
|
89
|
+
* @param messages - Array of chat messages
|
|
90
|
+
* @param options - Chat options (model, temperature, etc.)
|
|
91
|
+
* @yields Chat stream chunks with text, reasoning, or tool calls
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* for await (const chunk of client.chatStream([
|
|
96
|
+
* { role: 'user', content: 'Tell me a story' }
|
|
97
|
+
* ])) {
|
|
98
|
+
* if (chunk.text) process.stdout.write(chunk.text);
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
49
101
|
*/
|
|
50
102
|
async *chatStream(messages, options = {}) {
|
|
51
103
|
const controller = new AbortController();
|
|
52
104
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
53
105
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
interface: 'puter-chat-completion',
|
|
61
|
-
service: 'ai-chat',
|
|
62
|
-
method: 'complete',
|
|
63
|
-
args: {
|
|
64
|
-
messages,
|
|
65
|
-
model: options.model || 'gpt-5-nano',
|
|
66
|
-
stream: true,
|
|
67
|
-
max_tokens: options.max_tokens,
|
|
68
|
-
temperature: options.temperature,
|
|
69
|
-
tools: options.tools,
|
|
106
|
+
// Retry the initial connection
|
|
107
|
+
const response = await withRetry(async () => {
|
|
108
|
+
const res = await fetch(`${this.apiUrl}/drivers/call`, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: {
|
|
111
|
+
'Content-Type': 'application/json',
|
|
70
112
|
},
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
113
|
+
body: JSON.stringify({
|
|
114
|
+
interface: 'puter-chat-completion',
|
|
115
|
+
service: 'ai-chat',
|
|
116
|
+
method: 'complete',
|
|
117
|
+
args: {
|
|
118
|
+
messages,
|
|
119
|
+
model: options.model || 'gpt-5-nano',
|
|
120
|
+
stream: true,
|
|
121
|
+
max_tokens: options.max_tokens,
|
|
122
|
+
temperature: options.temperature,
|
|
123
|
+
tools: options.tools,
|
|
124
|
+
},
|
|
125
|
+
auth_token: this.authToken,
|
|
126
|
+
}),
|
|
127
|
+
signal: controller.signal,
|
|
128
|
+
});
|
|
129
|
+
if (!res.ok) {
|
|
130
|
+
const errorText = await res.text();
|
|
131
|
+
throw new Error(`Puter API error (${res.status}): ${errorText}`);
|
|
132
|
+
}
|
|
133
|
+
return res;
|
|
134
|
+
}, this.retryOptions);
|
|
79
135
|
if (!response.body) {
|
|
80
136
|
throw new Error('No response body for streaming');
|
|
81
137
|
}
|
|
@@ -121,24 +177,39 @@ export class PuterClient {
|
|
|
121
177
|
}
|
|
122
178
|
}
|
|
123
179
|
/**
|
|
124
|
-
* List available models
|
|
180
|
+
* List available models from Puter API
|
|
181
|
+
*
|
|
182
|
+
* Falls back to a default model list if the API is unavailable.
|
|
183
|
+
*
|
|
184
|
+
* @returns Array of available model information
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* const models = await client.listModels();
|
|
189
|
+
* models.forEach(m => console.log(`${m.id}: ${m.name}`));
|
|
190
|
+
* ```
|
|
125
191
|
*/
|
|
126
192
|
async listModels() {
|
|
127
193
|
try {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
194
|
+
return await withRetry(async () => {
|
|
195
|
+
const response = await fetch(`${this.apiUrl}/puterai/chat/models/details`, {
|
|
196
|
+
method: 'GET',
|
|
197
|
+
headers: {
|
|
198
|
+
'Authorization': `Bearer ${this.authToken}`,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
if (!response.ok) {
|
|
202
|
+
throw new Error(`Failed to fetch models (${response.status})`);
|
|
203
|
+
}
|
|
204
|
+
const data = await response.json();
|
|
205
|
+
return data.models || data || [];
|
|
206
|
+
}, this.retryOptions);
|
|
139
207
|
}
|
|
140
|
-
catch
|
|
141
|
-
// Return default models if API fails
|
|
208
|
+
catch {
|
|
209
|
+
// Return default models if API fails after retries
|
|
210
|
+
if (this.debug) {
|
|
211
|
+
console.warn('[PuterClient] Failed to fetch models, using defaults');
|
|
212
|
+
}
|
|
142
213
|
return this.getDefaultModels();
|
|
143
214
|
}
|
|
144
215
|
}
|
|
@@ -164,38 +235,60 @@ export class PuterClient {
|
|
|
164
235
|
}
|
|
165
236
|
/**
|
|
166
237
|
* Make a generic API request to the drivers endpoint
|
|
238
|
+
*
|
|
239
|
+
* Includes automatic retry with exponential backoff for transient failures.
|
|
240
|
+
*
|
|
241
|
+
* @param method - API method to call
|
|
242
|
+
* @param args - Arguments to pass to the method
|
|
243
|
+
* @returns API response
|
|
244
|
+
* @throws Error if request fails after all retries
|
|
167
245
|
*/
|
|
168
246
|
async makeRequest(method, args) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
247
|
+
return withRetry(async () => {
|
|
248
|
+
const controller = new AbortController();
|
|
249
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
250
|
+
try {
|
|
251
|
+
const response = await fetch(`${this.apiUrl}/drivers/call`, {
|
|
252
|
+
method: 'POST',
|
|
253
|
+
headers: {
|
|
254
|
+
'Content-Type': 'application/json',
|
|
255
|
+
},
|
|
256
|
+
body: JSON.stringify({
|
|
257
|
+
interface: 'puter-chat-completion',
|
|
258
|
+
service: 'ai-chat',
|
|
259
|
+
method,
|
|
260
|
+
args,
|
|
261
|
+
auth_token: this.authToken,
|
|
262
|
+
}),
|
|
263
|
+
signal: controller.signal,
|
|
264
|
+
});
|
|
265
|
+
if (!response.ok) {
|
|
266
|
+
const errorText = await response.text();
|
|
267
|
+
throw new Error(`Puter API error (${response.status}): ${errorText}`);
|
|
268
|
+
}
|
|
269
|
+
const data = await response.json();
|
|
270
|
+
return data;
|
|
189
271
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
clearTimeout(timeoutId);
|
|
195
|
-
}
|
|
272
|
+
finally {
|
|
273
|
+
clearTimeout(timeoutId);
|
|
274
|
+
}
|
|
275
|
+
}, this.retryOptions);
|
|
196
276
|
}
|
|
197
277
|
/**
|
|
198
|
-
* Test the connection and auth token
|
|
278
|
+
* Test the connection and auth token validity
|
|
279
|
+
*
|
|
280
|
+
* Makes a minimal API call to verify the token works.
|
|
281
|
+
*
|
|
282
|
+
* @returns true if connection is successful, false otherwise
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```ts
|
|
286
|
+
* if (await client.testConnection()) {
|
|
287
|
+
* console.log('Connected to Puter!');
|
|
288
|
+
* } else {
|
|
289
|
+
* console.log('Connection failed');
|
|
290
|
+
* }
|
|
291
|
+
* ```
|
|
199
292
|
*/
|
|
200
293
|
async testConnection() {
|
|
201
294
|
try {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/retry.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry utilities with exponential backoff and jitter
|
|
3
|
+
*
|
|
4
|
+
* Provides robust retry logic for handling transient failures
|
|
5
|
+
* in API calls to Puter.com
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Configuration options for retry behavior
|
|
9
|
+
*/
|
|
10
|
+
export interface RetryOptions {
|
|
11
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
12
|
+
maxRetries?: number;
|
|
13
|
+
/** Initial delay in milliseconds (default: 1000) */
|
|
14
|
+
initialDelay?: number;
|
|
15
|
+
/** Maximum delay in milliseconds (default: 30000) */
|
|
16
|
+
maxDelay?: number;
|
|
17
|
+
/** Backoff multiplier (default: 2) */
|
|
18
|
+
backoffFactor?: number;
|
|
19
|
+
/** Add random jitter to delays (default: true) */
|
|
20
|
+
jitter?: boolean;
|
|
21
|
+
/** HTTP status codes that should trigger a retry (default: [429, 500, 502, 503, 504]) */
|
|
22
|
+
retryableStatuses?: number[];
|
|
23
|
+
/** Callback called before each retry attempt */
|
|
24
|
+
onRetry?: (attempt: number, error: Error, delay: number) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Error class for retry-related failures
|
|
28
|
+
*/
|
|
29
|
+
export declare class RetryError extends Error {
|
|
30
|
+
readonly attempts: number;
|
|
31
|
+
readonly lastError: Error;
|
|
32
|
+
constructor(message: string, attempts: number, lastError: Error);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Calculate delay with exponential backoff and optional jitter
|
|
36
|
+
*
|
|
37
|
+
* @param attempt - Current attempt number (0-indexed)
|
|
38
|
+
* @param options - Retry options
|
|
39
|
+
* @returns Delay in milliseconds
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* // Attempt 0: ~1000ms
|
|
44
|
+
* // Attempt 1: ~2000ms
|
|
45
|
+
* // Attempt 2: ~4000ms
|
|
46
|
+
* const delay = calculateDelay(2, { initialDelay: 1000, backoffFactor: 2 });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function calculateDelay(attempt: number, options?: Pick<RetryOptions, 'initialDelay' | 'maxDelay' | 'backoffFactor' | 'jitter'>): number;
|
|
50
|
+
/**
|
|
51
|
+
* Sleep for a specified duration
|
|
52
|
+
*
|
|
53
|
+
* @param ms - Duration in milliseconds
|
|
54
|
+
* @returns Promise that resolves after the delay
|
|
55
|
+
*/
|
|
56
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Check if an error is retryable based on HTTP status
|
|
59
|
+
*
|
|
60
|
+
* @param error - The error to check
|
|
61
|
+
* @param retryableStatuses - List of HTTP status codes that should trigger retry
|
|
62
|
+
* @returns true if the error should trigger a retry
|
|
63
|
+
*/
|
|
64
|
+
export declare function isRetryableError(error: unknown, retryableStatuses?: number[]): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Execute an async operation with retry logic
|
|
67
|
+
*
|
|
68
|
+
* Uses exponential backoff with jitter to handle transient failures.
|
|
69
|
+
* Only retries on specific error conditions (rate limits, server errors, network issues).
|
|
70
|
+
*
|
|
71
|
+
* @param operation - Async function to execute
|
|
72
|
+
* @param options - Retry configuration options
|
|
73
|
+
* @returns Result of the operation
|
|
74
|
+
* @throws RetryError if all retry attempts fail
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const result = await withRetry(
|
|
79
|
+
* () => fetch('https://api.example.com/data'),
|
|
80
|
+
* {
|
|
81
|
+
* maxRetries: 3,
|
|
82
|
+
* onRetry: (attempt, error, delay) => {
|
|
83
|
+
* console.log(`Retry ${attempt} after ${delay}ms: ${error.message}`);
|
|
84
|
+
* }
|
|
85
|
+
* }
|
|
86
|
+
* );
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function withRetry<T>(operation: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
90
|
+
/**
|
|
91
|
+
* Create a fetch wrapper with built-in retry logic
|
|
92
|
+
*
|
|
93
|
+
* @param options - Retry configuration options
|
|
94
|
+
* @returns A fetch function with retry capabilities
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const fetchWithRetry = createRetryFetch({ maxRetries: 3 });
|
|
99
|
+
* const response = await fetchWithRetry('https://api.example.com/data');
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function createRetryFetch(options?: RetryOptions): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
103
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClE;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,SAAS,EAAE,KAAK,CAAC;gBAErB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK;CAMhE;AAcD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,IAAI,CAAC,YAAY,EAAE,cAAc,GAAG,UAAU,GAAG,eAAe,GAAG,QAAQ,CAAM,GACzF,MAAM,CAsBR;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,iBAAiB,GAAE,MAAM,EAA4C,GACpE,OAAO,CA0BT;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,CAAC,CA8CZ;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,YAAiB,IAEvD,OAAO,WAAW,GAAG,GAAG,EACxB,OAAO,WAAW,KACjB,OAAO,CAAC,QAAQ,CAAC,CAarB"}
|
package/dist/retry.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry utilities with exponential backoff and jitter
|
|
3
|
+
*
|
|
4
|
+
* Provides robust retry logic for handling transient failures
|
|
5
|
+
* in API calls to Puter.com
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error class for retry-related failures
|
|
9
|
+
*/
|
|
10
|
+
export class RetryError extends Error {
|
|
11
|
+
attempts;
|
|
12
|
+
lastError;
|
|
13
|
+
constructor(message, attempts, lastError) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'RetryError';
|
|
16
|
+
this.attempts = attempts;
|
|
17
|
+
this.lastError = lastError;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Default retry options
|
|
22
|
+
*/
|
|
23
|
+
const DEFAULT_RETRY_OPTIONS = {
|
|
24
|
+
maxRetries: 3,
|
|
25
|
+
initialDelay: 1000,
|
|
26
|
+
maxDelay: 30000,
|
|
27
|
+
backoffFactor: 2,
|
|
28
|
+
jitter: true,
|
|
29
|
+
retryableStatuses: [429, 500, 502, 503, 504],
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Calculate delay with exponential backoff and optional jitter
|
|
33
|
+
*
|
|
34
|
+
* @param attempt - Current attempt number (0-indexed)
|
|
35
|
+
* @param options - Retry options
|
|
36
|
+
* @returns Delay in milliseconds
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* // Attempt 0: ~1000ms
|
|
41
|
+
* // Attempt 1: ~2000ms
|
|
42
|
+
* // Attempt 2: ~4000ms
|
|
43
|
+
* const delay = calculateDelay(2, { initialDelay: 1000, backoffFactor: 2 });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function calculateDelay(attempt, options = {}) {
|
|
47
|
+
const { initialDelay = DEFAULT_RETRY_OPTIONS.initialDelay, maxDelay = DEFAULT_RETRY_OPTIONS.maxDelay, backoffFactor = DEFAULT_RETRY_OPTIONS.backoffFactor, jitter = DEFAULT_RETRY_OPTIONS.jitter, } = options;
|
|
48
|
+
// Calculate base delay with exponential backoff
|
|
49
|
+
const baseDelay = initialDelay * Math.pow(backoffFactor, attempt);
|
|
50
|
+
// Cap at maxDelay
|
|
51
|
+
const cappedDelay = Math.min(baseDelay, maxDelay);
|
|
52
|
+
// Add jitter (±25% randomness) to prevent thundering herd
|
|
53
|
+
if (jitter) {
|
|
54
|
+
const jitterRange = cappedDelay * 0.25;
|
|
55
|
+
const randomJitter = (Math.random() - 0.5) * 2 * jitterRange;
|
|
56
|
+
return Math.max(0, Math.round(cappedDelay + randomJitter));
|
|
57
|
+
}
|
|
58
|
+
return Math.round(cappedDelay);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Sleep for a specified duration
|
|
62
|
+
*
|
|
63
|
+
* @param ms - Duration in milliseconds
|
|
64
|
+
* @returns Promise that resolves after the delay
|
|
65
|
+
*/
|
|
66
|
+
export function sleep(ms) {
|
|
67
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if an error is retryable based on HTTP status
|
|
71
|
+
*
|
|
72
|
+
* @param error - The error to check
|
|
73
|
+
* @param retryableStatuses - List of HTTP status codes that should trigger retry
|
|
74
|
+
* @returns true if the error should trigger a retry
|
|
75
|
+
*/
|
|
76
|
+
export function isRetryableError(error, retryableStatuses = DEFAULT_RETRY_OPTIONS.retryableStatuses) {
|
|
77
|
+
if (error instanceof Error) {
|
|
78
|
+
const message = error.message.toLowerCase();
|
|
79
|
+
// Check for status codes in error message
|
|
80
|
+
for (const status of retryableStatuses) {
|
|
81
|
+
if (message.includes(`(${status})`) || message.includes(`status ${status}`)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Check for common transient error patterns
|
|
86
|
+
if (message.includes('timeout') ||
|
|
87
|
+
message.includes('econnreset') ||
|
|
88
|
+
message.includes('econnrefused') ||
|
|
89
|
+
message.includes('network') ||
|
|
90
|
+
message.includes('socket hang up') ||
|
|
91
|
+
message.includes('rate limit') ||
|
|
92
|
+
message.includes('too many requests')) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Execute an async operation with retry logic
|
|
100
|
+
*
|
|
101
|
+
* Uses exponential backoff with jitter to handle transient failures.
|
|
102
|
+
* Only retries on specific error conditions (rate limits, server errors, network issues).
|
|
103
|
+
*
|
|
104
|
+
* @param operation - Async function to execute
|
|
105
|
+
* @param options - Retry configuration options
|
|
106
|
+
* @returns Result of the operation
|
|
107
|
+
* @throws RetryError if all retry attempts fail
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const result = await withRetry(
|
|
112
|
+
* () => fetch('https://api.example.com/data'),
|
|
113
|
+
* {
|
|
114
|
+
* maxRetries: 3,
|
|
115
|
+
* onRetry: (attempt, error, delay) => {
|
|
116
|
+
* console.log(`Retry ${attempt} after ${delay}ms: ${error.message}`);
|
|
117
|
+
* }
|
|
118
|
+
* }
|
|
119
|
+
* );
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export async function withRetry(operation, options = {}) {
|
|
123
|
+
const { maxRetries = DEFAULT_RETRY_OPTIONS.maxRetries, initialDelay = DEFAULT_RETRY_OPTIONS.initialDelay, maxDelay = DEFAULT_RETRY_OPTIONS.maxDelay, backoffFactor = DEFAULT_RETRY_OPTIONS.backoffFactor, jitter = DEFAULT_RETRY_OPTIONS.jitter, retryableStatuses = DEFAULT_RETRY_OPTIONS.retryableStatuses, onRetry, } = options;
|
|
124
|
+
let lastError = new Error('Unknown error');
|
|
125
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
126
|
+
try {
|
|
127
|
+
return await operation();
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
131
|
+
// Check if we should retry
|
|
132
|
+
const isLastAttempt = attempt === maxRetries;
|
|
133
|
+
const shouldRetry = !isLastAttempt && isRetryableError(error, retryableStatuses);
|
|
134
|
+
if (!shouldRetry) {
|
|
135
|
+
throw lastError;
|
|
136
|
+
}
|
|
137
|
+
// Calculate delay for next attempt
|
|
138
|
+
const delay = calculateDelay(attempt, { initialDelay, maxDelay, backoffFactor, jitter });
|
|
139
|
+
// Call onRetry callback if provided
|
|
140
|
+
if (onRetry) {
|
|
141
|
+
onRetry(attempt + 1, lastError, delay);
|
|
142
|
+
}
|
|
143
|
+
// Wait before retrying
|
|
144
|
+
await sleep(delay);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// This should never be reached, but TypeScript needs it
|
|
148
|
+
throw new RetryError(`Operation failed after ${maxRetries + 1} attempts`, maxRetries + 1, lastError);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Create a fetch wrapper with built-in retry logic
|
|
152
|
+
*
|
|
153
|
+
* @param options - Retry configuration options
|
|
154
|
+
* @returns A fetch function with retry capabilities
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* const fetchWithRetry = createRetryFetch({ maxRetries: 3 });
|
|
159
|
+
* const response = await fetchWithRetry('https://api.example.com/data');
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export function createRetryFetch(options = {}) {
|
|
163
|
+
return async function retryFetch(input, init) {
|
|
164
|
+
return withRetry(async () => {
|
|
165
|
+
const response = await fetch(input, init);
|
|
166
|
+
// Check if response status indicates a retryable error
|
|
167
|
+
const retryableStatuses = options.retryableStatuses || DEFAULT_RETRY_OPTIONS.retryableStatuses;
|
|
168
|
+
if (retryableStatuses.includes(response.status)) {
|
|
169
|
+
throw new Error(`HTTP error (${response.status}): ${response.statusText}`);
|
|
170
|
+
}
|
|
171
|
+
return response;
|
|
172
|
+
}, options);
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-puter-auth",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Puter.com OAuth auth plugin for OpenCode - FREE UNLIMITED access to Claude Opus 4.5, Sonnet 4.5, GPT-5, Gemini, and 500+ AI models",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|