You've already forked AstralRinth
fix: app user agent for api-client reqs using tauri http plugin (#6045)
fix: app user agent
This commit is contained in:
@@ -16,7 +16,7 @@ import { XHRUploadClient } from './xhr-upload-client'
|
||||
* const client = new GenericModrinthClient({
|
||||
* userAgent: 'my-app/1.0.0',
|
||||
* features: [
|
||||
* new AuthFeature({ token: 'mrp_...' }),
|
||||
* new AuthFeature({ token: async () => getOAuthToken() }),
|
||||
* new RetryFeature({ maxAttempts: 3 })
|
||||
* ]
|
||||
* })
|
||||
|
||||
@@ -66,13 +66,17 @@ export interface NuxtClientConfig extends ClientConfig {
|
||||
* ```typescript
|
||||
* // In a Nuxt composable
|
||||
* const config = useRuntimeConfig()
|
||||
* const auth = await useAuth()
|
||||
*
|
||||
* const client = new NuxtModrinthClient({
|
||||
* userAgent: 'my-nuxt-app/1.0.0',
|
||||
* rateLimitKey: import.meta.server ? config.rateLimitKey : undefined,
|
||||
* features: [
|
||||
* new AuthFeature({ token: () => auth.value.token })
|
||||
* new AuthFeature({
|
||||
* token: async () => getOAuthToken()
|
||||
* }),
|
||||
* new CircuitBreakerFeature({
|
||||
* storage: new NuxtCircuitBreakerStorage()
|
||||
* })
|
||||
* ]
|
||||
* })
|
||||
*
|
||||
@@ -171,9 +175,9 @@ export class NuxtModrinthClient extends XHRUploadClient {
|
||||
return super.normalizeError(error)
|
||||
}
|
||||
|
||||
protected buildDefaultHeaders(): Record<string, string> {
|
||||
protected async buildDefaultHeaders(): Promise<Record<string, string>> {
|
||||
const headers: Record<string, string> = {
|
||||
...super.buildDefaultHeaders(),
|
||||
...(await super.buildDefaultHeaders()),
|
||||
}
|
||||
|
||||
// Use the resolved key (populated by resolveRateLimitKey in request())
|
||||
|
||||
@@ -27,11 +27,10 @@ interface HttpError extends Error {
|
||||
* ```typescript
|
||||
* import { getVersion } from '@tauri-apps/api/app'
|
||||
*
|
||||
* const version = await getVersion()
|
||||
* const client = new TauriModrinthClient({
|
||||
* userAgent: `modrinth/theseus/${version} (support@modrinth.com)`,
|
||||
* userAgent: async () => `modrinth/theseus/${await getVersion()} (support@modrinth.com)`,
|
||||
* features: [
|
||||
* new AuthFeature({ token: 'mrp_...' })
|
||||
* new AuthFeature({ token: async () => getOAuthToken() })
|
||||
* ]
|
||||
* })
|
||||
*
|
||||
|
||||
@@ -27,50 +27,57 @@ export abstract class XHRUploadClient extends AbstractModrinthClient {
|
||||
|
||||
const url = this.buildUrl(path, baseUrl, options.version)
|
||||
|
||||
// For FormData uploads, don't set Content-Type (let browser set multipart boundary)
|
||||
// For file uploads, use application/octet-stream
|
||||
const isFormData = 'formData' in options && options.formData instanceof FormData
|
||||
const baseHeaders = this.buildDefaultHeaders()
|
||||
// Remove Content-Type for FormData so browser can set multipart/form-data with boundary
|
||||
if (isFormData) {
|
||||
delete baseHeaders['Content-Type']
|
||||
} else {
|
||||
baseHeaders['Content-Type'] = 'application/octet-stream'
|
||||
}
|
||||
|
||||
const mergedOptions: UploadRequestOptions = {
|
||||
retry: false, // default: don't retry uploads
|
||||
...options,
|
||||
headers: {
|
||||
...baseHeaders,
|
||||
...options.headers,
|
||||
},
|
||||
}
|
||||
this.attachArchonSentryCaptureHeader(mergedOptions)
|
||||
|
||||
const context = this.buildUploadContext(url, path, mergedOptions)
|
||||
|
||||
const progressCallbacks: Array<(p: UploadProgress) => void> = []
|
||||
if (mergedOptions.onProgress) {
|
||||
progressCallbacks.push(mergedOptions.onProgress)
|
||||
if (options.onProgress) {
|
||||
progressCallbacks.push(options.onProgress)
|
||||
}
|
||||
const abortController = new AbortController()
|
||||
|
||||
if (mergedOptions.signal) {
|
||||
mergedOptions.signal.addEventListener('abort', () => abortController.abort())
|
||||
if (options.signal) {
|
||||
options.signal.addEventListener('abort', () => abortController.abort())
|
||||
}
|
||||
|
||||
let context: RequestContext | undefined
|
||||
const handle: UploadHandle<T> = {
|
||||
promise: this.executeUploadFeatureChain<T>(context, progressCallbacks, abortController)
|
||||
.then(async (result) => {
|
||||
await this.config.hooks?.onResponse?.(result, context)
|
||||
return result
|
||||
})
|
||||
.catch(async (error) => {
|
||||
const apiError = this.normalizeError(error, context)
|
||||
promise: (async () => {
|
||||
const isFormData = 'formData' in options && options.formData instanceof FormData
|
||||
const baseHeaders = await this.buildDefaultHeaders()
|
||||
if (isFormData) {
|
||||
delete baseHeaders['Content-Type']
|
||||
} else {
|
||||
baseHeaders['Content-Type'] = 'application/octet-stream'
|
||||
}
|
||||
|
||||
const mergedOptions: UploadRequestOptions = {
|
||||
retry: false,
|
||||
...options,
|
||||
headers: {
|
||||
...baseHeaders,
|
||||
...options.headers,
|
||||
},
|
||||
}
|
||||
this.attachArchonSentryCaptureHeader(mergedOptions)
|
||||
|
||||
const uploadContext = this.buildUploadContext(url, path, mergedOptions)
|
||||
context = uploadContext
|
||||
if (abortController.signal.aborted) {
|
||||
throw new ModrinthApiError('Upload cancelled')
|
||||
}
|
||||
|
||||
const result = await this.executeUploadFeatureChain<T>(
|
||||
uploadContext,
|
||||
progressCallbacks,
|
||||
abortController,
|
||||
)
|
||||
await this.config.hooks?.onResponse?.(result, uploadContext)
|
||||
return result
|
||||
})().catch(async (error) => {
|
||||
const apiError = this.normalizeError(error, context)
|
||||
if (context) {
|
||||
await this.config.hooks?.onError?.(apiError, context)
|
||||
throw apiError
|
||||
}),
|
||||
}
|
||||
throw apiError
|
||||
}),
|
||||
onProgress: (callback) => {
|
||||
progressCallbacks.push(callback)
|
||||
return handle
|
||||
|
||||
Reference in New Issue
Block a user