mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 08:47:44 +00:00
feat(oauth): add Qwen OAuth integration
This commit is contained in:
125
packages/cli/src/ui/hooks/useQwenAuth.ts
Normal file
125
packages/cli/src/ui/hooks/useQwenAuth.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { LoadedSettings } from '../../config/settings.js';
|
||||
import {
|
||||
AuthType,
|
||||
qwenOAuth2Events,
|
||||
QwenOAuth2Event,
|
||||
} from '@qwen-code/qwen-code-core';
|
||||
|
||||
export interface DeviceAuthorizationInfo {
|
||||
verification_uri: string;
|
||||
verification_uri_complete: string;
|
||||
user_code: string;
|
||||
expires_in: number;
|
||||
}
|
||||
|
||||
interface QwenAuthState {
|
||||
isQwenAuthenticating: boolean;
|
||||
deviceAuth: DeviceAuthorizationInfo | null;
|
||||
authStatus:
|
||||
| 'idle'
|
||||
| 'polling'
|
||||
| 'success'
|
||||
| 'error'
|
||||
| 'timeout'
|
||||
| 'rate_limit';
|
||||
authMessage: string | null;
|
||||
}
|
||||
|
||||
export const useQwenAuth = (
|
||||
settings: LoadedSettings,
|
||||
isAuthenticating: boolean,
|
||||
) => {
|
||||
const [qwenAuthState, setQwenAuthState] = useState<QwenAuthState>({
|
||||
isQwenAuthenticating: false,
|
||||
deviceAuth: null,
|
||||
authStatus: 'idle',
|
||||
authMessage: null,
|
||||
});
|
||||
|
||||
const isQwenAuth = settings.merged.selectedAuthType === AuthType.QWEN_OAUTH;
|
||||
|
||||
// Set up event listeners when authentication starts
|
||||
useEffect(() => {
|
||||
if (!isQwenAuth || !isAuthenticating) {
|
||||
// Reset state when not authenticating or not Qwen auth
|
||||
setQwenAuthState({
|
||||
isQwenAuthenticating: false,
|
||||
deviceAuth: null,
|
||||
authStatus: 'idle',
|
||||
authMessage: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setQwenAuthState((prev) => ({
|
||||
...prev,
|
||||
isQwenAuthenticating: true,
|
||||
authStatus: 'idle',
|
||||
}));
|
||||
|
||||
// Set up event listeners
|
||||
const handleDeviceAuth = (deviceAuth: {
|
||||
verification_uri: string;
|
||||
verification_uri_complete: string;
|
||||
user_code: string;
|
||||
expires_in: number;
|
||||
}) => {
|
||||
setQwenAuthState((prev) => ({
|
||||
...prev,
|
||||
deviceAuth: {
|
||||
verification_uri: deviceAuth.verification_uri,
|
||||
verification_uri_complete: deviceAuth.verification_uri_complete,
|
||||
user_code: deviceAuth.user_code,
|
||||
expires_in: deviceAuth.expires_in,
|
||||
},
|
||||
authStatus: 'polling',
|
||||
}));
|
||||
};
|
||||
|
||||
const handleAuthProgress = (
|
||||
status: 'success' | 'error' | 'polling' | 'timeout' | 'rate_limit',
|
||||
message?: string,
|
||||
) => {
|
||||
setQwenAuthState((prev) => ({
|
||||
...prev,
|
||||
authStatus: status,
|
||||
authMessage: message || null,
|
||||
}));
|
||||
};
|
||||
|
||||
// Add event listeners
|
||||
qwenOAuth2Events.on(QwenOAuth2Event.AuthUri, handleDeviceAuth);
|
||||
qwenOAuth2Events.on(QwenOAuth2Event.AuthProgress, handleAuthProgress);
|
||||
|
||||
// Cleanup event listeners when component unmounts or auth finishes
|
||||
return () => {
|
||||
qwenOAuth2Events.off(QwenOAuth2Event.AuthUri, handleDeviceAuth);
|
||||
qwenOAuth2Events.off(QwenOAuth2Event.AuthProgress, handleAuthProgress);
|
||||
};
|
||||
}, [isQwenAuth, isAuthenticating]);
|
||||
|
||||
const cancelQwenAuth = useCallback(() => {
|
||||
// Emit cancel event to stop polling
|
||||
qwenOAuth2Events.emit(QwenOAuth2Event.AuthCancel);
|
||||
|
||||
setQwenAuthState({
|
||||
isQwenAuthenticating: false,
|
||||
deviceAuth: null,
|
||||
authStatus: 'idle',
|
||||
authMessage: null,
|
||||
});
|
||||
}, []);
|
||||
|
||||
return {
|
||||
...qwenAuthState,
|
||||
isQwenAuth,
|
||||
cancelQwenAuth,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user