mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
Co-authored-by: tanzhenxin <tanzhenxing1987@gmail.com> Co-authored-by: pomelo-nwu <czynwu@outlook.com>
121 lines
3.0 KiB
TypeScript
121 lines
3.0 KiB
TypeScript
/**
|
|
* @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: DeviceAuthorizationInfo) => {
|
|
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,
|
|
};
|
|
};
|