intelicoreact 2.0.9 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Classes/RESTAPI/index.d.ts +29 -7
- package/dist/Classes/RESTAPI/partials/AbortableFetch.d.ts +45 -40
- package/dist/Classes/RESTAPI/partials/ApiBase.d.ts +14 -3
- package/dist/Classes/RESTAPI/partials/ApiRequestCreators.d.ts +56 -7
- package/dist/Classes/RESTAPI/partials/ApiUtils.d.ts +61 -10
- package/dist/Classes/RESTAPI/partials/CredentialsProcessing.d.ts +73 -18
- package/dist/Classes/RESTAPI/partials/Utils.d.ts +18 -2
- package/dist/Classes/RESTAPI/partials/_utils.d.ts +54 -9
- package/dist/Classes/RESTAPI/partials/sse.d.ts +27 -0
- package/dist/Classes/RESTAPI/partials/types.d.ts +159 -0
- package/dist/Functions/sdk/runtime-sdk/client.d.ts +1 -1
- package/dist/Molecular/FormWithDependOn/FormWithDependOn.interface.d.ts +2 -2
- package/dist/charts.cjs.map +1 -1
- package/dist/classes.cjs +629 -237
- package/dist/classes.cjs.map +4 -4
- package/dist/classes.js +629 -237
- package/dist/classes.js.map +4 -4
- package/dist/index.cjs +627 -235
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +627 -235
- package/dist/index.js.map +4 -4
- package/dist/sdk.cjs.map +1 -1
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.js.map +1 -1
- package/package.json +2 -2
package/dist/classes.js
CHANGED
|
@@ -393,7 +393,11 @@ var AnimatedHandler = class {
|
|
|
393
393
|
};
|
|
394
394
|
var AnimatedHandler_default = AnimatedHandler;
|
|
395
395
|
|
|
396
|
-
// src/Classes/RESTAPI/partials/AbortableFetch.
|
|
396
|
+
// src/Classes/RESTAPI/partials/AbortableFetch.ts
|
|
397
|
+
var HTTP_METHODS = ["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"];
|
|
398
|
+
function isHttpMethod(value) {
|
|
399
|
+
return HTTP_METHODS.includes(value);
|
|
400
|
+
}
|
|
397
401
|
var RESPONSE_AS_OBJECT_ALWAYS_VALUE2 = "always";
|
|
398
402
|
var AbortableFetch2 = class {
|
|
399
403
|
#pathPrefix = null;
|
|
@@ -406,6 +410,8 @@ var AbortableFetch2 = class {
|
|
|
406
410
|
#catchCallback = null;
|
|
407
411
|
#everyPromiseCallback = null;
|
|
408
412
|
#isResponseAsObject = false;
|
|
413
|
+
// ? Последний вход request() — используется repeatRequest() для повторного запроса той же пачки.
|
|
414
|
+
requestInput = [];
|
|
409
415
|
constructor(input) {
|
|
410
416
|
if (input && !getIsOnlyAnObject(input)) throw new Error("Not valid input value!");
|
|
411
417
|
this.getPathPrefix = this.getPathPrefix.bind(this);
|
|
@@ -436,20 +442,30 @@ var AbortableFetch2 = class {
|
|
|
436
442
|
this.repeatRequest = this.repeatRequest.bind(this);
|
|
437
443
|
this.setProps(input || {});
|
|
438
444
|
}
|
|
445
|
+
/**
|
|
446
|
+
* Выполняет один или несколько HTTP-запросов (нативный fetch) с возможностью отмены.
|
|
447
|
+
*
|
|
448
|
+
* Метод `abort()` навешивается на прототип возвращаемого промиса (как в исходной реализации),
|
|
449
|
+
* что позволяет отменить всю цепочку запросов вызовом `abort()` на возвращённом промисе.
|
|
450
|
+
*
|
|
451
|
+
* @param props - путь, объект описания запроса или их массив.
|
|
452
|
+
* @returns Промис с результатом (форма зависит от isResponseAsObject); на прототипе доступен `abort()`.
|
|
453
|
+
*/
|
|
439
454
|
async request(props) {
|
|
440
455
|
if (!getIsOnlyAnObject(props) && !Array.isArray(props) && typeof props !== "string") throw new Error("Not valid props value!");
|
|
441
|
-
const stringifyBody = (b) => b
|
|
456
|
+
const stringifyBody = (b) => b instanceof FormData ? b : JSON.stringify(b);
|
|
442
457
|
this.requestInput = props;
|
|
443
458
|
const requests = getRequestsArray.call(this, props);
|
|
444
459
|
const ABORTABLE_FETCH_CONTEXT = this;
|
|
445
460
|
const abortController = new AbortController();
|
|
446
461
|
const addProps = (response, request) => {
|
|
447
|
-
response
|
|
448
|
-
|
|
449
|
-
|
|
462
|
+
return Object.assign(response, {
|
|
463
|
+
request,
|
|
464
|
+
...ABORTABLE_FETCH_CONTEXT.#isResponseAsObject ? { name: getIsOnlyAnObject(request) ? request.name || "" : "" } : {}
|
|
465
|
+
});
|
|
450
466
|
};
|
|
451
|
-
|
|
452
|
-
requests.map(
|
|
467
|
+
const externalRequest = Promise.all(
|
|
468
|
+
requests.map((item) => {
|
|
453
469
|
const safelyQuery = item.path.includes("?") ? `&${item.queryParameters.replace(/\?/g, "")}` : item.queryParameters;
|
|
454
470
|
const internalRequest = fetch(`${item.pathPrefix}${item.path}${safelyQuery}`, {
|
|
455
471
|
...item.options,
|
|
@@ -460,12 +476,15 @@ var AbortableFetch2 = class {
|
|
|
460
476
|
}).then(async (response) => addProps(response, item)).catch(async (response) => {
|
|
461
477
|
if (response instanceof Response) return Promise.resolve(addProps(response, item));
|
|
462
478
|
return Promise.resolve(
|
|
463
|
-
addProps(
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
479
|
+
addProps(
|
|
480
|
+
{
|
|
481
|
+
ok: false,
|
|
482
|
+
status: 0,
|
|
483
|
+
statusText: response,
|
|
484
|
+
request: item
|
|
485
|
+
},
|
|
486
|
+
item
|
|
487
|
+
)
|
|
469
488
|
);
|
|
470
489
|
}).then(async (res) => {
|
|
471
490
|
return typeof ABORTABLE_FETCH_CONTEXT.#everyPromiseCallback === "function" && !item.isSkipEveryPromiseCallback ? await ABORTABLE_FETCH_CONTEXT.#everyPromiseCallback(res) : res;
|
|
@@ -474,7 +493,8 @@ var AbortableFetch2 = class {
|
|
|
474
493
|
}).then(async (res) => {
|
|
475
494
|
return { request: item, response: res, ...item.name ? { name: item.name } : {} };
|
|
476
495
|
});
|
|
477
|
-
|
|
496
|
+
const internalProto = Object.getPrototypeOf(internalRequest);
|
|
497
|
+
internalProto.abort = () => abortController.abort();
|
|
478
498
|
return internalRequest;
|
|
479
499
|
})
|
|
480
500
|
).then(async (resArr) => {
|
|
@@ -482,16 +502,17 @@ var AbortableFetch2 = class {
|
|
|
482
502
|
return ABORTABLE_FETCH_CONTEXT.#isResponseAsObject ? {} : [];
|
|
483
503
|
}
|
|
484
504
|
if (ABORTABLE_FETCH_CONTEXT.#isResponseAsObject === RESPONSE_AS_OBJECT_ALWAYS_VALUE2) {
|
|
485
|
-
return resArr.reduce((ac, item) => ({ ...ac, [item.name]: item.response }), {});
|
|
505
|
+
return resArr.reduce((ac, item) => ({ ...ac, [String(item.name)]: item.response }), {});
|
|
486
506
|
}
|
|
487
507
|
if (resArr.length === 1) return resArr[0].response;
|
|
488
|
-
return ABORTABLE_FETCH_CONTEXT.#isResponseAsObject === true ? resArr.reduce((ac, item) => ({ ...ac, [item.name]: item.response }), {}) : resArr.map((item) => item.response);
|
|
508
|
+
return ABORTABLE_FETCH_CONTEXT.#isResponseAsObject === true ? resArr.reduce((ac, item) => ({ ...ac, [String(item.name)]: item.response }), {}) : resArr.map((item) => item.response);
|
|
489
509
|
}).then(async (res) => {
|
|
490
510
|
return typeof ABORTABLE_FETCH_CONTEXT.#callback === "function" ? await ABORTABLE_FETCH_CONTEXT.#callback(res) : res;
|
|
491
511
|
}).catch(async (res) => {
|
|
492
512
|
return typeof ABORTABLE_FETCH_CONTEXT.#catchCallback === "function" ? await ABORTABLE_FETCH_CONTEXT.#catchCallback(res) : res;
|
|
493
513
|
});
|
|
494
|
-
|
|
514
|
+
const externalProto = Object.getPrototypeOf(externalRequest);
|
|
515
|
+
externalProto.abort = () => abortController.abort();
|
|
495
516
|
return externalRequest;
|
|
496
517
|
function getRequestsArray(input) {
|
|
497
518
|
const requestsArray = (() => {
|
|
@@ -516,15 +537,17 @@ var AbortableFetch2 = class {
|
|
|
516
537
|
callback: omitCallback,
|
|
517
538
|
mergeProps: omitMergeProps,
|
|
518
539
|
...optionsRest
|
|
519
|
-
} = options
|
|
540
|
+
} = getIsOnlyAnObject(options) ? options : {};
|
|
541
|
+
const localMethod = typeof method === "string" && isHttpMethod(method) ? method : null;
|
|
542
|
+
const localCallback = typeof callback === "function" ? (res) => callback(res) : void 0;
|
|
520
543
|
return [
|
|
521
544
|
...ac,
|
|
522
545
|
{
|
|
523
546
|
path,
|
|
524
547
|
pathPrefix: getMergeProps("pathPrefix") === "onlyLocal" || isNoPathPrefix ? "" : this.#pathPrefix || "",
|
|
525
548
|
method: (() => {
|
|
526
|
-
if (getMergeProps("method") === "onlyLocal") return
|
|
527
|
-
return getMergeProps("method") === "onlyGlobal" ? this.#method || "GET" :
|
|
549
|
+
if (getMergeProps("method") === "onlyLocal") return localMethod || "GET";
|
|
550
|
+
return getMergeProps("method") === "onlyGlobal" ? this.#method || "GET" : localMethod || this.#method || "GET";
|
|
528
551
|
})(),
|
|
529
552
|
queryParameters: (() => {
|
|
530
553
|
if ((getMergeProps("queryParameters") ?? getMergeProps("query")) === "onlyLocal") {
|
|
@@ -533,31 +556,34 @@ var AbortableFetch2 = class {
|
|
|
533
556
|
return (getMergeProps("queryParameters") ?? getMergeProps("query")) === "onlyGlobal" ? this.getQueryString(this.getQueryArray(this.#queryParameters)) : this.getQueryString([...this.getQueryArray(this.#queryParameters), ...this.getQueryArray(queryParameters)]);
|
|
534
557
|
})(),
|
|
535
558
|
headers: (() => {
|
|
536
|
-
if (getMergeProps("headers") === "onlyLocal") return this.getHeadersObj(headers
|
|
559
|
+
if (getMergeProps("headers") === "onlyLocal") return this.getHeadersObj(getIsOnlyAnObject(headers) ? headers : {});
|
|
537
560
|
return getMergeProps("headers") === "onlyGlobal" ? this.getHeadersObj({ ...this.#headers || {} }) : this.getHeadersObj({
|
|
538
561
|
...this.#headers || {},
|
|
539
|
-
...headers
|
|
562
|
+
...getIsOnlyAnObject(headers) ? headers : {}
|
|
540
563
|
});
|
|
541
564
|
})(),
|
|
542
565
|
body: (() => {
|
|
543
566
|
if (getMergeProps("body") === "onlyLocal") return body || null;
|
|
544
567
|
if (getMergeProps("body") === "onlyGlobal") return this.#body || null;
|
|
545
568
|
if (body && this.#body && typeof body === typeof this.#body && typeof body === "object") {
|
|
546
|
-
return Array.isArray(body) ? [...this.#body, ...body] : { ...this.#body, ...body };
|
|
547
|
-
} else
|
|
569
|
+
return Array.isArray(body) ? [...Array.isArray(this.#body) ? this.#body : [], ...body] : { ...getIsOnlyAnObject(this.#body) ? this.#body : {}, ...getIsOnlyAnObject(body) ? body : {} };
|
|
570
|
+
} else {
|
|
571
|
+
return body || this.#body || null;
|
|
572
|
+
}
|
|
548
573
|
})(),
|
|
549
574
|
options: (() => {
|
|
550
|
-
if (getMergeProps("options") === "onlyLocal") return { ...optionsRest
|
|
551
|
-
return getMergeProps("options") === "onlyGlobal" ? { ...this.#options || {} } : { ...this.#options || {}, ...optionsRest
|
|
575
|
+
if (getMergeProps("options") === "onlyLocal") return { ...optionsRest };
|
|
576
|
+
return getMergeProps("options") === "onlyGlobal" ? { ...this.#options || {} } : { ...this.#options || {}, ...optionsRest };
|
|
552
577
|
})(),
|
|
553
|
-
callback,
|
|
554
|
-
isSkipEveryPromiseCallback,
|
|
578
|
+
callback: localCallback,
|
|
579
|
+
isSkipEveryPromiseCallback: Boolean(isSkipEveryPromiseCallback),
|
|
555
580
|
...this.getIsResponseAsObject() ? { name: name && typeof name === "string" ? name : index } : {}
|
|
556
581
|
}
|
|
557
582
|
];
|
|
558
583
|
}, []);
|
|
559
584
|
}
|
|
560
585
|
}
|
|
586
|
+
/** Повторяет последний выполненный запрос (ту же пачку). */
|
|
561
587
|
repeatRequest() {
|
|
562
588
|
return this.request(this.requestInput);
|
|
563
589
|
}
|
|
@@ -573,19 +599,23 @@ var AbortableFetch2 = class {
|
|
|
573
599
|
return this.#method;
|
|
574
600
|
}
|
|
575
601
|
setMethod(value) {
|
|
576
|
-
|
|
577
|
-
if (value && !methods.includes(value)) throw new Error("Not valid method value!");
|
|
602
|
+
if (value && !isHttpMethod(value)) throw new Error("Not valid method value!");
|
|
578
603
|
this.#method = value || null;
|
|
579
604
|
}
|
|
580
605
|
getQueryParameters() {
|
|
581
606
|
return this.#queryParameters;
|
|
582
607
|
}
|
|
583
608
|
getQueryArray(value) {
|
|
584
|
-
if (typeof value === "string")
|
|
585
|
-
|
|
586
|
-
else if (
|
|
587
|
-
return
|
|
588
|
-
} else
|
|
609
|
+
if (typeof value === "string") {
|
|
610
|
+
return (value[0] === "?" ? value.slice(1) : value).split("&");
|
|
611
|
+
} else if (Array.isArray(value)) {
|
|
612
|
+
return value.map((item) => `${item}`);
|
|
613
|
+
} else if (typeof value === "object" && value !== null) {
|
|
614
|
+
const record = getIsOnlyAnObject(value) ? value : {};
|
|
615
|
+
return Object.keys(record).filter((key) => Boolean(key) && Boolean(record[key])).map((key) => `${key}=${record[key]}`);
|
|
616
|
+
} else {
|
|
617
|
+
return [];
|
|
618
|
+
}
|
|
589
619
|
}
|
|
590
620
|
getQueryString(value) {
|
|
591
621
|
if (!value) return "";
|
|
@@ -604,7 +634,7 @@ var AbortableFetch2 = class {
|
|
|
604
634
|
if (!obj) return headers;
|
|
605
635
|
if (typeof obj !== "object" || Array.isArray(obj)) throw new Error("Not valid headers value!");
|
|
606
636
|
Object.keys(obj).forEach((key) => {
|
|
607
|
-
headers.append(key, obj[key]);
|
|
637
|
+
headers.append(key, `${obj[key]}`);
|
|
608
638
|
});
|
|
609
639
|
return headers;
|
|
610
640
|
}
|
|
@@ -680,39 +710,64 @@ var AbortableFetch2 = class {
|
|
|
680
710
|
// isAnywayRunCallback,
|
|
681
711
|
isResponseAsObject
|
|
682
712
|
} = input;
|
|
683
|
-
if (pathPrefix) this.setPathPrefix(pathPrefix);
|
|
684
|
-
if (method) this.setMethod(method);
|
|
713
|
+
if (pathPrefix) this.setPathPrefix(typeof pathPrefix === "string" ? pathPrefix : null);
|
|
714
|
+
if (method) this.setMethod(typeof method === "string" && isHttpMethod(method) ? method : null);
|
|
685
715
|
if (queryParameters) this.setQueryParameters(this.getQueryArray(queryParameters));
|
|
686
|
-
if (headers) this.setHeaders(headers);
|
|
716
|
+
if (headers) this.setHeaders(getIsOnlyAnObject(headers) ? headers : null);
|
|
687
717
|
if (body) this.setBody(body);
|
|
688
|
-
if (options) this.setOptions(options);
|
|
689
|
-
if (callback
|
|
690
|
-
|
|
691
|
-
|
|
718
|
+
if (options) this.setOptions(getIsOnlyAnObject(options) ? options : null);
|
|
719
|
+
if (callback && typeof callback === "function") {
|
|
720
|
+
const fn = callback;
|
|
721
|
+
this.setCallback(function wrappedCallback(response) {
|
|
722
|
+
return fn.call(this, response);
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
if (catchCallback && typeof catchCallback === "function") {
|
|
726
|
+
const fn = catchCallback;
|
|
727
|
+
this.setCatchCallback(function wrappedCatchCallback(response) {
|
|
728
|
+
return fn.call(this, response);
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
if (everyPromiseCallback && typeof everyPromiseCallback === "function") {
|
|
732
|
+
const fn = everyPromiseCallback;
|
|
733
|
+
this.setEveryPromiseCallback(function wrappedEveryPromiseCallback(response) {
|
|
734
|
+
return fn.call(this, response);
|
|
735
|
+
});
|
|
736
|
+
}
|
|
692
737
|
if (isResponseAsObject !== void 0) this.setIsResponseAsObject(isResponseAsObject);
|
|
693
738
|
}
|
|
694
739
|
};
|
|
695
740
|
var AbortableFetch_default2 = AbortableFetch2;
|
|
696
741
|
|
|
697
|
-
// src/Classes/RESTAPI/partials/_utils.
|
|
742
|
+
// src/Classes/RESTAPI/partials/_utils.ts
|
|
698
743
|
function getIsOnlyAnObject(input) {
|
|
699
|
-
return typeof input === "object" &&
|
|
700
|
-
input instanceof Object && // "отбивает" null
|
|
701
|
-
!Array.isArray(input) && // "отбивает" массивы
|
|
702
|
-
!(input instanceof Set) && // "отбивает" сеты
|
|
703
|
-
!(input instanceof Map);
|
|
744
|
+
return typeof input === "object" && input instanceof Object && !Array.isArray(input) && !(input instanceof Set) && !(input instanceof Map);
|
|
704
745
|
}
|
|
705
|
-
|
|
746
|
+
function clone(input) {
|
|
706
747
|
if (input === null || typeof input !== "object") return input;
|
|
707
|
-
|
|
708
|
-
|
|
748
|
+
if (Array.isArray(input)) return input.map((item) => clone(item));
|
|
749
|
+
const source = getIsOnlyAnObject(input) ? input : {};
|
|
750
|
+
const data = {};
|
|
751
|
+
Object.keys(source).forEach((key) => {
|
|
752
|
+
data[key] = clone(source[key]);
|
|
753
|
+
});
|
|
709
754
|
return data;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
}
|
|
715
|
-
|
|
755
|
+
}
|
|
756
|
+
function omitKeys(obj, keys = []) {
|
|
757
|
+
const source = obj ?? {};
|
|
758
|
+
const keySet = new Set(keys);
|
|
759
|
+
const result = {};
|
|
760
|
+
Object.keys(source).forEach((key) => {
|
|
761
|
+
if (!keySet.has(key)) result[key] = source[key];
|
|
762
|
+
});
|
|
763
|
+
return result;
|
|
764
|
+
}
|
|
765
|
+
async function getResponseClone(res) {
|
|
766
|
+
if (res && typeof res === "object" && "clone" in res && typeof res.clone === "function") {
|
|
767
|
+
return res.clone();
|
|
768
|
+
}
|
|
769
|
+
return clone(res);
|
|
770
|
+
}
|
|
716
771
|
function addCustomMethods(data, prefix) {
|
|
717
772
|
const preparedPrefix = (prefix || "").toString();
|
|
718
773
|
Object.keys(data).forEach((key) => {
|
|
@@ -726,7 +781,7 @@ async function getInstanceOfFetchSystem(isGetBody) {
|
|
|
726
781
|
let credentials = {};
|
|
727
782
|
if (CREDENTIALS_CONTEXT) {
|
|
728
783
|
const cred = await CREDENTIALS_CONTEXT.getCredentials();
|
|
729
|
-
credentials = CREDENTIALS_CONTEXT.isUseRefreshTokensPropcessing ? await CREDENTIALS_CONTEXT.waitRefresh(cred.isNeedRefresh && !CREDENTIALS_CONTEXT.getIsTokenStartRefresh()).then(
|
|
784
|
+
credentials = CREDENTIALS_CONTEXT.isUseRefreshTokensPropcessing ? await CREDENTIALS_CONTEXT.waitRefresh(Boolean(cred.isNeedRefresh) && !CREDENTIALS_CONTEXT.getIsTokenStartRefresh()).then(
|
|
730
785
|
async () => CREDENTIALS_CONTEXT.processCredentials(await CREDENTIALS_CONTEXT.getCredentials())
|
|
731
786
|
) : cred;
|
|
732
787
|
}
|
|
@@ -744,52 +799,57 @@ async function getInstanceOfFetchSystem(isGetBody) {
|
|
|
744
799
|
}
|
|
745
800
|
return (CREDENTIALS_CONTEXT?.isUseRefreshTokensPropcessing ? CREDENTIALS_CONTEXT.waitRefresh() : Promise.resolve()).then(
|
|
746
801
|
async () => new AbortableFetch_default2({
|
|
747
|
-
|
|
802
|
+
// ? Метод по умолчанию
|
|
748
803
|
method: "GET",
|
|
749
|
-
|
|
804
|
+
// ? Заголовки по умолчанию
|
|
750
805
|
headers: {
|
|
751
806
|
...headersToAbortableFetchInstance,
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
807
|
+
// ? (*) Тут обрабатываются кейсы
|
|
808
|
+
// ? - когда нет this.credentialsProcessing
|
|
809
|
+
// ? (мы НЕ хотим добавлять токены в принципе, не зашли в верхнюю if-ку)
|
|
810
|
+
// ? - когда есть this.credentialsProcessing, но нет credentials.token (не авторизованы)
|
|
811
|
+
// ? (зашли в верхнюю if-ку, попробовали получить/обновить креды)
|
|
757
812
|
...credentials.token ? CREDENTIALS_CONTEXT?.getHeadersForAuthorize?.(credentials.token) || {} : {}
|
|
758
813
|
},
|
|
759
814
|
queryParameters: await API_CONTEXT.processQueryParams(queryParamsToAbortableFetchInstance),
|
|
760
|
-
|
|
815
|
+
// ? Опции по умолчанию
|
|
761
816
|
options: {
|
|
762
817
|
mode: "cors",
|
|
763
818
|
redirect: "follow",
|
|
764
819
|
...optionsToAbortableFetchInstance
|
|
765
820
|
},
|
|
766
|
-
|
|
821
|
+
// ? Каждый запрос (каждый запрос мультизапроса), сделаный методом request этого экземпляра выполнит этот колбек
|
|
767
822
|
everyPromiseCallback: async function everyPromiseCallback(response) {
|
|
768
823
|
const ABORTABLE_FETCH_INSTANCE = this;
|
|
769
824
|
if (!response.status) {
|
|
770
|
-
const
|
|
771
|
-
const
|
|
825
|
+
const reqInput = ABORTABLE_FETCH_INSTANCE.requestInput;
|
|
826
|
+
const responseRequest = getIsOnlyAnObject(response.request) ? response.request : {};
|
|
827
|
+
const request = Array.isArray(reqInput) ? reqInput.find((item) => getIsOnlyAnObject(item) && item.path === responseRequest.path) : void 0;
|
|
828
|
+
const mesageOptions = getIsOnlyAnObject(request) && getIsOnlyAnObject(request.mesageOptions) ? request.mesageOptions : void 0;
|
|
829
|
+
const isUseErrorToast = mesageOptions?.isUseErrorToast;
|
|
772
830
|
if (isUseErrorToast) {
|
|
773
|
-
API_CONTEXT.sendMessage?.(API_CONTEXT.NO_INET,
|
|
831
|
+
API_CONTEXT.sendMessage?.(API_CONTEXT.NO_INET, mesageOptions, response);
|
|
774
832
|
}
|
|
775
833
|
}
|
|
776
|
-
return API_CONTEXT.REJECT_CODES.includes(response.status) || CREDENTIALS_CONTEXT?.isUseRefreshTokensPropcessing && CREDENTIALS_CONTEXT?.CODES_USING_THE_REFRESH_ATTEMPT?.includes
|
|
834
|
+
return API_CONTEXT.REJECT_CODES.includes(Number(response.status)) || CREDENTIALS_CONTEXT?.isUseRefreshTokensPropcessing && Boolean(CREDENTIALS_CONTEXT?.CODES_USING_THE_REFRESH_ATTEMPT?.includes(Number(response.status))) ? Promise.reject(new Error(`status:${Number(response.status)}`)) : Promise.resolve(!isGetBody ? response : await API_CONTEXT.getResponseBody(response));
|
|
777
835
|
},
|
|
778
|
-
|
|
779
|
-
|
|
836
|
+
// ? Если хоть один запрос из пачки будет зареджекчен, зареджектится вся пачка.
|
|
837
|
+
// ? В этом случае будет выполнен этот колбэк
|
|
780
838
|
catchCallback: async function catchCallback(res) {
|
|
781
839
|
const ABORTABLE_FETCH_INSTANCE = this;
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
840
|
+
if (!CREDENTIALS_CONTEXT) return Promise.reject(res);
|
|
841
|
+
const code = Number(res instanceof Error ? res.message.split(":")[1] : "");
|
|
842
|
+
if (CREDENTIALS_CONTEXT.CODES_USING_THE_REFRESH_ATTEMPT?.includes(code)) {
|
|
843
|
+
const isDoRefresh = !CREDENTIALS_CONTEXT.getIsTokenStartRefresh();
|
|
844
|
+
return CREDENTIALS_CONTEXT.waitRefresh(isDoRefresh).then(async () => {
|
|
845
|
+
const newCredentials = await CREDENTIALS_CONTEXT.processCredentials({
|
|
846
|
+
...await CREDENTIALS_CONTEXT.getCredentials(true),
|
|
788
847
|
isCatchCallbackProcess: isDoRefresh
|
|
789
848
|
});
|
|
849
|
+
const currentHeaders = ABORTABLE_FETCH_INSTANCE.getHeaders();
|
|
790
850
|
ABORTABLE_FETCH_INSTANCE.setHeaders({
|
|
791
|
-
...
|
|
792
|
-
...newCredentials
|
|
851
|
+
...getIsOnlyAnObject(currentHeaders) ? currentHeaders : {},
|
|
852
|
+
...newCredentials.token ? { Authorization: `Bearer ${newCredentials.token}` } : {}
|
|
793
853
|
});
|
|
794
854
|
if (newCredentials.token) return ABORTABLE_FETCH_INSTANCE.repeatRequest();
|
|
795
855
|
return Promise.reject(res);
|
|
@@ -801,13 +861,23 @@ async function getInstanceOfFetchSystem(isGetBody) {
|
|
|
801
861
|
);
|
|
802
862
|
}
|
|
803
863
|
|
|
804
|
-
// src/Classes/RESTAPI/partials/Utils.
|
|
864
|
+
// src/Classes/RESTAPI/partials/Utils.ts
|
|
805
865
|
var Utils = class {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
866
|
+
// ! Могут содержаться НЕасинхронные методы!
|
|
867
|
+
/**
|
|
868
|
+
* Нормализатор сложных query-параметров.
|
|
869
|
+
*
|
|
870
|
+
* Например: `&key1=&&&===&&&key2====&&&&&&&&key3=...`. Для корректной работы на вход нужно подавать
|
|
871
|
+
* НЕ кодированные значения. По умолчанию выходные значения query-параметров НЕ кодируются.
|
|
872
|
+
*
|
|
873
|
+
* @param queryParams - query в виде строки, массива или объекта.
|
|
874
|
+
* @param settings - формат вывода (`array` | `string` | `object`) и флаг кодирования.
|
|
875
|
+
* @returns Нормализованные query-параметры в выбранном формате.
|
|
876
|
+
*/
|
|
877
|
+
// ? Ф-я normalizeQueryParams является нормализатором сложных квери
|
|
878
|
+
// ? Например: &key1=&&&===&&&key2====&&&&&&&&key3=....
|
|
879
|
+
// ? Для корректной работы на вход нужно подавать НЕ кодированные значения
|
|
880
|
+
// ? По умолчанию выходные значения квери-параметров НЕ кодируются
|
|
811
881
|
normalizeQueryParams(queryParams, settings) {
|
|
812
882
|
if (settings && !getIsOnlyAnObject(settings)) {
|
|
813
883
|
throw new Error("Bad settings [class Utils, normalizeQueryParams]");
|
|
@@ -826,9 +896,13 @@ var Utils = class {
|
|
|
826
896
|
if (index === -1) return [item];
|
|
827
897
|
return [item.slice(0, index), item.slice(index + 1)];
|
|
828
898
|
}).filter(([key]) => Boolean(key)).map(([key, value]) => prepareParam(key, value));
|
|
829
|
-
} else if (getIsOnlyAnObject(input))
|
|
830
|
-
|
|
831
|
-
else
|
|
899
|
+
} else if (getIsOnlyAnObject(input)) {
|
|
900
|
+
return Object.keys(input).map((key) => prepareParam(key, input[key]));
|
|
901
|
+
} else if (typeof input === "string") {
|
|
902
|
+
return (input[0] === "?" ? input.slice(1) : input).split("&");
|
|
903
|
+
} else {
|
|
904
|
+
return [];
|
|
905
|
+
}
|
|
832
906
|
};
|
|
833
907
|
const { isEncode = false, outputAs = "array" } = settings || {};
|
|
834
908
|
const initialStructure = getInitialArr(queryParams);
|
|
@@ -845,7 +919,9 @@ var Utils = class {
|
|
|
845
919
|
if (index !== -1 && index !== 0) {
|
|
846
920
|
const key = str.slice(0, index);
|
|
847
921
|
acc.result.push(`${key}=${encodeURIComponent(str.slice(index + 1))}`);
|
|
848
|
-
} else
|
|
922
|
+
} else {
|
|
923
|
+
acc.toJoin = str;
|
|
924
|
+
}
|
|
849
925
|
if (idx === initialStructure.length - 1 && typeof acc.toJoin === "string") processToJoin(acc.toJoin);
|
|
850
926
|
return acc;
|
|
851
927
|
},
|
|
@@ -853,7 +929,7 @@ var Utils = class {
|
|
|
853
929
|
).result;
|
|
854
930
|
const outputStructure = normalizedStructure.map((item) => {
|
|
855
931
|
const [key, value] = item.split("=");
|
|
856
|
-
return [key, !isEncode ? decodeURIComponent(value) : value];
|
|
932
|
+
return [key, !isEncode ? decodeURIComponent(value ?? "") : value ?? ""];
|
|
857
933
|
});
|
|
858
934
|
switch (outputAs) {
|
|
859
935
|
case "string":
|
|
@@ -867,16 +943,25 @@ var Utils = class {
|
|
|
867
943
|
};
|
|
868
944
|
var Utils_default = Utils;
|
|
869
945
|
|
|
870
|
-
// src/Classes/RESTAPI/partials/ApiUtils.
|
|
946
|
+
// src/Classes/RESTAPI/partials/ApiUtils.ts
|
|
871
947
|
var ApiUtils = class extends Utils_default {
|
|
948
|
+
/** Корневой путь API (раскладывается в ApiBase из constants.API_PATH). */
|
|
949
|
+
API_PATH;
|
|
872
950
|
constructor(settings) {
|
|
873
951
|
super();
|
|
874
952
|
const { utils } = settings || {};
|
|
875
953
|
if (getIsOnlyAnObject(utils)) addCustomMethods.call(this, utils);
|
|
876
954
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
955
|
+
/**
|
|
956
|
+
* Разбирает единый объект параметров запроса на части в зависимости от варианта использования.
|
|
957
|
+
*
|
|
958
|
+
* @param apiParams - объединённые параметры запроса.
|
|
959
|
+
* @param variant - `'doRequestMapping'` для мультизапроса либо `undefined` для одиночного.
|
|
960
|
+
* @returns Для `doRequestMapping` — объект параметров; иначе кортеж `[параметры, настройки]`.
|
|
961
|
+
*/
|
|
962
|
+
// ? Планируется, что метод будет использоваться неизменно, однако технически его можно перегрузить на экземпляре
|
|
963
|
+
// ? Метод не планировался как асинхронный,
|
|
964
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
880
965
|
async splitProperties(apiParams, variant) {
|
|
881
966
|
const {
|
|
882
967
|
isResponseAsObject,
|
|
@@ -935,79 +1020,224 @@ var ApiUtils = class extends Utils_default {
|
|
|
935
1020
|
];
|
|
936
1021
|
}
|
|
937
1022
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1023
|
+
/**
|
|
1024
|
+
* Обработчик пропы `api` из объекта описания запроса — возвращает корневой путь API.
|
|
1025
|
+
*
|
|
1026
|
+
* @returns Корневой путь (по умолчанию — API_PATH).
|
|
1027
|
+
*/
|
|
1028
|
+
// ! Обработчик пропы api из объекта описания запроса
|
|
1029
|
+
// ? Планируется, что метод будет перегружаться на экземпляре,
|
|
1030
|
+
// ? т.к. на разных проектах могут быть разные интерпретации пропы api
|
|
1031
|
+
// ? Метод не планировался как асинхронный,
|
|
1032
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
943
1033
|
async getRootPath() {
|
|
944
1034
|
return this.API_PATH;
|
|
945
1035
|
}
|
|
946
|
-
|
|
947
|
-
|
|
1036
|
+
/**
|
|
1037
|
+
* Извлекает тело ответа в нужном виде (json/blob/text/arrayBuffer/formData) либо по content-type.
|
|
1038
|
+
*
|
|
1039
|
+
* @param response - объект Response (иначе значение возвращается как есть).
|
|
1040
|
+
* @param getBodyAs - желаемый способ извлечения тела.
|
|
1041
|
+
* @returns Промис с телом ответа (или исходным значением / null при ошибке).
|
|
1042
|
+
*/
|
|
1043
|
+
// ? Планируется, что метод будет использоваться неизменно, однако технически его можно перегрузить на экземпляре
|
|
1044
|
+
// ? Метод планировался как асинхронный
|
|
948
1045
|
async getResponseBody(response, getBodyAs) {
|
|
949
1046
|
if (!(response instanceof Response)) return response;
|
|
950
1047
|
const contentType = response.headers.get("content-type");
|
|
951
1048
|
if (!contentType) return "";
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1049
|
+
const bodyReaders = {
|
|
1050
|
+
json: (r) => r.json(),
|
|
1051
|
+
blob: (r) => r.blob(),
|
|
1052
|
+
text: (r) => r.text(),
|
|
1053
|
+
arrayBuffer: (r) => r.arrayBuffer(),
|
|
1054
|
+
formData: (r) => r.formData()
|
|
1055
|
+
};
|
|
1056
|
+
const isBodyKey = (key) => key in bodyReaders;
|
|
1057
|
+
const reader = typeof getBodyAs === "string" && isBodyKey(getBodyAs) ? bodyReaders[getBodyAs] : contentType.includes("text/csv") ? bodyReaders.blob : contentType.includes("json") ? bodyReaders.json : bodyReaders.text;
|
|
961
1058
|
try {
|
|
962
|
-
return await
|
|
1059
|
+
return await reader(response);
|
|
963
1060
|
} catch {
|
|
964
1061
|
console.log("Failed to extract the body");
|
|
965
1062
|
return null;
|
|
966
1063
|
}
|
|
967
1064
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1065
|
+
/**
|
|
1066
|
+
* Формирует структуру ошибки из тела ответа (точка расширения под формат бэкенда).
|
|
1067
|
+
*
|
|
1068
|
+
* @param res - уже извлечённое тело ответа.
|
|
1069
|
+
* @returns Структура сообщения об ошибке.
|
|
1070
|
+
*/
|
|
1071
|
+
// ! Обработчик структуры для ошибки (не рендер месседжа, а имеено формирование ошибки),
|
|
1072
|
+
// ? Планируется, что метод будет перегружаться на экземпляре,
|
|
1073
|
+
// ? т.к. на разных проектах могут быть разные структуры тела ответа для ошибки
|
|
1074
|
+
// ? Метод не планировался как асинхронный,
|
|
1075
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
1076
|
+
// ? res - уже тело ответа
|
|
974
1077
|
async getErrorMessage(res) {
|
|
975
1078
|
return res;
|
|
976
1079
|
}
|
|
977
|
-
|
|
978
|
-
|
|
1080
|
+
/**
|
|
1081
|
+
* Проверяет код ответа и (если задан sendMessage) информирует пользователя об успехе/ошибке.
|
|
1082
|
+
*
|
|
1083
|
+
* @param res - объект Response (или совместимый с полем `ok`).
|
|
1084
|
+
* @param settings - сообщения и настройки тостов для данного запроса.
|
|
1085
|
+
* @returns Исходный `res` (метод не меняет ответ, только сигналит сообщением).
|
|
1086
|
+
*/
|
|
1087
|
+
// ? Планируется, что метод будет использоваться неизменно, однако технически его можно перегрузить на экземпляре
|
|
1088
|
+
// ? Метод планировался как асинхронный
|
|
979
1089
|
async checkResponseCode(res, settings) {
|
|
980
|
-
|
|
1090
|
+
const send = this.sendMessage;
|
|
1091
|
+
if (typeof send !== "function") return res;
|
|
981
1092
|
const { successMess, errorMess } = settings || {};
|
|
982
|
-
const
|
|
1093
|
+
const isOk = getIsOnlyAnObject(res) ? Boolean(res.ok) : false;
|
|
1094
|
+
const message = isOk ? successMess || this.DEFAULT_SUCCESS_MESSAGE : errorMess || await this.getErrorMessage(await this.getResponseBody(await getResponseClone(res)));
|
|
983
1095
|
try {
|
|
984
|
-
|
|
985
|
-
} catch
|
|
1096
|
+
send(message, settings, await getResponseClone(res));
|
|
1097
|
+
} catch {
|
|
986
1098
|
}
|
|
987
1099
|
return res;
|
|
988
1100
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1101
|
+
/**
|
|
1102
|
+
* Структуры, которые будут использоваться для КАЖДОГО запроса, сделанного экземпляром RESTAPI.
|
|
1103
|
+
*
|
|
1104
|
+
* @returns Объект `{ headers, queryParameters, options }` (по умолчанию пустой).
|
|
1105
|
+
*/
|
|
1106
|
+
// ? Суть метода:
|
|
1107
|
+
// ? передать из вне структуры, которые будут использоваться для КАЖДОГО запроса сделанного экземпляром RESTAPI
|
|
1108
|
+
// ! Данные затрут прочие настройки КРОМЕ данных по логике авторизации
|
|
1109
|
+
// ? Планируется, что метод будет перегружаться на экземпляре
|
|
1110
|
+
// ? Метод не планировался как асинхронный,
|
|
1111
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
995
1112
|
async addAsCommon() {
|
|
996
1113
|
return {};
|
|
997
1114
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1115
|
+
/**
|
|
1116
|
+
* Общий обработчик query-параметров (точка расширения, напр. кодирование/приведение к массиву).
|
|
1117
|
+
*
|
|
1118
|
+
* @param queryParams - входные query-параметры.
|
|
1119
|
+
* @returns Обработанные query-параметры (по умолчанию — без изменений).
|
|
1120
|
+
*/
|
|
1121
|
+
// ! Обработчик квери-параметров для общего процессинга,
|
|
1122
|
+
// ! Например для кодирования decodeURIComponent или/и приведения в формат массива
|
|
1123
|
+
// ? Планируется, что метод будет перегружаться на экземпляре,
|
|
1124
|
+
// ? т.к. на разных проектах могут быть разные договоренности по форматам
|
|
1125
|
+
// ? Метод не планировался как асинхронный,
|
|
1126
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
1004
1127
|
async processQueryParams(queryParams) {
|
|
1005
1128
|
return queryParams;
|
|
1006
1129
|
}
|
|
1007
1130
|
};
|
|
1008
1131
|
var ApiUtils_default = ApiUtils;
|
|
1009
1132
|
|
|
1010
|
-
// src/Classes/RESTAPI/partials/
|
|
1133
|
+
// src/Classes/RESTAPI/partials/sse.ts
|
|
1134
|
+
function parseSSEEvent(block) {
|
|
1135
|
+
if (typeof block !== "string") return null;
|
|
1136
|
+
const event = { event: "message", data: "", id: void 0, retry: void 0 };
|
|
1137
|
+
const dataLines = [];
|
|
1138
|
+
let hasField = false;
|
|
1139
|
+
block.split("\n").forEach((line) => {
|
|
1140
|
+
if (line === "" || line[0] === ":") return;
|
|
1141
|
+
const colonIdx = line.indexOf(":");
|
|
1142
|
+
const field = colonIdx === -1 ? line : line.slice(0, colonIdx);
|
|
1143
|
+
let value = colonIdx === -1 ? "" : line.slice(colonIdx + 1);
|
|
1144
|
+
if (value[0] === " ") value = value.slice(1);
|
|
1145
|
+
switch (field) {
|
|
1146
|
+
case "event":
|
|
1147
|
+
event.event = value;
|
|
1148
|
+
hasField = true;
|
|
1149
|
+
break;
|
|
1150
|
+
case "data":
|
|
1151
|
+
dataLines.push(value);
|
|
1152
|
+
hasField = true;
|
|
1153
|
+
break;
|
|
1154
|
+
case "id":
|
|
1155
|
+
event.id = value;
|
|
1156
|
+
hasField = true;
|
|
1157
|
+
break;
|
|
1158
|
+
case "retry":
|
|
1159
|
+
if (/^\d+$/.test(value)) {
|
|
1160
|
+
event.retry = Number(value);
|
|
1161
|
+
hasField = true;
|
|
1162
|
+
}
|
|
1163
|
+
break;
|
|
1164
|
+
default:
|
|
1165
|
+
break;
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
if (!hasField) return null;
|
|
1169
|
+
event.data = dataLines.join("\n");
|
|
1170
|
+
return event;
|
|
1171
|
+
}
|
|
1172
|
+
function safeCall(fn, ...args) {
|
|
1173
|
+
if (typeof fn !== "function") return;
|
|
1174
|
+
try {
|
|
1175
|
+
fn(...args);
|
|
1176
|
+
} catch {
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
async function readSSE(response, { onEvent, onChunk, handlers, parseJson } = {}) {
|
|
1180
|
+
const events = [];
|
|
1181
|
+
const stream = response.body;
|
|
1182
|
+
if (!stream) return events;
|
|
1183
|
+
const reader = stream.getReader();
|
|
1184
|
+
const decoder = new TextDecoder("utf-8");
|
|
1185
|
+
let buffer = "";
|
|
1186
|
+
let pendingCR = "";
|
|
1187
|
+
const normalize = (chunk) => chunk.replace(/\r\n|\r/g, "\n");
|
|
1188
|
+
const flush = (rawBlock) => {
|
|
1189
|
+
const event = parseSSEEvent(rawBlock);
|
|
1190
|
+
if (!event) return;
|
|
1191
|
+
if (parseJson && typeof event.data === "string" && event.data !== "") {
|
|
1192
|
+
try {
|
|
1193
|
+
event.data = JSON.parse(event.data);
|
|
1194
|
+
} catch {
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
events.push(event);
|
|
1198
|
+
safeCall(onEvent, event);
|
|
1199
|
+
safeCall(onChunk, event.data, event);
|
|
1200
|
+
if (handlers) safeCall(handlers[event.event], event.data, event);
|
|
1201
|
+
};
|
|
1202
|
+
try {
|
|
1203
|
+
while (true) {
|
|
1204
|
+
const { done, value } = await reader.read();
|
|
1205
|
+
if (done) break;
|
|
1206
|
+
let chunk = pendingCR + decoder.decode(value, { stream: true });
|
|
1207
|
+
pendingCR = "";
|
|
1208
|
+
if (chunk.endsWith("\r")) {
|
|
1209
|
+
pendingCR = "\r";
|
|
1210
|
+
chunk = chunk.slice(0, -1);
|
|
1211
|
+
}
|
|
1212
|
+
buffer += normalize(chunk);
|
|
1213
|
+
let sepIdx;
|
|
1214
|
+
while ((sepIdx = buffer.indexOf("\n\n")) !== -1) {
|
|
1215
|
+
const rawBlock = buffer.slice(0, sepIdx);
|
|
1216
|
+
buffer = buffer.slice(sepIdx + 2);
|
|
1217
|
+
flush(rawBlock);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
buffer += normalize(pendingCR + decoder.decode());
|
|
1221
|
+
buffer = buffer.replace(/\n+$/g, "");
|
|
1222
|
+
if (buffer !== "") flush(buffer);
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
const name = error && typeof error === "object" && "name" in error ? error.name : void 0;
|
|
1225
|
+
if (name !== "AbortError") throw error;
|
|
1226
|
+
} finally {
|
|
1227
|
+
try {
|
|
1228
|
+
reader.releaseLock?.();
|
|
1229
|
+
} catch {
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
return events;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// src/Classes/RESTAPI/partials/ApiRequestCreators.ts
|
|
1236
|
+
function isStreamResponse(value) {
|
|
1237
|
+
if (!getIsOnlyAnObject(value) || !value.ok) return false;
|
|
1238
|
+
const body = value.body;
|
|
1239
|
+
return typeof body === "object" && body !== null && "getReader" in body && typeof body.getReader === "function";
|
|
1240
|
+
}
|
|
1011
1241
|
var PREFIX_OF_CLASS_UTILS = "createRequest_";
|
|
1012
1242
|
var ApiRequestCreators = class extends ApiUtils_default {
|
|
1013
1243
|
constructor(settings) {
|
|
@@ -1015,8 +1245,14 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1015
1245
|
const { requestsCreators } = settings || {};
|
|
1016
1246
|
if (getIsOnlyAnObject(requestsCreators)) addCustomMethods.call(this, requestsCreators, PREFIX_OF_CLASS_UTILS);
|
|
1017
1247
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1248
|
+
/**
|
|
1249
|
+
* Крейтер типа `toJson`: пользовательский callback получит тело ответа (Response.json()).
|
|
1250
|
+
*
|
|
1251
|
+
* @param props - объект описания запроса.
|
|
1252
|
+
* @param variant - вариант обработки splitProperties.
|
|
1253
|
+
*/
|
|
1254
|
+
// ? При типе toJson пользовательский callback на вход получит тело ответа реализованное методом Response.json()
|
|
1255
|
+
// ? независимо от насторойки isGetBody
|
|
1020
1256
|
async createRequest_toJson(props, variant) {
|
|
1021
1257
|
const safelyProps = omitKeys(props, ["getBodyAs"]);
|
|
1022
1258
|
return this.splitProperties(
|
|
@@ -1025,15 +1261,21 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1025
1261
|
isGetBody: false,
|
|
1026
1262
|
callback: async (res) => {
|
|
1027
1263
|
const output = await this.getResponseBody(res, "json");
|
|
1028
|
-
return await (
|
|
1264
|
+
return await (props.callback?.(output) ?? output);
|
|
1029
1265
|
}
|
|
1030
1266
|
},
|
|
1031
1267
|
variant
|
|
1032
1268
|
);
|
|
1033
1269
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1270
|
+
/**
|
|
1271
|
+
* Крейтер типа `toJsonAdvanced`: callback получит структуру `{ response, result }`.
|
|
1272
|
+
*
|
|
1273
|
+
* @param props - объект описания запроса.
|
|
1274
|
+
* @param variant - вариант обработки splitProperties.
|
|
1275
|
+
*/
|
|
1276
|
+
// ? При типе toJsonAdvanced пользовательский callback на вход получит структуру { response, result },
|
|
1277
|
+
// ? где response - объект Response, result - тело ответа реализованное методом Response.json()
|
|
1278
|
+
// ? независимо от насторойки isGetBody
|
|
1037
1279
|
async createRequest_toJsonAdvanced(props, variant) {
|
|
1038
1280
|
const safelyProps = omitKeys(props, ["getBodyAs"]);
|
|
1039
1281
|
return this.splitProperties(
|
|
@@ -1045,14 +1287,20 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1045
1287
|
response: res,
|
|
1046
1288
|
result: await this.getResponseBody(await getResponseClone(res), "json")
|
|
1047
1289
|
};
|
|
1048
|
-
return await (
|
|
1290
|
+
return await (props.callback?.(output) ?? output);
|
|
1049
1291
|
}
|
|
1050
1292
|
},
|
|
1051
1293
|
variant
|
|
1052
1294
|
);
|
|
1053
1295
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1296
|
+
/**
|
|
1297
|
+
* Крейтер типа `blob`: callback получит тело ответа (Response.blob()).
|
|
1298
|
+
*
|
|
1299
|
+
* @param props - объект описания запроса.
|
|
1300
|
+
* @param variant - вариант обработки splitProperties.
|
|
1301
|
+
*/
|
|
1302
|
+
// ? При типе blob пользовательский callback на вход получит тело ответа реализованное методом Response.blob(),
|
|
1303
|
+
// ? независимо от насторойки isGetBody
|
|
1056
1304
|
async createRequest_blob(props, variant) {
|
|
1057
1305
|
const safelyProps = omitKeys(props, ["getBodyAs"]);
|
|
1058
1306
|
return this.splitProperties(
|
|
@@ -1061,14 +1309,67 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1061
1309
|
isGetBody: false,
|
|
1062
1310
|
callback: async (res) => {
|
|
1063
1311
|
const output = await this.getResponseBody(await getResponseClone(res), "blob");
|
|
1064
|
-
return await (
|
|
1312
|
+
return await (props.callback?.(output) ?? output);
|
|
1065
1313
|
}
|
|
1066
1314
|
},
|
|
1067
1315
|
variant
|
|
1068
1316
|
);
|
|
1069
1317
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1318
|
+
/**
|
|
1319
|
+
* Крейтер типа `sse`: обрабатывает ответ как поток Server-Sent Events (text/event-stream).
|
|
1320
|
+
*
|
|
1321
|
+
* Дополнительные пропы объекта описания запроса: `onEvent`, `onChunk`, `handlers`, `parseJson`.
|
|
1322
|
+
* По умолчанию добавляется заголовок `Accept: text/event-stream`. Метод doRequest резолвится
|
|
1323
|
+
* массивом всех событий ПОСЛЕ закрытия потока; отмена — методом `.abort()` возвращённого промиса.
|
|
1324
|
+
*
|
|
1325
|
+
* @param props - объект описания запроса (плюс onEvent/onChunk/handlers/parseJson).
|
|
1326
|
+
* @param variant - вариант обработки splitProperties.
|
|
1327
|
+
*/
|
|
1328
|
+
// ? При типе sse запрос обрабатывается как поток Server-Sent Events (text/event-stream).
|
|
1329
|
+
// ? Дополнительные пропы объекта описания запроса:
|
|
1330
|
+
// ? - onEvent(event) — вызывается на каждое распарсенное событие { event, data, id, retry };
|
|
1331
|
+
// ? - onChunk(data, event) — вызывается на полезную нагрузку (поле data) каждого события;
|
|
1332
|
+
// ? - handlers — карта { имяСобытия: cb } для типизированной обработки по полю event
|
|
1333
|
+
// ? (например { delta, status, done }); cb получает (data, event);
|
|
1334
|
+
// ? - parseJson — если true, поле data каждого события прогоняется через JSON.parse.
|
|
1335
|
+
// ? По умолчанию добавляется заголовок Accept: text/event-stream (его можно переопределить через headers).
|
|
1336
|
+
// ? Пользовательский callback (если передан) на вход получит итоговый массив всех событий.
|
|
1337
|
+
// ? Метод doRequest резолвится массивом всех событий ПОСЛЕ закрытия потока;
|
|
1338
|
+
// ? отмена потока выполняется методом .abort() возвращённого промиса (через встроенный AbortController).
|
|
1339
|
+
async createRequest_sse(props, variant) {
|
|
1340
|
+
const safelyProps = omitKeys(props, ["getBodyAs", "onChunk", "onEvent", "handlers", "parseJson"]);
|
|
1341
|
+
const { onChunk, onEvent, handlers, parseJson } = props;
|
|
1342
|
+
const sseOptions = {
|
|
1343
|
+
onChunk: typeof onChunk === "function" ? (data, event) => onChunk(data, event) : void 0,
|
|
1344
|
+
onEvent: typeof onEvent === "function" ? (event) => onEvent(event) : void 0,
|
|
1345
|
+
parseJson: Boolean(parseJson),
|
|
1346
|
+
handlers: getIsOnlyAnObject(handlers) ? Object.keys(handlers).reduce((acc, key) => {
|
|
1347
|
+
const fn = handlers[key];
|
|
1348
|
+
acc[key] = typeof fn === "function" ? (data, event) => fn(data, event) : void 0;
|
|
1349
|
+
return acc;
|
|
1350
|
+
}, {}) : void 0
|
|
1351
|
+
};
|
|
1352
|
+
return this.splitProperties(
|
|
1353
|
+
{
|
|
1354
|
+
...safelyProps,
|
|
1355
|
+
headers: { Accept: "text/event-stream", ...getIsOnlyAnObject(safelyProps.headers) ? safelyProps.headers : {} },
|
|
1356
|
+
isGetBody: false,
|
|
1357
|
+
callback: async (res) => {
|
|
1358
|
+
const output = isStreamResponse(res) ? await readSSE(res, sseOptions) : res;
|
|
1359
|
+
return await (props.callback?.(output) ?? output);
|
|
1360
|
+
}
|
|
1361
|
+
},
|
|
1362
|
+
variant
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Крейтер типа `testBadResponse`: callback получит синтетический Response со статусом 401.
|
|
1367
|
+
*
|
|
1368
|
+
* @param props - объект описания запроса.
|
|
1369
|
+
* @param variant - вариант обработки splitProperties.
|
|
1370
|
+
*/
|
|
1371
|
+
// ? При типе testBadResponse пользовательский callback на вход получит объект Response в 401-м статусе
|
|
1372
|
+
// ? независимо независимо вообще ни от чего
|
|
1072
1373
|
async createRequest_testBadResponse(props, variant) {
|
|
1073
1374
|
return this.splitProperties(
|
|
1074
1375
|
{
|
|
@@ -1088,17 +1389,33 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1088
1389
|
variant
|
|
1089
1390
|
);
|
|
1090
1391
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1392
|
+
/**
|
|
1393
|
+
* Крейтер по умолчанию: callback получит объект Response (или тело ответа при isGetBody: 'first').
|
|
1394
|
+
*
|
|
1395
|
+
* @param props - объект описания запроса.
|
|
1396
|
+
* @param variant - вариант обработки splitProperties.
|
|
1397
|
+
*/
|
|
1398
|
+
// ? По умолчанию пользовательский callback на вход получит
|
|
1399
|
+
// ? - либо объект Response
|
|
1400
|
+
// ? - либо тело ответа (в случае isGetBody: 'first') полученное методом getResponseBody (смотри класс ApiUtils)
|
|
1094
1401
|
async createRequest_default(props, variant) {
|
|
1095
1402
|
return this.splitProperties(props, variant);
|
|
1096
1403
|
}
|
|
1097
1404
|
};
|
|
1098
1405
|
var ApiRequestCreators_default = ApiRequestCreators;
|
|
1099
1406
|
|
|
1100
|
-
// src/Classes/RESTAPI/partials/ApiBase.
|
|
1407
|
+
// src/Classes/RESTAPI/partials/ApiBase.ts
|
|
1101
1408
|
var ApiBase = class extends ApiRequestCreators_default {
|
|
1409
|
+
/** Текст ошибки невалидных данных запроса. */
|
|
1410
|
+
BAD_REQUEST_DATA_TEXT;
|
|
1411
|
+
/** Текст сообщения об успехе по умолчанию. */
|
|
1412
|
+
DEFAULT_SUCCESS_MESSAGE;
|
|
1413
|
+
/** Текст сообщения об ошибке по умолчанию. */
|
|
1414
|
+
DEFAULT_ERROR_MESSAGE;
|
|
1415
|
+
/** Текст сообщения об отсутствии сети. */
|
|
1416
|
+
NO_INET;
|
|
1417
|
+
/** Коды ответа, по которым запрос считается отклонённым. */
|
|
1418
|
+
REJECT_CODES;
|
|
1102
1419
|
constructor(settings) {
|
|
1103
1420
|
super(settings);
|
|
1104
1421
|
const {
|
|
@@ -1127,49 +1444,76 @@ var ApiBase = class extends ApiRequestCreators_default {
|
|
|
1127
1444
|
};
|
|
1128
1445
|
var ApiBase_default = ApiBase;
|
|
1129
1446
|
|
|
1130
|
-
// src/Classes/RESTAPI/partials/CredentialsProcessing.
|
|
1447
|
+
// src/Classes/RESTAPI/partials/CredentialsProcessing.ts
|
|
1131
1448
|
function decodeJWT(token) {
|
|
1132
1449
|
try {
|
|
1133
|
-
const payload = token.split(".")[1];
|
|
1134
|
-
|
|
1135
|
-
|
|
1450
|
+
const payload = token.split(".")[1] ?? "";
|
|
1451
|
+
const decoded = JSON.parse(atob(payload));
|
|
1452
|
+
return getIsOnlyAnObject(decoded) ? decoded : null;
|
|
1453
|
+
} catch {
|
|
1136
1454
|
return null;
|
|
1137
1455
|
}
|
|
1138
1456
|
}
|
|
1139
1457
|
var CredentialsProcessing = class {
|
|
1458
|
+
/** Включён ли флоу рефреша токенов. */
|
|
1459
|
+
isUseRefreshTokensPropcessing = false;
|
|
1460
|
+
/** Учётные данные по умолчанию (пустые). */
|
|
1461
|
+
DEFAULT_CREDENTIALS = {};
|
|
1462
|
+
/** Внешний метод получения учётных данных. */
|
|
1463
|
+
getCredentialsByOuter;
|
|
1464
|
+
/** Внешний метод формирования заголовков авторизации по токену. */
|
|
1465
|
+
getHeadersForAuthorize;
|
|
1466
|
+
/** Необязательный преобразователь учётных данных после getCredentials. */
|
|
1467
|
+
importCredentials;
|
|
1468
|
+
/** Необязательный метод сохранения учётных данных (обязателен для флоу рефреша). */
|
|
1469
|
+
saveCredentials;
|
|
1470
|
+
/** Внешний метод рефреша учётных данных. */
|
|
1471
|
+
refreshCredentialsByOuter;
|
|
1472
|
+
/** Полный путь до эндпоинта рефреша токена. */
|
|
1473
|
+
REFRESH_TOKEN_PATH;
|
|
1474
|
+
/** Коды ответа, по которым триггерится попытка рефреша. */
|
|
1475
|
+
CODES_USING_THE_REFRESH_ATTEMPT;
|
|
1476
|
+
/** Ключ флага «рефреш начат» в localStorage. */
|
|
1477
|
+
REFRESH_TOKEN_FLAG = "refreshTokenFlag";
|
|
1478
|
+
/** Интервал опроса флага обновления токена, мс. */
|
|
1479
|
+
INTERVAL_FOR_CHECKING_TOKEN_UPDATE = 50;
|
|
1480
|
+
/** Колбэк, вызываемый после неудачного рефреша. */
|
|
1481
|
+
callbackAfterRejectRefresh;
|
|
1482
|
+
/** Доступ к верхнему контексту RESTAPI (навешивается из конструктора RESTAPI). */
|
|
1483
|
+
getRESTAPIContext;
|
|
1140
1484
|
constructor(settings) {
|
|
1141
1485
|
const { credentialsProcessing } = settings;
|
|
1142
1486
|
const {
|
|
1143
|
-
|
|
1144
|
-
|
|
1487
|
+
// ? Для корректной работы установки токенов в запросы от API
|
|
1488
|
+
// ? нужно передавать методы getCredentials и getHeadersForAuthorize
|
|
1145
1489
|
getCredentials,
|
|
1146
1490
|
getHeadersForAuthorize,
|
|
1147
|
-
|
|
1148
|
-
|
|
1491
|
+
// ? На вход получит токен, должна вернуть объект для коструктора Headers
|
|
1492
|
+
// ? Так же опционально можно передавать
|
|
1149
1493
|
importCredentials,
|
|
1150
|
-
|
|
1494
|
+
// ? если он передается, то он будет применяться к выводу от вызова getCredentials
|
|
1151
1495
|
saveCredentials,
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1496
|
+
// ? можно будет найти в объекте credentialsProcessing, чтобы использовать кастомными методами
|
|
1497
|
+
// ! Либо вызов getCredentials, либо цепочка вызовов importCredentials(getCredentials())
|
|
1498
|
+
// ! должна возвращать требуемую классом структуру
|
|
1499
|
+
// ! Класс требует структуры
|
|
1500
|
+
// ! - { token }, если флоу рефреш токена НЕ используется
|
|
1501
|
+
// ! - { token, refreshToken, expires }, если используется флоу рефреш токена
|
|
1158
1502
|
// *********
|
|
1159
|
-
|
|
1503
|
+
// ? Подключает флоу рефреша токенов
|
|
1160
1504
|
isUseRefreshTokensPropcessing = false,
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1505
|
+
// ! Для корректной работы флоу рефреша токенов передача метода saveCredentials становится ОБЯЗАТЕЛЬНОЙ
|
|
1506
|
+
// ? Так же для корректной работы флоу рефреша токенов нужно
|
|
1507
|
+
// ? - либо
|
|
1164
1508
|
refreshCredentials,
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1509
|
+
// ! метод должен возвращать такую же структуру как и метод getCredentials,
|
|
1510
|
+
// ? на вход получит текущие креды, к выходу будет применен importCredentials, если этот метод передавался
|
|
1511
|
+
// ? - либо
|
|
1168
1512
|
REFRESH_TOKEN_PATH,
|
|
1169
|
-
|
|
1513
|
+
// ! REFRESH_TOKEN_PATH передается ПОЛНОСТЬЮ (глобальная адресация)!
|
|
1170
1514
|
CODES_USING_THE_REFRESH_ATTEMPT,
|
|
1171
|
-
|
|
1172
|
-
|
|
1515
|
+
// ? указывает по каким кодам ответа триггериться рефреш, массив чисел
|
|
1516
|
+
// ? Опционально
|
|
1173
1517
|
REFRESH_TOKEN_FLAG = "refreshTokenFlag",
|
|
1174
1518
|
INTERVAL_FOR_CHECKING_TOKEN_UPDATE = 50,
|
|
1175
1519
|
// ms
|
|
@@ -1177,40 +1521,44 @@ var CredentialsProcessing = class {
|
|
|
1177
1521
|
} = credentialsProcessing || {};
|
|
1178
1522
|
if (typeof getCredentials !== "function") throw new Error("No getCredentials method [CredentialsProcessing]");
|
|
1179
1523
|
if (typeof getHeadersForAuthorize !== "function") {
|
|
1180
|
-
throw new
|
|
1524
|
+
throw new TypeError("No getHeadersForAuthorize method [CredentialsProcessing]");
|
|
1181
1525
|
}
|
|
1182
1526
|
if (importCredentials && typeof importCredentials !== "function") {
|
|
1183
1527
|
throw new Error("Bad importCredentials method [CredentialsProcessing]");
|
|
1184
1528
|
}
|
|
1185
|
-
this.isUseRefreshTokensPropcessing = isUseRefreshTokensPropcessing;
|
|
1529
|
+
this.isUseRefreshTokensPropcessing = Boolean(isUseRefreshTokensPropcessing);
|
|
1186
1530
|
this.DEFAULT_CREDENTIALS = {};
|
|
1187
|
-
this.getCredentialsByOuter = getCredentials;
|
|
1188
|
-
this.getHeadersForAuthorize =
|
|
1189
|
-
|
|
1531
|
+
this.getCredentialsByOuter = () => getCredentials();
|
|
1532
|
+
this.getHeadersForAuthorize = (token) => {
|
|
1533
|
+
const result = getHeadersForAuthorize(token);
|
|
1534
|
+
return getIsOnlyAnObject(result) ? result : {};
|
|
1535
|
+
};
|
|
1536
|
+
if (typeof importCredentials === "function") this.importCredentials = (cred) => importCredentials(cred);
|
|
1190
1537
|
if (saveCredentials || isUseRefreshTokensPropcessing) {
|
|
1191
1538
|
if (typeof saveCredentials !== "function") throw new Error("No saveCredentials method [CredentialsProcessing]");
|
|
1192
|
-
else this.saveCredentials = saveCredentials;
|
|
1539
|
+
else this.saveCredentials = (cred) => saveCredentials(cred);
|
|
1193
1540
|
}
|
|
1194
1541
|
if (isUseRefreshTokensPropcessing) {
|
|
1195
|
-
if (typeof refreshCredentials === "function")
|
|
1196
|
-
|
|
1542
|
+
if (typeof refreshCredentials === "function") {
|
|
1543
|
+
this.refreshCredentialsByOuter = (cred) => refreshCredentials(cred);
|
|
1544
|
+
} else {
|
|
1197
1545
|
if (typeof this.refreshCredentialsByOuter === "function" && typeof REFRESH_TOKEN_PATH !== "string") {
|
|
1198
|
-
throw new
|
|
1546
|
+
throw new TypeError("No REFRESH_TOKEN_PATH [CredentialsProcessing]");
|
|
1199
1547
|
}
|
|
1200
|
-
this.REFRESH_TOKEN_PATH = REFRESH_TOKEN_PATH;
|
|
1548
|
+
this.REFRESH_TOKEN_PATH = typeof REFRESH_TOKEN_PATH === "string" ? REFRESH_TOKEN_PATH : void 0;
|
|
1201
1549
|
}
|
|
1202
1550
|
if (!Array.isArray(CODES_USING_THE_REFRESH_ATTEMPT)) {
|
|
1203
|
-
throw new
|
|
1551
|
+
throw new TypeError("No CODES_USING_THE_REFRESH_ATTEMPT [CredentialsProcessing]");
|
|
1204
1552
|
}
|
|
1205
1553
|
if (!CODES_USING_THE_REFRESH_ATTEMPT.every((i) => typeof i === "number")) {
|
|
1206
1554
|
throw new Error("Invalid format of CODES_USING_THE_REFRESH_ATTEMPT elements [CredentialsProcessing]");
|
|
1207
1555
|
}
|
|
1208
1556
|
if (typeof REFRESH_TOKEN_FLAG !== "string") throw new Error("Bad REFRESH_TOKEN_FLAG [CredentialsProcessing]");
|
|
1209
1557
|
if (typeof INTERVAL_FOR_CHECKING_TOKEN_UPDATE !== "number") {
|
|
1210
|
-
throw new
|
|
1558
|
+
throw new TypeError("Bad INTERVAL_FOR_CHECKING_TOKEN_UPDATE [CredentialsProcessing]");
|
|
1211
1559
|
}
|
|
1212
1560
|
if (typeof INTERVAL_FOR_CHECKING_TOKEN_UPDATE !== "number") {
|
|
1213
|
-
throw new
|
|
1561
|
+
throw new TypeError("Bad INTERVAL_FOR_CHECKING_TOKEN_UPDATE [CredentialsProcessing]");
|
|
1214
1562
|
}
|
|
1215
1563
|
if (callbackAfterRejectRefresh && typeof callbackAfterRejectRefresh !== "function") {
|
|
1216
1564
|
throw new Error("Bad INTERVAL_FOR_CHECKING_TOKEN_UPDATE [CredentialsProcessing]");
|
|
@@ -1218,23 +1566,33 @@ var CredentialsProcessing = class {
|
|
|
1218
1566
|
this.CODES_USING_THE_REFRESH_ATTEMPT = CODES_USING_THE_REFRESH_ATTEMPT;
|
|
1219
1567
|
this.REFRESH_TOKEN_FLAG = REFRESH_TOKEN_FLAG;
|
|
1220
1568
|
this.INTERVAL_FOR_CHECKING_TOKEN_UPDATE = INTERVAL_FOR_CHECKING_TOKEN_UPDATE;
|
|
1221
|
-
if (callbackAfterRejectRefresh) this.callbackAfterRejectRefresh = callbackAfterRejectRefresh;
|
|
1569
|
+
if (typeof callbackAfterRejectRefresh === "function") this.callbackAfterRejectRefresh = () => callbackAfterRejectRefresh();
|
|
1222
1570
|
}
|
|
1223
1571
|
}
|
|
1572
|
+
/** Возвращает значение флага «рефреш начат» из localStorage. */
|
|
1224
1573
|
getIsTokenStartRefresh() {
|
|
1225
1574
|
return localStorage.getItem(this.REFRESH_TOKEN_FLAG);
|
|
1226
1575
|
}
|
|
1576
|
+
/** Выставляет флаг «рефреш начат» в localStorage. */
|
|
1227
1577
|
setIsTokenStartRefresh() {
|
|
1228
|
-
localStorage.setItem(this.REFRESH_TOKEN_FLAG, true);
|
|
1578
|
+
localStorage.setItem(this.REFRESH_TOKEN_FLAG, String(true));
|
|
1229
1579
|
}
|
|
1580
|
+
/** Снимает флаг «рефреш начат» из localStorage. */
|
|
1230
1581
|
removeIsTokenStartRefresh() {
|
|
1231
1582
|
localStorage.removeItem(this.REFRESH_TOKEN_FLAG);
|
|
1232
1583
|
}
|
|
1584
|
+
/**
|
|
1585
|
+
* Возвращает текущие учётные данные (с учётом importCredentials и проверки истечения JWT).
|
|
1586
|
+
*
|
|
1587
|
+
* @param isCatchCallbackProcess - флаг процесса обработки ошибки (отключает проверку истечения).
|
|
1588
|
+
* @param callback - необязательный колбэк, получающий итоговые учётные данные.
|
|
1589
|
+
* @returns Промис с учётными данными.
|
|
1590
|
+
*/
|
|
1233
1591
|
async getCredentials(isCatchCallbackProcess, callback) {
|
|
1234
1592
|
let credentials = await this.getCredentialsByOuter();
|
|
1235
1593
|
if (typeof this.importCredentials === "function") credentials = await this.importCredentials(credentials);
|
|
1236
|
-
|
|
1237
|
-
const token =
|
|
1594
|
+
const credObj = getIsOnlyAnObject(credentials) ? credentials : {};
|
|
1595
|
+
const token = credObj.token || null;
|
|
1238
1596
|
if (token && !isCatchCallbackProcess) {
|
|
1239
1597
|
let decoded;
|
|
1240
1598
|
try {
|
|
@@ -1243,11 +1601,18 @@ var CredentialsProcessing = class {
|
|
|
1243
1601
|
decoded = null;
|
|
1244
1602
|
}
|
|
1245
1603
|
const currentTime = Date.now() / 1e3;
|
|
1246
|
-
if (decoded !== null && Number(decoded.exp) < currentTime)
|
|
1604
|
+
if (decoded !== null && Number(decoded.exp) < currentTime) credObj.isNeedRefresh = true;
|
|
1247
1605
|
}
|
|
1248
|
-
if (callback) await callback({ ...
|
|
1249
|
-
return { ...
|
|
1250
|
-
}
|
|
1606
|
+
if (callback) await callback({ ...credObj, isCatchCallbackProcess });
|
|
1607
|
+
return { ...credObj, isCatchCallbackProcess };
|
|
1608
|
+
}
|
|
1609
|
+
/**
|
|
1610
|
+
* Выполняет рефреш учётных данных (внешним методом либо дефолтным OAuth-флоу).
|
|
1611
|
+
*
|
|
1612
|
+
* @param currentCredentials - текущие учётные данные.
|
|
1613
|
+
* @param callback - необязательный колбэк сохранения новых учётных данных.
|
|
1614
|
+
* @returns Промис с новыми учётными данными.
|
|
1615
|
+
*/
|
|
1251
1616
|
async refreshCredentials(currentCredentials, callback) {
|
|
1252
1617
|
const CONTEXT = this;
|
|
1253
1618
|
async function finalize(cred) {
|
|
@@ -1260,11 +1625,10 @@ var CredentialsProcessing = class {
|
|
|
1260
1625
|
if (!currentCredentials?.token || !currentCredentials?.refreshToken) return finalize(CONTEXT.DEFAULT_CREDENTIALS);
|
|
1261
1626
|
async function refreshCredentialsByDefault() {
|
|
1262
1627
|
const { token, refreshToken } = currentCredentials;
|
|
1263
|
-
const headers = new Headers();
|
|
1264
|
-
headers.append(...Object.entries(CONTEXT.getHeadersForAuthorize(token)));
|
|
1628
|
+
const headers = new Headers(Object.entries(CONTEXT.getHeadersForAuthorize(token || "")).map(([key, value]) => [key, `${value}`]));
|
|
1265
1629
|
const body = new FormData();
|
|
1266
1630
|
body.append("grant_type", "refresh_token");
|
|
1267
|
-
body.append("refresh_token", refreshToken);
|
|
1631
|
+
body.append("refresh_token", refreshToken || "");
|
|
1268
1632
|
body.append("client_id", "oauth");
|
|
1269
1633
|
body.append("client_secret", "secret");
|
|
1270
1634
|
body.append("access_type", "offline");
|
|
@@ -1277,8 +1641,14 @@ var CredentialsProcessing = class {
|
|
|
1277
1641
|
});
|
|
1278
1642
|
}
|
|
1279
1643
|
const newCredentials = typeof CONTEXT.refreshCredentialsByOuter === "function" ? await CONTEXT.refreshCredentialsByOuter(currentCredentials) : await refreshCredentialsByDefault();
|
|
1280
|
-
return finalize(newCredentials);
|
|
1281
|
-
}
|
|
1644
|
+
return finalize(getIsOnlyAnObject(newCredentials) ? newCredentials : CONTEXT.DEFAULT_CREDENTIALS);
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Ожидает завершения рефреша токена (или запускает его флаг при необходимости).
|
|
1648
|
+
*
|
|
1649
|
+
* @param isNeedRefresh - выставить ли флаг «рефреш начат» при отсутствии активного рефреша.
|
|
1650
|
+
* @returns Промис, который резолвится по завершении ожидания.
|
|
1651
|
+
*/
|
|
1282
1652
|
async waitRefresh(isNeedRefresh) {
|
|
1283
1653
|
return new Promise((resolve) => {
|
|
1284
1654
|
if (!this.getIsTokenStartRefresh()) {
|
|
@@ -1294,10 +1664,16 @@ var CredentialsProcessing = class {
|
|
|
1294
1664
|
}
|
|
1295
1665
|
});
|
|
1296
1666
|
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Обрабатывает учётные данные: при необходимости рефрешит токен и возвращает актуальные данные.
|
|
1669
|
+
*
|
|
1670
|
+
* @param cred - текущие учётные данные.
|
|
1671
|
+
* @returns Промис с актуальными учётными данными (с флагом isRefreshFailed при неудаче).
|
|
1672
|
+
*/
|
|
1297
1673
|
async processCredentials(cred) {
|
|
1298
1674
|
if (!cred.isNeedRefresh && !cred.isCatchCallbackProcess) return cred;
|
|
1299
1675
|
const CONTEXT = this;
|
|
1300
|
-
return CONTEXT.refreshCredentials(cred, (response) => CONTEXT.saveCredentials(response)).then(() => {
|
|
1676
|
+
return CONTEXT.refreshCredentials(cred, (response) => CONTEXT.saveCredentials?.(response)).then(() => {
|
|
1301
1677
|
return new Promise((resolve) => {
|
|
1302
1678
|
setTimeout(async () => {
|
|
1303
1679
|
const newCredentials = await CONTEXT.getCredentials();
|
|
@@ -1315,11 +1691,15 @@ var CredentialsProcessing = class {
|
|
|
1315
1691
|
};
|
|
1316
1692
|
var CredentialsProcessing_default = CredentialsProcessing;
|
|
1317
1693
|
|
|
1318
|
-
// src/Classes/RESTAPI/index.
|
|
1694
|
+
// src/Classes/RESTAPI/index.ts
|
|
1319
1695
|
function returnTheContext() {
|
|
1320
1696
|
return this;
|
|
1321
1697
|
}
|
|
1322
1698
|
var RESTAPI = class extends ApiBase_default {
|
|
1699
|
+
/** Функция показа сообщений пользователю (или null, если информирование отключено). */
|
|
1700
|
+
sendMessage = null;
|
|
1701
|
+
/** Обработчик учётных данных (создаётся при наличии настройки credentialsProcessing). */
|
|
1702
|
+
credentialsProcessing;
|
|
1323
1703
|
constructor(settings) {
|
|
1324
1704
|
super(settings);
|
|
1325
1705
|
const { sendMessage, credentialsProcessing } = settings || {};
|
|
@@ -1329,7 +1709,14 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1329
1709
|
this.credentialsProcessing.getRESTAPIContext = returnTheContext.bind(this);
|
|
1330
1710
|
}
|
|
1331
1711
|
}
|
|
1332
|
-
|
|
1712
|
+
/**
|
|
1713
|
+
* Основной (базовый) метод API: выполняет мультизапрос (или одиночный запрос).
|
|
1714
|
+
*
|
|
1715
|
+
* @param inputRequests - путь, объект описания запроса или их массив.
|
|
1716
|
+
* @param settings - общие настройки запроса (формат ответа, тосты, сообщения и т.п.).
|
|
1717
|
+
* @returns Промис с результатом (форма зависит от isResponseAsObject).
|
|
1718
|
+
*/
|
|
1719
|
+
// ! Основной (базовый) метод API, мультизапросы
|
|
1333
1720
|
async doRequest(inputRequests, settings) {
|
|
1334
1721
|
if (typeof inputRequests !== "string" && typeof inputRequests !== "object") {
|
|
1335
1722
|
return Promise.reject(new Error(this.BAD_REQUEST_DATA_TEXT));
|
|
@@ -1353,24 +1740,29 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1353
1740
|
throw new Error("It is impossible to make a request!");
|
|
1354
1741
|
}
|
|
1355
1742
|
instance.setIsResponseAsObject(isResponseAsObject ?? true);
|
|
1356
|
-
if (callback) instance.setCallback(callback);
|
|
1743
|
+
if (typeof callback === "function") instance.setCallback(callback);
|
|
1357
1744
|
function getRequests() {
|
|
1358
1745
|
let output;
|
|
1359
1746
|
if (typeof inputRequests === "string") output = [{ path: inputRequests }];
|
|
1360
1747
|
else output = Array.isArray(inputRequests) ? inputRequests : [inputRequests];
|
|
1361
1748
|
function getCallback(item, mesageOptions) {
|
|
1362
|
-
const
|
|
1749
|
+
const getBodyAs = typeof item.getBodyAs === "string" ? item.getBodyAs : void 0;
|
|
1363
1750
|
const finalIsGetBody = typeof item.isGetBody === "boolean" || typeof item.isGetBody === "string" ? item.isGetBody : isGetBody;
|
|
1364
1751
|
const finalIsGetBodyFirst = finalIsGetBody === "first";
|
|
1365
|
-
const checkResponseCallback = finalIsGetBodyFirst ? async (res,
|
|
1366
|
-
const
|
|
1367
|
-
|
|
1752
|
+
const checkResponseCallback = finalIsGetBodyFirst ? async (res, options) => API_CONTEXT.getResponseBody(await API_CONTEXT.checkResponseCode(res, options), getBodyAs) : async (res, options) => API_CONTEXT.checkResponseCode(res, options);
|
|
1753
|
+
const itemCallback = item.callback;
|
|
1754
|
+
const callbackFn = typeof itemCallback === "function" ? async (res) => itemCallback(await checkResponseCallback(res, mesageOptions)) : async (res) => checkResponseCallback(res, mesageOptions);
|
|
1755
|
+
return finalIsGetBody && !finalIsGetBodyFirst ? async (res) => API_CONTEXT.getResponseBody(await callbackFn(res), getBodyAs) : callbackFn;
|
|
1368
1756
|
}
|
|
1369
1757
|
async function getRequestItem(item, idx) {
|
|
1370
|
-
const
|
|
1758
|
+
const itemObj = getIsOnlyAnObject(item) ? item : { path: item };
|
|
1759
|
+
const { type, ...partialRestFirst } = itemObj;
|
|
1371
1760
|
const itemAfterRequestCreating = await (async () => {
|
|
1372
|
-
const key = `createRequest_${type
|
|
1373
|
-
|
|
1761
|
+
const key = `createRequest_${typeof type === "string" ? type : "default"}`;
|
|
1762
|
+
const creator = key in API_CONTEXT ? API_CONTEXT[key] : void 0;
|
|
1763
|
+
const result = typeof creator === "function" ? creator.call(API_CONTEXT, partialRestFirst, "doRequestMapping") : API_CONTEXT.createRequest_default(partialRestFirst, "doRequestMapping");
|
|
1764
|
+
const awaited = await result;
|
|
1765
|
+
return getIsOnlyAnObject(awaited) ? awaited : {};
|
|
1374
1766
|
})();
|
|
1375
1767
|
const { fullPath, api, path, query, queryParameters, ...partialRestSecond } = itemAfterRequestCreating;
|
|
1376
1768
|
const {
|
|
@@ -1386,23 +1778,25 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1386
1778
|
isNoToast,
|
|
1387
1779
|
...rest
|
|
1388
1780
|
} = partialRestSecond;
|
|
1781
|
+
const successMessagesArr = Array.isArray(successMessages) ? successMessages : void 0;
|
|
1782
|
+
const errorMessagesArr = Array.isArray(errorMessages) ? errorMessages : void 0;
|
|
1389
1783
|
const useSuccessMessageFlag = Boolean(
|
|
1390
|
-
successMess || commonSuccessMessage ||
|
|
1784
|
+
successMess || commonSuccessMessage || successMessagesArr?.[idx] || CSMfromSettings || isToastResult || isToastFromSettings
|
|
1391
1785
|
);
|
|
1392
1786
|
const isUseSuccessToast = useSuccessMessageFlag && !isNoToast && !isNoToastFromSettings && !isNoToastSuccess && !isNTSFromSettings;
|
|
1393
1787
|
const isUseErrorToast = !isNoToast && !isNoToastFromSettings && !isNoToastError && !isNTEFromSettings;
|
|
1394
1788
|
const mesageOptions = {
|
|
1395
|
-
successMess: successMess || commonSuccessMessage ||
|
|
1789
|
+
successMess: successMess || commonSuccessMessage || successMessagesArr?.[idx] || CSMfromSettings,
|
|
1396
1790
|
successMessageType: successMessageType || SMTfromSettings,
|
|
1397
|
-
errorMess: errorMess || commonErrorMessage ||
|
|
1791
|
+
errorMess: errorMess || commonErrorMessage || errorMessagesArr?.[idx] || CEMfromSettings,
|
|
1398
1792
|
isUseSuccessToast,
|
|
1399
1793
|
isUseErrorToast,
|
|
1400
1794
|
toastOptions: toastOptions || TOFomSettings
|
|
1401
1795
|
};
|
|
1402
1796
|
return {
|
|
1403
1797
|
...rest,
|
|
1404
|
-
path: `${fullPath || await API_CONTEXT.getRootPath(
|
|
1405
|
-
|
|
1798
|
+
path: `${fullPath || await API_CONTEXT.getRootPath() + (typeof path === "string" ? path : "")}`,
|
|
1799
|
+
// ? Запускаем самовызывающуюся асинхронную ф-ю, ждем резолва промиса от нее
|
|
1406
1800
|
queryParameters: await (async () => {
|
|
1407
1801
|
const queryParams = query || queryParameters || "";
|
|
1408
1802
|
const preparedQueryParams = await API_CONTEXT.processQueryParams(queryParams);
|
|
@@ -1412,16 +1806,25 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1412
1806
|
callback: getCallback(itemAfterRequestCreating, mesageOptions)
|
|
1413
1807
|
};
|
|
1414
1808
|
}
|
|
1415
|
-
return output
|
|
1809
|
+
return output.map((item, idx) => getRequestItem(item, idx));
|
|
1416
1810
|
}
|
|
1417
1811
|
return instance.request(await Promise.all(getRequests()));
|
|
1418
1812
|
}
|
|
1419
|
-
|
|
1813
|
+
/**
|
|
1814
|
+
* Метод API для одиночных запросов: применяет крейтер по `type` и делегирует в {@link RESTAPI.doRequest}.
|
|
1815
|
+
*
|
|
1816
|
+
* @param requestSettings - объект описания одиночного запроса (с необязательным `type`).
|
|
1817
|
+
* @returns Промис с результатом запроса.
|
|
1818
|
+
*/
|
|
1819
|
+
// ! Метод API для одиночных запросов
|
|
1420
1820
|
async doMonoRequest(requestSettings) {
|
|
1421
1821
|
if (!getIsOnlyAnObject(requestSettings)) throw new Error(`${this.BAD_REQUEST_DATA_TEXT} [RESTAPI.doMonoRequest]`);
|
|
1422
1822
|
const { type, ...requestSettingsRest } = requestSettings;
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1823
|
+
const key = `createRequest_${typeof type === "string" ? type : ""}`;
|
|
1824
|
+
const creator = type && key in this ? this[key] : void 0;
|
|
1825
|
+
const created = typeof creator === "function" ? await creator.call(this, requestSettingsRest) : await this.createRequest_default(requestSettingsRest);
|
|
1826
|
+
const doRequestArgs = Array.isArray(created) ? created : [created];
|
|
1827
|
+
return this.doRequest(doRequestArgs[0], doRequestArgs[1]);
|
|
1425
1828
|
}
|
|
1426
1829
|
};
|
|
1427
1830
|
var RESTAPI_default = RESTAPI;
|
|
@@ -1430,15 +1833,4 @@ export {
|
|
|
1430
1833
|
AnimatedHandler_default as AnimatedHandler,
|
|
1431
1834
|
RESTAPI_default as RESTAPI
|
|
1432
1835
|
};
|
|
1433
|
-
//! При получении экземпляра, если sendMessage не является ф-ей,
|
|
1434
|
-
//! то это воспринимается как отключение шага информирования об ошибке запроса как такового
|
|
1435
|
-
//! Планируемая структура { headers, queryParameters, options }, где
|
|
1436
|
-
//! - headers и options - объекты,
|
|
1437
|
-
//! - queryParameters - строка, массив или объект
|
|
1438
|
-
//! ВНИМАНИЕ! Данный механизм рефреша принят на проекте finturfreactfrontend (админка)
|
|
1439
|
-
//! На кабинете он ТОЧНО НЕ ТАКОЙ
|
|
1440
|
-
//! currentCredentials передаются в формате класса! ({ token, refreshToken, expires })
|
|
1441
|
-
//! Наличие credentialsProcessing подключает ДОБАВЛЕНИЕ ТОКЕНОВ В ЗАПРОСЫ,
|
|
1442
|
-
//! НО по умолчанию НЕ добавляет флоу рефреша токенов
|
|
1443
|
-
//! (флоу рефреша подключается пропой isUseRefreshTokensPropcessing из credentialsProcessing)
|
|
1444
1836
|
//# sourceMappingURL=classes.js.map
|