laravel-nuxt/nuxt/app/plugins/app.ts

131 lines
3.5 KiB
TypeScript

import { ofetch } from 'ofetch'
import type { FetchOptions } from 'ofetch'
export default defineNuxtPlugin({
name: 'app',
enforce: 'default',
parallel: true,
async setup(nuxtApp) {
const config = useRuntimeConfig()
const auth = useAuthStore()
nuxtApp.provide('storage', (path: string): string => {
if (!path) return ''
return path.startsWith('http://') || path.startsWith('https://')
? path
: config.public.storageBase + path
})
function buildHeaders(headers: HeadersInit = {}): HeadersInit {
// Initial headers with Accept
const initialHeaders = {
...headers,
Accept: 'application/json',
}
// Conditionally add server-specific headers
if (import.meta.server) {
const serverHeaders = {
referer: useRequestURL().toString(),
...useRequestHeaders(['x-forwarded-for', 'user-agent', 'referer']),
}
Object.assign(initialHeaders, serverHeaders)
}
// Conditionally add authorization header if logged in
if (auth.isLoggedIn) {
const authHeaders = {
Authorization: `Bearer ${auth.token}`,
}
Object.assign(initialHeaders, authHeaders)
}
return initialHeaders
}
function buildBaseURL(baseURL: string): string {
if (baseURL) return baseURL
return import.meta.server
? config.apiLocal + config.public.apiPrefix
: config.public.apiBase + config.public.apiPrefix
}
function buildSecureMethod(options: FetchOptions): void {
if (import.meta.server) return
const method = options.method?.toLowerCase() ?? 'get'
if (options.body instanceof FormData && method === 'put') {
options.method = 'POST'
options.body.append('_method', 'PUT')
}
}
function isRequestWithAuth(baseURL: string, path: string): boolean {
return !baseURL
&& !path.startsWith('/_nuxt')
&& !path.startsWith('http://')
&& !path.startsWith('https://')
}
globalThis.$fetch = ofetch.create({
retry: false,
onRequest({ request, options }) {
if (!isRequestWithAuth(options.baseURL ?? '', request.toString())) return
options.credentials = 'include'
options.baseURL = buildBaseURL(options.baseURL ?? '')
options.headers = buildHeaders(options.headers)
buildSecureMethod(options)
},
onRequestError({ error }) {
if (import.meta.server) return
if (error.name === 'AbortError') return
useToast().add({
icon: 'i-heroicons-exclamation-circle-solid',
color: 'red',
title: error.message ?? 'Something went wrong',
})
},
onResponseError({ response }) {
if (response.status === 401) {
if (auth.isLoggedIn) {
auth.token = ''
auth.user = {} as User
}
if (import.meta.client) {
useToast().add({
title: 'Please log in to continue',
icon: 'i-heroicons-exclamation-circle-solid',
color: 'primary',
})
}
}
else if (response.status !== 422) {
if (import.meta.client) {
useToast().add({
icon: 'i-heroicons-exclamation-circle-solid',
color: 'red',
title: response._data?.message ?? response.statusText ?? 'Something went wrong',
})
}
}
},
} as FetchOptions)
if (auth.isLoggedIn) {
await auth.fetchUser()
}
},
})