Untitled
unknown
javascript
2 years ago
4.8 kB
24
Indexable
import { error, type NumericRange } from "@sveltejs/kit"
import Cookie from "cookie"
import { setCookie } from "./cookie"
import { isDev } from "~config"
type RecursiveUrlParams = { [key: string]: RecursiveUrlParams | string | boolean | unknown }
interface FetchOptions {
method?: "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "HEAD" | "PATCH"
headers?: Record<string, string>
body?: BodyInit | null | undefined
data?: unknown
mode?: "cors" | "no-cors" | "same-origin"
credentials?: "include" | "omit" | "same-origin"
withCredentials?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
params?: Record<string, RecursiveUrlParams | string> | any
cache?: "default" | "no-store" | "reload" | "no-cache" | "force-cache" | "only-if-cached"
redirect?: "follow" | "error" | "manual"
referrer?: string
referrerPolicy?:
| "no-referrer"
| "no-referrer-when-downgrade"
| "origin"
| "origin-when-cross-origin"
| "same-origin"
| "strict-origin"
| "strict-origin-when-cross-origin"
| "unsafe-url"
integrity?: string
keepalive?: boolean
signal?: AbortSignal | null
baseURL?: string
url?: string
fetch?: typeof fetch
}
export const isObject = (value: unknown): value is Record<string, unknown> => {
return typeof value === "object" && value !== null && !Array.isArray(value)
}
export const encodeQueryParams = (params: Record<string, unknown>): string => {
const customEncodeURIComponent = (str: string): string => {
return encodeURIComponent(str)
.replace(/[!'()*~]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)
.replace(/%20/g, "%20")
}
const encode = (key: string, value: unknown): string => {
if (value === undefined) {
return ""
}
if (Array.isArray(value)) {
if (value.length === 0) {
return `${customEncodeURIComponent(key)}%5B%5D=`
}
return value
.map((v, i) => encode(`${key}[${i}]`, v))
.filter(Boolean)
.join("&")
}
if (isObject(value)) {
return Object.entries(value)
.map(([k, v]) => encode(`${key}[${k}]`, v))
.filter(Boolean)
.join("&")
}
return `${customEncodeURIComponent(key)}=${customEncodeURIComponent(String(value))}`
}
return Object.entries(params)
.map(([k, v]) => encode(k, v))
.filter(Boolean)
.join("&")
}
export async function fetcher<T>(options: FetchOptions = {}) {
const defaultOptions = {
method: "GET",
} as FetchOptions
let response
if (["POST", "PUT"].includes(options.method || "") && !options.headers?.["Content-Type"]) {
defaultOptions.headers = {
"Content-Type": "application/json",
}
}
const mergedOptions = {
// credentials: "include" as RequestCredentials,
...defaultOptions,
...options,
headers: {
...defaultOptions.headers,
...options.headers,
},
}
// Map withCredentials to the fetch credentials option
if (options.withCredentials) {
mergedOptions.credentials = "include"
}
if (options.data) {
if (options.headers?.["Content-Type"] === "application/x-www-form-urlencoded") {
const formBody = []
for (const [key, value] of Object.entries(options.data)) {
const encodedKey = encodeURIComponent(key)
const encodedValue = encodeURIComponent(value as string)
formBody.push(encodedKey + "=" + encodedValue)
}
mergedOptions.body = formBody.join("&")
} else {
mergedOptions.body = JSON.stringify(options.data)
}
delete mergedOptions.data
}
const urlObject = new URL(`${options.baseURL || ""}${options.url || ""}`)
if (options.params) {
const queryString = encodeQueryParams(options.params as Record<string, unknown>)
urlObject.search = queryString
}
const fullUrl = urlObject.toString()
try {
const fetchingHandler = isDev ? fetch : options?.fetch || fetch
response = await fetchingHandler?.(fullUrl, mergedOptions)
const setCookieHeader = response.headers.get("Set-Cookie")
try {
if (setCookieHeader) {
const parsedCookie = Cookie.parse(setCookieHeader)
if (parsedCookie.id_token) setCookie("id_token", parsedCookie.id_token)
if (parsedCookie.access_token) setCookie("access_token", parsedCookie.access_token)
}
} catch (error) {
console.log("setCookieHeader error :>> ", error)
}
if (+response?.status >= 400) {
const errorData = await response?.json()
console.log("errorData :>> ", fullUrl, errorData)
error(response?.status as NumericRange<400, 599>, errorData || "Fetch error")
}
const data = (await response?.json()) as T
return { data } as { data: T }
} catch (err: unknown) {
console.error("Fetch error:", fullUrl, JSON.stringify(err))
// console.error("error response", response);
let status
if (response?.status) status = +response?.status < 400 ? 400 : +response?.status
error(
(status as NumericRange<400, 599>) || 500,
((err as ErrorEvent).message || err || "Fetch error") as Error,
)
}
}
Editor is loading...
Leave a Comment