@magpie-community/opencode-zcode-auth 0.1.24 → 0.1.25

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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/index.mjs +49 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -53,6 +53,11 @@ over Anthropic's Messages API. Provider id: `zcode`.
53
53
  another's credentials: to use both, add the app's sign-in once for each.
54
54
  - **GLM Coding Plan API key**
55
55
  - Paste a key (`<id>.<secret>`) and say which site it is from.
56
+ - A key reaches the GLM Coding Plan alone. ZCode's gift plans (the
57
+ Start Plan, ZCode 1024 Dev Day) are served to ZCode's own session,
58
+ which a key doesn't carry: for an account with only a gift plan, the
59
+ card and each refused request (1113) say to sign in with ZCode
60
+ instead.
56
61
 
57
62
  ## Where the sign-in is kept
58
63
 
package/index.mjs CHANGED
@@ -437,14 +437,54 @@ async function codingUsage(s) {
437
437
  if (level) out.plan = "GLM Coding " + level[0].toUpperCase() + level.slice(1)
438
438
  out.windows = limitWindows(d)
439
439
  const resets = personalResets(root, s.key)
440
+ let subs = null
440
441
  try {
441
- Object.assign(out, termOf(await call("GET", root + "/api/biz/subscription/list", { auth: s.key })))
442
+ subs = await call("GET", root + "/api/biz/subscription/list", { auth: s.key })
443
+ Object.assign(out, termOf(subs))
442
444
  } catch {}
443
445
  const r = await resets
444
446
  if (r) out.resets = r
447
+ // a key whose account has no plan in force, read as such, says so
448
+ // rather than showing an empty card: what a key can spend is a GLM
449
+ // Coding Plan alone (a ZCode gift plan is never one, see NO_PLAN_KEY).
450
+ // A list that couldn't be read, a level, a counted window or a plan
451
+ // the sign-in saved keeps the card as it was.
452
+ const valid = (Array.isArray(subs) ? subs : []).some((x) => String(x?.status ?? "").toUpperCase() === "VALID")
453
+ if (subs !== null && !valid && !level && !s.plan && !out.windows.some((w) => !w.aside)) return { error: NO_PLAN_KEY }
445
454
  return out
446
455
  }
447
456
 
457
+ // NO_PLAN_KEY is a key with no GLM Coding Plan behind it. ZCode's gift
458
+ // plans (its Start Plan, ZCode 1024 Dev Day) are served by zcode.z.ai
459
+ // to ZCode's own session token, which a sign-in with ZCode (the app's,
460
+ // or Z.ai's or BigModel's in the browser) carries and a key never does:
461
+ // with a key, a gift-only account has nothing to spend, and Z.ai answers
462
+ // each request 1113 (rtbeilin on X, 10-24).
463
+ const NO_PLAN_KEY =
464
+ "this key's account has no GLM Coding Plan; ZCode's gift plans (the Start Plan, ZCode 1024 Dev Day) are spent only with ZCode's sign-in, never with a key — add the account with \"ZCode app's sign-in\" or a ZCode sign-in in the browser"
465
+
466
+ // noPlanKey is a coding plan's 1113 refusal (no plan, no resource
467
+ // package) to a sign-in with no ZCode session, its message followed by
468
+ // NO_PLAN_KEY; anything else goes on as it came. Read only once the
469
+ // answer has failed.
470
+ function noPlanKey(res, text) {
471
+ let v
472
+ try {
473
+ v = JSON.parse(text)
474
+ } catch {
475
+ return null
476
+ }
477
+ // Z.ai names the code in error.code ("1113", as magpie's
478
+ // zhipu_coding_test has it) or error.type (its 401's "1000"), BigModel's
479
+ // envelope in code
480
+ if (![v?.error?.code, v?.error?.type, v?.code].some((c) => String(c ?? "") === "1113")) return null
481
+ const said = first(v?.error?.message, v?.msg, v?.message)
482
+ const out = v?.error && typeof v.error === "object" ? { ...v, error: { ...v.error, message: (said ? said + " — " : "") + NO_PLAN_KEY } } : { ...v, msg: (said ? said + " — " : "") + NO_PLAN_KEY }
483
+ const h = new Headers(res.headers)
484
+ h.set("content-type", "application/json")
485
+ return new Response(JSON.stringify(out), { status: res.status, statusText: res.statusText, headers: h })
486
+ }
487
+
448
488
  // startNum reads a number the balance gives as a number or a string.
449
489
  function startNum(v) {
450
490
  if (isNum(v)) return v
@@ -1840,6 +1880,14 @@ export async function ZCodeAuthPlugin({ client }) {
1840
1880
  if (startRefused(res.status, text)) return kept(startBlocked(res, text))
1841
1881
  res = new Response(text, { status: res.status, statusText: res.statusText, headers: res.headers })
1842
1882
  }
1883
+ // a key with no plan behind it: what Z.ai said, and why a
1884
+ // ZCode gift plan can't be had with a key (NO_PLAN_KEY)
1885
+ if (!start && !s.jwt && res.status >= 400) {
1886
+ const text = await res.text()
1887
+ const why = noPlanKey(res, text)
1888
+ if (why) return done(kept(why))
1889
+ res = new Response(text, { status: res.status, statusText: res.statusText, headers: res.headers })
1890
+ }
1843
1891
  // a trial entry's gift answer that can't serve the request is
1844
1892
  // the agent's answer, not the coding plan's: the user picked the
1845
1893
  // gift, so a spent bucket says 429 (its quota error inside a 200
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-zcode-auth",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "OpenCode provider plugin: signs in to Z.ai's or BigModel's (智谱) GLM Coding Plan as ZCode does, including team seats and ZCode's Start Plan",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",