@hyper-fetch/core
Version:
Cache, Queue and Persist your requests no matter if you are online or offline!
1,301 lines (1,283 loc) • 95.2 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/index.ts
var src_exports = {};
__export(src_exports, {
AppEvents: () => AppEvents,
AppManager: () => AppManager,
Cache: () => Cache,
Client: () => Client,
DateInterval: () => DateInterval,
Dispatcher: () => Dispatcher,
DispatcherRequestType: () => DispatcherRequestType,
HttpMethodsEnum: () => HttpMethodsEnum,
LoggerManager: () => LoggerManager,
Request: () => Request,
RequestEffect: () => RequestEffect,
RequestManager: () => RequestManager,
adapter: () => adapter3,
appManagerInitialOptions: () => appManagerInitialOptions,
canRetryRequest: () => canRetryRequest,
defaultTimeout: () => defaultTimeout,
getAbortByIdEventKey: () => getAbortByIdEventKey,
getAbortEventKey: () => getAbortEventKey,
getAdapterBindings: () => getAdapterBindings,
getAdapterHeaders: () => getAdapterHeaders,
getAdapterPayload: () => getAdapterPayload,
getAppManagerEvents: () => getAppManagerEvents,
getCacheData: () => getCacheData,
getCacheEvents: () => getCacheEvents,
getCacheIdKey: () => getCacheIdKey,
getCacheKey: () => getCacheKey,
getDispatcherChangeEventKey: () => getDispatcherChangeEventKey,
getDispatcherDrainedEventKey: () => getDispatcherDrainedEventKey,
getDispatcherEvents: () => getDispatcherEvents,
getDispatcherStatusEventKey: () => getDispatcherStatusEventKey,
getDownloadProgressEventKey: () => getDownloadProgressEventKey,
getDownloadProgressIdEventKey: () => getDownloadProgressIdEventKey,
getErrorMessage: () => getErrorMessage,
getInvalidateEventKey: () => getInvalidateEventKey,
getIsEqualTimestamp: () => getIsEqualTimestamp,
getLoadingEventKey: () => getLoadingEventKey,
getLoadingIdEventKey: () => getLoadingIdEventKey,
getProgressData: () => getProgressData,
getProgressValue: () => getProgressValue,
getRemoveEventKey: () => getRemoveEventKey,
getRemoveIdEventKey: () => getRemoveIdEventKey,
getRequestDispatcher: () => getRequestDispatcher,
getRequestEta: () => getRequestEta,
getRequestKey: () => getRequestKey,
getRequestManagerEvents: () => getRequestManagerEvents,
getRequestStartEventKey: () => getRequestStartEventKey,
getRequestStartIdEventKey: () => getRequestStartIdEventKey,
getRequestType: () => getRequestType,
getResponseEventKey: () => getResponseEventKey,
getResponseHeaders: () => getResponseHeaders,
getResponseIdEventKey: () => getResponseIdEventKey,
getResponseStartEventKey: () => getResponseStartEventKey,
getResponseStartIdEventKey: () => getResponseStartIdEventKey,
getSimpleKey: () => getSimpleKey,
getTime: () => getTime,
getUniqueRequestId: () => getUniqueRequestId,
getUploadProgressEventKey: () => getUploadProgressEventKey,
getUploadProgressIdEventKey: () => getUploadProgressIdEventKey,
hasDocument: () => hasDocument,
hasWindow: () => hasWindow,
interceptRequest: () => interceptRequest,
interceptResponse: () => interceptResponse,
logger: () => logger,
loggerIconLevels: () => loggerIconLevels,
loggerStyles: () => loggerStyles,
mocker: () => mocker,
onDocumentEvent: () => onDocumentEvent,
onWindowEvent: () => onWindowEvent,
parseErrorResponse: () => parseErrorResponse,
parseResponse: () => parseResponse,
sendRequest: () => sendRequest,
severity: () => severity,
stringifyDefaultOptions: () => stringifyDefaultOptions,
stringifyKey: () => stringifyKey,
stringifyQueryParams: () => stringifyQueryParams,
stringifyValue: () => stringifyValue,
xhrExtra: () => xhrExtra
});
module.exports = __toCommonJS(src_exports);
// src/effect/request.effect.ts
var RequestEffect = class {
constructor(config) {
this.config = config;
this.getEffectKey = () => {
return this.config.effectKey;
};
this.onTrigger = (request) => {
var _a, _b;
(_b = (_a = this.config).onTrigger) == null ? void 0 : _b.call(_a, request);
};
this.onStart = (request) => {
var _a, _b;
(_b = (_a = this.config).onStart) == null ? void 0 : _b.call(_a, request);
};
this.onSuccess = (response, request) => {
var _a, _b;
(_b = (_a = this.config).onSuccess) == null ? void 0 : _b.call(_a, response, request);
};
this.onError = (response, request) => {
var _a, _b;
(_b = (_a = this.config).onError) == null ? void 0 : _b.call(_a, response, request);
};
this.onFinished = (response, request) => {
var _a, _b;
(_b = (_a = this.config).onFinished) == null ? void 0 : _b.call(_a, response, request);
};
}
};
// src/constants/time.constants.ts
var DateInterval = /* @__PURE__ */ ((DateInterval2) => {
DateInterval2[DateInterval2["second"] = 1e3] = "second";
DateInterval2[DateInterval2["minute"] = 6e4] = "minute";
DateInterval2[DateInterval2["hour"] = 36e5] = "hour";
DateInterval2[DateInterval2["day"] = 864e5] = "day";
DateInterval2[DateInterval2["week"] = 6048e5] = "week";
DateInterval2[DateInterval2["month30"] = 2592e6] = "month30";
DateInterval2[DateInterval2["month31"] = 26784e5] = "month31";
DateInterval2[DateInterval2["year"] = 31536e6] = "year";
DateInterval2[DateInterval2["yearLeap"] = 316224e5] = "yearLeap";
return DateInterval2;
})(DateInterval || {});
// src/adapter/adapter.constants.ts
var defaultTimeout = 1e3 /* second */ * 5;
var xhrExtra = {
headers: {}
};
// src/adapter/adapter.browser.ts
var adapter = (request, requestId) => __async(void 0, null, function* () {
const {
makeRequest,
fullUrl,
config,
payload,
headers,
onError,
onResponseEnd,
onTimeoutError,
onRequestEnd,
createAbortListener,
onResponseProgress,
onRequestProgress,
onResponseStart,
onBeforeRequest,
onRequestStart,
onSuccess
} = yield getAdapterBindings(request, requestId, 0, {
headers: {}
});
const { method = "GET" } = request;
return makeRequest((resolve) => {
const xhr = new XMLHttpRequest();
xhr.timeout = defaultTimeout;
const abort = () => xhr.abort();
Object.entries(config).forEach(([name, value]) => {
xhr[name] = value;
});
xhr.open(method, fullUrl, true);
Object.entries(headers).forEach(([name, value]) => xhr.setRequestHeader(name, value));
const unmountListener = createAbortListener(0, xhrExtra, abort, resolve);
xhr.upload.onprogress = onRequestProgress;
xhr.onloadstart = () => {
onRequestEnd();
onResponseStart();
};
xhr.onprogress = onResponseProgress;
xhr.onloadend = () => {
onResponseEnd();
unmountListener();
};
xhr.ontimeout = () => onTimeoutError(0, xhrExtra, resolve);
xhr.onreadystatechange = (e) => {
const event = e;
const finishedState = 4;
if (event.target && event.target.readyState === finishedState) {
const { status } = event.target;
const success = String(status).startsWith("2") || String(status).startsWith("3");
const responseHeaders = getResponseHeaders(xhr.getAllResponseHeaders());
if (success) {
const data = parseResponse(event.target.response);
onSuccess(data, status, { headers: responseHeaders }, resolve);
} else {
const data = parseErrorResponse(event.target.response);
onError(data, status, { headers: responseHeaders }, resolve);
}
}
};
onBeforeRequest();
onRequestStart();
xhr.send(payload);
});
});
// src/adapter/adapter.server.ts
var import_http = __toESM(require("http"));
var import_https = __toESM(require("https"));
// src/constants/http.constants.ts
var HttpMethodsEnum = /* @__PURE__ */ ((HttpMethodsEnum2) => {
HttpMethodsEnum2["get"] = "GET";
HttpMethodsEnum2["post"] = "POST";
HttpMethodsEnum2["put"] = "PUT";
HttpMethodsEnum2["patch"] = "PATCH";
HttpMethodsEnum2["delete"] = "DELETE";
return HttpMethodsEnum2;
})(HttpMethodsEnum || {});
// src/adapter/adapter.server.ts
var adapter2 = (request, requestId) => __async(void 0, null, function* () {
const {
makeRequest,
fullUrl,
config,
headers,
payload,
onError,
onResponseEnd,
onTimeoutError,
onRequestEnd,
createAbortListener,
onResponseProgress,
onResponseStart,
onBeforeRequest,
onRequestStart,
onSuccess
} = yield getAdapterBindings(request, requestId, 0, xhrExtra);
const { method = "GET" /* get */, client } = request;
const httpClient = client.url.includes("https://") ? import_https.default : import_http.default;
const options = {
method,
headers,
timeout: defaultTimeout
};
Object.entries(config).forEach(([name, value]) => {
options[name] = value;
});
let unmountListener = () => null;
onBeforeRequest();
if (payload) {
options.headers["Content-Length"] = Buffer.byteLength(JSON.stringify(payload));
}
const requestUrl = !fullUrl.startsWith("http") ? `http://${fullUrl}` : fullUrl;
return makeRequest((resolve) => {
const httpRequest = httpClient.request(requestUrl, options, (response) => {
response.setEncoding("utf8");
unmountListener = createAbortListener(0, xhrExtra, response.destroy, resolve);
let chunks = "";
const totalDownloadBytes = Number(response.headers["content-length"]);
let downloadedBytes = 0;
onRequestStart();
response.on("data", (chunk) => {
if (!chunks) {
onRequestEnd();
onResponseStart();
}
downloadedBytes += chunk.length;
chunks += chunk;
onResponseProgress({ total: totalDownloadBytes, loaded: downloadedBytes });
});
response.on("end", () => {
const { statusCode } = response;
const success = String(statusCode).startsWith("2") || String(statusCode).startsWith("3");
if (success) {
const data = parseResponse(chunks);
onSuccess(data, statusCode, { headers: response.headers }, resolve);
} else {
const data = parseErrorResponse(chunks);
onError(data, statusCode, { headers: response.headers }, resolve);
}
unmountListener();
onResponseEnd();
});
});
httpRequest.on("timeout", () => onTimeoutError(0, xhrExtra, resolve));
httpRequest.on("error", (error) => onError(error, 0, xhrExtra, resolve));
if (payload) {
httpRequest.write(payload);
}
httpRequest.end();
});
});
// src/adapter/adapter.ts
var adapter3 = (request, requestId) => __async(void 0, null, function* () {
if (typeof XMLHttpRequest !== "undefined") {
return adapter(request, requestId);
}
return adapter2(request, requestId);
});
// src/adapter/adapter.utils.ts
var getErrorMessage = (errorCase) => {
if (errorCase === "timeout") {
return new Error("Request timeout");
}
if (errorCase === "abort") {
return new Error("Request cancelled");
}
return new Error("Unexpected error");
};
var getResponseHeaders = (headersString) => {
const arr = headersString.trim().split(/[\r\n]+/);
const headers = {};
arr.forEach((line) => {
const parts = line.split(": ");
const header = parts.shift();
const value = parts.join(": ");
headers[header] = value;
});
return headers;
};
var parseResponse = (response) => {
try {
return JSON.parse(response);
} catch (err) {
return response;
}
};
var parseErrorResponse = (response) => {
return response ? parseResponse(response) : getErrorMessage();
};
// src/utils/uuid.utils.ts
var getUniqueRequestId = (key) => {
return `${key}_${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`;
};
// src/request/request.ts
var Request = class {
constructor(client, requestOptions, requestJSON) {
this.client = client;
this.requestOptions = requestOptions;
this.requestJSON = requestJSON;
this.isMockEnabled = false;
this.setHeaders = (headers) => {
return this.clone({ headers });
};
this.setAuth = (auth) => {
return this.clone({ auth });
};
this.setParams = (params) => {
return this.clone({ params });
};
this.setData = (data) => {
return this.clone({
data
});
};
this.setQueryParams = (queryParams) => {
return this.clone({ queryParams });
};
this.setOptions = (options) => {
return this.clone({ options });
};
this.setCancelable = (cancelable) => {
return this.clone({ cancelable });
};
this.setRetry = (retry) => {
return this.clone({ retry });
};
this.setRetryTime = (retryTime) => {
return this.clone({ retryTime });
};
this.setGarbageCollection = (garbageCollection) => {
return this.clone({ garbageCollection });
};
this.setCache = (cache) => {
return this.clone({ cache });
};
this.setCacheTime = (cacheTime) => {
return this.clone({ cacheTime });
};
this.setQueued = (queued) => {
return this.clone({ queued });
};
this.setAbortKey = (abortKey) => {
this.updatedAbortKey = true;
return this.clone({ abortKey });
};
this.setCacheKey = (cacheKey) => {
this.updatedCacheKey = true;
return this.clone({ cacheKey });
};
this.setQueueKey = (queueKey) => {
this.updatedQueueKey = true;
return this.clone({ queueKey });
};
this.setEffectKey = (effectKey) => {
this.updatedEffectKey = true;
return this.clone({ effectKey });
};
this.setDeduplicate = (deduplicate) => {
return this.clone({ deduplicate });
};
this.setDeduplicateTime = (deduplicateTime) => {
return this.clone({ deduplicateTime });
};
this.setUsed = (used) => {
return this.clone({ used });
};
this.setOffline = (offline) => {
return this.clone({ offline });
};
this.setMock = (mockData) => {
const mockGenerator = function* mocked(mockedValues) {
if (Array.isArray(mockData)) {
let iteration = 0;
while (true) {
yield mockedValues[iteration];
iteration = mockData.length === iteration + 1 ? 0 : iteration + 1;
}
} else {
while (true) {
yield mockData;
}
}
};
this.mockData = mockData;
this.mock = mockGenerator(mockData);
this.isMockEnabled = true;
return this;
};
this.removeMock = () => {
this.mockData = null;
this.mock = null;
this.isMockEnabled = false;
return this;
};
this.setEnableMocking = (isMockEnabled) => {
this.isMockEnabled = isMockEnabled;
return this;
};
this.setDataMapper = (dataMapper) => {
const cloned = this.clone(void 0);
cloned.dataMapper = dataMapper;
return cloned;
};
this.setRequestMapper = (requestMapper) => {
const cloned = this.clone(void 0);
cloned.requestMapper = requestMapper;
return cloned;
};
this.setResponseMapper = (responseMapper) => {
const cloned = this.clone();
cloned.responseMapper = responseMapper;
return cloned;
};
this.paramsMapper = (params, queryParams) => {
let endpoint = this.requestOptions.endpoint;
if (params) {
Object.entries(params).forEach(([key, value]) => {
endpoint = endpoint.replace(new RegExp(`:${key}`, "g"), String(value));
});
}
if (queryParams) {
endpoint += this.client.stringifyQueryParams(queryParams);
}
return endpoint;
};
this.abort = () => {
const { requestManager } = this.client;
requestManager.abortByKey(this.abortKey);
return this.clone();
};
this.exec = (options) => __async(this, null, function* () {
const { adapter: adapter4, requestManager } = this.client;
const request = this.clone(options);
const requestId = getUniqueRequestId(this.queueKey);
requestManager.addAbortController(this.abortKey, requestId);
const response = yield adapter4(request, requestId);
requestManager.removeAbortController(this.abortKey, requestId);
if (request.responseMapper) {
return request.responseMapper(response);
}
return response;
});
this.send = (options) => __async(this, null, function* () {
const _a = options || {}, { dispatcherType } = _a, rest = __objRest(_a, ["dispatcherType"]);
const request = this.clone(rest);
return sendRequest(request, options);
});
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
const {
endpoint,
headers,
auth = true,
method = client.defaultMethod,
options,
cancelable = false,
retry = 0,
retryTime = 500,
garbageCollection = 6e4 /* minute */ * 5,
cache = true,
cacheTime = 6e4 /* minute */ * 5,
queued = false,
offline = true,
abortKey,
cacheKey,
queueKey,
effectKey,
deduplicate = false,
deduplicateTime = 10
} = __spreadValues(__spreadValues({}, (_b = (_a = this.client).requestDefaultOptions) == null ? void 0 : _b.call(_a, requestOptions)), requestOptions);
this.endpoint = (_c = requestJSON == null ? void 0 : requestJSON.endpoint) != null ? _c : endpoint;
this.headers = (_d = requestJSON == null ? void 0 : requestJSON.headers) != null ? _d : headers;
this.auth = (_e = requestJSON == null ? void 0 : requestJSON.auth) != null ? _e : auth;
this.method = method;
this.params = requestJSON == null ? void 0 : requestJSON.params;
this.data = requestJSON == null ? void 0 : requestJSON.data;
this.queryParams = requestJSON == null ? void 0 : requestJSON.queryParams;
this.options = (_f = requestJSON == null ? void 0 : requestJSON.options) != null ? _f : options;
this.cancelable = (_g = requestJSON == null ? void 0 : requestJSON.cancelable) != null ? _g : cancelable;
this.retry = (_h = requestJSON == null ? void 0 : requestJSON.retry) != null ? _h : retry;
this.retryTime = (_i = requestJSON == null ? void 0 : requestJSON.retryTime) != null ? _i : retryTime;
this.garbageCollection = (_j = requestJSON == null ? void 0 : requestJSON.garbageCollection) != null ? _j : garbageCollection;
this.cache = (_k = requestJSON == null ? void 0 : requestJSON.cache) != null ? _k : cache;
this.cacheTime = (_l = requestJSON == null ? void 0 : requestJSON.cacheTime) != null ? _l : cacheTime;
this.queued = (_m = requestJSON == null ? void 0 : requestJSON.queued) != null ? _m : queued;
this.offline = (_n = requestJSON == null ? void 0 : requestJSON.offline) != null ? _n : offline;
this.abortKey = (_p = (_o = requestJSON == null ? void 0 : requestJSON.abortKey) != null ? _o : abortKey) != null ? _p : this.client.abortKeyMapper(this);
this.cacheKey = (_r = (_q = requestJSON == null ? void 0 : requestJSON.cacheKey) != null ? _q : cacheKey) != null ? _r : this.client.cacheKeyMapper(this);
this.queueKey = (_t = (_s = requestJSON == null ? void 0 : requestJSON.queueKey) != null ? _s : queueKey) != null ? _t : this.client.queueKeyMapper(this);
this.effectKey = (_v = (_u = requestJSON == null ? void 0 : requestJSON.effectKey) != null ? _u : effectKey) != null ? _v : this.client.effectKeyMapper(this);
this.used = (_w = requestJSON == null ? void 0 : requestJSON.used) != null ? _w : false;
this.deduplicate = (_x = requestJSON == null ? void 0 : requestJSON.deduplicate) != null ? _x : deduplicate;
this.deduplicateTime = (_y = requestJSON == null ? void 0 : requestJSON.deduplicateTime) != null ? _y : deduplicateTime;
this.updatedAbortKey = (_z = requestJSON == null ? void 0 : requestJSON.updatedAbortKey) != null ? _z : false;
this.updatedCacheKey = (_A = requestJSON == null ? void 0 : requestJSON.updatedCacheKey) != null ? _A : false;
this.updatedQueueKey = (_B = requestJSON == null ? void 0 : requestJSON.updatedQueueKey) != null ? _B : false;
this.updatedEffectKey = (_C = requestJSON == null ? void 0 : requestJSON.updatedEffectKey) != null ? _C : false;
}
toJSON() {
return {
requestOptions: this.requestOptions,
endpoint: this.endpoint,
headers: this.headers,
auth: this.auth,
method: this.method,
params: this.params,
data: this.data,
queryParams: this.queryParams,
options: this.options,
cancelable: this.cancelable,
retry: this.retry,
retryTime: this.retryTime,
garbageCollection: this.garbageCollection,
cache: this.cache,
cacheTime: this.cacheTime,
queued: this.queued,
offline: this.offline,
abortKey: this.abortKey,
cacheKey: this.cacheKey,
queueKey: this.queueKey,
effectKey: this.effectKey,
used: this.used,
disableResponseInterceptors: this.requestOptions.disableResponseInterceptors,
disableRequestInterceptors: this.requestOptions.disableRequestInterceptors,
updatedAbortKey: this.updatedAbortKey,
updatedCacheKey: this.updatedCacheKey,
updatedQueueKey: this.updatedQueueKey,
updatedEffectKey: this.updatedEffectKey,
deduplicate: this.deduplicate,
deduplicateTime: this.deduplicateTime
};
}
clone(options) {
const json = this.toJSON();
const requestJSON = __spreadProps(__spreadValues(__spreadValues({}, json), options), {
abortKey: this.updatedAbortKey ? (options == null ? void 0 : options.abortKey) || this.abortKey : void 0,
cacheKey: this.updatedCacheKey ? (options == null ? void 0 : options.cacheKey) || this.cacheKey : void 0,
queueKey: this.updatedQueueKey ? (options == null ? void 0 : options.queueKey) || this.queueKey : void 0,
endpoint: this.paramsMapper((options == null ? void 0 : options.params) || this.params, (options == null ? void 0 : options.queryParams) || this.queryParams),
queryParams: (options == null ? void 0 : options.queryParams) || this.queryParams,
data: (options == null ? void 0 : options.data) || this.data
});
const cloned = new Request(
this.client,
this.requestOptions,
requestJSON
);
cloned.dataMapper = this.dataMapper;
cloned.responseMapper = this.responseMapper;
cloned.requestMapper = this.requestMapper;
cloned.mockData = this.mockData;
cloned.mock = this.mock;
cloned.isMockEnabled = this.isMockEnabled;
return cloned;
}
};
// src/dispatcher/dispatcher.constants.ts
var DispatcherRequestType = /* @__PURE__ */ ((DispatcherRequestType2) => {
DispatcherRequestType2["oneByOne"] = "one-by-one";
DispatcherRequestType2["allAtOnce"] = "all-at-once";
DispatcherRequestType2["previousCanceled"] = "previous-canceled";
DispatcherRequestType2["deduplicated"] = "deduplicated";
return DispatcherRequestType2;
})(DispatcherRequestType || {});
// src/dispatcher/dispatcher.events.ts
var getDispatcherEvents = (emitter) => ({
setDrained: (queueKey, values) => {
emitter.emit(getDispatcherDrainedEventKey(queueKey), values);
},
setQueueStatus: (queueKey, values) => {
emitter.emit(getDispatcherStatusEventKey(queueKey), values);
},
setQueueChanged: (queueKey, values) => {
emitter.emit(getDispatcherChangeEventKey(queueKey), values);
},
onDrained: (queueKey, callback) => {
emitter.on(getDispatcherDrainedEventKey(queueKey), callback);
return () => emitter.removeListener(getDispatcherDrainedEventKey(queueKey), callback);
},
onQueueStatus: (queueKey, callback) => {
emitter.on(getDispatcherStatusEventKey(queueKey), callback);
return () => emitter.removeListener(getDispatcherStatusEventKey(queueKey), callback);
},
onQueueChange: (queueKey, callback) => {
emitter.on(getDispatcherChangeEventKey(queueKey), callback);
return () => emitter.removeListener(getDispatcherChangeEventKey(queueKey), callback);
}
});
// src/dispatcher/dispatcher.ts
var import_events = __toESM(require("events"));
var Dispatcher = class {
constructor(client, options) {
this.client = client;
this.options = options;
this.emitter = new import_events.default();
this.events = getDispatcherEvents(this.emitter);
this.storage = /* @__PURE__ */ new Map();
this.requestCount = /* @__PURE__ */ new Map();
this.runningRequests = /* @__PURE__ */ new Map();
this.start = (queueKey) => {
const queue = this.getQueue(queueKey);
queue.stopped = false;
this.setQueue(queueKey, queue);
this.flushQueue(queueKey);
this.events.setQueueStatus(queueKey, queue);
};
this.pause = (queueKey) => {
const queue = this.getQueue(queueKey);
queue.stopped = true;
this.setQueue(queueKey, queue);
this.events.setQueueStatus(queueKey, queue);
};
this.stop = (queueKey) => {
const queue = this.getQueue(queueKey);
queue.stopped = true;
this.setQueue(queueKey, queue);
this.cancelRunningRequests(queueKey);
this.events.setQueueStatus(queueKey, queue);
};
this.getQueuesKeys = () => {
return Array.from(this.storage.keys());
};
this.getQueue = (queueKey) => {
const initialQueueState = { requests: [], stopped: false };
const storedEntity = this.storage.get(queueKey);
return storedEntity || initialQueueState;
};
this.getRequest = (queueKey, requestId) => {
const initialQueueState = { requests: [], stopped: false };
const storedEntity = this.storage.get(queueKey) || initialQueueState;
return storedEntity.requests.find((req) => req.requestId === requestId);
};
this.getIsActiveQueue = (queueKey) => {
const queue = this.getQueue(queueKey);
const hasAvailableRequests = queue.requests.some((req) => !req.stopped);
const isRunningQueue = !queue.stopped;
return hasAvailableRequests && isRunningQueue;
};
this.addQueueElement = (queueKey, dispatcherDump) => {
const queue = this.getQueue(queueKey);
queue.requests.push(dispatcherDump);
this.setQueue(queueKey, queue);
};
this.setQueue = (queueKey, queue) => {
var _a, _b;
this.storage.set(queueKey, queue);
(_b = (_a = this.options) == null ? void 0 : _a.onUpdateStorage) == null ? void 0 : _b.call(_a, queueKey, queue);
this.events.setQueueChanged(queueKey, queue);
return queue;
};
this.clearQueue = (queueKey) => {
var _a, _b;
const queue = this.getQueue(queueKey);
const newQueue = { requests: [], stopped: queue.stopped };
this.storage.set(queueKey, newQueue);
(_b = (_a = this.options) == null ? void 0 : _a.onDeleteFromStorage) == null ? void 0 : _b.call(_a, queueKey, newQueue);
this.events.setQueueChanged(queueKey, newQueue);
return newQueue;
};
this.flushQueue = (queueKey) => __async(this, null, function* () {
const queue = this.getQueue(queueKey);
const runningRequests = this.getRunningRequests(queueKey);
const queueElement = queue.requests.find((request) => !request.stopped);
const isStopped = queue && queue.stopped;
const isOffline = !this.client.appManager.isOnline;
const isConcurrent = !(queueElement == null ? void 0 : queueElement.request.queued);
const isInactive = !runningRequests.length;
const isEmpty = !queueElement;
if (isStopped || isOffline || isEmpty) {
this.logger.debug("Skipping queue trigger", { isStopped, isOffline, isEmpty });
} else if (isConcurrent) {
queue.requests.forEach((element) => {
if (!this.hasRunningRequest(queueKey, element.requestId)) {
this.performRequest(element);
}
});
} else if (isInactive) {
yield this.performRequest(queueElement);
this.flushQueue(queueKey);
}
});
this.flush = () => __async(this, null, function* () {
const keys = this.getQueuesKeys();
for (const key of keys) {
const storageElement = this.getQueue(key);
if (storageElement) {
this.flushQueue(key);
}
}
});
this.clear = () => {
var _a, _b;
const keys = this.getQueuesKeys();
keys.forEach((queueKey) => this.cancelRunningRequests(queueKey));
this.runningRequests.clear();
this.storage.clear();
(_b = (_a = this.options) == null ? void 0 : _a.onClearStorage) == null ? void 0 : _b.call(_a, this);
};
this.startRequest = (queueKey, requestId) => {
const queue = this.getQueue(queueKey);
const request = queue.requests.find((element) => element.requestId === requestId);
if (request) {
request.stopped = false;
this.setQueue(queueKey, queue);
this.flushQueue(queueKey);
this.events.setQueueStatus(queueKey, queue);
}
};
this.stopRequest = (queueKey, requestId) => {
const queue = this.getQueue(queueKey);
const request = queue.requests.find((element) => element.requestId === requestId);
if (request) {
request.stopped = true;
this.setQueue(queueKey, queue);
this.cancelRunningRequest(queueKey, requestId);
this.events.setQueueStatus(queueKey, queue);
}
};
this.getAllRunningRequest = () => {
return Array.from(this.runningRequests.values()).flat();
};
this.getRunningRequests = (queueKey) => {
return this.runningRequests.get(queueKey) || [];
};
this.getRunningRequest = (queueKey, requestId) => {
const runningRequests = this.getRunningRequests(queueKey);
return runningRequests.find((req) => req.requestId === requestId);
};
this.addRunningRequest = (queueKey, requestId, request) => {
const runningRequests = this.getRunningRequests(queueKey);
runningRequests.push({ requestId, request, timestamp: Date.now() });
this.runningRequests.set(queueKey, runningRequests);
};
this.hasRunningRequests = (queueKey) => {
return !!this.getRunningRequests(queueKey).length;
};
this.hasRunningRequest = (queueKey, requestId) => {
const runningRequests = this.getRunningRequests(queueKey);
return !!runningRequests.find((req) => req.requestId === requestId);
};
this.cancelRunningRequests = (queueKey) => {
var _a;
(_a = this.runningRequests.get(queueKey)) == null ? void 0 : _a.forEach((request) => {
this.client.requestManager.abortByRequestId(request.request.abortKey, request.requestId);
});
this.deleteRunningRequests(queueKey);
};
this.cancelRunningRequest = (queueKey, requestId) => {
const requests = this.getRunningRequests(queueKey).filter((request) => {
if (request.requestId === requestId) {
this.client.requestManager.abortByRequestId(request.request.abortKey, request.requestId);
return false;
}
return true;
});
this.runningRequests.set(queueKey, requests);
};
this.deleteRunningRequests = (queueKey) => {
this.runningRequests.set(queueKey, []);
};
this.deleteRunningRequest = (queueKey, requestId) => {
const runningRequests = this.getRunningRequests(queueKey);
this.runningRequests.set(
queueKey,
runningRequests.filter((req) => req.requestId !== requestId)
);
};
this.getQueueRequestCount = (queueKey) => {
return this.requestCount.get(queueKey) || 0;
};
this.incrementQueueRequestCount = (queueKey) => {
const count = this.requestCount.get(queueKey) || 0;
this.requestCount.set(queueKey, count + 1);
};
this.createStorageElement = (request) => {
const requestId = getUniqueRequestId(request.queueKey);
const storageElement = {
requestId,
timestamp: +new Date(),
request,
retries: 0,
stopped: false
};
return storageElement;
};
this.add = (request) => {
const { queueKey } = request;
const storageElement = this.createStorageElement(request);
const { requestId } = storageElement;
const queue = this.getQueue(queueKey);
const [latestRequest] = queue.requests.slice(-1);
const requestType = getRequestType(request, latestRequest);
this.logger.debug("Adding request to queue", { requestType, request, requestId });
switch (requestType) {
case "one-by-one" /* oneByOne */: {
this.addQueueElement(queueKey, storageElement);
this.flushQueue(queueKey);
return requestId;
}
case "previous-canceled" /* previousCanceled */: {
this.cancelRunningRequests(queueKey);
this.clearQueue(queueKey);
this.addQueueElement(queueKey, storageElement);
this.flushQueue(queueKey);
return requestId;
}
case "deduplicated" /* deduplicated */: {
return queue.requests[0].requestId;
}
default: {
this.addQueueElement(queueKey, storageElement);
this.flushQueue(queueKey);
return requestId;
}
}
};
this.delete = (queueKey, requestId, abortKey) => {
var _a, _b;
this.logger.debug("Deleting request", { queueKey, requestId, abortKey });
const queue = this.getQueue(queueKey);
const queueElement = queue.requests.find((req) => req.requestId === requestId);
if (!queueElement)
return;
queue.requests = queue.requests.filter((req) => req.requestId !== requestId);
this.storage.set(queueKey, queue);
if (this.hasRunningRequest(queueKey, requestId)) {
this.deleteRunningRequest(queueKey, requestId);
this.client.requestManager.abortByRequestId(abortKey, requestId);
}
(_b = (_a = this.options) == null ? void 0 : _a.onDeleteFromStorage) == null ? void 0 : _b.call(_a, queueKey, queue);
this.events.setQueueChanged(queueKey, queue);
this.client.requestManager.events.emitRemove(queueKey, requestId, { requestId, request: queueElement.request });
if (!queue.requests.length) {
this.events.setDrained(queueKey, queue);
}
return queue;
};
this.performRequest = (storageElement) => __async(this, null, function* () {
var _a;
const { request, requestId } = storageElement;
this.logger.info("Performing request", { request, requestId });
const { retry, retryTime, queueKey, cacheKey, abortKey, offline } = request;
const { adapter: adapter4, requestManager, cache, appManager } = this.client;
const canRetry = canRetryRequest(storageElement.retries, retry);
const isOffline = !appManager.isOnline && offline;
const isAlreadyRunning = this.hasRunningRequest(queueKey, requestId);
const isStopped = storageElement.stopped;
if (isOffline || isAlreadyRunning || isStopped) {
return this.logger.warning("Unable to perform request", { isOffline, isAlreadyRunning, isStopped });
}
this.addRunningRequest(queueKey, requestId, request);
requestManager.events.emitLoading(queueKey, requestId, {
queueKey,
requestId,
loading: true,
isRetry: !!storageElement.retries,
isOffline
});
this.incrementQueueRequestCount(queueKey);
requestManager.addAbortController(abortKey, requestId);
const response = yield adapter4(request, requestId);
requestManager.removeAbortController(abortKey, requestId);
const isOfflineResponseStatus = !appManager.isOnline;
const isCancelMessage = getErrorMessage("abort").message === ((_a = response.error) == null ? void 0 : _a.message);
const isCanceled = !this.hasRunningRequest(queueKey, requestId) || isCancelMessage;
this.deleteRunningRequest(queueKey, requestId);
const requestDetails = {
isCanceled,
isOffline: isOfflineResponseStatus,
retries: storageElement.retries,
timestamp: +new Date()
};
requestManager.events.emitResponse(cacheKey, requestId, response, requestDetails);
requestManager.events.emitLoading(queueKey, requestId, {
queueKey,
requestId,
loading: false,
isRetry: !!storageElement.retries,
isOffline
});
cache.set(request, __spreadValues(__spreadValues({}, response), requestDetails));
this.logger.info("Request finished", { requestId, request, response, requestDetails });
if (isCanceled) {
const queue = this.getQueue(queueKey);
const queueElement = queue.requests.find((req) => req.requestId === requestId);
if (!queue.stopped && !(queueElement == null ? void 0 : queueElement.stopped)) {
this.logger.debug("Request paused", { response, requestDetails, request });
return this.delete(queueKey, requestId, abortKey);
}
return this.logger.debug("Request canceled", { response, requestDetails, request });
}
if (!response.success && isOfflineResponseStatus) {
if (!offline) {
this.logger.warning("Removing non-offline request", { response, requestDetails, request });
return this.delete(queueKey, requestId, abortKey);
}
return this.logger.debug("Awaiting for network restoration", { response, requestDetails, request });
}
if (response.success) {
this.delete(queueKey, requestId, abortKey);
return this.logger.debug("Successful response, removing request from queue.", {
response,
requestDetails,
request
});
}
if (!response.success && canRetry) {
this.logger.debug("Waiting for retry", { response, requestDetails, request });
setTimeout(() => {
this.logger.warning("Error response, performing retry");
this.performRequest(__spreadProps(__spreadValues({}, storageElement), {
retries: storageElement.retries + 1
}));
}, retryTime || 0);
} else {
this.logger.error("All retries have been used. Removing request from queue.");
this.delete(queueKey, requestId, abortKey);
}
});
var _a, _b, _c;
this.logger = client.loggerManager.init("Dispatcher");
if ((_a = this.options) == null ? void 0 : _a.storage) {
this.storage = this.options.storage;
}
this.client.appManager.events.onOnline(() => {
this.flush();
});
(_c = (_b = this.options) == null ? void 0 : _b.onInitialization) == null ? void 0 : _c.call(_b, this);
}
};
// src/dispatcher/dispatcher.utils.ts
var getDispatcherDrainedEventKey = (key) => {
return `${key}-drained-event`;
};
var getDispatcherStatusEventKey = (key) => {
return `${key}-status-event`;
};
var getDispatcherChangeEventKey = (key) => {
return `${key}-change-event`;
};
var getIsEqualTimestamp = (currentTimestamp, threshold, queueTimestamp) => {
if (!queueTimestamp) {
return false;
}
return queueTimestamp - currentTimestamp <= threshold;
};
var canRetryRequest = (currentRetries, retry) => {
if (retry && currentRetries < retry) {
return true;
}
return false;
};
var getRequestType = (request, latestRequest) => {
const { queued, cancelable, deduplicate } = request;
const canDeduplicate = latestRequest ? +new Date() - latestRequest.timestamp <= request.deduplicateTime : false;
if (queued) {
return "one-by-one" /* oneByOne */;
}
if (cancelable) {
return "previous-canceled" /* previousCanceled */;
}
if (canDeduplicate && deduplicate) {
return "deduplicated" /* deduplicated */;
}
return "all-at-once" /* allAtOnce */;
};
// src/request/request.utils.ts
var stringifyKey = (value) => {
try {
if (typeof value === "string")
return value;
if (value === void 0 || value === null)
return "";
const data = JSON.stringify(value);
if (typeof data !== "string")
throw new Error();
return data;
} catch (_) {
return "";
}
};
var getProgressValue = ({ loaded, total }) => {
if (!loaded || !total)
return 0;
return Number((loaded * 100 / total).toFixed(0));
};
var getRequestEta = (startDate, progressDate, { total, loaded }) => {
const timeElapsed = +progressDate - +startDate || 1;
const uploadSpeed = loaded / timeElapsed;
const totalValue = Math.max(total, loaded);
const sizeLeft = totalValue - loaded;
const estimatedTimeValue = uploadSpeed ? sizeLeft / uploadSpeed : null;
const timeLeft = totalValue === loaded ? 0 : estimatedTimeValue;
return { timeLeft, sizeLeft };
};
var getProgressData = (requestStartTime, progressDate, progressEvent) => {
const { total, loaded } = progressEvent;
if (Number.isNaN(total) || Number.isNaN(loaded)) {
return {
progress: 0,
timeLeft: 0,
sizeLeft: 0,
total: 0,
loaded: 0,
startTimestamp: +requestStartTime
};
}
const { timeLeft, sizeLeft } = getRequestEta(requestStartTime, progressDate, progressEvent);
return {
progress: getProgressValue(progressEvent),
timeLeft,
sizeLeft,
total,
loaded,
startTimestamp: +requestStartTime
};
};
var getSimpleKey = (request) => {
return `${request.method}_${request.requestOptions.endpoint}_${request.cancelable}`;
};
var getRequestKey = (request, useInitialValues) => {
const methodKey = stringifyKey(request.method);
const endpointKey = useInitialValues ? request.requestOptions.endpoint : stringifyKey(request.endpoint);
return `${methodKey}_${endpointKey}`;
};
var getRequestDispatcher = (request, dispatcherType = "auto") => {
const { fetchDispatcher, submitDispatcher } = request.client;
const isGet = request.method === "GET" /* get */;
const isFetchDispatcher = dispatcherType === "auto" && isGet || dispatcherType === "fetch";
const dispatcher = isFetchDispatcher ? fetchDispatcher : submitDispatcher;
return [dispatcher, isFetchDispatcher];
};
var sendRequest = (request, options) => {
const { requestManager } = request.client;
const [dispatcher] = getRequestDispatcher(request, options == null ? void 0 : options.dispatcherType);
return new Promise((resolve) => {
var _a;
let isResolved = false;
const requestId = dispatcher.add(request);
(_a = options == null ? void 0 : options.onSettle) == null ? void 0 : _a.call(options, requestId, request);
const unmountRequestStart = requestManager.events.onRequestStartById(
requestId,
(...props) => {
var _a2;
return (_a2 = options == null ? void 0 : options.onRequestStart) == null ? void 0 : _a2.call(options, ...props);
}
);
const unmountResponseStart = requestManager.events.onResponseStartById(
requestId,
(...props) => {
var _a2;
return (_a2 = options == null ? void 0 : options.onResponseStart) == null ? void 0 : _a2.call(options, ...props);
}
);
const unmountUpload = requestManager.events.onUploadProgressById(
requestId,
(...props) => {
var _a2;
return (_a2 = options == null ? void 0 : options.onUploadProgress) == null ? void 0 : _a2.call(options, ...props);
}
);
const unmountDownload = requestManager.events.onDownloadProgressById(
requestId,
(...props) => {
var _a2;
return (_a2 = options == null ? void 0 : options.onDownloadProgress) == null ? void 0 : _a2.call(options, ...props);
}
);
const unmountResponse = requestManager.events.onResponseById(requestId, (response, details) => {
var _a2;
isResolved = true;
const mapping = (_a2 = request.responseMapper) == null ? void 0 : _a2.call(request, response);
const isOfflineStatus = request.offline && details.isOffline;
const willRetry = canRetryRequest(details.retries, request.retry);
const handleResponse = (success, data) => {
var _a3;
if (!success && isOfflineStatus)
return;
if (!success && willRetry)
return;
(_a3 = options == null ? void 0 : options.onResponse) == null ? void 0 : _a3.call(options, data, details);
resolve(data);
umountAll();
};
if (mapping instanceof Promise) {
(() => __async(void 0, null, function* () {
const responseData = yield mapping;
const { success } = responseData;
handleResponse(success, responseData);
}))();
} else {
const data = mapping || response;
const { success } = data;
handleResponse(success, data);
}
});
const unmountRemoveQueueElement = requestManager.events.onRemoveById(requestId, (...props) => {
var _a2;
if (!isResolved) {
(_a2 = options == null ? void 0 : options.onRemove) == null ? void 0 : _a2.call(options, ...props);
resolve({
data: null,
status: null,
success: null,
error: getErrorMessage("deleted"),
extra: request.client.defaultExtra
});
umountAll();
}
});
function umountAll() {
unmountRequestStart();
unmountResponseStart();
unmountUpload();
unmountDownload();
unmountResponse();
unmountRemoveQueueElement();
}
});
};
// src/mocker/mocker.ts
var mocker = (_0, _1) => __async(void 0, [_0, _1], function* (request, {
onError,
onResponseEnd,
onTimeoutError,
onRequestEnd,
createAbortListener,
onResponseProgress,
onRequestProgress,
onResponseStart,
onBeforeRequest,
onRequestStart,
onSuccess
}) {
const mock = request.mock.next();
const result = mock.value instanceof Function ? yield mock.value(request) : mock.value;
return new Promise((resolve) => {
const { data, status = 200, success = true, extra, config } = result;
const {
requestTime = 20,
responseTime = 20,
totalUploaded = 1,
totalDownloaded = 1,
timeout = false
} = config || {};
createAbortListener(0, {}, () => {
}, resolve);
onBeforeRequest();
onRequestStart();
const progress = (totalTime, totalSize, progressFunction) => new Promise((resolveProgress) => {
const interval = 20;
const dataStart = +new Date();
const chunkSize = Math.floor(totalSize / Math.floor(totalTime / Math.min(totalTime, interval)));
let currentlyLoaded = 0;
const timer = setInterval(function handleProgressInterval() {
const currentTime = Math.min(totalTime, +new Date() - dataStart);
currentlyLoaded += currentlyLoaded + chunkSize >= totalSize ? totalSize - currentlyLoaded : chunkSize;
if (currentTime >= totalTime) {
resolveProgress(true);
clearInterval(timer);
} else {
progressFunction({
total: totalSize,
loaded: currentlyLoaded
});
}
}, interval);
});
const getResponse = () => __async(void 0, null, function* () {
yield progress(requestTime, totalUploaded, onRequestProgress);
onRequestEnd();
onResponseStart();
yield progress(responseTime, totalDownloaded, onResponseProgress);
if (success) {
onSuccess(data, status, extra || {}, resolve);
} else {
onError(data, status, extra || {}, resolve);
}
});
if (timeout) {
setTimeout(() => onTimeoutError(0, extra || {}, resolve), 1);
} else {
setTimeout(getResponse, requestTime + res