@magpie-community/opencode-kiro-auth 0.1.14 → 0.1.15
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 +6 -2
- package/index.mjs +70 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,8 +46,12 @@ Power) and makes its requests, in OpenCode and in magpie. Provider id:
|
|
|
46
46
|
kiro-cli refreshes its own token first (`kiro-cli debug refresh-auth-token`).
|
|
47
47
|
A token the plugin refreshes itself is written back, so kiro-cli and the
|
|
48
48
|
IDE go on with it.
|
|
49
|
-
- **Kiro API key (`ksk_…`)**: sent with `tokentype: API_KEY
|
|
50
|
-
|
|
49
|
+
- **Kiro API key (`ksk_…`)**: sent with `tokentype: API_KEY`, as kiro-cli
|
|
50
|
+
sends it. `GetProfile` is asked in us-east-1, then eu-central-1, for the
|
|
51
|
+
region the key's profile is in; a key it finds none for is used in
|
|
52
|
+
us-east-1, as kiro-cli uses it. Its models are listed with the control
|
|
53
|
+
plane's `ListAvailableModels` and its credits with `GetUsageLimits`, and
|
|
54
|
+
no profile is named in its calls, as kiro-cli names none.
|
|
51
55
|
|
|
52
56
|
A browser sign-in is kept where OpenCode keeps sign-ins (`auth.json`; in
|
|
53
57
|
magpie, `plugin-auth.json`) as an `oauth` entry. The entry holds the
|
package/index.mjs
CHANGED
|
@@ -333,25 +333,48 @@ async function managementCall(region, a, method, query, body) {
|
|
|
333
333
|
return JSON.parse(text)
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
-
//
|
|
337
|
-
// key
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
336
|
+
// controlCall is one of Kiro's management operations as kiro-cli sends it
|
|
337
|
+
// for an API key: AWS JSON 1.0, the operation named in X-Amz-Target, POSTed
|
|
338
|
+
// to the endpoint's root (with ?origin=KIRO_CLI where kiro-cli adds it).
|
|
339
|
+
async function controlCall(region, a, target, body, query) {
|
|
340
|
+
const res = await fetch(management(region) + "/" + (query ? "?" + new URLSearchParams(query) : ""), {
|
|
341
|
+
method: "POST",
|
|
342
|
+
headers: { ...authHeaders(a), "Content-Type": "application/x-amz-json-1.0", "X-Amz-Target": target,
|
|
343
|
+
"x-amzn-codewhisperer-optout": "false" },
|
|
344
|
+
body: JSON.stringify(body),
|
|
345
|
+
signal: AbortSignal.timeout(20_000),
|
|
346
|
+
})
|
|
347
|
+
const text = await res.text()
|
|
348
|
+
if (!res.ok) throw new KiroError(res.status, text)
|
|
349
|
+
return JSON.parse(text)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// KEY_REGIONS are where kiro-cli asks GetProfile for an API key's profile,
|
|
353
|
+
// in its order (the GovCloud and ISO ones after them aren't Kiro's
|
|
354
|
+
// subscriptions).
|
|
355
|
+
const KEY_REGIONS = ["us-east-1", "eu-central-1"]
|
|
356
|
+
|
|
357
|
+
// keyProfile is an API key's profile, as kiro-cli finds it: GetProfile in
|
|
358
|
+
// each region until one answers with a profile. kiro-cli goes on without
|
|
359
|
+
// one when every region turns it down (a key from an account with no
|
|
360
|
+
// CodeWhisperer profile answers 400), and so does this: "" then, and the
|
|
361
|
+
// key's calls are made in us-east-1 without a profile, as kiro-cli makes
|
|
362
|
+
// them (Hollowhere, on magpie's Discord: a key kiro-cli 2.33.1 served
|
|
363
|
+
// failed every request here with "Kiro didn't take the API key: 400").
|
|
364
|
+
async function keyProfile(c) {
|
|
365
|
+
for (const region of KEY_REGIONS) {
|
|
366
|
+
try {
|
|
367
|
+
const arn = (await controlCall(region, { token: c.access, tokenType: "API_KEY" }, "AmazonCodeWhispererService.GetProfile", {}))
|
|
368
|
+
?.profile?.arn
|
|
369
|
+
if (arn) return arn
|
|
370
|
+
} catch {}
|
|
354
371
|
}
|
|
372
|
+
return ""
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// profileOf finds the profile a sign-in that doesn't name one uses:
|
|
376
|
+
// Builder ID's, or the first Kiro lists in either of its regions.
|
|
377
|
+
async function profileOf(c) {
|
|
355
378
|
if (c.builderID) return BUILDER_ID_PROFILE
|
|
356
379
|
let last
|
|
357
380
|
for (const region of ["us-east-1", "eu-central-1"]) {
|
|
@@ -370,6 +393,8 @@ async function profileOf(c) {
|
|
|
370
393
|
|
|
371
394
|
// usageLimits is Get-Usage-Limits: the plan, the account's email, credits.
|
|
372
395
|
function usageLimits(a, email) {
|
|
396
|
+
// an API key's, as kiro-cli asks for it: no profile, no email asked
|
|
397
|
+
if (a.tokenType === "API_KEY") return controlCall(a.region, a, "AmazonCodeWhispererService.GetUsageLimits", { origin: "KIRO_CLI" }, { origin: "KIRO_CLI" })
|
|
373
398
|
return managementCall(a.region, a, "Get-Usage-Limits",
|
|
374
399
|
{ origin: "KIRO_CLI", profileArn: a.profile, resourceType: "CREDIT", isEmailRequired: String(email) })
|
|
375
400
|
}
|
|
@@ -497,7 +522,12 @@ function account(client) {
|
|
|
497
522
|
saved = true
|
|
498
523
|
}
|
|
499
524
|
}
|
|
500
|
-
if (
|
|
525
|
+
if (c.method === "apikey") {
|
|
526
|
+
if (!c.asked) {
|
|
527
|
+
c.profile = await keyProfile(c)
|
|
528
|
+
c.asked = true
|
|
529
|
+
}
|
|
530
|
+
} else if (!c.profile) {
|
|
501
531
|
c.profile = await profileOf(c)
|
|
502
532
|
if (!auth?.profileArn && !saved) {
|
|
503
533
|
await save(auth, c)
|
|
@@ -510,7 +540,10 @@ function account(client) {
|
|
|
510
540
|
await save(auth, c)
|
|
511
541
|
}
|
|
512
542
|
held = { id, c }
|
|
513
|
-
|
|
543
|
+
// kiro-cli names no profile in an API key's calls, even one GetProfile
|
|
544
|
+
// found; the profile only says the key's region
|
|
545
|
+
const profile = c.method === "apikey" ? "" : c.profile
|
|
546
|
+
return { token: c.access, tokenType: tokenType(c), profile, region: regionOf(c.profile, c.region) }
|
|
514
547
|
})
|
|
515
548
|
// renew is auth.refresh's: a sign-in kept here (not kiro-cli's or the
|
|
516
549
|
// IDE's, which their owners keep) renewed under the same lock as the
|
|
@@ -584,9 +617,25 @@ function runtimeModel(m) {
|
|
|
584
617
|
// picks a model for each request.
|
|
585
618
|
const MODELS = [{ id: "auto", name: "Auto" }]
|
|
586
619
|
|
|
620
|
+
// keyModels is an API key's list, asked as kiro-cli asks it: Kiro's
|
|
621
|
+
// control plane's ListAvailableModels, with no profile, each page.
|
|
622
|
+
async function keyModels(a) {
|
|
623
|
+
const out = { models: [] }
|
|
624
|
+
let next
|
|
625
|
+
for (let i = 0; i < 20; i++) {
|
|
626
|
+
const page = await controlCall(a.region, a, "KiroControlPlaneBearerService.ListAvailableModels",
|
|
627
|
+
{ origin: "KIRO_CLI", ...(next ? { nextToken: next } : {}) }, { origin: "KIRO_CLI" })
|
|
628
|
+
out.models.push(...(page?.models ?? []))
|
|
629
|
+
out.defaultModel ??= page?.defaultModel
|
|
630
|
+
next = page?.nextToken
|
|
631
|
+
if (!next) break
|
|
632
|
+
}
|
|
633
|
+
return out
|
|
634
|
+
}
|
|
635
|
+
|
|
587
636
|
// listModels is List-Available-Models, the default first.
|
|
588
637
|
async function listModels(a) {
|
|
589
|
-
const out = await managementCall(a.region, a, "List-Available-Models", { origin: "KIRO_CLI", profileArn: a.profile })
|
|
638
|
+
const out = a.tokenType === "API_KEY" ? await keyModels(a) : await managementCall(a.region, a, "List-Available-Models", { origin: "KIRO_CLI", profileArn: a.profile })
|
|
590
639
|
const list = []
|
|
591
640
|
for (const m of out?.models ?? []) {
|
|
592
641
|
if (!m?.modelId) continue
|