@ant-design/x-sdk
Version:
placeholder for @ant-design/x-sdk
230 lines (228 loc) • 6.96 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.XRequestClass = exports.AbstractXRequestClass = void 0;
exports.setXRequestGlobalOptions = setXRequestGlobalOptions;
var _xStream = _interopRequireDefault(require("../x-stream"));
var _xFetch = _interopRequireDefault(require("./x-fetch"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @description Global options for the request
*/
const globalOptions = {
manual: false,
headers: {
'Content-Type': 'application/json'
}
};
/**
* Set global options for the request
* @param options XRequestGlobalOptions<Input, Output>
*/
function setXRequestGlobalOptions(options) {
Object.assign(globalOptions, options);
}
class AbstractXRequestClass {
baseURL;
options;
constructor(baseURL, options) {
if (!baseURL || typeof baseURL !== 'string') throw new Error('The baseURL is not valid!');
this.baseURL = baseURL;
this.options = options || {};
}
}
exports.AbstractXRequestClass = AbstractXRequestClass;
class XRequestClass extends AbstractXRequestClass {
_asyncHandler;
timeoutHandler;
_isTimeout = false;
streamTimeoutHandler;
_isStreamTimeout = false;
abortController;
_isRequesting = false;
_manual = false;
get asyncHandler() {
return this._asyncHandler;
}
get isTimeout() {
return this._isTimeout;
}
set isTimeout(value) {
this._isTimeout = value;
}
get isStreamTimeout() {
return this._isStreamTimeout;
}
set isStreamTimeout(value) {
this._isStreamTimeout = value;
}
get isRequesting() {
return this._isRequesting;
}
get manual() {
return this._manual;
}
constructor(baseURL, options) {
super(baseURL, options);
this._manual = options?.manual || false;
if (!this.manual) {
this.init();
}
}
run(params) {
if (this.manual) {
this.init(params);
} else {
console.warn('The request is not manual, so it cannot be run!');
}
}
abort() {
clearTimeout(this.timeoutHandler);
clearTimeout(this.streamTimeoutHandler);
this.abortController.abort();
}
init(extraParams) {
this.abortController = new AbortController();
const {
callbacks,
params,
headers = {},
transformStream,
fetch,
timeout,
streamTimeout,
middlewares,
...otherOptions
} = this.options;
const requestInit = {
...otherOptions,
method: 'POST',
body: JSON.stringify({
...params,
...(extraParams || {})
}),
params: {
...params,
...extraParams
},
headers: Object.assign({}, globalOptions.headers || {}, headers),
signal: this.abortController.signal,
middlewares
};
if (timeout && timeout > 0) {
this.timeoutHandler = window.setTimeout(() => {
this.isTimeout = true;
this.finishRequest();
callbacks?.onError?.(new Error('TimeoutError'));
}, timeout);
}
this.startRequest();
// save and export a async handler to wait for the request to be finished
// though it is not necessary, but it is useful for some scenarios
this._asyncHandler = (0, _xFetch.default)(this.baseURL, {
fetch,
...requestInit
}).then(async response => {
clearTimeout(this.timeoutHandler);
if (this.isTimeout) return;
if (transformStream) {
let transformer = transformStream;
if (typeof transformStream === 'function') {
transformer = transformStream(this.baseURL, response.headers);
}
await this.customResponseHandler(response, callbacks, transformer, streamTimeout);
return;
}
const contentType = response.headers.get('content-type') || '';
const mimeType = contentType.split(';')[0].trim();
switch (mimeType) {
/** SSE */
case 'text/event-stream':
await this.sseResponseHandler(response, callbacks, streamTimeout);
break;
/** JSON */
case 'application/json':
await this.jsonResponseHandler(response, callbacks);
break;
default:
throw new Error(`The response content-type: ${contentType} is not support!`);
}
}).catch(error => {
clearTimeout(this.timeoutHandler);
this.finishRequest();
// abort() throw a DOMException, so we need to check it
const err = error instanceof Error || error instanceof DOMException ? error : new Error('Unknown error!');
callbacks?.onError?.(err);
});
}
startRequest() {
this._isRequesting = true;
}
finishRequest() {
this._isRequesting = false;
}
customResponseHandler = async (response, callbacks, transformStream, streamTimeout) => {
const stream = (0, _xStream.default)({
readableStream: response.body,
transformStream
});
await this.processStream(stream, response, callbacks, streamTimeout);
};
sseResponseHandler = async (response, callbacks, streamTimeout) => {
const stream = (0, _xStream.default)({
readableStream: response.body
});
await this.processStream(stream, response, callbacks, streamTimeout);
};
async processStream(stream, response, callbacks, streamTimeout) {
const chunks = [];
const iterator = stream[Symbol.asyncIterator]();
let result;
do {
// if streamTimeout is set, start the stream timeout timer
// every time the stream is updated, reset the timer
if (streamTimeout) {
this.streamTimeoutHandler = window.setTimeout(() => {
this.isStreamTimeout = true;
this.finishRequest();
callbacks?.onError?.(new Error('StreamTimeoutError'));
}, streamTimeout);
}
result = await iterator.next();
chunks.push(result.value);
callbacks?.onUpdate?.(result.value, response.headers);
clearTimeout(this.streamTimeoutHandler);
if (this.isStreamTimeout) {
break;
}
} while (!result.done);
if (streamTimeout) {
clearTimeout(this.streamTimeoutHandler);
if (this.isStreamTimeout) {
this.finishRequest();
return;
}
}
this.finishRequest();
callbacks?.onSuccess?.(chunks, response.headers);
}
jsonResponseHandler = async (response, callbacks) => {
const chunk = await response.json();
if (chunk?.success === false) {
const error = new Error(chunk.message || 'System error');
error.name = chunk.name || 'SystemError';
callbacks?.onError?.(error);
} else {
callbacks?.onUpdate?.(chunk, response.headers);
this.finishRequest();
// keep type consistency with stream mode
callbacks?.onSuccess?.([chunk], response.headers);
}
};
}
exports.XRequestClass = XRequestClass;
function XRequest(baseURL, options) {
return new XRequestClass(baseURL, options);
}
var _default = exports.default = XRequest;