Download src/auth/resolver.ts from bolikoto/zcode-api: direct link, hf CLI and curl.
- Browser
- Download file 6.14 kB
-
https://huggingface.co/spaces/bolikoto/zcode-api/resolve/main/src/auth/resolver.ts
- Command line
-
hf download hf://spaces/bolikoto/zcode-api/src/auth/resolver.ts
-
curl -L -o resolver.ts https://huggingface.co/spaces/bolikoto/zcode-api/resolve/main/src/auth/resolver.ts
6.14 kB
| import type { Credential } from "./types.js"; | |
| import type { ProviderId } from "../provider/types.js"; | |
| import type { FetchFn } from "./oauth.js"; | |
| const ZAI_API_KEY_NAME = "zcode-api-key"; | |
| const DEFAULT_ORG_MARKER = "\u9ED8\u8BA4\u673A\u6784"; // 默认机构 | |
| const DEFAULT_PROJECT_MARKER = "\u9ED8\u8BA4\u9879\u76EE"; // 默认项目 | |
| async function requestBizApi( | |
| fetchImpl: FetchFn, | |
| url: string, | |
| authorization: string, | |
| init?: RequestInit, | |
| ): Promise<any> { | |
| const resp = await fetchImpl(url, { | |
| ...init, | |
| headers: { | |
| Authorization: authorization, | |
| "Content-Type": "application/json", | |
| ...(init?.headers ?? {}), | |
| }, | |
| }); | |
| if (!resp.ok) { | |
| throw new Error(`Biz API ${url} failed: ${resp.status}`); | |
| } | |
| const body = await resp.json(); | |
| const code = body.code ?? body.status; | |
| if (code != null && code !== 0 && code !== 200 && code !== "0" && code !== "200") { | |
| throw new Error(body.msg ?? `Biz API error ${code}`); | |
| } | |
| return body.data ?? body; | |
| } | |
| export class KeyResolver { | |
| constructor(private fetchImpl: FetchFn = fetch) {} | |
| async resolveZaiBizToken(accessToken: string): Promise<string> { | |
| const resp = await this.fetchImpl("https://api.z.ai/api/auth/z/login", { | |
| method: "POST", | |
| headers: { "content-type": "application/json" }, | |
| body: JSON.stringify({ token: accessToken }), | |
| }); | |
| if (!resp.ok) { | |
| throw new Error(`z/login failed: ${resp.status}`); | |
| } | |
| const data = await resp.json(); | |
| const token = data.access_token ?? data.accessToken ?? data.data?.access_token; | |
| // Shape guard: silently returning undefined used to store a bogus | |
| // credential that surfaced only as cryptic upstream 401s. | |
| if (typeof token !== "string" || token.length === 0) { | |
| throw new Error("z/login returned unexpected shape: access_token missing or empty"); | |
| } | |
| return token; | |
| } | |
| async resolveCustomerInfo( | |
| host: string, | |
| authorization: string, | |
| ): Promise<{ orgId: string; projectId: string }> { | |
| const data = await requestBizApi( | |
| this.fetchImpl, | |
| `${host}/api/biz/customer/getCustomerInfo`, | |
| authorization, | |
| { method: "GET" }, | |
| ); | |
| const orgs: any[] = data.organizations ?? data.orgs ?? []; | |
| if (!Array.isArray(orgs) || orgs.length === 0) { | |
| throw new Error("No organizations found"); | |
| } | |
| const org = orgs.find((o) => | |
| (o.organizationName ?? o.name ?? "").includes(DEFAULT_ORG_MARKER), | |
| ) ?? orgs[0]; | |
| const orgId = org.organizationId ?? org.id ?? org.orgId; | |
| const projects: any[] = org.projects ?? []; | |
| if (!Array.isArray(projects) || projects.length === 0) { | |
| throw new Error("No projects found in default organization"); | |
| } | |
| const project = projects.find((p) => | |
| (p.projectName ?? p.name ?? "").includes(DEFAULT_PROJECT_MARKER), | |
| ) ?? projects[0]; | |
| const projectId = project.projectId ?? project.id; | |
| return { orgId, projectId }; | |
| } | |
| async findOrCreateApiKey( | |
| host: string, | |
| authorization: string, | |
| orgId: string, | |
| projectId: string, | |
| ): Promise<{ apiKey: string }> { | |
| const listUrl = `${host}/api/biz/v1/organization/${orgId}/projects/${projectId}/api_keys`; | |
| let existing: any[] = []; | |
| try { | |
| existing = await requestBizApi(this.fetchImpl, listUrl, authorization, { method: "GET" }) ?? []; | |
| } catch { /* ignore — will create */ } | |
| if (Array.isArray(existing)) { | |
| const found = existing.find((k: any) => k.name === ZAI_API_KEY_NAME); | |
| // Reuse the listed key only when it has a usable shape; a malformed | |
| // entry falls through to the create path instead of poisoning the | |
| // stored credential. | |
| if (found && typeof found.apiKey === "string" && found.apiKey.length > 0) { | |
| return { apiKey: found.apiKey }; | |
| } | |
| } | |
| const created = await requestBizApi(this.fetchImpl, listUrl, authorization, { | |
| method: "POST", | |
| body: JSON.stringify({ name: ZAI_API_KEY_NAME }), | |
| }); | |
| // Shape guard (CL-06): an upstream response drift (renamed/nested field) | |
| // must fail the login with a clear error — not store the string | |
| // "undefined" and 401 on every later request. | |
| if (typeof created?.apiKey !== "string" || created.apiKey.length === 0) { | |
| throw new Error("API key creation returned unexpected shape: apiKey missing or empty"); | |
| } | |
| return { apiKey: created.apiKey }; | |
| } | |
| async getSecretKey( | |
| host: string, | |
| authorization: string, | |
| orgId: string, | |
| projectId: string, | |
| apiKey: string, | |
| ): Promise<string> { | |
| const url = `${host}/api/biz/v1/organization/${orgId}/projects/${projectId}/api_keys/copy/${encodeURIComponent(apiKey)}`; | |
| const data = await requestBizApi(this.fetchImpl, url, authorization, { method: "GET" }); | |
| return data.secretKey ?? data.secret_key ?? ""; | |
| } | |
| async resolveCodingPlanCredential( | |
| accessToken: string, | |
| provider: ProviderId, | |
| userId?: string, | |
| ): Promise<Credential> { | |
| if (provider === "zai") { | |
| const bizToken = await this.resolveZaiBizToken(accessToken); | |
| const host = "https://api.z.ai"; | |
| const authorization = `Bearer ${bizToken}`; | |
| const { orgId, projectId } = await this.resolveCustomerInfo(host, authorization); | |
| const { apiKey } = await this.findOrCreateApiKey(host, authorization, orgId, projectId); | |
| let secret: string | undefined; | |
| try { | |
| secret = await this.getSecretKey(host, authorization, orgId, projectId, apiKey); | |
| } catch { /* credential will be apiKey-only */ } | |
| return { apiKey, secret: secret || undefined, provider: "zai", userId }; | |
| } | |
| const host = "https://bigmodel.cn"; | |
| const authorization = accessToken; | |
| const { orgId, projectId } = await this.resolveCustomerInfo(host, authorization); | |
| const { apiKey } = await this.findOrCreateApiKey(host, authorization, orgId, projectId); | |
| let fullKey = apiKey; | |
| try { | |
| const secret = await this.getSecretKey(host, authorization, orgId, projectId, apiKey); | |
| if (secret) fullKey = `${apiKey}.${secret}`; | |
| } catch { /* use apiKey only */ } | |
| return { apiKey: fullKey, provider: "bigmodel", userId }; | |
| } | |
| } | |