@sunerpy/opencode-kiro-auth 0.6.0 → 0.6.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 +1 -0
- package/dist/core/request/request-handler.d.ts +6 -0
- package/dist/core/request/request-handler.js +9 -1
- package/dist/plugin/sync/kiro-cli-parser.d.ts +1 -0
- package/dist/plugin/sync/kiro-cli-parser.js +6 -0
- package/dist/plugin/sync/kiro-cli.js +48 -43
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@sunerpy/opencode-kiro-auth)
|
|
6
6
|
[](https://www.npmjs.com/package/@sunerpy/opencode-kiro-auth)
|
|
7
|
+
[](https://codecov.io/gh/sunerpy/opencode-kiro-auth)
|
|
7
8
|
[](https://www.npmjs.com/package/@sunerpy/opencode-kiro-auth)
|
|
8
9
|
|
|
9
10
|
> OpenCode plugin that lets OpenCode use AWS Kiro (CodeWhisperer) as a model
|
|
@@ -21,6 +21,12 @@ export declare class RequestHandler {
|
|
|
21
21
|
private enqueueKiroRequest;
|
|
22
22
|
private handleKiroRequest;
|
|
23
23
|
private extractModel;
|
|
24
|
+
/**
|
|
25
|
+
* Seam over the module-level SDK client factory so tests can inject a fake
|
|
26
|
+
* client without a real network call or a leaky module mock. Behavior is
|
|
27
|
+
* identical to calling createSdkClient directly.
|
|
28
|
+
*/
|
|
29
|
+
private makeSdkClient;
|
|
24
30
|
private prepareSdkRequest;
|
|
25
31
|
private handleSuccessfulRequest;
|
|
26
32
|
private logSdkRequest;
|
|
@@ -133,7 +133,7 @@ export class RequestHandler {
|
|
|
133
133
|
this.logSdkRequest(sdkPrep, acc, apiTimestamp);
|
|
134
134
|
}
|
|
135
135
|
try {
|
|
136
|
-
const client =
|
|
136
|
+
const client = this.makeSdkClient(auth, sdkPrep.region, sdkPrep.effort);
|
|
137
137
|
const command = new GenerateAssistantResponseCommand({
|
|
138
138
|
conversationState: sdkPrep.conversationState,
|
|
139
139
|
profileArn: sdkPrep.profileArn
|
|
@@ -183,6 +183,14 @@ export class RequestHandler {
|
|
|
183
183
|
extractModel(url) {
|
|
184
184
|
return url.match(/models\/([^/:]+)/)?.[1] || null;
|
|
185
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Seam over the module-level SDK client factory so tests can inject a fake
|
|
188
|
+
* client without a real network call or a leaky module mock. Behavior is
|
|
189
|
+
* identical to calling createSdkClient directly.
|
|
190
|
+
*/
|
|
191
|
+
makeSdkClient(auth, region, effort) {
|
|
192
|
+
return createSdkClient(auth, region, effort);
|
|
193
|
+
}
|
|
186
194
|
prepareSdkRequest(body, model, auth, think, budget, showToast) {
|
|
187
195
|
return transformToSdkRequest(body, model, auth, think, budget, showToast, {
|
|
188
196
|
effort: this.config.effort,
|
|
@@ -6,3 +6,4 @@ export declare function findClientCredsRecursive(input: unknown): {
|
|
|
6
6
|
clientSecret?: string;
|
|
7
7
|
};
|
|
8
8
|
export declare function makePlaceholderEmail(authMethod: string, region: string, clientId?: string, profileArn?: string): string;
|
|
9
|
+
export declare function isPlaceholderEmail(email: unknown): boolean;
|
|
@@ -70,3 +70,9 @@ export function makePlaceholderEmail(authMethod, region, clientId, profileArn) {
|
|
|
70
70
|
const h = createHash('sha256').update(seed).digest('hex').slice(0, 16);
|
|
71
71
|
return `${authMethod}-placeholder+${h}@awsapps.local`;
|
|
72
72
|
}
|
|
73
|
+
// Loose pre-filter ONLY. NOT authoritative: before deleting, callers must also
|
|
74
|
+
// require row.email === exact makePlaceholderEmail(...) AND row.id === recomputed
|
|
75
|
+
// placeholderId for the SAME identity, so a real account is never deleted.
|
|
76
|
+
export function isPlaceholderEmail(email) {
|
|
77
|
+
return (typeof email === 'string' && email.includes('-placeholder+') && email.endsWith('@awsapps.local'));
|
|
78
|
+
}
|
|
@@ -5,7 +5,7 @@ import { createDeterministicAccountId } from '../accounts.js';
|
|
|
5
5
|
import * as logger from '../logger.js';
|
|
6
6
|
import { kiroDb } from '../storage/sqlite.js';
|
|
7
7
|
import { fetchUsageLimits } from '../usage.js';
|
|
8
|
-
import { findClientCredsRecursive, getCliDbPath, makePlaceholderEmail, normalizeExpiresAt, safeJsonParse } from './kiro-cli-parser.js';
|
|
8
|
+
import { findClientCredsRecursive, getCliDbPath, isPlaceholderEmail, makePlaceholderEmail, normalizeExpiresAt, safeJsonParse } from './kiro-cli-parser.js';
|
|
9
9
|
import { readActiveProfileArnFromKiroCli } from './kiro-cli-profile.js';
|
|
10
10
|
import { getStaleKiroCliAccountIds, STALE_CLI_ACCOUNT_REASON } from './stale-accounts.js';
|
|
11
11
|
export async function syncFromKiroCli() {
|
|
@@ -96,61 +96,66 @@ export async function syncFromKiroCli() {
|
|
|
96
96
|
}
|
|
97
97
|
const all = kiroDb.getAccounts();
|
|
98
98
|
if (!email) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
99
|
+
const sameIdentity = all.filter((a) => {
|
|
100
|
+
if (profileArn && a.auth_method === authMethod && a.profile_arn === profileArn)
|
|
101
|
+
return true;
|
|
102
|
+
if (authMethod === 'idc' &&
|
|
103
|
+
clientId &&
|
|
104
|
+
a.auth_method === 'idc' &&
|
|
105
|
+
a.client_id === clientId)
|
|
106
|
+
return true;
|
|
107
|
+
return false;
|
|
108
|
+
});
|
|
109
|
+
const realAccount = sameIdentity.find((a) => typeof a.email === 'string' && a.email && !isPlaceholderEmail(a.email));
|
|
110
|
+
if (realAccount) {
|
|
111
|
+
email = realAccount.email;
|
|
108
112
|
}
|
|
109
113
|
else {
|
|
114
|
+
const placeholderId = createDeterministicAccountId(makePlaceholderEmail(authMethod, serviceRegion, clientId, profileArn), authMethod, clientId, profileArn);
|
|
115
|
+
if (await kiroDb.isAccountRemoved(placeholderId)) {
|
|
116
|
+
await kiroDb.clearRemovedAccount(placeholderId);
|
|
117
|
+
}
|
|
110
118
|
email = makePlaceholderEmail(authMethod, serviceRegion, clientId, profileArn);
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
121
|
const resolvedEmail = email || makePlaceholderEmail(authMethod, serviceRegion, clientId, profileArn);
|
|
122
|
+
const hasRealEmail = !!resolvedEmail && !isPlaceholderEmail(resolvedEmail);
|
|
114
123
|
const id = createDeterministicAccountId(resolvedEmail, authMethod, clientId, profileArn);
|
|
124
|
+
// Cleanup runs BEFORE the fresh-enough early-continue: a lingering
|
|
125
|
+
// same-identity placeholder must be removed even when the real account
|
|
126
|
+
// is already up to date and would otherwise skip the rest of the round.
|
|
127
|
+
if (hasRealEmail) {
|
|
128
|
+
for (const row of all) {
|
|
129
|
+
if (row.id === id)
|
|
130
|
+
continue;
|
|
131
|
+
const sameIdentity = (!!profileArn && row.auth_method === authMethod && row.profile_arn === profileArn) ||
|
|
132
|
+
(authMethod === 'idc' &&
|
|
133
|
+
!!clientId &&
|
|
134
|
+
row.auth_method === 'idc' &&
|
|
135
|
+
row.client_id === clientId);
|
|
136
|
+
if (!sameIdentity)
|
|
137
|
+
continue;
|
|
138
|
+
if (!isPlaceholderEmail(row.email))
|
|
139
|
+
continue;
|
|
140
|
+
// Prove the row is a genuine placeholder by self-consistency against
|
|
141
|
+
// its OWN fields (clientId rotates across device re-registration, so
|
|
142
|
+
// recomputing with the current token's clientId would miss it). A
|
|
143
|
+
// real email can never equal its own makePlaceholderEmail recompute,
|
|
144
|
+
// so this never deletes a real account.
|
|
145
|
+
const rowPlaceholderEmail = makePlaceholderEmail(row.auth_method, row.region, row.client_id, row.profile_arn);
|
|
146
|
+
const rowPlaceholderId = createDeterministicAccountId(rowPlaceholderEmail, row.auth_method, row.client_id, row.profile_arn);
|
|
147
|
+
if (row.email === rowPlaceholderEmail && row.id === rowPlaceholderId) {
|
|
148
|
+
await kiroDb.deleteAccount(row.id);
|
|
149
|
+
await kiroDb.addRemovedAccount(row.id);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
115
153
|
const existingById = all.find((a) => a.id === id);
|
|
116
154
|
if (existingById &&
|
|
117
155
|
existingById.is_healthy === 1 &&
|
|
118
156
|
existingById.expires_at >= cliExpiresAt &&
|
|
119
157
|
existingById.expires_at > Date.now())
|
|
120
158
|
continue;
|
|
121
|
-
if (usageOk) {
|
|
122
|
-
const placeholderEmail = makePlaceholderEmail(authMethod, serviceRegion, clientId, profileArn);
|
|
123
|
-
const placeholderId = createDeterministicAccountId(placeholderEmail, authMethod, clientId, profileArn);
|
|
124
|
-
if (placeholderId !== id) {
|
|
125
|
-
const placeholderRow = all.find((a) => a.id === placeholderId);
|
|
126
|
-
if (placeholderRow && (await kiroDb.isAccountRemoved(placeholderId))) {
|
|
127
|
-
skippedRemoved++;
|
|
128
|
-
}
|
|
129
|
-
else if (placeholderRow) {
|
|
130
|
-
await kiroDb.upsertAccount({
|
|
131
|
-
id: placeholderId,
|
|
132
|
-
email: placeholderRow.email,
|
|
133
|
-
authMethod,
|
|
134
|
-
region: placeholderRow.region || serviceRegion,
|
|
135
|
-
oidcRegion: placeholderRow.oidc_region || oidcRegion,
|
|
136
|
-
clientId,
|
|
137
|
-
clientSecret,
|
|
138
|
-
profileArn,
|
|
139
|
-
refreshToken: placeholderRow.refresh_token || refreshToken,
|
|
140
|
-
accessToken: placeholderRow.access_token || accessToken,
|
|
141
|
-
expiresAt: placeholderRow.expires_at || cliExpiresAt,
|
|
142
|
-
rateLimitResetTime: 0,
|
|
143
|
-
isHealthy: false,
|
|
144
|
-
failCount: 10,
|
|
145
|
-
unhealthyReason: 'Replaced by real email',
|
|
146
|
-
recoveryTime: Date.now() + 31536000000,
|
|
147
|
-
usedCount: placeholderRow.used_count || 0,
|
|
148
|
-
limitCount: placeholderRow.limit_count || 0,
|
|
149
|
-
lastSync: Date.now()
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
159
|
if (await kiroDb.isAccountRemoved(id)) {
|
|
155
160
|
skippedRemoved++;
|
|
156
161
|
continue;
|