@magpie-community/opencode-kiro-auth 0.1.0 → 0.1.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/index.mjs +57 -6
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -266,13 +266,18 @@ function regionOf(profile, signedIn) {
|
|
|
266
266
|
return String(signedIn ?? "").startsWith("eu-") ? "eu-central-1" : "us-east-1"
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
// STATUS_TEXT is Go's http.StatusText for the answers Kiro gives.
|
|
270
|
+
const STATUS_TEXT = { 400: "Bad Request", 401: "Unauthorized", 403: "Forbidden", 404: "Not Found", 408: "Request Timeout",
|
|
271
|
+
409: "Conflict", 413: "Request Entity Too Large", 429: "Too Many Requests", 500: "Internal Server Error", 502: "Bad Gateway",
|
|
272
|
+
503: "Service Unavailable", 504: "Gateway Timeout" }
|
|
273
|
+
|
|
269
274
|
class KiroError extends Error {
|
|
270
275
|
constructor(status, body) {
|
|
271
276
|
let msg = ""
|
|
272
277
|
try {
|
|
273
278
|
msg = JSON.parse(body)?.message ?? ""
|
|
274
279
|
} catch {}
|
|
275
|
-
super(msg ? `Kiro: ${msg} (${status})` : `Kiro:
|
|
280
|
+
super(msg ? `Kiro: ${msg} (${status})` : `Kiro: ${STATUS_TEXT[status] ?? ""}`)
|
|
276
281
|
this.status = status
|
|
277
282
|
}
|
|
278
283
|
}
|
|
@@ -333,6 +338,38 @@ function usageLimits(a, email) {
|
|
|
333
338
|
const planName = (title) =>
|
|
334
339
|
String(title ?? "").toLowerCase().split(/\s+/).filter(Boolean).map((w) => (w === "kiro" ? "Kiro" : w[0].toUpperCase() + w.slice(1))).join(" ")
|
|
335
340
|
|
|
341
|
+
// goG is Go's %g of x: an exponent from a million up.
|
|
342
|
+
function goG(x) {
|
|
343
|
+
const [m, e] = x.toExponential().split("e")
|
|
344
|
+
const exp = Number(e)
|
|
345
|
+
if (exp < -4 || exp >= 6) return `${m}e${exp < 0 ? "-" : "+"}${String(Math.abs(exp)).padStart(2, "0")}`
|
|
346
|
+
return String(x)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// usageOf is the allowance Get-Usage-Limits tells, as magpie's built-in
|
|
350
|
+
// said it: the account's email, the credits of each allowance, the month's and a free trial's
|
|
351
|
+
// while it runs.
|
|
352
|
+
function usageOf(l) {
|
|
353
|
+
const at = (secs) => (secs > 0 ? new Date(Math.trunc(secs) * 1000).toISOString() : undefined)
|
|
354
|
+
const count = (used, limit) => used.toFixed(2).replace(/0+$/, "").replace(/\.$/, "") + " / " + goG(limit)
|
|
355
|
+
const num = (x) => (typeof x === "number" && Number.isFinite(x) ? x : 0)
|
|
356
|
+
const windows = []
|
|
357
|
+
for (const u of l?.usageBreakdownList ?? []) {
|
|
358
|
+
const t = u?.freeTrialInfo
|
|
359
|
+
if (t && String(t.freeTrialStatus ?? "").toUpperCase() === "ACTIVE" && num(t.usageLimitWithPrecision) > 0) {
|
|
360
|
+
const used = num(t.currentUsageWithPrecision), limit = num(t.usageLimitWithPrecision)
|
|
361
|
+
windows.push({ name: "Free trial", used: (100 * used) / limit, resetsAt: at(num(t.freeTrialExpiry)), display: count(used, limit) })
|
|
362
|
+
}
|
|
363
|
+
const used = num(u?.currentUsageWithPrecision), limit = num(u?.usageLimitWithPrecision)
|
|
364
|
+
if (limit <= 0) continue
|
|
365
|
+
const reset = num(u?.nextDateReset) || num(l?.nextDateReset)
|
|
366
|
+
windows.push({ name: u?.displayNamePlural || u?.displayName || "Credits", used: (100 * used) / limit, resetsAt: at(reset),
|
|
367
|
+
display: count(used, limit), span: 30 * 24 * 3600 })
|
|
368
|
+
}
|
|
369
|
+
const email = l?.userInfo?.email
|
|
370
|
+
return { plan: planName(l?.subscriptionInfo?.subscriptionTitle), ...(typeof email === "string" && email ? { user: email } : {}), windows }
|
|
371
|
+
}
|
|
372
|
+
|
|
336
373
|
// ---- the account, as the plugin holds it -------------------------------------------
|
|
337
374
|
|
|
338
375
|
// credOf is the sign-in a stored auth names: a key, one signed in here, or
|
|
@@ -374,7 +411,11 @@ function account(client) {
|
|
|
374
411
|
const read = await credOf(auth)
|
|
375
412
|
if (!read) {
|
|
376
413
|
held = null
|
|
377
|
-
throw new Error(
|
|
414
|
+
throw new Error(
|
|
415
|
+
auth?.source
|
|
416
|
+
? "Kiro isn't signed in; add the Kiro subscription in magpie, sign in with `kiro-cli login` or the Kiro IDE, or save a Kiro API key on the provider"
|
|
417
|
+
: "this Kiro account's sign-in is gone; add it again in magpie",
|
|
418
|
+
)
|
|
378
419
|
}
|
|
379
420
|
let c = held?.id === id ? held.c : null
|
|
380
421
|
if (!c || read.access !== c.access || !fresh(c) || stale) {
|
|
@@ -1134,7 +1175,7 @@ async function browserSignIn() {
|
|
|
1134
1175
|
const q = url.searchParams
|
|
1135
1176
|
if (!waiting) return html(200, page(false, "This sign-in is over", "Start it again."))
|
|
1136
1177
|
const fail = (msg) => {
|
|
1137
|
-
finish({ type: "failed" })
|
|
1178
|
+
finish({ type: "failed", error: msg })
|
|
1138
1179
|
html(200, page(false, "Sign-in didn't finish", msg))
|
|
1139
1180
|
}
|
|
1140
1181
|
if (q.get("error")) return fail(q.get("error_description") || q.get("error"))
|
|
@@ -1189,7 +1230,7 @@ async function browserSignIn() {
|
|
|
1189
1230
|
html(200, page(true, "You're signed in", `${user} is signed in. You can close this tab.`))
|
|
1190
1231
|
})
|
|
1191
1232
|
|
|
1192
|
-
const timer = setTimeout(() => finish({ type: "failed" }), SIGN_IN_TIMEOUT)
|
|
1233
|
+
const timer = setTimeout(() => finish({ type: "failed", error: "the sign-in timed out" }), SIGN_IN_TIMEOUT)
|
|
1193
1234
|
done.then(() => {
|
|
1194
1235
|
clearTimeout(timer)
|
|
1195
1236
|
setTimeout(() => server.close(), 10_000).unref?.()
|
|
@@ -1214,7 +1255,7 @@ async function ownSignIn() {
|
|
|
1214
1255
|
callback: async () => {
|
|
1215
1256
|
const cli = await readCLI()
|
|
1216
1257
|
const c = cli ?? (await readIDE())
|
|
1217
|
-
if (!c) return { type: "failed" }
|
|
1258
|
+
if (!c) return { type: "failed", error: "neither kiro-cli nor the Kiro IDE is signed in" }
|
|
1218
1259
|
const who = fresh(c) ? await whoIs(c) : { email: "", plan: "" }
|
|
1219
1260
|
return { type: "success", provider: ID, refresh: "", access: "", expires: 0, source: cli ? "kiro-cli" : "kiro-ide",
|
|
1220
1261
|
accountId: who.email || (cli ? "kiro-cli's account" : "Kiro IDE's account"), ...(who.plan ? { plan: who.plan } : {}) }
|
|
@@ -1255,6 +1296,16 @@ export async function KiroAuthPlugin({ client } = {}) {
|
|
|
1255
1296
|
},
|
|
1256
1297
|
}
|
|
1257
1298
|
},
|
|
1299
|
+
// the account's credits, as magpie's built-in showed them
|
|
1300
|
+
async usage(getAuth) {
|
|
1301
|
+
const auth = await getAuth()
|
|
1302
|
+
if (!(auth?.type === "api" && auth.key) && auth?.type !== "oauth") return { error: "not signed in" }
|
|
1303
|
+
try {
|
|
1304
|
+
return usageOf(await usageLimits(await creds(auth), true))
|
|
1305
|
+
} catch (e) {
|
|
1306
|
+
return { error: e.message }
|
|
1307
|
+
}
|
|
1308
|
+
},
|
|
1258
1309
|
methods: [
|
|
1259
1310
|
{ type: "oauth", label: "Kiro (Google, GitHub, AWS Builder ID, IAM Identity Center)", authorize: browserSignIn },
|
|
1260
1311
|
{ type: "oauth", label: "Kiro CLI's or Kiro IDE's sign-in", authorize: ownSignIn },
|
|
@@ -1289,4 +1340,4 @@ export async function KiroAuthPlugin({ client } = {}) {
|
|
|
1289
1340
|
}
|
|
1290
1341
|
|
|
1291
1342
|
// for tests
|
|
1292
|
-
export const _internal = { buildKiro, events, reply, failure, toolID, thinking, readCLI, readIDE, regionOf, planName, frames }
|
|
1343
|
+
export const _internal = { usageOf, buildKiro, events, reply, failure, toolID, thinking, readCLI, readIDE, regionOf, planName, frames }
|