@magpie-community/opencode-trae-auth 0.1.3 → 0.1.4
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 +19 -0
- package/index.mjs +43 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -107,3 +107,22 @@ magpie's usage card shows the account's credits:
|
|
|
107
107
|
unlimited) and what the pack has used.
|
|
108
108
|
- **What it shows:** credits left as the balance, and the share used as a
|
|
109
109
|
window.
|
|
110
|
+
|
|
111
|
+
## Daily check-in
|
|
112
|
+
|
|
113
|
+
Trae CN gives credits for a daily check-in (每日签到). magpie can press it
|
|
114
|
+
once a day for each account (Settings, or the switch on the usage card).
|
|
115
|
+
It asks Trae CN's own pages through
|
|
116
|
+
this plugin's fetch, which sends them as the account: its Cloud-IDE-JWT
|
|
117
|
+
(renewed first when near its end) and its device id.
|
|
118
|
+
|
|
119
|
+
- **Status:** `POST api.trae.cn/trae/api/v2/ug/checkin_credits/status`,
|
|
120
|
+
body `{}`: `enable`, `checked_in`, `credits`.
|
|
121
|
+
- **Claim:** `POST api.trae.cn/trae/api/v2/ug/checkin_credits/claim`,
|
|
122
|
+
body `{}`, only while it is on and today's isn't in.
|
|
123
|
+
- **What comes back:** Trae's answer as it is. A 401 or code 1001 marks
|
|
124
|
+
the account for a new sign-in. Code 9095 means this device has checked
|
|
125
|
+
in today; nothing sends another device id to get round it.
|
|
126
|
+
|
|
127
|
+
Only `api.trae.cn`'s `/trae/api/` pages are sent this way; any other URL
|
|
128
|
+
that isn't a chat request is still refused (400). Needs 0.1.4 or later.
|
package/index.mjs
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
// agent's /api/agent/v3/llm_utils_chat, which answers in its own SSE
|
|
7
7
|
// events. Worked out from two open-source relays (wangqi233/trae2api and
|
|
8
8
|
// autumnsentiment/Trae2api-cn); not run against a real account here.
|
|
9
|
+
// The account's fetch also sends Trae CN's own pages on api.trae.cn
|
|
10
|
+
// (/trae/api/…) as the account, for magpie's daily check-in (每日签到:
|
|
11
|
+
// /trae/api/v2/ug/checkin_credits/status, then /claim).
|
|
9
12
|
import { randomBytes, randomUUID, randomInt } from "node:crypto"
|
|
10
13
|
import { createServer, STATUS_CODES } from "node:http"
|
|
11
14
|
|
|
@@ -132,6 +135,18 @@ function apiOf(a) {
|
|
|
132
135
|
return /mchost\.guru|trae-api-/i.test(h) ? h : HOSTS.api
|
|
133
136
|
}
|
|
134
137
|
|
|
138
|
+
// ownPage: url is one of Trae CN's own JSON pages on api.trae.cn
|
|
139
|
+
// (/trae/api/…: the daily check-in, credits), which the account's fetch
|
|
140
|
+
// sends as the account rather than as a chat
|
|
141
|
+
function ownPage(url) {
|
|
142
|
+
try {
|
|
143
|
+
const u = new URL(url)
|
|
144
|
+
return u.origin === new URL(HOSTS.auth).origin && u.pathname.startsWith("/trae/api/")
|
|
145
|
+
} catch {
|
|
146
|
+
return false
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
135
150
|
// ---- errors --------------------------------------------------------------------
|
|
136
151
|
|
|
137
152
|
class Expired extends Error {
|
|
@@ -819,6 +834,32 @@ export const TraeCNAuthPlugin = async ({ client }) => {
|
|
|
819
834
|
return { status: res.status, text, v: parseJSON(text) }
|
|
820
835
|
}
|
|
821
836
|
|
|
837
|
+
// ownRequest sends a request for one of Trae CN's own JSON pages as the
|
|
838
|
+
// account, as its IDE does: magpie asks the daily check-in
|
|
839
|
+
// (/trae/api/v2/ug/checkin_credits/status, then /claim) through the
|
|
840
|
+
// account's fetch, as it does WorkBuddy's. Trae's answer comes back as it
|
|
841
|
+
// is; a token it turned away (401, or code 1001 in a 200) marks the
|
|
842
|
+
// sign-in, as usage does.
|
|
843
|
+
const ownRequest = async (getAuth, a0, url, method, body, signal) => {
|
|
844
|
+
let a
|
|
845
|
+
try {
|
|
846
|
+
a = await fresh(getAuth)
|
|
847
|
+
} catch (e) {
|
|
848
|
+
if (e instanceof Expired) return errorResponse(401, `${a0.name || a0.uid}: ${e.message}`, "expired")
|
|
849
|
+
throw e
|
|
850
|
+
}
|
|
851
|
+
const res = await fetch(url, {
|
|
852
|
+
method,
|
|
853
|
+
headers: ideHeaders(a, { Accept: "application/json" }),
|
|
854
|
+
body: method === "GET" || method === "HEAD" ? undefined : typeof body === "string" ? body : "{}",
|
|
855
|
+
signal: signal ?? AbortSignal.timeout(20_000),
|
|
856
|
+
})
|
|
857
|
+
const text = await res.text()
|
|
858
|
+
const lapsed = res.status === 401 || lapsedCode(errorOf(text).code)
|
|
859
|
+
const headers = { "content-type": res.headers.get("content-type") ?? "application/json", "X-Magpie-Sign-In": lapsed ? "expired" : a.renewed ? "renewed" : "kept" }
|
|
860
|
+
return new Response(text, { status: res.status, headers })
|
|
861
|
+
}
|
|
862
|
+
|
|
822
863
|
const usage = async (getAuth) => {
|
|
823
864
|
let a
|
|
824
865
|
try {
|
|
@@ -981,6 +1022,8 @@ export const TraeCNAuthPlugin = async ({ client }) => {
|
|
|
981
1022
|
let body = init.body ?? (r0 ? await r0.text() : undefined)
|
|
982
1023
|
if (body instanceof ArrayBuffer) body = new TextDecoder().decode(body)
|
|
983
1024
|
else if (ArrayBuffer.isView(body)) body = new TextDecoder().decode(new Uint8Array(body.buffer, body.byteOffset, body.byteLength))
|
|
1025
|
+
const url = r0 ? r0.url : input instanceof URL ? input.href : String(input)
|
|
1026
|
+
if (ownPage(url)) return ownRequest(getAuth, a0, url, init.method ?? r0?.method ?? "POST", body, init.signal ?? r0?.signal)
|
|
984
1027
|
const req = parseJSON(body)
|
|
985
1028
|
if (!Array.isArray(req.messages)) return errorResponse(400, "Trae CN: only chat completions are served")
|
|
986
1029
|
let a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpie-community/opencode-trae-auth",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "OpenCode provider plugin for Trae CN (trae.cn): your Trae CN account's models, free tier included, with Trae's own browser sign-in",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.mjs",
|