@zhafron/opencode-kiro-auth 1.0.0 → 1.1.1
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 +1 -1
- package/dist/constants.js +7 -1
- package/dist/kiro/oauth-idc.js +4 -1
- package/dist/plugin/accounts.js +11 -2
- package/dist/plugin/auth-page.js +6 -1
- package/dist/plugin/config/loader.js +3 -1
- package/dist/plugin/config/schema.d.ts +3 -0
- package/dist/plugin/config/schema.js +4 -2
- package/dist/plugin/logger.d.ts +3 -0
- package/dist/plugin/logger.js +24 -6
- package/dist/plugin/request.js +154 -26
- package/dist/plugin/response.js +9 -2
- package/dist/plugin/server.js +16 -3
- package/dist/plugin/streaming.js +9 -2
- package/dist/plugin/types.d.ts +1 -1
- package/dist/plugin/usage.js +11 -2
- package/dist/plugin.js +84 -6
- package/package.json +2 -2
- package/dist/kiro/oauth-social.d.ts +0 -17
- package/dist/kiro/oauth-social.js +0 -51
- package/dist/plugin/cli.d.ts +0 -6
- package/dist/plugin/cli.js +0 -98
- package/dist/plugin/debug.d.ts +0 -2
- package/dist/plugin/debug.js +0 -9
- package/dist/plugin/oauth-parser.d.ts +0 -5
- package/dist/plugin/oauth-parser.js +0 -23
- package/dist/plugin/quota.d.ts +0 -15
- package/dist/plugin/quota.js +0 -68
- package/dist/plugin/recovery.d.ts +0 -19
- package/dist/plugin/recovery.js +0 -302
- package/dist/plugin/refresh-queue.d.ts +0 -14
- package/dist/plugin/refresh-queue.js +0 -69
- package/dist/src/constants.d.ts +0 -22
- package/dist/src/constants.js +0 -35
- package/dist/src/kiro/auth.d.ts +0 -5
- package/dist/src/kiro/auth.js +0 -69
- package/dist/src/kiro/oauth-idc.d.ts +0 -22
- package/dist/src/kiro/oauth-idc.js +0 -99
- package/dist/src/kiro/oauth-social.d.ts +0 -17
- package/dist/src/kiro/oauth-social.js +0 -69
- package/dist/src/plugin/accounts.d.ts +0 -23
- package/dist/src/plugin/accounts.js +0 -265
- package/dist/src/plugin/cli.d.ts +0 -6
- package/dist/src/plugin/cli.js +0 -98
- package/dist/src/plugin/config/index.d.ts +0 -3
- package/dist/src/plugin/config/index.js +0 -2
- package/dist/src/plugin/config/loader.d.ts +0 -7
- package/dist/src/plugin/config/loader.js +0 -143
- package/dist/src/plugin/config/schema.d.ts +0 -68
- package/dist/src/plugin/config/schema.js +0 -44
- package/dist/src/plugin/debug.d.ts +0 -2
- package/dist/src/plugin/debug.js +0 -9
- package/dist/src/plugin/errors.d.ts +0 -17
- package/dist/src/plugin/errors.js +0 -34
- package/dist/src/plugin/logger.d.ts +0 -4
- package/dist/src/plugin/logger.js +0 -17
- package/dist/src/plugin/models.d.ts +0 -3
- package/dist/src/plugin/models.js +0 -14
- package/dist/src/plugin/oauth-parser.d.ts +0 -5
- package/dist/src/plugin/oauth-parser.js +0 -23
- package/dist/src/plugin/quota.d.ts +0 -25
- package/dist/src/plugin/quota.js +0 -175
- package/dist/src/plugin/recovery.d.ts +0 -19
- package/dist/src/plugin/recovery.js +0 -302
- package/dist/src/plugin/refresh-queue.d.ts +0 -14
- package/dist/src/plugin/refresh-queue.js +0 -69
- package/dist/src/plugin/request.d.ts +0 -35
- package/dist/src/plugin/request.js +0 -411
- package/dist/src/plugin/response.d.ts +0 -6
- package/dist/src/plugin/response.js +0 -246
- package/dist/src/plugin/server.d.ts +0 -10
- package/dist/src/plugin/server.js +0 -203
- package/dist/src/plugin/storage.d.ts +0 -5
- package/dist/src/plugin/storage.js +0 -106
- package/dist/src/plugin/streaming.d.ts +0 -12
- package/dist/src/plugin/streaming.js +0 -444
- package/dist/src/plugin/token.d.ts +0 -8
- package/dist/src/plugin/token.js +0 -130
- package/dist/src/plugin/types.d.ts +0 -144
- package/dist/src/plugin/types.js +0 -0
- package/dist/src/plugin/usage.d.ts +0 -28
- package/dist/src/plugin/usage.js +0 -159
- package/dist/src/plugin.d.ts +0 -2
- package/dist/src/plugin.js +0 -341
package/dist/plugin.js
CHANGED
|
@@ -72,8 +72,41 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
const prep = transformToCodeWhisperer(url, init?.body, model, auth, think, budget);
|
|
75
|
+
const apiTimestamp = config.enable_log_api_request ? logger.getTimestamp() : null;
|
|
76
|
+
if (config.enable_log_api_request && apiTimestamp) {
|
|
77
|
+
let parsedBody = null;
|
|
78
|
+
if (prep.init.body && typeof prep.init.body === 'string') {
|
|
79
|
+
try {
|
|
80
|
+
parsedBody = JSON.parse(prep.init.body);
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
parsedBody = prep.init.body;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
logger.logApiRequest({
|
|
87
|
+
url: prep.url,
|
|
88
|
+
method: prep.init.method,
|
|
89
|
+
headers: prep.init.headers,
|
|
90
|
+
body: parsedBody,
|
|
91
|
+
conversationId: prep.conversationId,
|
|
92
|
+
model: prep.effectiveModel
|
|
93
|
+
}, apiTimestamp);
|
|
94
|
+
}
|
|
75
95
|
try {
|
|
76
96
|
const res = await fetch(prep.url, prep.init);
|
|
97
|
+
if (config.enable_log_api_request && apiTimestamp) {
|
|
98
|
+
const responseHeaders = {};
|
|
99
|
+
res.headers.forEach((value, key) => {
|
|
100
|
+
responseHeaders[key] = value;
|
|
101
|
+
});
|
|
102
|
+
logger.logApiResponse({
|
|
103
|
+
status: res.status,
|
|
104
|
+
statusText: res.statusText,
|
|
105
|
+
headers: responseHeaders,
|
|
106
|
+
conversationId: prep.conversationId,
|
|
107
|
+
model: prep.effectiveModel
|
|
108
|
+
}, apiTimestamp);
|
|
109
|
+
}
|
|
77
110
|
if (res.ok) {
|
|
78
111
|
if (config.usage_tracking_enabled)
|
|
79
112
|
fetchUsageLimits(auth)
|
|
@@ -104,16 +137,31 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
104
137
|
object: 'chat.completion',
|
|
105
138
|
created: Math.floor(Date.now() / 1000),
|
|
106
139
|
model,
|
|
107
|
-
choices: [
|
|
108
|
-
|
|
140
|
+
choices: [
|
|
141
|
+
{
|
|
142
|
+
index: 0,
|
|
143
|
+
message: { role: 'assistant', content: p.content },
|
|
144
|
+
finish_reason: p.stopReason === 'tool_use' ? 'tool_calls' : 'stop'
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
usage: {
|
|
148
|
+
prompt_tokens: p.inputTokens || 0,
|
|
149
|
+
completion_tokens: p.outputTokens || 0,
|
|
150
|
+
total_tokens: (p.inputTokens || 0) + (p.outputTokens || 0)
|
|
151
|
+
}
|
|
109
152
|
};
|
|
110
153
|
if (p.toolCalls.length > 0)
|
|
111
154
|
oai.choices[0].message.tool_calls = p.toolCalls.map((tc) => ({
|
|
112
155
|
id: tc.toolUseId,
|
|
113
156
|
type: 'function',
|
|
114
|
-
function: {
|
|
157
|
+
function: {
|
|
158
|
+
name: tc.name,
|
|
159
|
+
arguments: typeof tc.input === 'string' ? tc.input : JSON.stringify(tc.input)
|
|
160
|
+
}
|
|
115
161
|
}));
|
|
116
|
-
return new Response(JSON.stringify(oai), {
|
|
162
|
+
return new Response(JSON.stringify(oai), {
|
|
163
|
+
headers: { 'Content-Type': 'application/json' }
|
|
164
|
+
});
|
|
117
165
|
}
|
|
118
166
|
if (res.status === 401 && retry < config.rate_limit_max_retries) {
|
|
119
167
|
logger.warn(`Unauthorized (401) on ${acc.email}, retrying...`);
|
|
@@ -140,9 +188,30 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
140
188
|
await am.saveToDisk();
|
|
141
189
|
continue;
|
|
142
190
|
}
|
|
191
|
+
if (config.enable_log_api_request && apiTimestamp) {
|
|
192
|
+
const responseHeaders = {};
|
|
193
|
+
res.headers.forEach((value, key) => {
|
|
194
|
+
responseHeaders[key] = value;
|
|
195
|
+
});
|
|
196
|
+
logger.logApiResponse({
|
|
197
|
+
status: res.status,
|
|
198
|
+
statusText: res.statusText,
|
|
199
|
+
headers: responseHeaders,
|
|
200
|
+
error: `Kiro Error: ${res.status}`,
|
|
201
|
+
conversationId: prep.conversationId,
|
|
202
|
+
model: prep.effectiveModel
|
|
203
|
+
}, apiTimestamp);
|
|
204
|
+
}
|
|
143
205
|
throw new Error(`Kiro Error: ${res.status}`);
|
|
144
206
|
}
|
|
145
207
|
catch (e) {
|
|
208
|
+
if (config.enable_log_api_request && apiTimestamp) {
|
|
209
|
+
logger.logApiResponse({
|
|
210
|
+
error: String(e),
|
|
211
|
+
conversationId: prep.conversationId,
|
|
212
|
+
model: prep.effectiveModel
|
|
213
|
+
}, apiTimestamp);
|
|
214
|
+
}
|
|
146
215
|
if (isNetworkError(e) && retry < config.rate_limit_max_retries) {
|
|
147
216
|
const delay = 5000 * Math.pow(2, retry);
|
|
148
217
|
showToast(`Network error. Retrying in ${Math.ceil(delay / 1000)}s...`, 'warning');
|
|
@@ -188,7 +257,12 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
188
257
|
};
|
|
189
258
|
try {
|
|
190
259
|
const u = await fetchUsageLimits({
|
|
191
|
-
refresh: encodeRefreshToken({
|
|
260
|
+
refresh: encodeRefreshToken({
|
|
261
|
+
refreshToken: res.refreshToken,
|
|
262
|
+
clientId: res.clientId,
|
|
263
|
+
clientSecret: res.clientSecret,
|
|
264
|
+
authMethod: 'idc'
|
|
265
|
+
}),
|
|
192
266
|
access: res.accessToken,
|
|
193
267
|
expires: res.expiresAt,
|
|
194
268
|
authMethod: 'idc',
|
|
@@ -197,7 +271,11 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
197
271
|
clientSecret: res.clientSecret,
|
|
198
272
|
email: res.email
|
|
199
273
|
});
|
|
200
|
-
am.updateUsage(acc.id, {
|
|
274
|
+
am.updateUsage(acc.id, {
|
|
275
|
+
usedCount: u.usedCount,
|
|
276
|
+
limitCount: u.limitCount,
|
|
277
|
+
realEmail: u.email
|
|
278
|
+
});
|
|
201
279
|
}
|
|
202
280
|
catch (e) {
|
|
203
281
|
logger.warn(`Initial usage fetch failed: ${e.message}`);
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhafron/opencode-kiro-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc -p tsconfig.build.json",
|
|
10
|
-
"format": "prettier --write --no-config --no-semi --single-quote --trailing-comma none --print-width
|
|
10
|
+
"format": "prettier --write --no-config --no-semi --single-quote --trailing-comma none --print-width 100 'src/**/*.ts'",
|
|
11
11
|
"typecheck": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { KiroRegion } from '../plugin/types';
|
|
2
|
-
export interface KiroSocialAuthorization {
|
|
3
|
-
url: string;
|
|
4
|
-
verifier: string;
|
|
5
|
-
region: KiroRegion;
|
|
6
|
-
}
|
|
7
|
-
export interface KiroSocialTokenResult {
|
|
8
|
-
refreshToken: string;
|
|
9
|
-
accessToken: string;
|
|
10
|
-
expiresAt: number;
|
|
11
|
-
email: string;
|
|
12
|
-
profileArn: string;
|
|
13
|
-
region: KiroRegion;
|
|
14
|
-
authMethod: 'social';
|
|
15
|
-
}
|
|
16
|
-
export declare function authorizeKiroSocial(port: number, state: string, challenge: string, region?: KiroRegion): Promise<string>;
|
|
17
|
-
export declare function exchangeKiroSocial(code: string, verifier: string, region: KiroRegion, port: number): Promise<KiroSocialTokenResult>;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { KIRO_AUTH_SERVICE, KIRO_CONSTANTS } from '../constants';
|
|
2
|
-
export async function authorizeKiroSocial(port, state, challenge, region) {
|
|
3
|
-
const effectiveRegion = region || KIRO_CONSTANTS.DEFAULT_REGION;
|
|
4
|
-
const authServiceEndpoint = KIRO_AUTH_SERVICE.ENDPOINT.replace('{{region}}', effectiveRegion);
|
|
5
|
-
const redirectUri = `http://127.0.0.1:${port}/oauth/callback`;
|
|
6
|
-
const params = new URLSearchParams({
|
|
7
|
-
idp: 'Google',
|
|
8
|
-
redirect_uri: redirectUri,
|
|
9
|
-
code_challenge: challenge,
|
|
10
|
-
code_challenge_method: 'S256',
|
|
11
|
-
state: state,
|
|
12
|
-
prompt: 'select_account',
|
|
13
|
-
});
|
|
14
|
-
return `${authServiceEndpoint}/login?${params.toString()}`;
|
|
15
|
-
}
|
|
16
|
-
export async function exchangeKiroSocial(code, verifier, region, port) {
|
|
17
|
-
const authServiceEndpoint = KIRO_AUTH_SERVICE.ENDPOINT.replace('{{region}}', region);
|
|
18
|
-
const redirectUri = `http://127.0.0.1:${port}/oauth/callback`;
|
|
19
|
-
const tokenResponse = await fetch(`${authServiceEndpoint}/oauth/token`, {
|
|
20
|
-
method: 'POST',
|
|
21
|
-
headers: {
|
|
22
|
-
'Content-Type': 'application/json',
|
|
23
|
-
'User-Agent': KIRO_CONSTANTS.USER_AGENT,
|
|
24
|
-
},
|
|
25
|
-
body: JSON.stringify({
|
|
26
|
-
code,
|
|
27
|
-
code_verifier: verifier,
|
|
28
|
-
redirect_uri: redirectUri,
|
|
29
|
-
}),
|
|
30
|
-
});
|
|
31
|
-
if (!tokenResponse.ok) {
|
|
32
|
-
const errorText = await tokenResponse.text();
|
|
33
|
-
throw new Error(`Token exchange failed: ${tokenResponse.status} ${errorText}`);
|
|
34
|
-
}
|
|
35
|
-
const tokenData = await tokenResponse.json();
|
|
36
|
-
if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.profileArn) {
|
|
37
|
-
throw new Error('Invalid token response: missing required fields');
|
|
38
|
-
}
|
|
39
|
-
const expiresIn = tokenData.expiresIn || 3600;
|
|
40
|
-
const expiresAt = Date.now() + expiresIn * 1000;
|
|
41
|
-
const email = tokenData.email || 'unknown@kiro.dev';
|
|
42
|
-
return {
|
|
43
|
-
refreshToken: tokenData.refreshToken,
|
|
44
|
-
accessToken: tokenData.accessToken,
|
|
45
|
-
expiresAt,
|
|
46
|
-
email,
|
|
47
|
-
profileArn: tokenData.profileArn,
|
|
48
|
-
region,
|
|
49
|
-
authMethod: 'social',
|
|
50
|
-
};
|
|
51
|
-
}
|
package/dist/plugin/cli.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { KiroAuthMethod, KiroRegion } from './types';
|
|
2
|
-
export declare function promptAuthMethod(): Promise<KiroAuthMethod>;
|
|
3
|
-
export declare function promptRegion(): Promise<KiroRegion>;
|
|
4
|
-
export declare function promptConfirmation(message: string): Promise<boolean>;
|
|
5
|
-
export declare function displayAuthUrl(url: string): void;
|
|
6
|
-
export declare function cleanup(): void;
|
package/dist/plugin/cli.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { createInterface } from 'node:readline';
|
|
2
|
-
import * as logger from './logger';
|
|
3
|
-
let rl = null;
|
|
4
|
-
function getReadline() {
|
|
5
|
-
if (!rl) {
|
|
6
|
-
rl = createInterface({
|
|
7
|
-
input: process.stdin,
|
|
8
|
-
output: process.stdout,
|
|
9
|
-
});
|
|
10
|
-
rl.on('SIGINT', () => {
|
|
11
|
-
logger.log('Received SIGINT, closing readline');
|
|
12
|
-
closeReadline();
|
|
13
|
-
process.exit(130);
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
return rl;
|
|
17
|
-
}
|
|
18
|
-
function closeReadline() {
|
|
19
|
-
if (rl) {
|
|
20
|
-
rl.close();
|
|
21
|
-
rl = null;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function question(prompt) {
|
|
25
|
-
return new Promise((resolve) => {
|
|
26
|
-
const readline = getReadline();
|
|
27
|
-
readline.question(prompt, (answer) => {
|
|
28
|
-
resolve(answer.trim());
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
function clearLine() {
|
|
33
|
-
if (process.stdout.isTTY) {
|
|
34
|
-
process.stdout.clearLine(0);
|
|
35
|
-
process.stdout.cursorTo(0);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
export async function promptAuthMethod() {
|
|
39
|
-
console.log('\nSelect authentication method:');
|
|
40
|
-
console.log(' 1. Social (GitHub, Google, etc.)');
|
|
41
|
-
console.log(' 2. IDC (Identity Center)');
|
|
42
|
-
while (true) {
|
|
43
|
-
const answer = await question('\nEnter your choice (1 or 2): ');
|
|
44
|
-
if (answer === '1' || answer.toLowerCase() === 'social') {
|
|
45
|
-
clearLine();
|
|
46
|
-
return 'social';
|
|
47
|
-
}
|
|
48
|
-
if (answer === '2' || answer.toLowerCase() === 'idc') {
|
|
49
|
-
clearLine();
|
|
50
|
-
return 'idc';
|
|
51
|
-
}
|
|
52
|
-
console.log('Invalid choice. Please enter 1 or 2.');
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
export async function promptRegion() {
|
|
56
|
-
console.log('\nSelect AWS region:');
|
|
57
|
-
console.log(' 1. us-east-1 (default)');
|
|
58
|
-
console.log(' 2. us-west-2');
|
|
59
|
-
while (true) {
|
|
60
|
-
const answer = await question('\nEnter your choice (1 or 2, default: 1): ');
|
|
61
|
-
if (!answer || answer === '1' || answer.toLowerCase() === 'us-east-1') {
|
|
62
|
-
clearLine();
|
|
63
|
-
return 'us-east-1';
|
|
64
|
-
}
|
|
65
|
-
if (answer === '2' || answer.toLowerCase() === 'us-west-2') {
|
|
66
|
-
clearLine();
|
|
67
|
-
return 'us-west-2';
|
|
68
|
-
}
|
|
69
|
-
console.log('Invalid choice. Please enter 1 or 2.');
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
export async function promptConfirmation(message) {
|
|
73
|
-
while (true) {
|
|
74
|
-
const answer = await question(`${message} (y/n): `);
|
|
75
|
-
const lower = answer.toLowerCase();
|
|
76
|
-
if (lower === 'y' || lower === 'yes') {
|
|
77
|
-
clearLine();
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
if (lower === 'n' || lower === 'no') {
|
|
81
|
-
clearLine();
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
console.log('Invalid input. Please enter y or n.');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
export function displayAuthUrl(url) {
|
|
88
|
-
console.log('\n' + '='.repeat(70));
|
|
89
|
-
console.log('Authentication Required');
|
|
90
|
-
console.log('='.repeat(70));
|
|
91
|
-
console.log('\nPlease open the following URL in your browser to authenticate:\n');
|
|
92
|
-
console.log(` ${url}\n`);
|
|
93
|
-
console.log('Waiting for authentication to complete...');
|
|
94
|
-
console.log('='.repeat(70) + '\n');
|
|
95
|
-
}
|
|
96
|
-
export function cleanup() {
|
|
97
|
-
closeReadline();
|
|
98
|
-
}
|
package/dist/plugin/debug.d.ts
DELETED
package/dist/plugin/debug.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export function isDebugEnabled() {
|
|
2
|
-
return !!process.env.DEBUG;
|
|
3
|
-
}
|
|
4
|
-
export function debugLog(context, message, data) {
|
|
5
|
-
if (isDebugEnabled()) {
|
|
6
|
-
const formattedData = data !== undefined ? ` ${JSON.stringify(data)}` : '';
|
|
7
|
-
console.debug(`[${context}] ${message}${formattedData}`);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export function parseOAuthCallbackInput(input) {
|
|
2
|
-
const trimmed = input.trim();
|
|
3
|
-
try {
|
|
4
|
-
const url = new URL(trimmed);
|
|
5
|
-
const code = url.searchParams.get('code');
|
|
6
|
-
const state = url.searchParams.get('state');
|
|
7
|
-
if (!code || !state) {
|
|
8
|
-
throw new Error('Missing code or state in URL');
|
|
9
|
-
}
|
|
10
|
-
return { code, state };
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
const codeMatch = trimmed.match(/code=([^&\s]+)/);
|
|
14
|
-
const stateMatch = trimmed.match(/state=([^&\s]+)/);
|
|
15
|
-
if (codeMatch?.[1] && stateMatch?.[1]) {
|
|
16
|
-
return {
|
|
17
|
-
code: decodeURIComponent(codeMatch[1]),
|
|
18
|
-
state: decodeURIComponent(stateMatch[1]),
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
throw new Error('Invalid OAuth callback format. Expected full URL or query string with code and state parameters.');
|
|
22
|
-
}
|
|
23
|
-
}
|
package/dist/plugin/quota.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ManagedAccount } from './types';
|
|
2
|
-
export type QuotaStatus = 'healthy' | 'warning' | 'exhausted';
|
|
3
|
-
export interface QuotaInfo {
|
|
4
|
-
status: QuotaStatus;
|
|
5
|
-
used: number;
|
|
6
|
-
limit: number;
|
|
7
|
-
remaining: number;
|
|
8
|
-
percentage: number;
|
|
9
|
-
recoveryTime?: number;
|
|
10
|
-
}
|
|
11
|
-
export declare function checkQuotaStatus(account: ManagedAccount): QuotaStatus;
|
|
12
|
-
export declare function updateAccountQuota(account: ManagedAccount, usage: any, accountManager?: any): void;
|
|
13
|
-
export declare function sortAccountsByQuota(accounts: ManagedAccount[]): ManagedAccount[];
|
|
14
|
-
export declare function filterHealthyAccounts(accounts: ManagedAccount[]): ManagedAccount[];
|
|
15
|
-
export declare function getAccountWithMostQuota(accounts: ManagedAccount[]): ManagedAccount | null;
|
package/dist/plugin/quota.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { calculateUsagePercentage, isQuotaExhausted, getRemainingCount } from './usage';
|
|
2
|
-
const WARNING_THRESHOLD_PERCENT = 80;
|
|
3
|
-
export function checkQuotaStatus(account) {
|
|
4
|
-
if (!account.usedCount || !account.limitCount) {
|
|
5
|
-
return 'healthy';
|
|
6
|
-
}
|
|
7
|
-
const usage = {
|
|
8
|
-
usedCount: account.usedCount,
|
|
9
|
-
limitCount: account.limitCount,
|
|
10
|
-
};
|
|
11
|
-
if (isQuotaExhausted(usage)) {
|
|
12
|
-
return 'exhausted';
|
|
13
|
-
}
|
|
14
|
-
const percentage = calculateUsagePercentage(usage);
|
|
15
|
-
if (percentage >= WARNING_THRESHOLD_PERCENT) {
|
|
16
|
-
return 'warning';
|
|
17
|
-
}
|
|
18
|
-
return 'healthy';
|
|
19
|
-
}
|
|
20
|
-
export function updateAccountQuota(account, usage, accountManager) {
|
|
21
|
-
const metadata = {
|
|
22
|
-
usedCount: typeof usage.usedCount === 'number' ? usage.usedCount : 0,
|
|
23
|
-
limitCount: typeof usage.limitCount === 'number' ? usage.limitCount : 0,
|
|
24
|
-
realEmail: usage.email
|
|
25
|
-
};
|
|
26
|
-
account.usedCount = metadata.usedCount;
|
|
27
|
-
account.limitCount = metadata.limitCount;
|
|
28
|
-
if (metadata.realEmail) {
|
|
29
|
-
account.realEmail = metadata.realEmail;
|
|
30
|
-
}
|
|
31
|
-
if (accountManager) {
|
|
32
|
-
accountManager.updateUsage(account.id, metadata);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export function sortAccountsByQuota(accounts) {
|
|
36
|
-
return [...accounts].sort((a, b) => {
|
|
37
|
-
const aRemaining = getRemainingQuota(a);
|
|
38
|
-
const bRemaining = getRemainingQuota(b);
|
|
39
|
-
return bRemaining - aRemaining;
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
function getRemainingQuota(account) {
|
|
43
|
-
if (!account.usedCount || !account.limitCount) {
|
|
44
|
-
return Infinity;
|
|
45
|
-
}
|
|
46
|
-
const usage = {
|
|
47
|
-
usedCount: account.usedCount,
|
|
48
|
-
limitCount: account.limitCount,
|
|
49
|
-
};
|
|
50
|
-
return getRemainingCount(usage);
|
|
51
|
-
}
|
|
52
|
-
export function filterHealthyAccounts(accounts) {
|
|
53
|
-
return accounts.filter(account => {
|
|
54
|
-
if (!account.isHealthy) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
const status = checkQuotaStatus(account);
|
|
58
|
-
return status !== 'exhausted';
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
export function getAccountWithMostQuota(accounts) {
|
|
62
|
-
const healthyAccounts = filterHealthyAccounts(accounts);
|
|
63
|
-
if (healthyAccounts.length === 0) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
const sorted = sortAccountsByQuota(healthyAccounts);
|
|
67
|
-
return sorted[0] || null;
|
|
68
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export interface RecoveryState {
|
|
2
|
-
sessionId: string;
|
|
3
|
-
conversationId: string;
|
|
4
|
-
model: string;
|
|
5
|
-
lastMessageIndex: number;
|
|
6
|
-
errorCount: number;
|
|
7
|
-
lastError?: string;
|
|
8
|
-
timestamp: number;
|
|
9
|
-
}
|
|
10
|
-
export interface RecoveryStorage {
|
|
11
|
-
version: 1;
|
|
12
|
-
sessions: Record<string, RecoveryState>;
|
|
13
|
-
}
|
|
14
|
-
export interface SessionRecoveryHook {
|
|
15
|
-
handleSessionError(error: any, sessionId: string): Promise<boolean>;
|
|
16
|
-
isRecoverableError(error: any): boolean;
|
|
17
|
-
clearSession(sessionId: string): Promise<void>;
|
|
18
|
-
}
|
|
19
|
-
export declare function createSessionRecoveryHook(enabled: boolean, autoResume: boolean): SessionRecoveryHook;
|