forked from didirus/AstralRinth
feat: base api-client impl (#4694)
* feat: base api-client impl * fix: doc * feat: start work on module stuff * feat: migrate v2/v3 projects into module system * fix: lint & README.md contributing * refactor: remove utils old api client prototype * fix: lint * fix: api url issues * fix: baseurl in error.vue * fix: readme * fix typo in readme * Update apps/frontend/src/providers/api-client.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Calum H. <hendersoncal117@gmail.com> * Update packages/api-client/src/features/verbose-logging.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Calum H. <hendersoncal117@gmail.com> * Update packages/api-client/src/features/retry.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Calum H. <hendersoncal117@gmail.com> --------- Signed-off-by: Calum H. <hendersoncal117@gmail.com> Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
89
packages/api-client/src/features/auth.ts
Normal file
89
packages/api-client/src/features/auth.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { AbstractFeature, type FeatureConfig } from '../core/abstract-feature'
|
||||
import type { RequestContext } from '../types/request'
|
||||
|
||||
/**
|
||||
* Authentication feature configuration
|
||||
*/
|
||||
export interface AuthConfig extends FeatureConfig {
|
||||
/**
|
||||
* Authentication token
|
||||
* - string: static token
|
||||
* - function: async function that returns token (useful for dynamic tokens)
|
||||
*/
|
||||
token: string | (() => Promise<string | undefined>)
|
||||
|
||||
/**
|
||||
* Token prefix (e.g., 'Bearer', 'Token')
|
||||
* @default 'Bearer'
|
||||
*/
|
||||
tokenPrefix?: string
|
||||
|
||||
/**
|
||||
* Custom header name for the token
|
||||
* @default 'Authorization'
|
||||
*/
|
||||
headerName?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication feature
|
||||
*
|
||||
* Automatically injects authentication tokens into request headers.
|
||||
* Supports both static tokens and dynamic token providers.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Static token
|
||||
* const auth = new AuthFeature({
|
||||
* token: 'mrp_...'
|
||||
* })
|
||||
*
|
||||
* // Dynamic token (e.g., from auth state)
|
||||
* const auth = new AuthFeature({
|
||||
* token: async () => await getAuthToken()
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export class AuthFeature extends AbstractFeature {
|
||||
protected declare config: AuthConfig
|
||||
|
||||
async execute<T>(next: () => Promise<T>, context: RequestContext): Promise<T> {
|
||||
const token = await this.getToken()
|
||||
|
||||
if (token) {
|
||||
const headerName = this.config.headerName ?? 'Authorization'
|
||||
const tokenPrefix = this.config.tokenPrefix ?? 'Bearer'
|
||||
const headerValue = tokenPrefix ? `${tokenPrefix} ${token}` : token
|
||||
|
||||
context.options.headers = {
|
||||
...context.options.headers,
|
||||
[headerName]: headerValue,
|
||||
}
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
|
||||
shouldApply(context: RequestContext): boolean {
|
||||
if (context.options.skipAuth) {
|
||||
return false
|
||||
}
|
||||
|
||||
return super.shouldApply(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authentication token
|
||||
*
|
||||
* Handles both static tokens and async token providers
|
||||
*/
|
||||
private async getToken(): Promise<string | undefined> {
|
||||
const { token } = this.config
|
||||
|
||||
if (typeof token === 'function') {
|
||||
return await token()
|
||||
}
|
||||
|
||||
return token
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user