magicrew-auth 0.0.0-stage → 0.3.5

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 ADDED
@@ -0,0 +1,99 @@
1
+ // Magicrew · 超级麦吉 / MagiCrew —— magpie 供应商插件
2
+ //
3
+ // ═══ 这是一块「框」,不是插头 ═════════════════════════════════════════
4
+ //
5
+ // magpie 是主板:它规定了九个针脚,能力(调度、账号池、续期、UI、路由、
6
+ // 流式转发)全在主板那边。插件要做的只是把**自己那一份**填进去。
7
+ //
8
+ // 所以这里不实现任何东西 —— 每个针脚是一个独立的小模块:
9
+ //
10
+ // src/hooks/config.mjs ① config(cfg) 声明 provider + 模型表
11
+ // src/hooks/methods.mjs ② auth.methods[] 登录
12
+ // src/hooks/refresh.mjs ③ auth.refresh(auth) 续期
13
+ // src/hooks/loader.mjs ④ auth.loader(getAuth) 请求接管
14
+ // src/hooks/usage.mjs ⑤ auth.usage(getAuth) 额度
15
+ // src/hooks/checkin.mjs ⑥ auth.checkin(getAuth) 签到
16
+ // src/hooks/models.mjs ⑦ provider.models() 每账号模型目录
17
+ // src/hooks/headers.mjs ⑧ "chat.headers"() 每请求加头
18
+ //
19
+ // 每个模块只读一个 c(站点上下文,见 src/context.mjs),互不依赖:
20
+ // 一个坏了,其余照常 —— 按需加载的那两个(browser-login / tasks)尤其如此。
21
+ //
22
+ // 想只做一半功能?把对应那行从下面的 return 里删掉就行,不用改别处。
23
+ //
24
+ // ═══ 一个包,两个供应商 ═══════════════════════════════════════════════
25
+ //
26
+ // export const MagicrewAuthPlugin = buildPlugin(siteCtx(SITES.cn))
27
+ // export const MagicrewIntlAuthPlugin = buildPlugin(siteCtx(SITES.intl))
28
+ //
29
+ // magpie 把包里每个具名导出当成一个独立插件,所以它们在供应商列表、用量概览、
30
+ // 模型目录里各占一行,不聚合、不互相覆盖登录态。
31
+
32
+ import { startSelfRegister } from "./src/self-register.mjs"
33
+ import { SITES, siteCtx, REFRESH_LEAD_MS } from "./src/context.mjs"
34
+ import { makeConfig } from "./src/hooks/config.mjs"
35
+ import { makeMethods } from "./src/hooks/methods.mjs"
36
+ import { makeRefresh } from "./src/hooks/refresh.mjs"
37
+ import { makeLoader } from "./src/hooks/loader.mjs"
38
+ import { makeUsage } from "./src/hooks/usage.mjs"
39
+ import { makeCheckin } from "./src/hooks/checkin.mjs"
40
+ import { makeModels } from "./src/hooks/models.mjs"
41
+ import { makeHeaders } from "./src/hooks/headers.mjs"
42
+
43
+ const COMMUNITY_ENTRY = {
44
+ package: "Magicrew",
45
+ name: "超级麦吉 / MagiCrew",
46
+ providers: ["magicrew", "magicrew-intl"],
47
+ community: true,
48
+ summary: {
49
+ en: "Magicrew (super-magic) — an OpenAI-compatible gateway behind the agent platform, both builds: 超级麦吉 (letsmagic.cn) and MagiCrew (magicrew.ai).",
50
+ zh: "超级麦吉 / MagiCrew:Agent 平台背后的 OpenAI 兼容网关,国内站与国际站双份。",
51
+ },
52
+ }
53
+
54
+ /** 一个站点进,一个完整插件出 */
55
+ function buildPlugin(c) {
56
+ return async ({ client, directory }) => {
57
+ startSelfRegister(COMMUNITY_ENTRY, {
58
+ configDir: directory,
59
+ log: (msg) => {
60
+ try {
61
+ client?.app?.log?.({ service: c.PROVIDER, level: "info", message: msg })
62
+ } catch {}
63
+ },
64
+ })
65
+
66
+ return {
67
+ config: makeConfig(c),
68
+
69
+ auth: {
70
+ provider: c.PROVIDER,
71
+ icon: c.ICON,
72
+ maxConcurrency: 4,
73
+ refreshLead: REFRESH_LEAD_MS,
74
+
75
+ methods: makeMethods(c),
76
+ refresh: makeRefresh(c),
77
+ loader: makeLoader(c),
78
+ usage: makeUsage(c),
79
+ checkin: makeCheckin(c),
80
+ },
81
+
82
+ provider: {
83
+ id: c.PROVIDER,
84
+ models: makeModels(c),
85
+ },
86
+
87
+ "chat.headers": makeHeaders(c),
88
+ }
89
+ }
90
+ }
91
+
92
+ // ═══ 两个供应商,各占一行 ═════════════════════════════════════════════
93
+
94
+ export const MagicrewAuthPlugin = buildPlugin(siteCtx(SITES.cn))
95
+ export const MagicrewIntlAuthPlugin = buildPlugin(siteCtx(SITES.intl))
96
+
97
+ // 供测试引用(⚠ 入口文件不要导出别的「像插件的对象」,否则会被 magpie 当插件加载)
98
+ export { SITES }
99
+ export const _internal = { buildPlugin, siteCtx, SITES }
package/package.json CHANGED
@@ -1,6 +1,54 @@
1
1
  {
2
2
  "name": "magicrew-auth",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.5",
4
+ "description": "超级麦吉 / MagiCrew for magpie and OpenCode — one package, two providers: letsmagic.cn (国内) and magicrew.ai (international). Password or web-JWT sign-in, the account's own live model list, points balance, newcomer rewards, invite codes.",
5
+ "type": "module",
6
+ "main": "./index.mjs",
7
+ "exports": "./index.mjs",
8
+ "scripts": {
9
+ "publish:npm": "node publish-npm.mjs"
10
+ },
11
+ "files": [
12
+ "index.mjs",
13
+ "src",
14
+ "README.md",
15
+ "CHANGELOG.md",
16
+ "NOTICE.md",
17
+ "docs"
18
+ ],
19
+ "keywords": [
20
+ "magpie",
21
+ "magpie-plugin",
22
+ "opencode",
23
+ "opencode-plugin",
24
+ "opencode-provider",
25
+ "provider",
26
+ "auth",
27
+ "magicrew",
28
+ "magiccrew",
29
+ "super-magic",
30
+ "letsmagic",
31
+ "dtyq"
32
+ ],
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/MYCF711/magpie-magicrew-auth.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/MYCF711/magpie-magicrew-auth/issues"
40
+ },
41
+ "homepage": "https://github.com/MYCF711/magpie-magicrew-auth#readme",
42
+ "engines": {
43
+ "node": "^22.19.0 || >=24.0.0"
44
+ },
45
+ "magpie": {
46
+ "maxConcurrency": 4,
47
+ "autoCheckin": true,
48
+ "carries": [
49
+ "超级麦吉 (letsmagic.cn)",
50
+ "MagiCrew (magicrew.ai)"
51
+ ],
52
+ "icon": "data:image/png;base64,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"
53
+ }
54
+ }
package/src/api.mjs ADDED
@@ -0,0 +1,409 @@
1
+ // Magicrew / 超级麦吉 的 HTTP 层
2
+ //
3
+ // 一个产品两个站,后端不同、模型也不同:
4
+ //
5
+ // 国内 超级麦吉 www.letsmagic.cn i-magic-service.letsmagic.cn
6
+ // 国际 MagiCrew www.magicrew.ai 待定(客户端是同一个包,API host 还没摸到)
7
+ //
8
+ // 每个站点两个 base:
9
+ // 业务 API <host>/api/v1/... 要网页 JWT
10
+ // 模型网关 <host>/v1/... OpenAI 兼容,要 mgw_ api_key
11
+ //
12
+ // 三层凭证,有效期完全不同:
13
+ // ① 网页登录 JWT 30 天
14
+ // ② mgw_ api_key 2 小时
15
+ // ③ refresh_token 7 天(PUT 一次轮换一次,一次性)
16
+ //
17
+ // ⇒ 插件只需要 ① 在登录时拿一次,之后 30 天全靠 ③ 自动滚。
18
+
19
+ const UA =
20
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"
21
+
22
+ // 一个包 = 两个 provider。
23
+ //
24
+ // 每个站点的 `id` 就是它在 magpie 里的**供应商 id** —— 不是内部代号。
25
+ // 所以两个站会各自占一行(供应商列表、用量概览、模型目录全分开),
26
+ // 和 @magpie-community/opencode-workbuddy-auth 承载 WorkBuddy / WorkBuddy AI、
27
+ // opencode-qoder-auth 承载 Qoder / Qoder CN / QwenWork 是同一个做法:
28
+ // export const MagicrewAuthPlugin = makePlugin(SITES.cn)
29
+ // export const MagicrewIntlAuthPlugin = makePlugin(SITES.intl)
30
+ //
31
+ // ⚠ `cn` 的 id 必须保持 `magicrew` —— 已装的用户靠这个 id 认领登录态。
32
+ export const SITES = {
33
+ cn: {
34
+ id: "magicrew",
35
+ label: "国内 · 超级麦吉",
36
+ web: "https://www.letsmagic.cn",
37
+ host: "https://i-magic-service.letsmagic.cn",
38
+ },
39
+ intl: {
40
+ id: "magicrew-intl",
41
+ label: "国际 · MagiCrew",
42
+ web: "https://www.magicrew.ai",
43
+ // 实测(2026-10-27):来源是 www.magicrew.ai 的运行时配置注入页
44
+ // GET https://www.magicrew.ai/workspace → HTML 里内嵌 window 配置
45
+ // "MAGIC_SERVICE_BASE_URL":"https://magic-service.magicrew.ai"
46
+ // "MAGIC_APP_ENV":"international-prod"
47
+ //
48
+ // ⚠ api.magicrew.ai 不是这套 API —— 它是 MAGIC_GATEWAY_ADDRESS(teamshare 网关),
49
+ // 对 /v1/models、/api/v1/* 一律回 "not match rule path"。
50
+ //
51
+ // 该网关与国内 i-magic-service.letsmagic.cn 逐字符同构(同一个 Go 服务):
52
+ // GET / → hello, magic-service!
53
+ // GET /v1/models → {"code":403,"message":"token无效"}
54
+ // GET /api/v1/flows/models → {"code":2179,"message":"auth_token 不存在"}
55
+ host: "https://magic-service.magicrew.ai",
56
+ // 国际站 /v1/chat/completions **强制**要求 organization-code:
57
+ // 不带 → HTTP 500 "Internal Server Error."(22 字节裸文本,不是 JSON)
58
+ // 带上 → 200 正常 chat.completion
59
+ // 国内站 /v1/* 不需要(README 里那套一直是两条 base 分开用的)。
60
+ needsOrgOnGateway: true,
61
+ },
62
+ }
63
+
64
+ export function site(id) {
65
+ return SITES[id] ?? SITES.cn
66
+ }
67
+
68
+ class MagicrewError extends Error {
69
+ constructor(message, { status, code, site: s } = {}) {
70
+ super(message)
71
+ this.name = "MagicrewError"
72
+ this.status = status
73
+ this.code = code
74
+ this.site = s
75
+ }
76
+ }
77
+
78
+ function headersFor(token, org, host) {
79
+ const h = {
80
+ authorization: `Bearer ${token}`,
81
+ "content-type": "application/json",
82
+ "user-agent": UA,
83
+ accept: "application/json",
84
+ // 网关会看 Origin,缺了偶发 403
85
+ origin: host ? new URL(host).origin : "https://www.letsmagic.cn",
86
+ }
87
+ if (org) h["organization-code"] = org
88
+ return h
89
+ }
90
+
91
+ async function read(res) {
92
+ const text = await res.text()
93
+ let body
94
+ try {
95
+ body = text ? JSON.parse(text) : {}
96
+ } catch {
97
+ body = { message: text.slice(0, 200) }
98
+ }
99
+ if (!res.ok) {
100
+ throw new MagicrewError(body?.message || `HTTP ${res.status}`, { status: res.status, code: body?.code })
101
+ }
102
+ // magic 的业务错误码:1000 = ok,其它都是错
103
+ if (typeof body?.code === "number" && body.code !== 1000) {
104
+ throw new MagicrewError(body.message || `code ${body.code}`, { status: res.status, code: body.code })
105
+ }
106
+ return body
107
+ }
108
+
109
+ // ── ① 登录 ───────────────────────────────────────────────────────────
110
+
111
+ /**
112
+ * 手机号 + 密码登录。
113
+ *
114
+ * 实测(2026-10-27 国内站):type 只认 "phone_password";"phone_code" 直接 500。
115
+ * 账号不存在时返回 {"code":33002,"message":"账号不存在"}。
116
+ *
117
+ * 国际站登录页有 Google / Password / Email / Private Service 四种,password 这条大概率同构。
118
+ */
119
+ export async function login({
120
+ phone,
121
+ password,
122
+ stateCode = "+86",
123
+ organizationCode = "",
124
+ host = SITES.cn.host,
125
+ inviteCode = "",
126
+ }) {
127
+ const res = await fetch(`${host}/api/v1/sessions`, {
128
+ method: "POST",
129
+ headers: headersFor("", organizationCode, host),
130
+ body: JSON.stringify({
131
+ type: "phone_password",
132
+ phone: String(phone || "").replace(/[^\d]/g, ""),
133
+ password: password || "",
134
+ state_code: stateCode || "+86",
135
+ organization_code: organizationCode || "",
136
+ email: "",
137
+ redirect: "",
138
+ // 注册邀请码。
139
+ //
140
+ // 字段名来自上游前端 dtyq/magic 的 `types/login.ts`(`invite_code?: string`),
141
+ // 消费时机写在 `LoginService.ts` 的注释里:
142
+ // // PS: 改到在无组织下创建组织的时候再消费邀请码
143
+ // // values.invite_code = consumeInvitationCookie()
144
+ // ⇒ 不是登录那一下生效,是「该账号还没有组织、这次登录顺手建个人组织」时生效。
145
+ // 已经是老账号、组织早就有了,传了也不会再记账。
146
+ //
147
+ // 不传就是空串,服务端忽略(登录本身不受影响)。
148
+ invite_code: inviteCode || "",
149
+ }),
150
+ })
151
+ const body = await read(res)
152
+ const d = body?.data ?? body
153
+
154
+ // 字段名官方文档没有;三种写法都兜住,别赌一个
155
+ const token = d?.token || d?.access_token || d?.accessToken || d?.jwt || ""
156
+ if (!token) throw new MagicrewError("登录成功但没拿到 token", { code: body?.code })
157
+
158
+ return {
159
+ token,
160
+ organizationCode: d?.organization_code || d?.organizationCode || organizationCode || "",
161
+ raw: d,
162
+ }
163
+ }
164
+
165
+ // ── ② 模型网关的 key ─────────────────────────────────────────────────
166
+
167
+ /** 用登录 JWT 签发一把 mgw_ key(2 小时)。 */
168
+ export async function issueGatewayKey(token, org, host = SITES.cn.host) {
169
+ const res = await fetch(`${host}/api/v1/model-gateway/tokens`, {
170
+ method: "POST",
171
+ headers: headersFor(token, org, host),
172
+ body: "{}",
173
+ })
174
+ const body = await read(res)
175
+ const d = body?.data ?? {}
176
+ if (!d.api_key) throw new MagicrewError("签发密钥失败:没有 api_key")
177
+ return {
178
+ apiKey: d.api_key,
179
+ refreshToken: d.refresh_token,
180
+ apiKeyExpiresAt: d.api_key_expires_at,
181
+ refreshTokenExpiresAt: d.refresh_token_expires_at,
182
+ }
183
+ }
184
+
185
+ /**
186
+ * 用 refresh_token 换新的 api_key。
187
+ * 不需要登录态;refresh_token 会**轮换**(一次性的),必须串行调用。
188
+ */
189
+ export async function refreshGatewayKey(refreshToken, host = SITES.cn.host) {
190
+ const res = await fetch(`${host}/api/v1/model-gateway/tokens`, {
191
+ method: "PUT",
192
+ headers: { "content-type": "application/json", "user-agent": UA },
193
+ body: JSON.stringify({ refresh_token: refreshToken }),
194
+ })
195
+ const body = await read(res)
196
+ const d = body?.data ?? {}
197
+ if (!d.api_key) throw new MagicrewError("续期失败:没有 api_key")
198
+ return {
199
+ apiKey: d.api_key,
200
+ refreshToken: d.refresh_token,
201
+ apiKeyExpiresAt: d.api_key_expires_at,
202
+ refreshTokenExpiresAt: d.refresh_token_expires_at,
203
+ }
204
+ }
205
+
206
+ // ── ③ 模型 ───────────────────────────────────────────────────────────
207
+
208
+ /**
209
+ * 账号**当前能选**的语言模型。
210
+ *
211
+ * 注意别用 /v1/models —— 国内站它返回 44 个,含 VIP 锁定、生图、embedding,
212
+ * 塞进 magpie 会让用户选到根本调不动的模型。可选模型只有这里这 27 个。
213
+ *
214
+ * 实测返回字段:value / label / icon / tags / configs / vision
215
+ */
216
+ export async function fetchModels(token, org, host = SITES.cn.host) {
217
+ const res = await fetch(`${host}/api/v1/flows/models`, { headers: headersFor(token, org, host) })
218
+ const body = await read(res)
219
+ const list = body?.data?.models ?? []
220
+ return list.map((m) => ({
221
+ id: m.value,
222
+ name: (m.label || m.value).trim(),
223
+ vision: !!m.vision,
224
+ }))
225
+ }
226
+
227
+ /** 网关上的全量模型 id(含生图/视频/embedding),用来做分类。 */
228
+ export async function fetchAllModels(apiKey, host = SITES.cn.host) {
229
+ const res = await fetch(`${host}/v1/models`, {
230
+ headers: { authorization: `Bearer ${apiKey}`, "user-agent": UA },
231
+ })
232
+ const body = await read(res)
233
+ return (body?.data ?? []).map((m) => m.id)
234
+ }
235
+
236
+ /**
237
+ * 每个模型的计费类型与积分单价。
238
+ *
239
+ * billing_type: TextTokens / Tokens → 语言或向量
240
+ * Times / ImageCount / Seedream5ProImage → 生图
241
+ * input_points / output_points 是**每百万 token 的积分**。
242
+ */
243
+ export async function fetchModelPoints(token, org, modelIds, host = SITES.cn.host) {
244
+ const res = await fetch(`${host}/api/v1/products/model-points`, {
245
+ method: "POST",
246
+ headers: headersFor(token, org, host),
247
+ body: JSON.stringify({ model_ids: modelIds }),
248
+ })
249
+ const body = await read(res)
250
+ const out = {}
251
+ for (const m of body?.data ?? []) {
252
+ out[m.model_id] = {
253
+ billingType: m.billing_type,
254
+ inputPoints: m.input_points,
255
+ outputPoints: m.output_points,
256
+ kind: classify(m.billing_type, m.model_id),
257
+ }
258
+ }
259
+ return out
260
+ }
261
+
262
+ const EMBEDDING_RE = /embedding|dmeta/i
263
+ const IMAGE_RE = /image|seedream|aes_general/i
264
+
265
+ function classify(billingType, modelId) {
266
+ if (EMBEDDING_RE.test(modelId)) return "embedding"
267
+ if (billingType === "Times" || billingType === "ImageCount" || /Image$/i.test(billingType || "")) return "image"
268
+ if (IMAGE_RE.test(modelId)) return "image"
269
+ if (billingType === "TextTokens" || billingType === "Tokens") return "language"
270
+ return "other"
271
+ }
272
+
273
+ // ── ③b 新手任务(onboarding)──────────────────────────────────────────
274
+ //
275
+ // 这条是前端 chunk `onboarding-CZBI0pQt.js` 里挖出来的,只有一行:
276
+ // GET /api/v1/onboarding/tasks
277
+ // PUT /api/v1/onboarding/tasks/{code}/completion
278
+ //
279
+ // 8 项任务里 7 项可以纯 HTTP 完成(PUT 即到账),只有 `first_ai_work`
280
+ // 返回 9303「该新人引导任务不支持手动完成」—— 那项是真的要跑一次 AI 任务。
281
+
282
+ export async function fetchOnboardingTasks(token, org, host = SITES.cn.host) {
283
+ const res = await fetch(`${host}/api/v1/onboarding/tasks`, { headers: headersFor(token, org, host) })
284
+ const body = await read(res)
285
+ return (body?.data?.tasks ?? []).map((t) => ({
286
+ code: t.code,
287
+ title: t.title,
288
+ points: Number(t.points ?? 0),
289
+ status: t.status,
290
+ rewardStatus: t.reward_status,
291
+ completedAt: t.completed_at,
292
+ }))
293
+ }
294
+
295
+ /**
296
+ * 标记一项任务完成。成功返回 { points },失败抛出带 code 的错误。
297
+ * 已知失败码:9303 = 该任务不支持手动完成。
298
+ */
299
+ export async function completeOnboardingTask(token, org, code, host = SITES.cn.host) {
300
+ const res = await fetch(`${host}/api/v1/onboarding/tasks/${encodeURIComponent(code)}/completion`, {
301
+ method: "PUT",
302
+ headers: headersFor(token, org, host),
303
+ body: "{}",
304
+ })
305
+ const body = await read(res)
306
+ return { points: Number(body?.data?.points ?? 0) }
307
+ }
308
+
309
+ // ── ④ 积分与任务 ─────────────────────────────────────────────────────
310
+
311
+ /**
312
+ * 积分余额。
313
+ *
314
+ * expiring_quota_details 每一段是一个会过期的额度包,列表顺序 = 先过期的先扣。
315
+ */
316
+ export async function fetchPoints(token, org, host = SITES.cn.host) {
317
+ const res = await fetch(`${host}/api/v1/quota/points/total`, { headers: headersFor(token, org, host) })
318
+ const body = await read(res)
319
+ const d = body?.data ?? {}
320
+ return {
321
+ total: Number(d.total_points ?? 0),
322
+ expiring: (d.expiring_quota_details ?? []).map((q) => ({
323
+ points: Number(q.remaining_points ?? 0),
324
+ expiresAt: q.expires_at,
325
+ })),
326
+ nextGrant: d.next_cycle_grant ?? null,
327
+ }
328
+ }
329
+
330
+ /** 积分流水(倒序)。签到和任务做完后可以用来确认到账。 */
331
+ export async function fetchPointRecords(token, org, { page = 1, pageSize = 20, host = SITES.cn.host } = {}) {
332
+ // ⚠ 是 POST 不是 GET(GET 回 405 Allow: POST)
333
+ const res = await fetch(`${host}/api/v1/quota/points/records/queries`, {
334
+ method: "POST",
335
+ headers: headersFor(token, org, host),
336
+ body: JSON.stringify({ page: String(page), page_size: String(pageSize) }),
337
+ })
338
+ const body = await read(res)
339
+ return body?.data?.list ?? body?.data ?? []
340
+ }
341
+
342
+ // ── ④b 自己的邀请码 ──────────────────────────────────────────────────
343
+ //
344
+ // 「Free Points Program」那套分享激励。页面上看到的现成链接长这样:
345
+ //
346
+ // https://www.magicrew.ai/?invitation=IV75F0ZKVKXG
347
+ // https://www.letsmagic.cn/?invitation=<code>
348
+ //
349
+ // 奖励口径两站不同(来自上游前端 constants,2026-10-27 读的):
350
+ //
351
+ // 每次注册 每次订阅 邀请注册封顶 总额封顶
352
+ // 国内 1,000 3,000 60,000 300,000
353
+ // 国际 200 500 10,000 30,000
354
+ //
355
+ // 接口(2026-10-27 实测,从客户端 Cache/Cache_Data/data_1 里读出来的):
356
+ //
357
+ // GET /api/v1/invitations/info → { invite_code, invite_count, invited_users }
358
+ // GET /api/v1/invitations/activity → 活动配置
359
+ // GET /api/v1/invitations/rewards/total-points → 已赚积分
360
+ //
361
+ // ⚠ 这三个接口只认**客户端登录**的那把 JWT(438 字符),网页版那把
362
+ // localstorage 里的 JWT(354 字符)调过去回 {"code":2155,"message":"用户不存在"}。
363
+ // 两把都是同一账号签的,差别在 payload 里的用户字段 —— 网页版不带。
364
+ // ⇒ 所以「用我自己的邀请码」只能拿**本插件上次登录成功时存下的**那把 JWT,
365
+ // 没登录过就没得用(报错,不猜)。
366
+ export const INVITE_CODE_PATH = "/api/v1/invitations/info"
367
+
368
+ /** 拿不到就抛错 —— 调用方要的是「真实结果」,不是静默降级 */
369
+ export async function fetchOwnInviteCode(token, org, host = SITES.cn.host) {
370
+ const res = await fetch(`${host}${INVITE_CODE_PATH}`, { headers: headersFor(token, org, host) })
371
+ const body = await read(res)
372
+ const d = body?.data ?? {}
373
+ const code = d.invite_code || d.inviteCode || d.code || d.invitation_code || ""
374
+ if (!code) throw new MagicrewError("接口通了但返回里没有 invite_code")
375
+ return {
376
+ code,
377
+ count: Number(d.invite_count ?? 0),
378
+ invited: Array.isArray(d.invited_users) ? d.invited_users.length : 0,
379
+ }
380
+ }
381
+
382
+ // ── ④c 这个登录态是谁 ────────────────────────────────────────────────
383
+ //
384
+ // 卡片上原来显示组织码(orgcode67890 / orgcode12345),那是随机串,用户认不出是谁。
385
+ //
386
+ // 优先级:**手机号 → 邮箱 → 昵称 → 真名**。
387
+ //
388
+ // ⚠ 昵称排在后面是有原因的:那是用户自己填的,新账号可以不填、也可以随便填
389
+ // (作者自己的账号填的是 "MYCF711",跟他是谁毫无关系)。手机号是登录凭据本身,
390
+ // 改不了、也漏不掉。
391
+ //
392
+ // ⚠ 服务端把手机号打码了(实测 `138****8000`,中间四位星号),邮箱常常是 null。
393
+ // 打码归打码,它仍然是唯一稳定的账号标识 —— 至少能看出是哪个号。
394
+ //
395
+ // 接口来自客户端缓存里出现过的清单(docs/internals.md 第九节的办法找到的)。
396
+ export async function fetchWho(token, org, host = SITES.cn.host) {
397
+ const res = await fetch(`${host}/api/v1/contact/accounts/me/users`, { headers: headersFor(token, org, host) })
398
+ const body = await read(res)
399
+ const u = body?.data?.items?.[0] ?? body?.data ?? {}
400
+ const name = String(u.phone || u.email || u.nickname || u.real_name || "").trim()
401
+ return {
402
+ name,
403
+ nickname: String(u.nickname || "").trim(),
404
+ phone: String(u.phone || ""),
405
+ email: String(u.email || ""),
406
+ }
407
+ }
408
+
409
+ export { MagicrewError, headersFor as _headers }