✨ Add composable for interacting with Challonge API
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Challonge Client Composable
|
||||
*
|
||||
* Manages Challonge API client initialization with support for:
|
||||
* - API v1 and v2.1
|
||||
* - Multiple authentication methods (API Key, OAuth, Client Credentials)
|
||||
* - Smart auth selection based on tournament scope
|
||||
* - Reactive client updates
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const {
|
||||
* client,
|
||||
* apiVersion,
|
||||
* tournamentScope,
|
||||
* switchVersion,
|
||||
* setScope
|
||||
* } = useChallongeClient();
|
||||
*
|
||||
* // Use client for API calls
|
||||
* await client.value.tournaments.list();
|
||||
* ```
|
||||
*/
|
||||
|
||||
import { ref, computed } from 'vue';
|
||||
import { useChallongeApiKey } from './useChallongeApiKey.js';
|
||||
import { useChallongeOAuth } from './useChallongeOAuth.js';
|
||||
import { useChallongeClientCredentials } from './useChallongeClientCredentials.js';
|
||||
import {
|
||||
createChallongeV1Client,
|
||||
createChallongeV2Client,
|
||||
AuthType,
|
||||
ScopeType
|
||||
} from '../services/challonge.service.js';
|
||||
|
||||
export function useChallongeClient(options = {}) {
|
||||
const { debug = false } = options;
|
||||
|
||||
// Get authentication sources
|
||||
const { getApiKey } = useChallongeApiKey();
|
||||
const {
|
||||
isAuthenticated: isOAuthAuthenticated,
|
||||
accessToken: oauthToken
|
||||
} = useChallongeOAuth();
|
||||
const {
|
||||
isAuthenticated: isClientCredsAuthenticated,
|
||||
accessToken: clientCredsToken
|
||||
} = useChallongeClientCredentials();
|
||||
|
||||
// Configuration state
|
||||
const apiVersion = ref('v2.1'); // 'v1' or 'v2.1'
|
||||
const tournamentScope = ref(ScopeType.USER);
|
||||
const debugMode = ref(debug);
|
||||
|
||||
// Reactive API key
|
||||
const apiKey = computed(() => getApiKey());
|
||||
|
||||
// Masked API key for display
|
||||
const maskedApiKey = computed(() => {
|
||||
if (!apiKey.value) return '';
|
||||
return apiKey.value.slice(0, 4) + '•••••••' + apiKey.value.slice(-4);
|
||||
});
|
||||
|
||||
/**
|
||||
* Create API client reactively based on version, auth method, and scope
|
||||
*/
|
||||
const client = computed(() => {
|
||||
if (apiVersion.value === 'v1') {
|
||||
// v1 only supports API key
|
||||
if (!apiKey.value) return null;
|
||||
return createChallongeV1Client(apiKey.value);
|
||||
} else {
|
||||
// v2.1 supports OAuth, client credentials, and API key
|
||||
// Smart priority based on scope selection:
|
||||
// - APPLICATION scope: prefer client credentials (designed for this)
|
||||
// - USER scope: prefer OAuth user tokens or API key
|
||||
|
||||
if (tournamentScope.value === ScopeType.APPLICATION) {
|
||||
// APPLICATION scope - prefer client credentials
|
||||
if (isClientCredsAuthenticated.value && clientCredsToken.value) {
|
||||
if (debugMode.value) {
|
||||
console.log('🔐 Using Client Credentials token for APPLICATION scope');
|
||||
}
|
||||
return createChallongeV2Client(
|
||||
{ token: clientCredsToken.value, type: AuthType.OAUTH },
|
||||
{ debug: debugMode.value }
|
||||
);
|
||||
} else if (isOAuthAuthenticated.value && oauthToken.value) {
|
||||
if (debugMode.value) {
|
||||
console.log('🔐 Using OAuth user token for APPLICATION scope');
|
||||
}
|
||||
return createChallongeV2Client(
|
||||
{ token: oauthToken.value, type: AuthType.OAUTH },
|
||||
{ debug: debugMode.value }
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// USER scope - prefer OAuth user tokens or API key
|
||||
if (isOAuthAuthenticated.value && oauthToken.value) {
|
||||
if (debugMode.value) {
|
||||
console.log('🔐 Using OAuth user token for USER scope');
|
||||
}
|
||||
return createChallongeV2Client(
|
||||
{ token: oauthToken.value, type: AuthType.OAUTH },
|
||||
{ debug: debugMode.value }
|
||||
);
|
||||
} else if (apiKey.value) {
|
||||
if (debugMode.value) {
|
||||
console.log('🔑 Using API Key for USER scope');
|
||||
}
|
||||
return createChallongeV2Client(
|
||||
{ token: apiKey.value, type: AuthType.API_KEY },
|
||||
{ debug: debugMode.value }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: try API key
|
||||
if (apiKey.value) {
|
||||
if (debugMode.value) {
|
||||
console.log('🔑 Using API Key (fallback)');
|
||||
}
|
||||
return createChallongeV2Client(
|
||||
{ token: apiKey.value, type: AuthType.API_KEY },
|
||||
{ debug: debugMode.value }
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Current authentication type being used
|
||||
*/
|
||||
const authType = computed(() => {
|
||||
if (apiVersion.value === 'v1') {
|
||||
return 'API Key';
|
||||
}
|
||||
if (isClientCredsAuthenticated.value) {
|
||||
return 'Client Credentials';
|
||||
}
|
||||
if (isOAuthAuthenticated.value) {
|
||||
return 'OAuth';
|
||||
}
|
||||
return 'API Key';
|
||||
});
|
||||
|
||||
/**
|
||||
* Switch API version
|
||||
*/
|
||||
function switchVersion(version) {
|
||||
if (version !== 'v1' && version !== 'v2.1') {
|
||||
throw new Error('Invalid API version. Must be "v1" or "v2.1"');
|
||||
}
|
||||
apiVersion.value = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tournament scope (v2.1 only)
|
||||
*/
|
||||
function setScope(scope) {
|
||||
if (scope !== ScopeType.USER && scope !== ScopeType.APPLICATION) {
|
||||
throw new Error('Invalid scope type');
|
||||
}
|
||||
tournamentScope.value = scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle debug mode
|
||||
*/
|
||||
function setDebugMode(enabled) {
|
||||
debugMode.value = enabled;
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
apiVersion,
|
||||
tournamentScope,
|
||||
debugMode,
|
||||
apiKey,
|
||||
maskedApiKey,
|
||||
client,
|
||||
authType,
|
||||
isOAuthAuthenticated,
|
||||
isClientCredsAuthenticated,
|
||||
|
||||
// Methods
|
||||
switchVersion,
|
||||
setScope,
|
||||
setDebugMode,
|
||||
|
||||
// Constants
|
||||
ScopeType,
|
||||
AuthType
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user