Download packages/oauth/src/managed-userinfo.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 7.17 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/oauth/src/managed-userinfo.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/oauth/src/managed-userinfo.ts
-
curl -L -o managed-userinfo.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/oauth/src/managed-userinfo.ts
7.17 kB
| /** | |
| * Managed-platform profile fetch / parse. | |
| * | |
| * Only `managed:kimi-code` is supported today. The platform exposes a | |
| * `/me` endpoint that returns a payload of the shape: | |
| * | |
| * { | |
| * "user_id": "u_123", | |
| * "nickname": "moonwalker", | |
| * "status": "USER_STATUS_NORMAL", | |
| * "region": "REGION_CN", | |
| * "user_level": 30, | |
| * "user_level_name": "Vivace", | |
| * "domain": 1, | |
| * "domain_name": "DOMAIN_EXAMPLE", | |
| * "global_id": "u_123", | |
| * "avatar": "https://example.com/avatar.png", | |
| * "email": "user@example.com", | |
| * "phone": { "country_code": "86", "number": "176****0000" }, | |
| * "created_time": "2026-06-11T13:26:47.561184Z", | |
| * "last_login_time": "2026-07-16T03:12:03.033412Z" | |
| * } | |
| * | |
| * `user_id` / `nickname` / `status` / `region` / `user_level` / | |
| * `user_level_name` / `domain` / `domain_name` are always serialized | |
| * (possibly as zero values); the rest are optional (`phone` a nested | |
| * record, the timestamps RFC3339 strings passed through verbatim). The | |
| * parser normalizes the payload into a structured, camelCase domain | |
| * model; presentation is left to the consumer. | |
| * | |
| * The camelCase zod schemas below are the single source of truth for the | |
| * domain model and double as the daemon REST wire contract: new daemon | |
| * endpoints speak the camelCase domain shape directly, while legacy | |
| * snake_case endpoints are unaffected. | |
| */ | |
| import { z } from 'zod'; | |
| import { readApiErrorMessage } from './api-error'; | |
| import { kimiCodeBaseUrl } from './managed-usage'; | |
| import { isRecord } from './utils'; | |
| // The cloud path stays `/me` (owned by the backend); only the local | |
| // naming moved to "userinfo". | |
| export function kimiCodeUserInfoUrl(): string { | |
| return `${kimiCodeBaseUrl()}/me`; | |
| } | |
| export const managedUserInfoPhoneSchema = z.object({ | |
| countryCode: z.string(), | |
| number: z.string(), | |
| }); | |
| export type ManagedUserInfoPhone = z.infer<typeof managedUserInfoPhoneSchema>; | |
| export const managedUserInfoSchema = z.object({ | |
| userId: z.string(), | |
| nickname: z.string(), | |
| status: z.string(), | |
| region: z.string(), | |
| userLevel: z.number().int(), | |
| userLevelName: z.string(), | |
| domain: z.number().int(), | |
| domainName: z.string(), | |
| globalId: z.string().optional(), | |
| bio: z.string().optional(), | |
| avatar: z.string().optional(), | |
| username: z.string().optional(), | |
| email: z.string().optional(), | |
| phone: managedUserInfoPhoneSchema.optional(), | |
| /** Backend RFC3339 timestamp, passed through verbatim. */ | |
| createdTime: z.string().optional(), | |
| /** Backend RFC3339 timestamp, passed through verbatim. */ | |
| lastLoginTime: z.string().optional(), | |
| }); | |
| export type ManagedUserInfo = z.infer<typeof managedUserInfoSchema>; | |
| const managedUserInfoOkSchema = z.object({ | |
| kind: z.literal('ok'), | |
| userInfo: managedUserInfoSchema, | |
| }); | |
| const managedUserInfoErrorSchema = z.object({ | |
| kind: z.literal('error'), | |
| message: z.string(), | |
| status: z.number().int().optional(), | |
| }); | |
| export const managedUserInfoResultSchema = z.discriminatedUnion('kind', [ | |
| managedUserInfoOkSchema, | |
| managedUserInfoErrorSchema, | |
| ]); | |
| export type ManagedUserInfoResult = z.infer<typeof managedUserInfoResultSchema>; | |
| /** | |
| * Lenient parse: anything that is not a record, or lacks a `user_id` | |
| * string, is malformed; every other field degrades independently. | |
| */ | |
| export function parseManagedUserInfoPayload(payload: unknown): ManagedUserInfo | null { | |
| if (!isRecord(payload)) return null; | |
| const userId = stringField(payload, 'user_id'); | |
| if (userId === undefined) return null; | |
| return { | |
| userId, | |
| nickname: stringField(payload, 'nickname') ?? '', | |
| status: stringField(payload, 'status') ?? '', | |
| region: stringField(payload, 'region') ?? '', | |
| userLevel: intField(payload, 'user_level') ?? 0, | |
| userLevelName: stringField(payload, 'user_level_name') ?? '', | |
| domain: intField(payload, 'domain') ?? 0, | |
| domainName: stringField(payload, 'domain_name') ?? '', | |
| globalId: stringField(payload, 'global_id'), | |
| bio: stringField(payload, 'bio'), | |
| avatar: stringField(payload, 'avatar'), | |
| username: stringField(payload, 'username'), | |
| email: stringField(payload, 'email'), | |
| phone: parsePhone(payload['phone']), | |
| createdTime: stringField(payload, 'created_time'), | |
| lastLoginTime: stringField(payload, 'last_login_time'), | |
| }; | |
| } | |
| function parsePhone(raw: unknown): ManagedUserInfoPhone | undefined { | |
| if (!isRecord(raw)) return undefined; | |
| const countryCode = stringField(raw, 'country_code') ?? ''; | |
| const number = stringField(raw, 'number') ?? ''; | |
| if (countryCode === '' && number === '') return undefined; | |
| return { countryCode, number }; | |
| } | |
| function stringField(record: Record<string, unknown>, key: string): string | undefined { | |
| const value = record[key]; | |
| return typeof value === 'string' && value.length > 0 ? value : undefined; | |
| } | |
| function intField(record: Record<string, unknown>, key: string): number | undefined { | |
| const value = record[key]; | |
| if (typeof value === 'number') { | |
| return Number.isFinite(value) ? Math.trunc(value) : undefined; | |
| } | |
| if (typeof value === 'string') { | |
| const n = Number(value); | |
| return Number.isFinite(n) ? Math.trunc(n) : undefined; | |
| } | |
| return undefined; | |
| } | |
| // ββ HTTP fetch ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export interface FetchManagedUserInfoResult { | |
| readonly kind: 'ok'; | |
| readonly userInfo: ManagedUserInfo; | |
| } | |
| export interface FetchManagedUserInfoError { | |
| readonly kind: 'error'; | |
| readonly status?: number; | |
| readonly message: string; | |
| } | |
| export async function fetchManagedUserInfo( | |
| url: string, | |
| accessToken: string, | |
| opts: { timeoutMs?: number } = {}, | |
| ): Promise<FetchManagedUserInfoResult | FetchManagedUserInfoError> { | |
| const controller = new AbortController(); | |
| const timer = setTimeout(() => { | |
| controller.abort(); | |
| }, opts.timeoutMs ?? 8000); | |
| try { | |
| const res = await fetch(url, { | |
| headers: { | |
| Authorization: `Bearer ${accessToken}`, | |
| Accept: 'application/json', | |
| }, | |
| signal: controller.signal, | |
| }); | |
| if (!res.ok) { | |
| const status = res.status; | |
| const hint = | |
| status === 401 | |
| ? 'Authorization failed. Please check your API key (try /login).' | |
| : status === 404 | |
| ? 'Profile endpoint not available. Try Kimi For Coding.' | |
| : `Failed to fetch profile: HTTP ${String(status)}`; | |
| return { kind: 'error', status, message: await readApiErrorMessage(res, hint) }; | |
| } | |
| const json: unknown = await res.json(); | |
| const me = parseManagedUserInfoPayload(json); | |
| if (me === null) { | |
| return { kind: 'error', message: 'Failed to fetch profile: malformed response.' }; | |
| } | |
| return { kind: 'ok', userInfo: me }; | |
| } catch (error) { | |
| if (error instanceof Error && error.name === 'AbortError') { | |
| return { kind: 'error', message: 'Failed to fetch profile: request timed out.' }; | |
| } | |
| const msg = error instanceof Error ? error.message : String(error); | |
| return { kind: 'error', message: `Failed to fetch profile: ${msg}` }; | |
| } finally { | |
| clearTimeout(timer); | |
| } | |
| } | |