feat(oauth): add browser-safe ./device subpath export (#2885)
Some checks are pending
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions

* feat(oauth): add browser-safe ./device subpath export

* fix(oauth): guard env override lookup for browser consumers

* chore(oauth): add changeset for ./device subpath export

* fix(oauth): resolve env overrides via globalThis for DOM-only consumers
This commit is contained in:
liruifengv 2026-08-13 18:26:10 +08:00 committed by GitHub
parent 1811bd4baf
commit 4a93f70aa2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 52 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code-oauth": minor
---
Add a browser-safe `./device` subpath export exposing the device-code flow's pure-fetch HTTP wrappers and flow config, so browser bundles can run OAuth sign-in without pulling in Node-only modules. Import from `@moonshot-ai/kimi-code-oauth/device`.

View file

@ -32,6 +32,10 @@
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
},
"./device": {
"types": "./src/device.ts",
"default": "./src/device.ts"
}
},
"scripts": {

View file

@ -2,11 +2,20 @@ import type { OAuthFlowConfig } from './types';
export const DEFAULT_KIMI_CODE_OAUTH_HOST = 'https://auth.kimi.com';
/** Node-side env override lookup, resolved through `globalThis` so the module
stays loadable and typecheckable in browser bundles that have no
`process` global (browser consumers of the ./device entry land on the
default host). */
function envOverride(key: string): string | undefined {
const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;
return proc?.env?.[key];
}
export const KIMI_CODE_FLOW_CONFIG: OAuthFlowConfig = {
name: 'kimi-code',
oauthHost:
process.env['KIMI_CODE_OAUTH_HOST'] ??
process.env['KIMI_OAUTH_HOST'] ??
envOverride('KIMI_CODE_OAUTH_HOST') ??
envOverride('KIMI_OAUTH_HOST') ??
DEFAULT_KIMI_CODE_OAUTH_HOST,
clientId: '17e5f671-d194-4dfb-9706-5516cb48c098',
};

View file

@ -0,0 +1,31 @@
/**
* Browser-safe entry for the device-code flow (`@moonshot-ai/kimi-code-oauth/device`).
*
* The package root re-exports `OAuthManager`, token storage, and the identity
* helpers, which pull in `node:fs` / `node:os` / `proper-lockfile` fine for
* the CLI and desktop hosts, but unloadable in a browser bundle. This entry
* re-exports only the pure-`fetch` surface (every module in its import
* closure is Node-free): the three HTTP wrappers, the shared flow config,
* and the matching types/errors. Keep it that way anything that needs a
* Node builtin belongs behind the root entry, not here.
*
* Browser callers drive the flow themselves (request show the verification
* URI poll store the token); there is no manager here on purpose.
*/
export { KIMI_CODE_FLOW_CONFIG } from './constants';
export {
OAuthConnectionError,
OAuthError,
OAuthUnauthorizedError,
RetryableRefreshError,
} from './errors';
export type { DevicePollResult, RefreshOptions } from './oauth';
export { pollDeviceToken, refreshAccessToken, requestDeviceAuthorization } from './oauth';
export type {
DeviceAuthorization,
DeviceHeaders,
OAuthFlowConfig,
OAuthRequestHeaders,
TokenInfo,
} from './types';

View file

@ -1,7 +1,7 @@
import { defineConfig } from 'tsdown';
export default defineConfig({
entry: ['./src/index.ts'],
entry: ['./src/index.ts', './src/device.ts'],
format: ['esm'],
dts: true,
outDir: 'dist',