opusdev/vector-similarity-api
1
1import platform from "../platform/index.js";2import utils from "../utils.js";3import AxiosError from "../core/AxiosError.js";4import composeSignals from "../helpers/composeSignals.js";5import {trackStream} from "../helpers/trackStream.js";6import AxiosHeaders from "../core/AxiosHeaders.js";7import {progressEventReducer, progressEventDecorator, asyncDecorator} from "../helpers/progressEventReducer.js";8import resolveConfig from "../helpers/resolveConfig.js";9import settle from "../core/settle.js";10 11const DEFAULT_CHUNK_SIZE = 64 * 1024;12 13const {isFunction} = utils;14 15const globalFetchAPI = (({Request, Response}) => ({16 Request, Response17}))(utils.global);18 19const {20 ReadableStream, TextEncoder21} = utils.global;22 23 24const test = (fn, ...args) => {25 try {26 return !!fn(...args);27 } catch (e) {28 return false29 }30}31 32const factory = (env) => {33 env = utils.merge.call({34 skipUndefined: true35 }, globalFetchAPI, env);36 37 const {fetch: envFetch, Request, Response} = env;38 const isFetchSupported = envFetch ? isFunction(envFetch) : typeof fetch === 'function';39 const isRequestSupported = isFunction(Request);40 const isResponseSupported = isFunction(Response);41 42 if (!isFetchSupported) {43 return false;44 }45 46 const isReadableStreamSupported = isFetchSupported && isFunction(ReadableStream);47 48 const encodeText = isFetchSupported && (typeof TextEncoder === 'function' ?49 ((encoder) => (str) => encoder.encode(str))(new TextEncoder()) :50 async (str) => new Uint8Array(await new Request(str).arrayBuffer())51 );52 53 const supportsRequestStream = isRequestSupported && isReadableStreamSupported && test(() => {54 let duplexAccessed = false;55 56 const hasContentType = new Request(platform.origin, {57 body: new ReadableStream(),58 method: 'POST',59 get duplex() {60 duplexAccessed = true;61 return 'half';62 },63 }).headers.has('Content-Type');64 65 return duplexAccessed && !hasContentType;66 });67 68 const supportsResponseStream = isResponseSupported && isReadableStreamSupported &&69 test(() => utils.isReadableStream(new Response('').body));70 71 const resolvers = {72 stream: supportsResponseStream && ((res) => res.body)73 };74 75 isFetchSupported && ((() => {76 ['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach(type => {77 !resolvers[type] && (resolvers[type] = (res, config) => {78 let method = res && res[type];79 80 if (method) {81 return method.call(res);82 }83 84 throw new AxiosError(`Response type '${type}' is not supported`, AxiosError.ERR_NOT_SUPPORT, config);85 })86 });87 })());88 89 const getBodyLength = async (body) => {90 if (body == null) {91 return 0;92 }93 94 if (utils.isBlob(body)) {95 return body.size;96 }97 98 if (utils.isSpecCompliantForm(body)) {99 const _request = new Request(platform.origin, {100 method: 'POST',101 body,102 });103 return (await _request.arrayBuffer()).byteLength;104 }105 106 if (utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) {107 return body.byteLength;108 }109 110 if (utils.isURLSearchParams(body)) {111 body = body + '';112 }113 114 if (utils.isString(body)) {115 return (await encodeText(body)).byteLength;116 }117 }118 119 const resolveBodyLength = async (headers, body) => {120 const length = utils.toFiniteNumber(headers.getContentLength());121 122 return length == null ? getBodyLength(body) : length;123 }124 125 return async (config) => {126 let {127 url,128 method,129 data,130 signal,131 cancelToken,132 timeout,133 onDownloadProgress,134 onUploadProgress,135 responseType,136 headers,137 withCredentials = 'same-origin',138 fetchOptions139 } = resolveConfig(config);140 141 let _fetch = envFetch || fetch;142 143 responseType = responseType ? (responseType + '').toLowerCase() : 'text';144 145 let composedSignal = composeSignals([signal, cancelToken && cancelToken.toAbortSignal()], timeout);146 147 let request = null;148 149 const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => {150 composedSignal.unsubscribe();151 });152 153 let requestContentLength;154 155 try {156 if (157 onUploadProgress && supportsRequestStream && method !== 'get' && method !== 'head' &&158 (requestContentLength = await resolveBodyLength(headers, data)) !== 0159 ) {160 let _request = new Request(url, {161 method: 'POST',162 body: data,163 duplex: "half"164 });165 166 let contentTypeHeader;167 168 if (utils.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {169 headers.setContentType(contentTypeHeader)170 }171 172 if (_request.body) {173 const [onProgress, flush] = progressEventDecorator(174 requestContentLength,175 progressEventReducer(asyncDecorator(onUploadProgress))176 );177 178 data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);179 }180 }181 182 if (!utils.isString(withCredentials)) {183 withCredentials = withCredentials ? 'include' : 'omit';184 }185 186 // Cloudflare Workers throws when credentials are defined187 // see https://github.com/cloudflare/workerd/issues/902188 const isCredentialsSupported = isRequestSupported && "credentials" in Request.prototype;189 190 const resolvedOptions = {191 ...fetchOptions,192 signal: composedSignal,193 method: method.toUpperCase(),194 headers: headers.normalize().toJSON(),195 body: data,196 duplex: "half",197 credentials: isCredentialsSupported ? withCredentials : undefined198 };199 200 request = isRequestSupported && new Request(url, resolvedOptions);201 202 let response = await (isRequestSupported ? _fetch(request, fetchOptions) : _fetch(url, resolvedOptions));203 204 const isStreamResponse = supportsResponseStream && (responseType === 'stream' || responseType === 'response');205 206 if (supportsResponseStream && (onDownloadProgress || (isStreamResponse && unsubscribe))) {207 const options = {};208 209 ['status', 'statusText', 'headers'].forEach(prop => {210 options[prop] = response[prop];211 });212 213 const responseContentLength = utils.toFiniteNumber(response.headers.get('content-length'));214 215 const [onProgress, flush] = onDownloadProgress && progressEventDecorator(216 responseContentLength,217 progressEventReducer(asyncDecorator(onDownloadProgress), true)218 ) || [];219 220 response = new Response(221 trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {222 flush && flush();223 unsubscribe && unsubscribe();224 }),225 options226 );227 }228 229 responseType = responseType || 'text';230 231 let responseData = await resolvers[utils.findKey(resolvers, responseType) || 'text'](response, config);232 233 !isStreamResponse && unsubscribe && unsubscribe();234 235 return await new Promise((resolve, reject) => {236 settle(resolve, reject, {237 data: responseData,238 headers: AxiosHeaders.from(response.headers),239 status: response.status,240 statusText: response.statusText,241 config,242 request243 })244 })245 } catch (err) {246 unsubscribe && unsubscribe();247 248 if (err && err.name === 'TypeError' && /Load failed|fetch/i.test(err.message)) {249 throw Object.assign(250 new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request, err && err.response),251 {252 cause: err.cause || err253 }254 )255 }256 257 throw AxiosError.from(err, err && err.code, config, request, err && err.response);258 }259 }260}261 262const seedCache = new Map();263 264export const getFetch = (config) => {265 let env = (config && config.env) || {};266 const {fetch, Request, Response} = env;267 const seeds = [268 Request, Response, fetch269 ];270 271 let len = seeds.length, i = len,272 seed, target, map = seedCache;273 274 while (i--) {275 seed = seeds[i];276 target = map.get(seed);277 278 target === undefined && map.set(seed, target = (i ? new Map() : factory(env)))279 280 map = target;281 }282 283 return target;284};285 286const adapter = getFetch();287 288export default adapter;289 