Add semantic token highlighting for 'that' variable and comment file references in VS Code extension Add Phone_Text_Input and Currency_Input components with formatting utilities Implement client widgets, form standardization, and soft delete functionality Add modal scroll lock and update documentation Implement comprehensive modal system with form integration and validation Fix modal component instantiation using jQuery plugin API Implement modal system with responsive sizing, queuing, and validation support Implement form submission with validation, error handling, and loading states Implement country/state selectors with dynamic data loading and Bootstrap styling Revert Rsx::Route() highlighting in Blade/PHP files Target specific PHP scopes for Rsx::Route() highlighting in Blade Expand injection selector for Rsx::Route() highlighting Add custom syntax highlighting for Rsx::Route() and Rsx.Route() calls Update jqhtml packages to v2.2.165 Add bundle path validation for common mistakes (development mode only) Create Ajax_Select_Input widget and Rsx_Reference_Data controller Create Country_Select_Input widget with default country support Initialize Tom Select on Select_Input widgets Add Tom Select bundle for enhanced select dropdowns Implement ISO 3166 geographic data system for country/region selection Implement widget-based form system with disabled state support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
289 lines
8.0 KiB
JavaScript
289 lines
8.0 KiB
JavaScript
import platform from "../platform/index.js";
|
|
import utils from "../utils.js";
|
|
import AxiosError from "../core/AxiosError.js";
|
|
import composeSignals from "../helpers/composeSignals.js";
|
|
import {trackStream} from "../helpers/trackStream.js";
|
|
import AxiosHeaders from "../core/AxiosHeaders.js";
|
|
import {progressEventReducer, progressEventDecorator, asyncDecorator} from "../helpers/progressEventReducer.js";
|
|
import resolveConfig from "../helpers/resolveConfig.js";
|
|
import settle from "../core/settle.js";
|
|
|
|
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
|
|
const {isFunction} = utils;
|
|
|
|
const globalFetchAPI = (({Request, Response}) => ({
|
|
Request, Response
|
|
}))(utils.global);
|
|
|
|
const {
|
|
ReadableStream, TextEncoder
|
|
} = utils.global;
|
|
|
|
|
|
const test = (fn, ...args) => {
|
|
try {
|
|
return !!fn(...args);
|
|
} catch (e) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
const factory = (env) => {
|
|
env = utils.merge.call({
|
|
skipUndefined: true
|
|
}, globalFetchAPI, env);
|
|
|
|
const {fetch: envFetch, Request, Response} = env;
|
|
const isFetchSupported = envFetch ? isFunction(envFetch) : typeof fetch === 'function';
|
|
const isRequestSupported = isFunction(Request);
|
|
const isResponseSupported = isFunction(Response);
|
|
|
|
if (!isFetchSupported) {
|
|
return false;
|
|
}
|
|
|
|
const isReadableStreamSupported = isFetchSupported && isFunction(ReadableStream);
|
|
|
|
const encodeText = isFetchSupported && (typeof TextEncoder === 'function' ?
|
|
((encoder) => (str) => encoder.encode(str))(new TextEncoder()) :
|
|
async (str) => new Uint8Array(await new Request(str).arrayBuffer())
|
|
);
|
|
|
|
const supportsRequestStream = isRequestSupported && isReadableStreamSupported && test(() => {
|
|
let duplexAccessed = false;
|
|
|
|
const hasContentType = new Request(platform.origin, {
|
|
body: new ReadableStream(),
|
|
method: 'POST',
|
|
get duplex() {
|
|
duplexAccessed = true;
|
|
return 'half';
|
|
},
|
|
}).headers.has('Content-Type');
|
|
|
|
return duplexAccessed && !hasContentType;
|
|
});
|
|
|
|
const supportsResponseStream = isResponseSupported && isReadableStreamSupported &&
|
|
test(() => utils.isReadableStream(new Response('').body));
|
|
|
|
const resolvers = {
|
|
stream: supportsResponseStream && ((res) => res.body)
|
|
};
|
|
|
|
isFetchSupported && ((() => {
|
|
['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach(type => {
|
|
!resolvers[type] && (resolvers[type] = (res, config) => {
|
|
let method = res && res[type];
|
|
|
|
if (method) {
|
|
return method.call(res);
|
|
}
|
|
|
|
throw new AxiosError(`Response type '${type}' is not supported`, AxiosError.ERR_NOT_SUPPORT, config);
|
|
})
|
|
});
|
|
})());
|
|
|
|
const getBodyLength = async (body) => {
|
|
if (body == null) {
|
|
return 0;
|
|
}
|
|
|
|
if (utils.isBlob(body)) {
|
|
return body.size;
|
|
}
|
|
|
|
if (utils.isSpecCompliantForm(body)) {
|
|
const _request = new Request(platform.origin, {
|
|
method: 'POST',
|
|
body,
|
|
});
|
|
return (await _request.arrayBuffer()).byteLength;
|
|
}
|
|
|
|
if (utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) {
|
|
return body.byteLength;
|
|
}
|
|
|
|
if (utils.isURLSearchParams(body)) {
|
|
body = body + '';
|
|
}
|
|
|
|
if (utils.isString(body)) {
|
|
return (await encodeText(body)).byteLength;
|
|
}
|
|
}
|
|
|
|
const resolveBodyLength = async (headers, body) => {
|
|
const length = utils.toFiniteNumber(headers.getContentLength());
|
|
|
|
return length == null ? getBodyLength(body) : length;
|
|
}
|
|
|
|
return async (config) => {
|
|
let {
|
|
url,
|
|
method,
|
|
data,
|
|
signal,
|
|
cancelToken,
|
|
timeout,
|
|
onDownloadProgress,
|
|
onUploadProgress,
|
|
responseType,
|
|
headers,
|
|
withCredentials = 'same-origin',
|
|
fetchOptions
|
|
} = resolveConfig(config);
|
|
|
|
let _fetch = envFetch || fetch;
|
|
|
|
responseType = responseType ? (responseType + '').toLowerCase() : 'text';
|
|
|
|
let composedSignal = composeSignals([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
|
|
|
|
let request = null;
|
|
|
|
const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => {
|
|
composedSignal.unsubscribe();
|
|
});
|
|
|
|
let requestContentLength;
|
|
|
|
try {
|
|
if (
|
|
onUploadProgress && supportsRequestStream && method !== 'get' && method !== 'head' &&
|
|
(requestContentLength = await resolveBodyLength(headers, data)) !== 0
|
|
) {
|
|
let _request = new Request(url, {
|
|
method: 'POST',
|
|
body: data,
|
|
duplex: "half"
|
|
});
|
|
|
|
let contentTypeHeader;
|
|
|
|
if (utils.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {
|
|
headers.setContentType(contentTypeHeader)
|
|
}
|
|
|
|
if (_request.body) {
|
|
const [onProgress, flush] = progressEventDecorator(
|
|
requestContentLength,
|
|
progressEventReducer(asyncDecorator(onUploadProgress))
|
|
);
|
|
|
|
data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
|
|
}
|
|
}
|
|
|
|
if (!utils.isString(withCredentials)) {
|
|
withCredentials = withCredentials ? 'include' : 'omit';
|
|
}
|
|
|
|
// Cloudflare Workers throws when credentials are defined
|
|
// see https://github.com/cloudflare/workerd/issues/902
|
|
const isCredentialsSupported = isRequestSupported && "credentials" in Request.prototype;
|
|
|
|
const resolvedOptions = {
|
|
...fetchOptions,
|
|
signal: composedSignal,
|
|
method: method.toUpperCase(),
|
|
headers: headers.normalize().toJSON(),
|
|
body: data,
|
|
duplex: "half",
|
|
credentials: isCredentialsSupported ? withCredentials : undefined
|
|
};
|
|
|
|
request = isRequestSupported && new Request(url, resolvedOptions);
|
|
|
|
let response = await (isRequestSupported ? _fetch(request, fetchOptions) : _fetch(url, resolvedOptions));
|
|
|
|
const isStreamResponse = supportsResponseStream && (responseType === 'stream' || responseType === 'response');
|
|
|
|
if (supportsResponseStream && (onDownloadProgress || (isStreamResponse && unsubscribe))) {
|
|
const options = {};
|
|
|
|
['status', 'statusText', 'headers'].forEach(prop => {
|
|
options[prop] = response[prop];
|
|
});
|
|
|
|
const responseContentLength = utils.toFiniteNumber(response.headers.get('content-length'));
|
|
|
|
const [onProgress, flush] = onDownloadProgress && progressEventDecorator(
|
|
responseContentLength,
|
|
progressEventReducer(asyncDecorator(onDownloadProgress), true)
|
|
) || [];
|
|
|
|
response = new Response(
|
|
trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
|
|
flush && flush();
|
|
unsubscribe && unsubscribe();
|
|
}),
|
|
options
|
|
);
|
|
}
|
|
|
|
responseType = responseType || 'text';
|
|
|
|
let responseData = await resolvers[utils.findKey(resolvers, responseType) || 'text'](response, config);
|
|
|
|
!isStreamResponse && unsubscribe && unsubscribe();
|
|
|
|
return await new Promise((resolve, reject) => {
|
|
settle(resolve, reject, {
|
|
data: responseData,
|
|
headers: AxiosHeaders.from(response.headers),
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
config,
|
|
request
|
|
})
|
|
})
|
|
} catch (err) {
|
|
unsubscribe && unsubscribe();
|
|
|
|
if (err && err.name === 'TypeError' && /Load failed|fetch/i.test(err.message)) {
|
|
throw Object.assign(
|
|
new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request),
|
|
{
|
|
cause: err.cause || err
|
|
}
|
|
)
|
|
}
|
|
|
|
throw AxiosError.from(err, err && err.code, config, request);
|
|
}
|
|
}
|
|
}
|
|
|
|
const seedCache = new Map();
|
|
|
|
export const getFetch = (config) => {
|
|
let env = (config && config.env) || {};
|
|
const {fetch, Request, Response} = env;
|
|
const seeds = [
|
|
Request, Response, fetch
|
|
];
|
|
|
|
let len = seeds.length, i = len,
|
|
seed, target, map = seedCache;
|
|
|
|
while (i--) {
|
|
seed = seeds[i];
|
|
target = map.get(seed);
|
|
|
|
target === undefined && map.set(seed, target = (i ? new Map() : factory(env)))
|
|
|
|
map = target;
|
|
}
|
|
|
|
return target;
|
|
};
|
|
|
|
const adapter = getFetch();
|
|
|
|
export default adapter;
|