@magpie-community/opencode-workbuddy-auth 0.1.23 → 0.1.24

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 (2) hide show
  1. package/index.mjs +58 -7
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1136,17 +1136,67 @@ const STATUS_TEXT = {
1136
1136
  }
1137
1137
  const statusText = (n) => STATUS_TEXT[n] || `HTTP ${n}`
1138
1138
 
1139
- // meter asks the billing API as magpie's built-in did, its errors said
1140
- // the same: WorkBuddy's message, else its code, else the HTTP status.
1141
- async function meter(site, a, path, body = {}) {
1142
- const res = await fetch(site.endpoint + path, {
1139
+ // meterAsked is the billing API's reply to path, asked with a's sign-in.
1140
+ function meterAsked(site, a, path, body = {}, signal = AbortSignal.timeout(20000)) {
1141
+ return fetch(site.endpoint + path, {
1143
1142
  method: "POST",
1144
1143
  headers: { "Content-Type": "application/json", Accept: "application/json", "User-Agent": "WorkBuddy/" + UA_VERSION,
1145
1144
  Authorization: "Bearer " + a.access, "X-User-Id": a.uid ?? "", "X-Domain": domainOf(site, a), "X-Product": "SaaS",
1146
1145
  "X-IDE-Type": "WorkBuddy", ...enterpriseHeaders(a) },
1147
1146
  body: JSON.stringify(body),
1148
- signal: AbortSignal.timeout(20000),
1147
+ signal,
1149
1148
  })
1149
+ }
1150
+
1151
+ // EDGE_READS is how much of a request WorkBuddy's front door (APISIX, on
1152
+ // both sites) reads before it answers a sign-in it refuses. A refused
1153
+ // request with a longer body gets no answer at all: the connection is
1154
+ // reset, and the chat fails as "ECONNRESET: The socket connection was
1155
+ // closed unexpectedly", which says nothing of the sign-in (wyp on Discord,
1156
+ // 2026-10-15: a Claude Code session past 2 MiB failed on every turn).
1157
+ // Measured on 2026-10-15 on www.workbuddy.ai and copilot.tencent.com: a
1158
+ // body of 2097152 bytes with a refused token got 401, one of 2097153 a
1159
+ // reset; with an accepted token 20 MB went through.
1160
+ const EDGE_READS = 2 * 1024 * 1024
1161
+
1162
+ const byteLength = (b) =>
1163
+ typeof b === "string" ? Buffer.byteLength(b) : b instanceof ArrayBuffer || ArrayBuffer.isView(b) ? b.byteLength : 0
1164
+
1165
+ // unanswered is what a chat whose fetch failed with err comes to: a chat
1166
+ // past EDGE_READS that the connection was reset on is asked about at the
1167
+ // billing API, which answers a refused sign-in with its 401 whatever the
1168
+ // size. A 401 there is the chat's own answer, said as one; anything else
1169
+ // leaves err as it was, as does a smaller chat, which the front door
1170
+ // answers itself. The chat isn't sent again.
1171
+ async function unanswered(site, a, body, err, signal) {
1172
+ if (signal?.aborted || err?.name === "AbortError" || err?.name === "TimeoutError") throw err
1173
+ const size = byteLength(body)
1174
+ if (size <= EDGE_READS) throw err
1175
+ let status = 0
1176
+ try {
1177
+ const res = await meterAsked(site, a, "/billing/meter/get-user-resource-summary", {}, AbortSignal.timeout(20000))
1178
+ status = res.status
1179
+ await res.body?.cancel()
1180
+ } catch {
1181
+ throw err
1182
+ }
1183
+ if (status !== 401) throw err
1184
+ const mb = (size / (1024 * 1024)).toFixed(1)
1185
+ const message =
1186
+ `${site.name} refused this account's sign-in (401). It closes the connection on a refused request over 2 MiB ` +
1187
+ `(this one was ${mb} MiB) instead of answering, which is why it read as ECONNRESET. ` +
1188
+ (a.source === "desktop" ? `Sign in to ${site.name} desktop again.` : `Sign in to ${site.name} again in magpie.`)
1189
+ return new Response(JSON.stringify({ error: { message, type: "authentication_error", code: 401 } }), {
1190
+ status: 401,
1191
+ statusText: "Unauthorized",
1192
+ headers: { "content-type": "application/json" },
1193
+ })
1194
+ }
1195
+
1196
+ // meter asks the billing API as magpie's built-in did, its errors said
1197
+ // the same: WorkBuddy's message, else its code, else the HTTP status.
1198
+ async function meter(site, a, path, body = {}) {
1199
+ const res = await meterAsked(site, a, path, body)
1150
1200
  let env = {}
1151
1201
  try {
1152
1202
  env = JSON.parse(await res.text()) ?? {}
@@ -1555,7 +1605,8 @@ function makePlugin(site) {
1555
1605
  const fit = fitted(body)
1556
1606
  body = normalizeToolChoice(fit.body)
1557
1607
  attend(headers, body, session)
1558
- const send = (b) => fetch(req ? req.url : input, { ...init, method: init?.method ?? req?.method, headers, body: b })
1608
+ const send = (b) =>
1609
+ fetch(req ? req.url : input, { ...init, method: init?.method ?? req?.method, headers, body: b }).catch((e) => unanswered(site, a, b, e, init?.signal))
1559
1610
  // a model known to turn tool results then the user's message away
1560
1611
  // gets the empty reply between them up front (see endsAfterTools)
1561
1612
  const model = chatOf(body)?.model
@@ -1711,4 +1762,4 @@ export const WorkBuddyAuthPlugin = makePlugin(SITES.workbuddy)
1711
1762
  export const WorkBuddyAIAuthPlugin = makePlugin(SITES["workbuddy-ai"])
1712
1763
 
1713
1764
  // for tests
1714
- export const _internal = { fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, normalizeToolChoice, fitTools, fitted, renamed, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, freeCredits, creditsOf, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf }
1765
+ export const _internal = { EDGE_READS, fitShape, replyAfterTools, AFTER_TOOLS_REFUSED, enterpriseUsageOf, notDesktop, textOnly, runsOutOf, packagesOf, endOf, enterpriseHeaders, enterpriseOf, liveModels, browserSignIn, withSystem, normalizeToolChoice, fitTools, fitted, renamed, unflagged, usageOf, desktopHeld, explained, REFUSED_HINT, RESTRICTED_HINT, EXHAUSTED_HINT, freeCredits, creditsOf, priceOf, fresh, SITES, renewing, renewed, SESSION, attend, turnKey, conversationKey, signatureOf }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magpie-community/opencode-workbuddy-auth",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "OpenCode provider plugins for WorkBuddy's plans: WorkBuddy (CodeBuddy, copilot.tencent.com) and WorkBuddy AI (www.workbuddy.ai)",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",