UNPKG

@wevu/web-apis

Version:

Web API polyfills and global installers for mini-program runtimes

183 lines (182 loc) 6.59 kB
import { f as isUrlInstance, l as normalizeHeaderName, n as cloneArrayBuffer, p as isUrlSearchParamsInstance, r as cloneArrayBufferView } from "./shared-BB491DgN.mjs"; import { HeadersPolyfill, ResponsePolyfill } from "./http.mjs"; import { resolveRequestMiniProgramOptions } from "./networkDefaults.mjs"; import { wpi } from "@wevu/api"; //#region src/fetch.ts const REQUEST_METHODS = [ "GET", "HEAD", "OPTIONS", "POST", "PUT", "DELETE", "TRACE", "CONNECT" ]; const hasOwn = Object.prototype.hasOwnProperty; function isObject(value) { return typeof value === "object" && value !== null; } function createAbortError() { if (typeof DOMException === "function") return new DOMException("The operation was aborted.", "AbortError"); const error = /* @__PURE__ */ new Error("The operation was aborted."); error.name = "AbortError"; return error; } function normalizeMethod(method) { const normalized = (method ?? "GET").toUpperCase(); if (REQUEST_METHODS.includes(normalized)) return normalized; return "GET"; } function setHeader(target, key, value) { const normalizedKey = normalizeHeaderName(key); if (!normalizedKey) return; const nextValue = String(value); for (const currentKey of Object.keys(target)) if (normalizeHeaderName(currentKey) === normalizedKey) delete target[currentKey]; target[key] = nextValue; } function hasHeader(target, key) { const normalizedKey = normalizeHeaderName(key); return Object.keys(target).some((currentKey) => normalizeHeaderName(currentKey) === normalizedKey); } function mergeHeaderSource(target, source) { if (!source) return; if (typeof source.forEach === "function") { source.forEach((value, key) => { setHeader(target, key, value); }); return; } if (typeof source[Symbol.iterator] === "function") { for (const entry of source) { if (!entry || entry.length < 2) continue; setHeader(target, entry[0], entry[1]); } return; } if (!isObject(source)) return; for (const [key, value] of Object.entries(source)) { if (Array.isArray(value)) { setHeader(target, key, value.join(", ")); continue; } setHeader(target, key, value); } } function toHeaderMap(source) { const headers = {}; mergeHeaderSource(headers, source); return headers; } function isRequestLikeInput(input) { return isObject(input) && typeof input.url === "string"; } async function extractRequestBodyFromInput(input) { if (!input || typeof input.clone !== "function") return; if (input.bodyUsed) throw new TypeError("Failed to execute fetch: request body is already used"); const cloned = input.clone(); if (cloned?.arrayBuffer) return cloned.arrayBuffer(); if (cloned?.text) return cloned.text(); } async function normalizeRequestBody(body, headers) { if (body == null) return; if (typeof body === "string") { if (!hasHeader(headers, "content-type")) headers["content-type"] = "text/plain;charset=UTF-8"; return body; } if (isUrlSearchParamsInstance(body)) { if (!hasHeader(headers, "content-type")) headers["content-type"] = "application/x-www-form-urlencoded;charset=UTF-8"; return body.toString(); } if (body instanceof ArrayBuffer) return cloneArrayBuffer(body); if (ArrayBuffer.isView(body)) return cloneArrayBufferView(body); if (typeof Blob !== "undefined" && body instanceof Blob) { if (body.type && !hasHeader(headers, "content-type")) headers["content-type"] = body.type; return body.arrayBuffer(); } if (typeof FormData !== "undefined" && body instanceof FormData) throw new TypeError("Failed to execute fetch: FormData body is not supported in request globals fetch"); return String(body); } async function resolveRequestMeta(input, init = {}) { const requestInput = isRequestLikeInput(input) ? input : void 0; const url = typeof input === "string" ? input : isUrlInstance(input) ? input.toString() : requestInput?.url; if (!url) throw new TypeError("Failed to execute fetch: invalid request url"); const method = normalizeMethod(init.method ?? requestInput?.method); const headers = toHeaderMap(requestInput?.headers); mergeHeaderSource(headers, init.headers); const hasBodyInInit = hasOwn.call(init, "body"); let rawBody = hasBodyInInit ? init.body : await extractRequestBodyFromInput(requestInput); if (!hasBodyInInit && requestInput && (method === "GET" || method === "HEAD")) rawBody = void 0; if ((method === "GET" || method === "HEAD") && rawBody != null) throw new TypeError("Failed to execute fetch: GET/HEAD request cannot have body"); return { miniProgram: resolveRequestMiniProgramOptions(init.miniProgram, init.miniprogram), url, method, headers, body: await normalizeRequestBody(rawBody, headers), signal: init.signal ?? requestInput?.signal ?? null }; } function createFetchResponse(data, status, headers, url) { return new ResponsePolyfill(data instanceof Uint8Array ? cloneArrayBufferView(data) : data, { status, headers: new HeadersPolyfill(headers), url }); } function isRequestTask(value) { return isObject(value) && typeof value.abort === "function"; } /** * @description 使用 @wevu/api 的 request 能力实现 fetch 语义对齐。 */ function fetch(input, init) { return resolveRequestMeta(input, init).then((meta) => { if (meta.signal?.aborted) return Promise.reject(createAbortError()); return new Promise((resolve, reject) => { let settled = false; let aborted = false; let requestTask; function onAbort() { if (settled) return; aborted = true; requestTask?.abort(); settled = true; if (meta.signal) meta.signal.removeEventListener("abort", onAbort); reject(createAbortError()); } function cleanup() { if (meta.signal) meta.signal.removeEventListener("abort", onAbort); } if (meta.signal) meta.signal.addEventListener("abort", onAbort, { once: true }); const requestResult = wpi.request({ ...meta.miniProgram, url: meta.url, method: meta.method, header: meta.headers, data: meta.body, responseType: "arraybuffer", success: (res) => { if (settled) return; settled = true; cleanup(); resolve(createFetchResponse(res.data, res.statusCode, toHeaderMap(res.header), meta.url)); }, fail: (error) => { if (settled) return; settled = true; cleanup(); if (aborted) { reject(createAbortError()); return; } const message = isObject(error) && typeof error.errMsg === "string" ? error.errMsg : String(error); reject(new TypeError(message)); } }); requestTask = isRequestTask(requestResult) ? requestResult : void 0; }); }); } //#endregion export { fetch };