Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

35
Frontend-Learner/node_modules/ofetch/dist/index.cjs generated vendored Normal file
View file

@ -0,0 +1,35 @@
'use strict';
const fetch$1 = require('./shared/ofetch.BBShr9Pz.cjs');
require('destr');
require('ufo');
const _globalThis = (function() {
if (typeof globalThis !== "undefined") {
return globalThis;
}
if (typeof self !== "undefined") {
return self;
}
if (typeof window !== "undefined") {
return window;
}
if (typeof global !== "undefined") {
return global;
}
throw new Error("unable to locate global object");
})();
const fetch = _globalThis.fetch ? (...args) => _globalThis.fetch(...args) : () => Promise.reject(new Error("[ofetch] global.fetch is not supported!"));
const Headers = _globalThis.Headers;
const AbortController = _globalThis.AbortController;
const ofetch = fetch$1.createFetch({ fetch, Headers, AbortController });
const $fetch = ofetch;
exports.FetchError = fetch$1.FetchError;
exports.createFetch = fetch$1.createFetch;
exports.createFetchError = fetch$1.createFetchError;
exports.$fetch = $fetch;
exports.AbortController = AbortController;
exports.Headers = Headers;
exports.fetch = fetch;
exports.ofetch = ofetch;

17
Frontend-Learner/node_modules/ofetch/dist/index.d.cts generated vendored Normal file
View file

@ -0,0 +1,17 @@
import { $ as $Fetch } from './shared/ofetch.BbrTaNPp.cjs';
export { C as CreateFetchOptions, j as Fetch, d as FetchContext, F as FetchError, e as FetchHook, f as FetchHooks, b as FetchOptions, k as FetchRequest, i as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResolvedFetchOptions, g as ResponseMap, h as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.BbrTaNPp.cjs';
import 'undici';
declare const fetch: (input: string | URL | Request, init?: RequestInit | undefined) => Promise<Response>;
declare const Headers: {
new (init?: HeadersInit): Headers;
prototype: Headers;
};
declare const AbortController: {
new (): AbortController;
prototype: AbortController;
};
declare const ofetch: $Fetch;
declare const $fetch: $Fetch;
export { $Fetch, $fetch, AbortController, Headers, fetch, ofetch };

17
Frontend-Learner/node_modules/ofetch/dist/index.d.mts generated vendored Normal file
View file

@ -0,0 +1,17 @@
import { $ as $Fetch } from './shared/ofetch.BbrTaNPp.mjs';
export { C as CreateFetchOptions, j as Fetch, d as FetchContext, F as FetchError, e as FetchHook, f as FetchHooks, b as FetchOptions, k as FetchRequest, i as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResolvedFetchOptions, g as ResponseMap, h as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.BbrTaNPp.mjs';
import 'undici';
declare const fetch: (input: string | URL | Request, init?: RequestInit | undefined) => Promise<Response>;
declare const Headers: {
new (init?: HeadersInit): Headers;
prototype: Headers;
};
declare const AbortController: {
new (): AbortController;
prototype: AbortController;
};
declare const ofetch: $Fetch;
declare const $fetch: $Fetch;
export { $Fetch, $fetch, AbortController, Headers, fetch, ofetch };

17
Frontend-Learner/node_modules/ofetch/dist/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,17 @@
import { $ as $Fetch } from './shared/ofetch.BbrTaNPp.js';
export { C as CreateFetchOptions, j as Fetch, d as FetchContext, F as FetchError, e as FetchHook, f as FetchHooks, b as FetchOptions, k as FetchRequest, i as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResolvedFetchOptions, g as ResponseMap, h as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.BbrTaNPp.js';
import 'undici';
declare const fetch: (input: string | URL | Request, init?: RequestInit | undefined) => Promise<Response>;
declare const Headers: {
new (init?: HeadersInit): Headers;
prototype: Headers;
};
declare const AbortController: {
new (): AbortController;
prototype: AbortController;
};
declare const ofetch: $Fetch;
declare const $fetch: $Fetch;
export { $Fetch, $fetch, AbortController, Headers, fetch, ofetch };

27
Frontend-Learner/node_modules/ofetch/dist/index.mjs generated vendored Normal file
View file

@ -0,0 +1,27 @@
import { c as createFetch } from './shared/ofetch.CWycOUEr.mjs';
export { F as FetchError, a as createFetchError } from './shared/ofetch.CWycOUEr.mjs';
import 'destr';
import 'ufo';
const _globalThis = (function() {
if (typeof globalThis !== "undefined") {
return globalThis;
}
if (typeof self !== "undefined") {
return self;
}
if (typeof window !== "undefined") {
return window;
}
if (typeof global !== "undefined") {
return global;
}
throw new Error("unable to locate global object");
})();
const fetch = _globalThis.fetch ? (...args) => _globalThis.fetch(...args) : () => Promise.reject(new Error("[ofetch] global.fetch is not supported!"));
const Headers = _globalThis.Headers;
const AbortController = _globalThis.AbortController;
const ofetch = createFetch({ fetch, Headers, AbortController });
const $fetch = ofetch;
export { $fetch, AbortController, Headers, createFetch, fetch, ofetch };

47
Frontend-Learner/node_modules/ofetch/dist/node.cjs generated vendored Normal file
View file

@ -0,0 +1,47 @@
'use strict';
const http = require('node:http');
const https = require('node:https');
const nodeFetch = require('node-fetch-native');
const fetch$1 = require('./shared/ofetch.BBShr9Pz.cjs');
require('destr');
require('ufo');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const http__default = /*#__PURE__*/_interopDefaultCompat(http);
const https__default = /*#__PURE__*/_interopDefaultCompat(https);
const nodeFetch__default = /*#__PURE__*/_interopDefaultCompat(nodeFetch);
function createNodeFetch() {
const useKeepAlive = JSON.parse(process.env.FETCH_KEEP_ALIVE || "false");
if (!useKeepAlive) {
return nodeFetch__default;
}
const agentOptions = { keepAlive: true };
const httpAgent = new http__default.Agent(agentOptions);
const httpsAgent = new https__default.Agent(agentOptions);
const nodeFetchOptions = {
agent(parsedURL) {
return parsedURL.protocol === "http:" ? httpAgent : httpsAgent;
}
};
return function nodeFetchWithKeepAlive(input, init) {
return nodeFetch__default(input, { ...nodeFetchOptions, ...init });
};
}
const fetch = globalThis.fetch ? (...args) => globalThis.fetch(...args) : createNodeFetch();
const Headers = globalThis.Headers || nodeFetch.Headers;
const AbortController = globalThis.AbortController || nodeFetch.AbortController;
const ofetch = fetch$1.createFetch({ fetch, Headers, AbortController });
const $fetch = ofetch;
exports.FetchError = fetch$1.FetchError;
exports.createFetch = fetch$1.createFetch;
exports.createFetchError = fetch$1.createFetchError;
exports.$fetch = $fetch;
exports.AbortController = AbortController;
exports.Headers = Headers;
exports.createNodeFetch = createNodeFetch;
exports.fetch = fetch;
exports.ofetch = ofetch;

18
Frontend-Learner/node_modules/ofetch/dist/node.d.cts generated vendored Normal file
View file

@ -0,0 +1,18 @@
import { $ as $Fetch } from './shared/ofetch.BbrTaNPp.cjs';
export { C as CreateFetchOptions, j as Fetch, d as FetchContext, F as FetchError, e as FetchHook, f as FetchHooks, b as FetchOptions, k as FetchRequest, i as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResolvedFetchOptions, g as ResponseMap, h as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.BbrTaNPp.cjs';
import 'undici';
declare function createNodeFetch(): (input: RequestInfo, init?: RequestInit) => any;
declare const fetch: typeof globalThis.fetch;
declare const Headers: {
new (init?: HeadersInit): Headers;
prototype: Headers;
};
declare const AbortController: {
new (): AbortController;
prototype: AbortController;
};
declare const ofetch: $Fetch;
declare const $fetch: $Fetch;
export { $Fetch, $fetch, AbortController, Headers, createNodeFetch, fetch, ofetch };

18
Frontend-Learner/node_modules/ofetch/dist/node.d.mts generated vendored Normal file
View file

@ -0,0 +1,18 @@
import { $ as $Fetch } from './shared/ofetch.BbrTaNPp.mjs';
export { C as CreateFetchOptions, j as Fetch, d as FetchContext, F as FetchError, e as FetchHook, f as FetchHooks, b as FetchOptions, k as FetchRequest, i as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResolvedFetchOptions, g as ResponseMap, h as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.BbrTaNPp.mjs';
import 'undici';
declare function createNodeFetch(): (input: RequestInfo, init?: RequestInit) => any;
declare const fetch: typeof globalThis.fetch;
declare const Headers: {
new (init?: HeadersInit): Headers;
prototype: Headers;
};
declare const AbortController: {
new (): AbortController;
prototype: AbortController;
};
declare const ofetch: $Fetch;
declare const $fetch: $Fetch;
export { $Fetch, $fetch, AbortController, Headers, createNodeFetch, fetch, ofetch };

18
Frontend-Learner/node_modules/ofetch/dist/node.d.ts generated vendored Normal file
View file

@ -0,0 +1,18 @@
import { $ as $Fetch } from './shared/ofetch.BbrTaNPp.js';
export { C as CreateFetchOptions, j as Fetch, d as FetchContext, F as FetchError, e as FetchHook, f as FetchHooks, b as FetchOptions, k as FetchRequest, i as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResolvedFetchOptions, g as ResponseMap, h as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.BbrTaNPp.js';
import 'undici';
declare function createNodeFetch(): (input: RequestInfo, init?: RequestInit) => any;
declare const fetch: typeof globalThis.fetch;
declare const Headers: {
new (init?: HeadersInit): Headers;
prototype: Headers;
};
declare const AbortController: {
new (): AbortController;
prototype: AbortController;
};
declare const ofetch: $Fetch;
declare const $fetch: $Fetch;
export { $Fetch, $fetch, AbortController, Headers, createNodeFetch, fetch, ofetch };

32
Frontend-Learner/node_modules/ofetch/dist/node.mjs generated vendored Normal file
View file

@ -0,0 +1,32 @@
import http from 'node:http';
import https from 'node:https';
import nodeFetch, { AbortController as AbortController$1, Headers as Headers$1 } from 'node-fetch-native';
import { c as createFetch } from './shared/ofetch.CWycOUEr.mjs';
export { F as FetchError, a as createFetchError } from './shared/ofetch.CWycOUEr.mjs';
import 'destr';
import 'ufo';
function createNodeFetch() {
const useKeepAlive = JSON.parse(process.env.FETCH_KEEP_ALIVE || "false");
if (!useKeepAlive) {
return nodeFetch;
}
const agentOptions = { keepAlive: true };
const httpAgent = new http.Agent(agentOptions);
const httpsAgent = new https.Agent(agentOptions);
const nodeFetchOptions = {
agent(parsedURL) {
return parsedURL.protocol === "http:" ? httpAgent : httpsAgent;
}
};
return function nodeFetchWithKeepAlive(input, init) {
return nodeFetch(input, { ...nodeFetchOptions, ...init });
};
}
const fetch = globalThis.fetch ? (...args) => globalThis.fetch(...args) : createNodeFetch();
const Headers = globalThis.Headers || Headers$1;
const AbortController = globalThis.AbortController || AbortController$1;
const ofetch = createFetch({ fetch, Headers, AbortController });
const $fetch = ofetch;
export { $fetch, AbortController, Headers, createFetch, createNodeFetch, fetch, ofetch };

View file

@ -0,0 +1,357 @@
'use strict';
const destr = require('destr');
const ufo = require('ufo');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const destr__default = /*#__PURE__*/_interopDefaultCompat(destr);
class FetchError extends Error {
constructor(message, opts) {
super(message, opts);
this.name = "FetchError";
if (opts?.cause && !this.cause) {
this.cause = opts.cause;
}
}
}
function createFetchError(ctx) {
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
const method = ctx.request?.method || ctx.options?.method || "GET";
const url = ctx.request?.url || String(ctx.request) || "/";
const requestStr = `[${method}] ${JSON.stringify(url)}`;
const statusStr = ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>";
const message = `${requestStr}: ${statusStr}${errorMessage ? ` ${errorMessage}` : ""}`;
const fetchError = new FetchError(
message,
ctx.error ? { cause: ctx.error } : void 0
);
for (const key of ["request", "options", "response"]) {
Object.defineProperty(fetchError, key, {
get() {
return ctx[key];
}
});
}
for (const [key, refKey] of [
["data", "_data"],
["status", "status"],
["statusCode", "status"],
["statusText", "statusText"],
["statusMessage", "statusText"]
]) {
Object.defineProperty(fetchError, key, {
get() {
return ctx.response && ctx.response[refKey];
}
});
}
return fetchError;
}
const payloadMethods = new Set(
Object.freeze(["PATCH", "POST", "PUT", "DELETE"])
);
function isPayloadMethod(method = "GET") {
return payloadMethods.has(method.toUpperCase());
}
function isJSONSerializable(value) {
if (value === void 0) {
return false;
}
const t = typeof value;
if (t === "string" || t === "number" || t === "boolean" || t === null) {
return true;
}
if (t !== "object") {
return false;
}
if (Array.isArray(value)) {
return true;
}
if (value.buffer) {
return false;
}
if (value instanceof FormData || value instanceof URLSearchParams) {
return false;
}
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
}
const textTypes = /* @__PURE__ */ new Set([
"image/svg",
"application/xml",
"application/xhtml",
"application/html"
]);
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
function detectResponseType(_contentType = "") {
if (!_contentType) {
return "json";
}
const contentType = _contentType.split(";").shift() || "";
if (JSON_RE.test(contentType)) {
return "json";
}
if (contentType === "text/event-stream") {
return "stream";
}
if (textTypes.has(contentType) || contentType.startsWith("text/")) {
return "text";
}
return "blob";
}
function resolveFetchOptions(request, input, defaults, Headers) {
const headers = mergeHeaders(
input?.headers ?? request?.headers,
defaults?.headers,
Headers
);
let query;
if (defaults?.query || defaults?.params || input?.params || input?.query) {
query = {
...defaults?.params,
...defaults?.query,
...input?.params,
...input?.query
};
}
return {
...defaults,
...input,
query,
params: query,
headers
};
}
function mergeHeaders(input, defaults, Headers) {
if (!defaults) {
return new Headers(input);
}
const headers = new Headers(defaults);
if (input) {
for (const [key, value] of Symbol.iterator in input || Array.isArray(input) ? input : new Headers(input)) {
headers.set(key, value);
}
}
return headers;
}
async function callHooks(context, hooks) {
if (hooks) {
if (Array.isArray(hooks)) {
for (const hook of hooks) {
await hook(context);
}
} else {
await hooks(context);
}
}
}
const retryStatusCodes = /* @__PURE__ */ new Set([
408,
// Request Timeout
409,
// Conflict
425,
// Too Early (Experimental)
429,
// Too Many Requests
500,
// Internal Server Error
502,
// Bad Gateway
503,
// Service Unavailable
504
// Gateway Timeout
]);
const nullBodyResponses = /* @__PURE__ */ new Set([101, 204, 205, 304]);
function createFetch(globalOptions = {}) {
const {
fetch = globalThis.fetch,
Headers = globalThis.Headers,
AbortController = globalThis.AbortController
} = globalOptions;
async function onError(context) {
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
if (context.options.retry !== false && !isAbort) {
let retries;
if (typeof context.options.retry === "number") {
retries = context.options.retry;
} else {
retries = isPayloadMethod(context.options.method) ? 0 : 1;
}
const responseCode = context.response && context.response.status || 500;
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
if (retryDelay > 0) {
await new Promise((resolve) => setTimeout(resolve, retryDelay));
}
return $fetchRaw(context.request, {
...context.options,
retry: retries - 1
});
}
}
const error = createFetchError(context);
if (Error.captureStackTrace) {
Error.captureStackTrace(error, $fetchRaw);
}
throw error;
}
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
const context = {
request: _request,
options: resolveFetchOptions(
_request,
_options,
globalOptions.defaults,
Headers
),
response: void 0,
error: void 0
};
if (context.options.method) {
context.options.method = context.options.method.toUpperCase();
}
if (context.options.onRequest) {
await callHooks(context, context.options.onRequest);
if (!(context.options.headers instanceof Headers)) {
context.options.headers = new Headers(
context.options.headers || {}
/* compat */
);
}
}
if (typeof context.request === "string") {
if (context.options.baseURL) {
context.request = ufo.withBase(context.request, context.options.baseURL);
}
if (context.options.query) {
context.request = ufo.withQuery(context.request, context.options.query);
delete context.options.query;
}
if ("query" in context.options) {
delete context.options.query;
}
if ("params" in context.options) {
delete context.options.params;
}
}
if (context.options.body && isPayloadMethod(context.options.method)) {
if (isJSONSerializable(context.options.body)) {
const contentType = context.options.headers.get("content-type");
if (typeof context.options.body !== "string") {
context.options.body = contentType === "application/x-www-form-urlencoded" ? new URLSearchParams(
context.options.body
).toString() : JSON.stringify(context.options.body);
}
if (!contentType) {
context.options.headers.set("content-type", "application/json");
}
if (!context.options.headers.has("accept")) {
context.options.headers.set("accept", "application/json");
}
} else if (
// ReadableStream Body
"pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || // Node.js Stream Body
typeof context.options.body.pipe === "function"
) {
if (!("duplex" in context.options)) {
context.options.duplex = "half";
}
}
}
let abortTimeout;
if (!context.options.signal && context.options.timeout) {
const controller = new AbortController();
abortTimeout = setTimeout(() => {
const error = new Error(
"[TimeoutError]: The operation was aborted due to timeout"
);
error.name = "TimeoutError";
error.code = 23;
controller.abort(error);
}, context.options.timeout);
context.options.signal = controller.signal;
}
try {
context.response = await fetch(
context.request,
context.options
);
} catch (error) {
context.error = error;
if (context.options.onRequestError) {
await callHooks(
context,
context.options.onRequestError
);
}
return await onError(context);
} finally {
if (abortTimeout) {
clearTimeout(abortTimeout);
}
}
const hasBody = (context.response.body || // https://github.com/unjs/ofetch/issues/324
// https://github.com/unjs/ofetch/issues/294
// https://github.com/JakeChampion/fetch/issues/1454
context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD";
if (hasBody) {
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
switch (responseType) {
case "json": {
const data = await context.response.text();
const parseFunction = context.options.parseResponse || destr__default;
context.response._data = parseFunction(data);
break;
}
case "stream": {
context.response._data = context.response.body || context.response._bodyInit;
break;
}
default: {
context.response._data = await context.response[responseType]();
}
}
}
if (context.options.onResponse) {
await callHooks(
context,
context.options.onResponse
);
}
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
if (context.options.onResponseError) {
await callHooks(
context,
context.options.onResponseError
);
}
return await onError(context);
}
return context.response;
};
const $fetch = async function $fetch2(request, options) {
const r = await $fetchRaw(request, options);
return r._data;
};
$fetch.raw = $fetchRaw;
$fetch.native = (...args) => fetch(...args);
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
...globalOptions,
...customGlobalOptions,
defaults: {
...globalOptions.defaults,
...customGlobalOptions.defaults,
...defaultOptions
}
});
return $fetch;
}
exports.FetchError = FetchError;
exports.createFetch = createFetch;
exports.createFetchError = createFetchError;

View file

@ -0,0 +1,114 @@
import * as undici from 'undici';
interface $Fetch {
<T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<MappedResponseType<R, T>>;
raw<T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<FetchResponse<MappedResponseType<R, T>>>;
native: Fetch;
create(defaults: FetchOptions, globalOptions?: CreateFetchOptions): $Fetch;
}
interface FetchOptions<R extends ResponseType = ResponseType, T = any> extends Omit<RequestInit, "body">, FetchHooks<T, R> {
baseURL?: string;
body?: RequestInit["body"] | Record<string, any>;
ignoreResponseError?: boolean;
/**
* @deprecated use query instead.
*/
params?: Record<string, any>;
query?: Record<string, any>;
parseResponse?: (responseText: string) => any;
responseType?: R;
/**
* @experimental Set to "half" to enable duplex streaming.
* Will be automatically set to "half" when using a ReadableStream as body.
* @see https://fetch.spec.whatwg.org/#enumdef-requestduplex
*/
duplex?: "half" | undefined;
/**
* Only supported in Node.js >= 18 using undici
*
* @see https://undici.nodejs.org/#/docs/api/Dispatcher
*/
dispatcher?: InstanceType<typeof undici.Dispatcher>;
/**
* Only supported older Node.js versions using node-fetch-native polyfill.
*/
agent?: unknown;
/** timeout in milliseconds */
timeout?: number;
retry?: number | false;
/** Delay between retries in milliseconds. */
retryDelay?: number | ((context: FetchContext<T, R>) => number);
/** Default is [408, 409, 425, 429, 500, 502, 503, 504] */
retryStatusCodes?: number[];
}
interface ResolvedFetchOptions<R extends ResponseType = ResponseType, T = any> extends FetchOptions<R, T> {
headers: Headers;
}
interface CreateFetchOptions {
defaults?: FetchOptions;
fetch?: Fetch;
Headers?: typeof Headers;
AbortController?: typeof AbortController;
}
type GlobalOptions = Pick<FetchOptions, "timeout" | "retry" | "retryDelay">;
interface FetchContext<T = any, R extends ResponseType = ResponseType> {
request: FetchRequest;
options: ResolvedFetchOptions<R>;
response?: FetchResponse<T>;
error?: Error;
}
type MaybePromise<T> = T | Promise<T>;
type MaybeArray<T> = T | T[];
type FetchHook<C extends FetchContext = FetchContext> = (context: C) => MaybePromise<void>;
interface FetchHooks<T = any, R extends ResponseType = ResponseType> {
onRequest?: MaybeArray<FetchHook<FetchContext<T, R>>>;
onRequestError?: MaybeArray<FetchHook<FetchContext<T, R> & {
error: Error;
}>>;
onResponse?: MaybeArray<FetchHook<FetchContext<T, R> & {
response: FetchResponse<T>;
}>>;
onResponseError?: MaybeArray<FetchHook<FetchContext<T, R> & {
response: FetchResponse<T>;
}>>;
}
interface ResponseMap {
blob: Blob;
text: string;
arrayBuffer: ArrayBuffer;
stream: ReadableStream<Uint8Array>;
}
type ResponseType = keyof ResponseMap | "json";
type MappedResponseType<R extends ResponseType, JsonType = any> = R extends keyof ResponseMap ? ResponseMap[R] : JsonType;
interface FetchResponse<T> extends Response {
_data?: T;
}
interface IFetchError<T = any> extends Error {
request?: FetchRequest;
options?: FetchOptions;
response?: FetchResponse<T>;
data?: T;
status?: number;
statusText?: string;
statusCode?: number;
statusMessage?: string;
}
type Fetch = typeof globalThis.fetch;
type FetchRequest = RequestInfo;
interface SearchParameters {
[key: string]: any;
}
declare function createFetch(globalOptions?: CreateFetchOptions): $Fetch;
declare class FetchError<T = any> extends Error implements IFetchError<T> {
constructor(message: string, opts?: {
cause: unknown;
});
}
interface FetchError<T = any> extends IFetchError<T> {
}
declare function createFetchError<T = any>(ctx: FetchContext<T>): IFetchError<T>;
export { FetchError as F, createFetchError as a, createFetch as c };
export type { $Fetch as $, CreateFetchOptions as C, GlobalOptions as G, IFetchError as I, MappedResponseType as M, ResolvedFetchOptions as R, SearchParameters as S, FetchOptions as b, FetchContext as d, FetchHook as e, FetchHooks as f, ResponseMap as g, ResponseType as h, FetchResponse as i, Fetch as j, FetchRequest as k };

View file

@ -0,0 +1,114 @@
import * as undici from 'undici';
interface $Fetch {
<T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<MappedResponseType<R, T>>;
raw<T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<FetchResponse<MappedResponseType<R, T>>>;
native: Fetch;
create(defaults: FetchOptions, globalOptions?: CreateFetchOptions): $Fetch;
}
interface FetchOptions<R extends ResponseType = ResponseType, T = any> extends Omit<RequestInit, "body">, FetchHooks<T, R> {
baseURL?: string;
body?: RequestInit["body"] | Record<string, any>;
ignoreResponseError?: boolean;
/**
* @deprecated use query instead.
*/
params?: Record<string, any>;
query?: Record<string, any>;
parseResponse?: (responseText: string) => any;
responseType?: R;
/**
* @experimental Set to "half" to enable duplex streaming.
* Will be automatically set to "half" when using a ReadableStream as body.
* @see https://fetch.spec.whatwg.org/#enumdef-requestduplex
*/
duplex?: "half" | undefined;
/**
* Only supported in Node.js >= 18 using undici
*
* @see https://undici.nodejs.org/#/docs/api/Dispatcher
*/
dispatcher?: InstanceType<typeof undici.Dispatcher>;
/**
* Only supported older Node.js versions using node-fetch-native polyfill.
*/
agent?: unknown;
/** timeout in milliseconds */
timeout?: number;
retry?: number | false;
/** Delay between retries in milliseconds. */
retryDelay?: number | ((context: FetchContext<T, R>) => number);
/** Default is [408, 409, 425, 429, 500, 502, 503, 504] */
retryStatusCodes?: number[];
}
interface ResolvedFetchOptions<R extends ResponseType = ResponseType, T = any> extends FetchOptions<R, T> {
headers: Headers;
}
interface CreateFetchOptions {
defaults?: FetchOptions;
fetch?: Fetch;
Headers?: typeof Headers;
AbortController?: typeof AbortController;
}
type GlobalOptions = Pick<FetchOptions, "timeout" | "retry" | "retryDelay">;
interface FetchContext<T = any, R extends ResponseType = ResponseType> {
request: FetchRequest;
options: ResolvedFetchOptions<R>;
response?: FetchResponse<T>;
error?: Error;
}
type MaybePromise<T> = T | Promise<T>;
type MaybeArray<T> = T | T[];
type FetchHook<C extends FetchContext = FetchContext> = (context: C) => MaybePromise<void>;
interface FetchHooks<T = any, R extends ResponseType = ResponseType> {
onRequest?: MaybeArray<FetchHook<FetchContext<T, R>>>;
onRequestError?: MaybeArray<FetchHook<FetchContext<T, R> & {
error: Error;
}>>;
onResponse?: MaybeArray<FetchHook<FetchContext<T, R> & {
response: FetchResponse<T>;
}>>;
onResponseError?: MaybeArray<FetchHook<FetchContext<T, R> & {
response: FetchResponse<T>;
}>>;
}
interface ResponseMap {
blob: Blob;
text: string;
arrayBuffer: ArrayBuffer;
stream: ReadableStream<Uint8Array>;
}
type ResponseType = keyof ResponseMap | "json";
type MappedResponseType<R extends ResponseType, JsonType = any> = R extends keyof ResponseMap ? ResponseMap[R] : JsonType;
interface FetchResponse<T> extends Response {
_data?: T;
}
interface IFetchError<T = any> extends Error {
request?: FetchRequest;
options?: FetchOptions;
response?: FetchResponse<T>;
data?: T;
status?: number;
statusText?: string;
statusCode?: number;
statusMessage?: string;
}
type Fetch = typeof globalThis.fetch;
type FetchRequest = RequestInfo;
interface SearchParameters {
[key: string]: any;
}
declare function createFetch(globalOptions?: CreateFetchOptions): $Fetch;
declare class FetchError<T = any> extends Error implements IFetchError<T> {
constructor(message: string, opts?: {
cause: unknown;
});
}
interface FetchError<T = any> extends IFetchError<T> {
}
declare function createFetchError<T = any>(ctx: FetchContext<T>): IFetchError<T>;
export { FetchError as F, createFetchError as a, createFetch as c };
export type { $Fetch as $, CreateFetchOptions as C, GlobalOptions as G, IFetchError as I, MappedResponseType as M, ResolvedFetchOptions as R, SearchParameters as S, FetchOptions as b, FetchContext as d, FetchHook as e, FetchHooks as f, ResponseMap as g, ResponseType as h, FetchResponse as i, Fetch as j, FetchRequest as k };

View file

@ -0,0 +1,114 @@
import * as undici from 'undici';
interface $Fetch {
<T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<MappedResponseType<R, T>>;
raw<T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<FetchResponse<MappedResponseType<R, T>>>;
native: Fetch;
create(defaults: FetchOptions, globalOptions?: CreateFetchOptions): $Fetch;
}
interface FetchOptions<R extends ResponseType = ResponseType, T = any> extends Omit<RequestInit, "body">, FetchHooks<T, R> {
baseURL?: string;
body?: RequestInit["body"] | Record<string, any>;
ignoreResponseError?: boolean;
/**
* @deprecated use query instead.
*/
params?: Record<string, any>;
query?: Record<string, any>;
parseResponse?: (responseText: string) => any;
responseType?: R;
/**
* @experimental Set to "half" to enable duplex streaming.
* Will be automatically set to "half" when using a ReadableStream as body.
* @see https://fetch.spec.whatwg.org/#enumdef-requestduplex
*/
duplex?: "half" | undefined;
/**
* Only supported in Node.js >= 18 using undici
*
* @see https://undici.nodejs.org/#/docs/api/Dispatcher
*/
dispatcher?: InstanceType<typeof undici.Dispatcher>;
/**
* Only supported older Node.js versions using node-fetch-native polyfill.
*/
agent?: unknown;
/** timeout in milliseconds */
timeout?: number;
retry?: number | false;
/** Delay between retries in milliseconds. */
retryDelay?: number | ((context: FetchContext<T, R>) => number);
/** Default is [408, 409, 425, 429, 500, 502, 503, 504] */
retryStatusCodes?: number[];
}
interface ResolvedFetchOptions<R extends ResponseType = ResponseType, T = any> extends FetchOptions<R, T> {
headers: Headers;
}
interface CreateFetchOptions {
defaults?: FetchOptions;
fetch?: Fetch;
Headers?: typeof Headers;
AbortController?: typeof AbortController;
}
type GlobalOptions = Pick<FetchOptions, "timeout" | "retry" | "retryDelay">;
interface FetchContext<T = any, R extends ResponseType = ResponseType> {
request: FetchRequest;
options: ResolvedFetchOptions<R>;
response?: FetchResponse<T>;
error?: Error;
}
type MaybePromise<T> = T | Promise<T>;
type MaybeArray<T> = T | T[];
type FetchHook<C extends FetchContext = FetchContext> = (context: C) => MaybePromise<void>;
interface FetchHooks<T = any, R extends ResponseType = ResponseType> {
onRequest?: MaybeArray<FetchHook<FetchContext<T, R>>>;
onRequestError?: MaybeArray<FetchHook<FetchContext<T, R> & {
error: Error;
}>>;
onResponse?: MaybeArray<FetchHook<FetchContext<T, R> & {
response: FetchResponse<T>;
}>>;
onResponseError?: MaybeArray<FetchHook<FetchContext<T, R> & {
response: FetchResponse<T>;
}>>;
}
interface ResponseMap {
blob: Blob;
text: string;
arrayBuffer: ArrayBuffer;
stream: ReadableStream<Uint8Array>;
}
type ResponseType = keyof ResponseMap | "json";
type MappedResponseType<R extends ResponseType, JsonType = any> = R extends keyof ResponseMap ? ResponseMap[R] : JsonType;
interface FetchResponse<T> extends Response {
_data?: T;
}
interface IFetchError<T = any> extends Error {
request?: FetchRequest;
options?: FetchOptions;
response?: FetchResponse<T>;
data?: T;
status?: number;
statusText?: string;
statusCode?: number;
statusMessage?: string;
}
type Fetch = typeof globalThis.fetch;
type FetchRequest = RequestInfo;
interface SearchParameters {
[key: string]: any;
}
declare function createFetch(globalOptions?: CreateFetchOptions): $Fetch;
declare class FetchError<T = any> extends Error implements IFetchError<T> {
constructor(message: string, opts?: {
cause: unknown;
});
}
interface FetchError<T = any> extends IFetchError<T> {
}
declare function createFetchError<T = any>(ctx: FetchContext<T>): IFetchError<T>;
export { FetchError as F, createFetchError as a, createFetch as c };
export type { $Fetch as $, CreateFetchOptions as C, GlobalOptions as G, IFetchError as I, MappedResponseType as M, ResolvedFetchOptions as R, SearchParameters as S, FetchOptions as b, FetchContext as d, FetchHook as e, FetchHooks as f, ResponseMap as g, ResponseType as h, FetchResponse as i, Fetch as j, FetchRequest as k };

View file

@ -0,0 +1,349 @@
import destr from 'destr';
import { withBase, withQuery } from 'ufo';
class FetchError extends Error {
constructor(message, opts) {
super(message, opts);
this.name = "FetchError";
if (opts?.cause && !this.cause) {
this.cause = opts.cause;
}
}
}
function createFetchError(ctx) {
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
const method = ctx.request?.method || ctx.options?.method || "GET";
const url = ctx.request?.url || String(ctx.request) || "/";
const requestStr = `[${method}] ${JSON.stringify(url)}`;
const statusStr = ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>";
const message = `${requestStr}: ${statusStr}${errorMessage ? ` ${errorMessage}` : ""}`;
const fetchError = new FetchError(
message,
ctx.error ? { cause: ctx.error } : void 0
);
for (const key of ["request", "options", "response"]) {
Object.defineProperty(fetchError, key, {
get() {
return ctx[key];
}
});
}
for (const [key, refKey] of [
["data", "_data"],
["status", "status"],
["statusCode", "status"],
["statusText", "statusText"],
["statusMessage", "statusText"]
]) {
Object.defineProperty(fetchError, key, {
get() {
return ctx.response && ctx.response[refKey];
}
});
}
return fetchError;
}
const payloadMethods = new Set(
Object.freeze(["PATCH", "POST", "PUT", "DELETE"])
);
function isPayloadMethod(method = "GET") {
return payloadMethods.has(method.toUpperCase());
}
function isJSONSerializable(value) {
if (value === void 0) {
return false;
}
const t = typeof value;
if (t === "string" || t === "number" || t === "boolean" || t === null) {
return true;
}
if (t !== "object") {
return false;
}
if (Array.isArray(value)) {
return true;
}
if (value.buffer) {
return false;
}
if (value instanceof FormData || value instanceof URLSearchParams) {
return false;
}
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
}
const textTypes = /* @__PURE__ */ new Set([
"image/svg",
"application/xml",
"application/xhtml",
"application/html"
]);
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
function detectResponseType(_contentType = "") {
if (!_contentType) {
return "json";
}
const contentType = _contentType.split(";").shift() || "";
if (JSON_RE.test(contentType)) {
return "json";
}
if (contentType === "text/event-stream") {
return "stream";
}
if (textTypes.has(contentType) || contentType.startsWith("text/")) {
return "text";
}
return "blob";
}
function resolveFetchOptions(request, input, defaults, Headers) {
const headers = mergeHeaders(
input?.headers ?? request?.headers,
defaults?.headers,
Headers
);
let query;
if (defaults?.query || defaults?.params || input?.params || input?.query) {
query = {
...defaults?.params,
...defaults?.query,
...input?.params,
...input?.query
};
}
return {
...defaults,
...input,
query,
params: query,
headers
};
}
function mergeHeaders(input, defaults, Headers) {
if (!defaults) {
return new Headers(input);
}
const headers = new Headers(defaults);
if (input) {
for (const [key, value] of Symbol.iterator in input || Array.isArray(input) ? input : new Headers(input)) {
headers.set(key, value);
}
}
return headers;
}
async function callHooks(context, hooks) {
if (hooks) {
if (Array.isArray(hooks)) {
for (const hook of hooks) {
await hook(context);
}
} else {
await hooks(context);
}
}
}
const retryStatusCodes = /* @__PURE__ */ new Set([
408,
// Request Timeout
409,
// Conflict
425,
// Too Early (Experimental)
429,
// Too Many Requests
500,
// Internal Server Error
502,
// Bad Gateway
503,
// Service Unavailable
504
// Gateway Timeout
]);
const nullBodyResponses = /* @__PURE__ */ new Set([101, 204, 205, 304]);
function createFetch(globalOptions = {}) {
const {
fetch = globalThis.fetch,
Headers = globalThis.Headers,
AbortController = globalThis.AbortController
} = globalOptions;
async function onError(context) {
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
if (context.options.retry !== false && !isAbort) {
let retries;
if (typeof context.options.retry === "number") {
retries = context.options.retry;
} else {
retries = isPayloadMethod(context.options.method) ? 0 : 1;
}
const responseCode = context.response && context.response.status || 500;
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
if (retryDelay > 0) {
await new Promise((resolve) => setTimeout(resolve, retryDelay));
}
return $fetchRaw(context.request, {
...context.options,
retry: retries - 1
});
}
}
const error = createFetchError(context);
if (Error.captureStackTrace) {
Error.captureStackTrace(error, $fetchRaw);
}
throw error;
}
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
const context = {
request: _request,
options: resolveFetchOptions(
_request,
_options,
globalOptions.defaults,
Headers
),
response: void 0,
error: void 0
};
if (context.options.method) {
context.options.method = context.options.method.toUpperCase();
}
if (context.options.onRequest) {
await callHooks(context, context.options.onRequest);
if (!(context.options.headers instanceof Headers)) {
context.options.headers = new Headers(
context.options.headers || {}
/* compat */
);
}
}
if (typeof context.request === "string") {
if (context.options.baseURL) {
context.request = withBase(context.request, context.options.baseURL);
}
if (context.options.query) {
context.request = withQuery(context.request, context.options.query);
delete context.options.query;
}
if ("query" in context.options) {
delete context.options.query;
}
if ("params" in context.options) {
delete context.options.params;
}
}
if (context.options.body && isPayloadMethod(context.options.method)) {
if (isJSONSerializable(context.options.body)) {
const contentType = context.options.headers.get("content-type");
if (typeof context.options.body !== "string") {
context.options.body = contentType === "application/x-www-form-urlencoded" ? new URLSearchParams(
context.options.body
).toString() : JSON.stringify(context.options.body);
}
if (!contentType) {
context.options.headers.set("content-type", "application/json");
}
if (!context.options.headers.has("accept")) {
context.options.headers.set("accept", "application/json");
}
} else if (
// ReadableStream Body
"pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || // Node.js Stream Body
typeof context.options.body.pipe === "function"
) {
if (!("duplex" in context.options)) {
context.options.duplex = "half";
}
}
}
let abortTimeout;
if (!context.options.signal && context.options.timeout) {
const controller = new AbortController();
abortTimeout = setTimeout(() => {
const error = new Error(
"[TimeoutError]: The operation was aborted due to timeout"
);
error.name = "TimeoutError";
error.code = 23;
controller.abort(error);
}, context.options.timeout);
context.options.signal = controller.signal;
}
try {
context.response = await fetch(
context.request,
context.options
);
} catch (error) {
context.error = error;
if (context.options.onRequestError) {
await callHooks(
context,
context.options.onRequestError
);
}
return await onError(context);
} finally {
if (abortTimeout) {
clearTimeout(abortTimeout);
}
}
const hasBody = (context.response.body || // https://github.com/unjs/ofetch/issues/324
// https://github.com/unjs/ofetch/issues/294
// https://github.com/JakeChampion/fetch/issues/1454
context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD";
if (hasBody) {
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
switch (responseType) {
case "json": {
const data = await context.response.text();
const parseFunction = context.options.parseResponse || destr;
context.response._data = parseFunction(data);
break;
}
case "stream": {
context.response._data = context.response.body || context.response._bodyInit;
break;
}
default: {
context.response._data = await context.response[responseType]();
}
}
}
if (context.options.onResponse) {
await callHooks(
context,
context.options.onResponse
);
}
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
if (context.options.onResponseError) {
await callHooks(
context,
context.options.onResponseError
);
}
return await onError(context);
}
return context.response;
};
const $fetch = async function $fetch2(request, options) {
const r = await $fetchRaw(request, options);
return r._data;
};
$fetch.raw = $fetchRaw;
$fetch.native = (...args) => fetch(...args);
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
...globalOptions,
...customGlobalOptions,
defaults: {
...globalOptions.defaults,
...customGlobalOptions.defaults,
...defaultOptions
}
});
return $fetch;
}
export { FetchError as F, createFetchError as a, createFetch as c };