intelicoreact 2.0.8 → 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/Atomic/FormElements/Dropdown/components/DropdownLoader.d.ts +4 -0
- package/dist/Atomic/FormElements/FormattedRawSSN/FormattedRawSSN_old.d.ts +11 -0
- package/dist/Atomic/FormElements/NumericInput/NumericInput.d.ts +36 -0
- package/dist/Atomic/FormElements/RangeCalendar/RangeCalendar.d.ts +2 -0
- package/dist/Atomic/FormElements/RangeSlider/RangeSlider.d.ts +19 -0
- package/dist/Atomic/FormElements/SwitcherTagsDropdown/partial/States.d.ts +5 -0
- package/dist/Atomic/FormElements/VariantsListRadio/VariantsListRadio.d.ts +17 -0
- package/dist/Atomic/FormElements/VariantsListRadio/partials/VariantsListRadioItem.d.ts +12 -0
- package/dist/Atomic/FormElements/WidgetPseudoTable/WidgetPseudoTable.d.ts +2 -0
- package/dist/Atomic/FormElements/WidgetPseudoTable/partial/constructor.d.ts +23 -0
- package/dist/Atomic/FormElements/WidgetWithSwitchableRows/WidgetWithSwitchableRows.d.ts +2 -0
- package/dist/Atomic/FormElements/WidgetWithSwitchableRows/partial/constructor.d.ts +38 -0
- package/dist/Atomic/UI/AccordionTable/AccordionTable.d.ts +10 -0
- package/dist/Atomic/UI/AccordionText/AccordionText.d.ts +8 -0
- package/dist/Atomic/UI/Chart/partial/Chart.constants.d.ts +78 -0
- package/dist/Atomic/UI/Chart/partial/datasetSetters.d.ts +13 -0
- package/dist/Atomic/UI/Chart/partial/optionsConstructor.d.ts +145 -0
- package/dist/Atomic/UI/Chart/partial/optionsSetters.d.ts +4 -0
- package/dist/Atomic/UI/CircleProgressBar/CircleProgressBar.d.ts +14 -0
- package/dist/Atomic/UI/ExampleChartIntegration/ExampleChartIntegration.d.ts +2 -0
- package/dist/Atomic/UI/ExampleChartIntegration/partial/utils.d.ts +4 -0
- package/dist/Atomic/UI/MonoAccordion/MonoAccordion._test.d.ts +1 -0
- package/dist/Atomic/UI/MonoAccordion/MonoAccordion.d.ts +12 -0
- package/dist/Atomic/UI/PieChart/PieChart.d.ts +8 -0
- package/dist/Atomic/UI/Table/Partials/TdCell.d.ts +13 -0
- package/dist/Atomic/UI/Table/Partials/TdHeader.d.ts +5 -0
- package/dist/Atomic/UI/Table/Partials/TdRow.d.ts +17 -0
- package/dist/Atomic/UI/Table/Partials/TdTitle.d.ts +5 -0
- package/dist/Atomic/UI/Table/Table.d.ts +9 -0
- package/dist/Atomic/UI/Table/TdTypes/TdActions.d.ts +6 -0
- package/dist/Atomic/UI/Table/TdTypes/TdPriority.d.ts +6 -0
- package/dist/Atomic/UI/Table/TdTypes/TdRange.d.ts +4 -0
- package/dist/Atomic/UI/Table/TdTypes/TdWeight.d.ts +7 -0
- package/dist/Atomic/UI/WizardStepper/constructor.d.ts +51 -0
- package/dist/Classes/AbortableFetch.d.ts +43 -0
- package/dist/Classes/AnimatedHandler.d.ts +4 -0
- package/dist/Classes/RESTAPI/index.d.ts +31 -0
- package/dist/Classes/RESTAPI/partials/AbortableFetch.d.ts +48 -0
- package/dist/Classes/RESTAPI/partials/ApiBase.d.ts +21 -0
- package/dist/Classes/RESTAPI/partials/ApiRequestCreators.d.ts +58 -0
- package/dist/Classes/RESTAPI/partials/ApiUtils.d.ts +63 -0
- package/dist/Classes/RESTAPI/partials/CredentialsProcessing.d.ts +79 -0
- package/dist/Classes/RESTAPI/partials/Utils.d.ts +20 -0
- package/dist/Classes/RESTAPI/partials/_utils.d.ts +54 -0
- package/dist/Classes/RESTAPI/partials/sse.d.ts +27 -0
- package/dist/Classes/RESTAPI/partials/types.d.ts +159 -0
- package/dist/Constants/index.constants.d.ts +20 -0
- package/dist/Functions/Portal.d.ts +6 -0
- package/dist/Functions/customEventListener.d.ts +27 -0
- package/dist/Functions/dateTime.d.ts +95 -0
- package/dist/Functions/fieldValueFormatters.d.ts +19 -0
- package/dist/Functions/hooks/useFormFieldsChangesManager.d.ts +15 -0
- package/dist/Functions/locale/createTranslator.d.ts +3 -0
- package/dist/Functions/operations.d.ts +1 -0
- package/dist/Functions/presets/inputMaskPresets.d.ts +136 -0
- package/dist/Functions/presets/inputPresets.d.ts +16 -0
- package/dist/Functions/presets/mobileKeyboardTypesPresets.d.ts +17 -0
- package/dist/Functions/schemas.d.ts +3 -0
- package/dist/Functions/sdk/runtime-sdk/client.d.ts +1 -1
- package/dist/Functions/useBodyScrollLock.d.ts +2 -0
- package/dist/Functions/useClickOutside.d.ts +1 -0
- package/dist/Functions/useDebounce.d.ts +4 -0
- package/dist/Functions/useFieldFocus.d.ts +7 -0
- package/dist/Functions/useFormTools/form-drivers/ArrayWithObjects.d.ts +15 -0
- package/dist/Functions/useFormTools/form-drivers/ObjectWithIterableObjects.d.ts +12 -0
- package/dist/Functions/useFormTools/form-drivers/ObjectWithNamedKeyObjects.d.ts +15 -0
- package/dist/Functions/useFormTools/functions/General.d.ts +15 -0
- package/dist/Functions/useFormTools/functions/RenderFields.d.ts +7 -0
- package/dist/Functions/useFormTools/functions/usePrevious.d.ts +2 -0
- package/dist/Functions/useFormTools/index.d.ts +86 -0
- package/dist/Functions/useInputHighlightError.d.ts +12 -0
- package/dist/Functions/useLocalStorage.d.ts +2 -0
- package/dist/Functions/useLocationParams.d.ts +1 -0
- package/dist/Functions/useMediaQuery.d.ts +2 -0
- package/dist/Functions/useMetaInfo.d.ts +8 -0
- package/dist/Functions/useMouseUpOutside.d.ts +1 -0
- package/dist/Functions/useOnlineStatus.d.ts +2 -0
- package/dist/Functions/usePasswordChecker.d.ts +7 -0
- package/dist/Functions/usePrevious.d.ts +2 -0
- package/dist/Functions/useResize.d.ts +3 -0
- package/dist/Functions/useScrollTo.d.ts +2 -0
- package/dist/Functions/useToggle.d.ts +7 -0
- package/dist/Functions/utils.d.ts +40 -0
- package/dist/Langs.d.ts +179 -0
- package/dist/Molecular/FormWithDependOn/FormWithDependOn.d.ts +3 -0
- package/dist/Molecular/FormWithDependOn/FormWithDependOn.interface.d.ts +2 -2
- package/dist/Molecular/FormWithDependOn/partials/_utils.d.ts +8 -0
- 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 +5 -3
- package/styles.css +1 -0
package/dist/classes.cjs
CHANGED
|
@@ -420,7 +420,11 @@ var AnimatedHandler = class {
|
|
|
420
420
|
};
|
|
421
421
|
var AnimatedHandler_default = AnimatedHandler;
|
|
422
422
|
|
|
423
|
-
// src/Classes/RESTAPI/partials/AbortableFetch.
|
|
423
|
+
// src/Classes/RESTAPI/partials/AbortableFetch.ts
|
|
424
|
+
var HTTP_METHODS = ["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"];
|
|
425
|
+
function isHttpMethod(value) {
|
|
426
|
+
return HTTP_METHODS.includes(value);
|
|
427
|
+
}
|
|
424
428
|
var RESPONSE_AS_OBJECT_ALWAYS_VALUE2 = "always";
|
|
425
429
|
var AbortableFetch2 = class {
|
|
426
430
|
#pathPrefix = null;
|
|
@@ -433,6 +437,8 @@ var AbortableFetch2 = class {
|
|
|
433
437
|
#catchCallback = null;
|
|
434
438
|
#everyPromiseCallback = null;
|
|
435
439
|
#isResponseAsObject = false;
|
|
440
|
+
// ? Последний вход request() — используется repeatRequest() для повторного запроса той же пачки.
|
|
441
|
+
requestInput = [];
|
|
436
442
|
constructor(input) {
|
|
437
443
|
if (input && !getIsOnlyAnObject(input)) throw new Error("Not valid input value!");
|
|
438
444
|
this.getPathPrefix = this.getPathPrefix.bind(this);
|
|
@@ -463,20 +469,30 @@ var AbortableFetch2 = class {
|
|
|
463
469
|
this.repeatRequest = this.repeatRequest.bind(this);
|
|
464
470
|
this.setProps(input || {});
|
|
465
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* Выполняет один или несколько HTTP-запросов (нативный fetch) с возможностью отмены.
|
|
474
|
+
*
|
|
475
|
+
* Метод `abort()` навешивается на прототип возвращаемого промиса (как в исходной реализации),
|
|
476
|
+
* что позволяет отменить всю цепочку запросов вызовом `abort()` на возвращённом промисе.
|
|
477
|
+
*
|
|
478
|
+
* @param props - путь, объект описания запроса или их массив.
|
|
479
|
+
* @returns Промис с результатом (форма зависит от isResponseAsObject); на прототипе доступен `abort()`.
|
|
480
|
+
*/
|
|
466
481
|
async request(props) {
|
|
467
482
|
if (!getIsOnlyAnObject(props) && !Array.isArray(props) && typeof props !== "string") throw new Error("Not valid props value!");
|
|
468
|
-
const stringifyBody = (b) => b
|
|
483
|
+
const stringifyBody = (b) => b instanceof FormData ? b : JSON.stringify(b);
|
|
469
484
|
this.requestInput = props;
|
|
470
485
|
const requests = getRequestsArray.call(this, props);
|
|
471
486
|
const ABORTABLE_FETCH_CONTEXT = this;
|
|
472
487
|
const abortController = new AbortController();
|
|
473
488
|
const addProps = (response, request) => {
|
|
474
|
-
response
|
|
475
|
-
|
|
476
|
-
|
|
489
|
+
return Object.assign(response, {
|
|
490
|
+
request,
|
|
491
|
+
...ABORTABLE_FETCH_CONTEXT.#isResponseAsObject ? { name: getIsOnlyAnObject(request) ? request.name || "" : "" } : {}
|
|
492
|
+
});
|
|
477
493
|
};
|
|
478
|
-
|
|
479
|
-
requests.map(
|
|
494
|
+
const externalRequest = Promise.all(
|
|
495
|
+
requests.map((item) => {
|
|
480
496
|
const safelyQuery = item.path.includes("?") ? `&${item.queryParameters.replace(/\?/g, "")}` : item.queryParameters;
|
|
481
497
|
const internalRequest = fetch(`${item.pathPrefix}${item.path}${safelyQuery}`, {
|
|
482
498
|
...item.options,
|
|
@@ -487,12 +503,15 @@ var AbortableFetch2 = class {
|
|
|
487
503
|
}).then(async (response) => addProps(response, item)).catch(async (response) => {
|
|
488
504
|
if (response instanceof Response) return Promise.resolve(addProps(response, item));
|
|
489
505
|
return Promise.resolve(
|
|
490
|
-
addProps(
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
506
|
+
addProps(
|
|
507
|
+
{
|
|
508
|
+
ok: false,
|
|
509
|
+
status: 0,
|
|
510
|
+
statusText: response,
|
|
511
|
+
request: item
|
|
512
|
+
},
|
|
513
|
+
item
|
|
514
|
+
)
|
|
496
515
|
);
|
|
497
516
|
}).then(async (res) => {
|
|
498
517
|
return typeof ABORTABLE_FETCH_CONTEXT.#everyPromiseCallback === "function" && !item.isSkipEveryPromiseCallback ? await ABORTABLE_FETCH_CONTEXT.#everyPromiseCallback(res) : res;
|
|
@@ -501,7 +520,8 @@ var AbortableFetch2 = class {
|
|
|
501
520
|
}).then(async (res) => {
|
|
502
521
|
return { request: item, response: res, ...item.name ? { name: item.name } : {} };
|
|
503
522
|
});
|
|
504
|
-
|
|
523
|
+
const internalProto = Object.getPrototypeOf(internalRequest);
|
|
524
|
+
internalProto.abort = () => abortController.abort();
|
|
505
525
|
return internalRequest;
|
|
506
526
|
})
|
|
507
527
|
).then(async (resArr) => {
|
|
@@ -509,16 +529,17 @@ var AbortableFetch2 = class {
|
|
|
509
529
|
return ABORTABLE_FETCH_CONTEXT.#isResponseAsObject ? {} : [];
|
|
510
530
|
}
|
|
511
531
|
if (ABORTABLE_FETCH_CONTEXT.#isResponseAsObject === RESPONSE_AS_OBJECT_ALWAYS_VALUE2) {
|
|
512
|
-
return resArr.reduce((ac, item) => ({ ...ac, [item.name]: item.response }), {});
|
|
532
|
+
return resArr.reduce((ac, item) => ({ ...ac, [String(item.name)]: item.response }), {});
|
|
513
533
|
}
|
|
514
534
|
if (resArr.length === 1) return resArr[0].response;
|
|
515
|
-
return ABORTABLE_FETCH_CONTEXT.#isResponseAsObject === true ? resArr.reduce((ac, item) => ({ ...ac, [item.name]: item.response }), {}) : resArr.map((item) => item.response);
|
|
535
|
+
return ABORTABLE_FETCH_CONTEXT.#isResponseAsObject === true ? resArr.reduce((ac, item) => ({ ...ac, [String(item.name)]: item.response }), {}) : resArr.map((item) => item.response);
|
|
516
536
|
}).then(async (res) => {
|
|
517
537
|
return typeof ABORTABLE_FETCH_CONTEXT.#callback === "function" ? await ABORTABLE_FETCH_CONTEXT.#callback(res) : res;
|
|
518
538
|
}).catch(async (res) => {
|
|
519
539
|
return typeof ABORTABLE_FETCH_CONTEXT.#catchCallback === "function" ? await ABORTABLE_FETCH_CONTEXT.#catchCallback(res) : res;
|
|
520
540
|
});
|
|
521
|
-
|
|
541
|
+
const externalProto = Object.getPrototypeOf(externalRequest);
|
|
542
|
+
externalProto.abort = () => abortController.abort();
|
|
522
543
|
return externalRequest;
|
|
523
544
|
function getRequestsArray(input) {
|
|
524
545
|
const requestsArray = (() => {
|
|
@@ -543,15 +564,17 @@ var AbortableFetch2 = class {
|
|
|
543
564
|
callback: omitCallback,
|
|
544
565
|
mergeProps: omitMergeProps,
|
|
545
566
|
...optionsRest
|
|
546
|
-
} = options
|
|
567
|
+
} = getIsOnlyAnObject(options) ? options : {};
|
|
568
|
+
const localMethod = typeof method === "string" && isHttpMethod(method) ? method : null;
|
|
569
|
+
const localCallback = typeof callback === "function" ? (res) => callback(res) : void 0;
|
|
547
570
|
return [
|
|
548
571
|
...ac,
|
|
549
572
|
{
|
|
550
573
|
path,
|
|
551
574
|
pathPrefix: getMergeProps("pathPrefix") === "onlyLocal" || isNoPathPrefix ? "" : this.#pathPrefix || "",
|
|
552
575
|
method: (() => {
|
|
553
|
-
if (getMergeProps("method") === "onlyLocal") return
|
|
554
|
-
return getMergeProps("method") === "onlyGlobal" ? this.#method || "GET" :
|
|
576
|
+
if (getMergeProps("method") === "onlyLocal") return localMethod || "GET";
|
|
577
|
+
return getMergeProps("method") === "onlyGlobal" ? this.#method || "GET" : localMethod || this.#method || "GET";
|
|
555
578
|
})(),
|
|
556
579
|
queryParameters: (() => {
|
|
557
580
|
if ((getMergeProps("queryParameters") ?? getMergeProps("query")) === "onlyLocal") {
|
|
@@ -560,31 +583,34 @@ var AbortableFetch2 = class {
|
|
|
560
583
|
return (getMergeProps("queryParameters") ?? getMergeProps("query")) === "onlyGlobal" ? this.getQueryString(this.getQueryArray(this.#queryParameters)) : this.getQueryString([...this.getQueryArray(this.#queryParameters), ...this.getQueryArray(queryParameters)]);
|
|
561
584
|
})(),
|
|
562
585
|
headers: (() => {
|
|
563
|
-
if (getMergeProps("headers") === "onlyLocal") return this.getHeadersObj(headers
|
|
586
|
+
if (getMergeProps("headers") === "onlyLocal") return this.getHeadersObj(getIsOnlyAnObject(headers) ? headers : {});
|
|
564
587
|
return getMergeProps("headers") === "onlyGlobal" ? this.getHeadersObj({ ...this.#headers || {} }) : this.getHeadersObj({
|
|
565
588
|
...this.#headers || {},
|
|
566
|
-
...headers
|
|
589
|
+
...getIsOnlyAnObject(headers) ? headers : {}
|
|
567
590
|
});
|
|
568
591
|
})(),
|
|
569
592
|
body: (() => {
|
|
570
593
|
if (getMergeProps("body") === "onlyLocal") return body || null;
|
|
571
594
|
if (getMergeProps("body") === "onlyGlobal") return this.#body || null;
|
|
572
595
|
if (body && this.#body && typeof body === typeof this.#body && typeof body === "object") {
|
|
573
|
-
return Array.isArray(body) ? [...this.#body, ...body] : { ...this.#body, ...body };
|
|
574
|
-
} else
|
|
596
|
+
return Array.isArray(body) ? [...Array.isArray(this.#body) ? this.#body : [], ...body] : { ...getIsOnlyAnObject(this.#body) ? this.#body : {}, ...getIsOnlyAnObject(body) ? body : {} };
|
|
597
|
+
} else {
|
|
598
|
+
return body || this.#body || null;
|
|
599
|
+
}
|
|
575
600
|
})(),
|
|
576
601
|
options: (() => {
|
|
577
|
-
if (getMergeProps("options") === "onlyLocal") return { ...optionsRest
|
|
578
|
-
return getMergeProps("options") === "onlyGlobal" ? { ...this.#options || {} } : { ...this.#options || {}, ...optionsRest
|
|
602
|
+
if (getMergeProps("options") === "onlyLocal") return { ...optionsRest };
|
|
603
|
+
return getMergeProps("options") === "onlyGlobal" ? { ...this.#options || {} } : { ...this.#options || {}, ...optionsRest };
|
|
579
604
|
})(),
|
|
580
|
-
callback,
|
|
581
|
-
isSkipEveryPromiseCallback,
|
|
605
|
+
callback: localCallback,
|
|
606
|
+
isSkipEveryPromiseCallback: Boolean(isSkipEveryPromiseCallback),
|
|
582
607
|
...this.getIsResponseAsObject() ? { name: name && typeof name === "string" ? name : index } : {}
|
|
583
608
|
}
|
|
584
609
|
];
|
|
585
610
|
}, []);
|
|
586
611
|
}
|
|
587
612
|
}
|
|
613
|
+
/** Повторяет последний выполненный запрос (ту же пачку). */
|
|
588
614
|
repeatRequest() {
|
|
589
615
|
return this.request(this.requestInput);
|
|
590
616
|
}
|
|
@@ -600,19 +626,23 @@ var AbortableFetch2 = class {
|
|
|
600
626
|
return this.#method;
|
|
601
627
|
}
|
|
602
628
|
setMethod(value) {
|
|
603
|
-
|
|
604
|
-
if (value && !methods.includes(value)) throw new Error("Not valid method value!");
|
|
629
|
+
if (value && !isHttpMethod(value)) throw new Error("Not valid method value!");
|
|
605
630
|
this.#method = value || null;
|
|
606
631
|
}
|
|
607
632
|
getQueryParameters() {
|
|
608
633
|
return this.#queryParameters;
|
|
609
634
|
}
|
|
610
635
|
getQueryArray(value) {
|
|
611
|
-
if (typeof value === "string")
|
|
612
|
-
|
|
613
|
-
else if (
|
|
614
|
-
return
|
|
615
|
-
} else
|
|
636
|
+
if (typeof value === "string") {
|
|
637
|
+
return (value[0] === "?" ? value.slice(1) : value).split("&");
|
|
638
|
+
} else if (Array.isArray(value)) {
|
|
639
|
+
return value.map((item) => `${item}`);
|
|
640
|
+
} else if (typeof value === "object" && value !== null) {
|
|
641
|
+
const record = getIsOnlyAnObject(value) ? value : {};
|
|
642
|
+
return Object.keys(record).filter((key) => Boolean(key) && Boolean(record[key])).map((key) => `${key}=${record[key]}`);
|
|
643
|
+
} else {
|
|
644
|
+
return [];
|
|
645
|
+
}
|
|
616
646
|
}
|
|
617
647
|
getQueryString(value) {
|
|
618
648
|
if (!value) return "";
|
|
@@ -631,7 +661,7 @@ var AbortableFetch2 = class {
|
|
|
631
661
|
if (!obj) return headers;
|
|
632
662
|
if (typeof obj !== "object" || Array.isArray(obj)) throw new Error("Not valid headers value!");
|
|
633
663
|
Object.keys(obj).forEach((key) => {
|
|
634
|
-
headers.append(key, obj[key]);
|
|
664
|
+
headers.append(key, `${obj[key]}`);
|
|
635
665
|
});
|
|
636
666
|
return headers;
|
|
637
667
|
}
|
|
@@ -707,39 +737,64 @@ var AbortableFetch2 = class {
|
|
|
707
737
|
// isAnywayRunCallback,
|
|
708
738
|
isResponseAsObject
|
|
709
739
|
} = input;
|
|
710
|
-
if (pathPrefix) this.setPathPrefix(pathPrefix);
|
|
711
|
-
if (method) this.setMethod(method);
|
|
740
|
+
if (pathPrefix) this.setPathPrefix(typeof pathPrefix === "string" ? pathPrefix : null);
|
|
741
|
+
if (method) this.setMethod(typeof method === "string" && isHttpMethod(method) ? method : null);
|
|
712
742
|
if (queryParameters) this.setQueryParameters(this.getQueryArray(queryParameters));
|
|
713
|
-
if (headers) this.setHeaders(headers);
|
|
743
|
+
if (headers) this.setHeaders(getIsOnlyAnObject(headers) ? headers : null);
|
|
714
744
|
if (body) this.setBody(body);
|
|
715
|
-
if (options) this.setOptions(options);
|
|
716
|
-
if (callback
|
|
717
|
-
|
|
718
|
-
|
|
745
|
+
if (options) this.setOptions(getIsOnlyAnObject(options) ? options : null);
|
|
746
|
+
if (callback && typeof callback === "function") {
|
|
747
|
+
const fn = callback;
|
|
748
|
+
this.setCallback(function wrappedCallback(response) {
|
|
749
|
+
return fn.call(this, response);
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
if (catchCallback && typeof catchCallback === "function") {
|
|
753
|
+
const fn = catchCallback;
|
|
754
|
+
this.setCatchCallback(function wrappedCatchCallback(response) {
|
|
755
|
+
return fn.call(this, response);
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
if (everyPromiseCallback && typeof everyPromiseCallback === "function") {
|
|
759
|
+
const fn = everyPromiseCallback;
|
|
760
|
+
this.setEveryPromiseCallback(function wrappedEveryPromiseCallback(response) {
|
|
761
|
+
return fn.call(this, response);
|
|
762
|
+
});
|
|
763
|
+
}
|
|
719
764
|
if (isResponseAsObject !== void 0) this.setIsResponseAsObject(isResponseAsObject);
|
|
720
765
|
}
|
|
721
766
|
};
|
|
722
767
|
var AbortableFetch_default2 = AbortableFetch2;
|
|
723
768
|
|
|
724
|
-
// src/Classes/RESTAPI/partials/_utils.
|
|
769
|
+
// src/Classes/RESTAPI/partials/_utils.ts
|
|
725
770
|
function getIsOnlyAnObject(input) {
|
|
726
|
-
return typeof input === "object" &&
|
|
727
|
-
input instanceof Object && // "отбивает" null
|
|
728
|
-
!Array.isArray(input) && // "отбивает" массивы
|
|
729
|
-
!(input instanceof Set) && // "отбивает" сеты
|
|
730
|
-
!(input instanceof Map);
|
|
771
|
+
return typeof input === "object" && input instanceof Object && !Array.isArray(input) && !(input instanceof Set) && !(input instanceof Map);
|
|
731
772
|
}
|
|
732
|
-
|
|
773
|
+
function clone(input) {
|
|
733
774
|
if (input === null || typeof input !== "object") return input;
|
|
734
|
-
|
|
735
|
-
|
|
775
|
+
if (Array.isArray(input)) return input.map((item) => clone(item));
|
|
776
|
+
const source = getIsOnlyAnObject(input) ? input : {};
|
|
777
|
+
const data = {};
|
|
778
|
+
Object.keys(source).forEach((key) => {
|
|
779
|
+
data[key] = clone(source[key]);
|
|
780
|
+
});
|
|
736
781
|
return data;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
}
|
|
742
|
-
|
|
782
|
+
}
|
|
783
|
+
function omitKeys(obj, keys = []) {
|
|
784
|
+
const source = obj ?? {};
|
|
785
|
+
const keySet = new Set(keys);
|
|
786
|
+
const result = {};
|
|
787
|
+
Object.keys(source).forEach((key) => {
|
|
788
|
+
if (!keySet.has(key)) result[key] = source[key];
|
|
789
|
+
});
|
|
790
|
+
return result;
|
|
791
|
+
}
|
|
792
|
+
async function getResponseClone(res) {
|
|
793
|
+
if (res && typeof res === "object" && "clone" in res && typeof res.clone === "function") {
|
|
794
|
+
return res.clone();
|
|
795
|
+
}
|
|
796
|
+
return clone(res);
|
|
797
|
+
}
|
|
743
798
|
function addCustomMethods(data, prefix) {
|
|
744
799
|
const preparedPrefix = (prefix || "").toString();
|
|
745
800
|
Object.keys(data).forEach((key) => {
|
|
@@ -753,7 +808,7 @@ async function getInstanceOfFetchSystem(isGetBody) {
|
|
|
753
808
|
let credentials = {};
|
|
754
809
|
if (CREDENTIALS_CONTEXT) {
|
|
755
810
|
const cred = await CREDENTIALS_CONTEXT.getCredentials();
|
|
756
|
-
credentials = CREDENTIALS_CONTEXT.isUseRefreshTokensPropcessing ? await CREDENTIALS_CONTEXT.waitRefresh(cred.isNeedRefresh && !CREDENTIALS_CONTEXT.getIsTokenStartRefresh()).then(
|
|
811
|
+
credentials = CREDENTIALS_CONTEXT.isUseRefreshTokensPropcessing ? await CREDENTIALS_CONTEXT.waitRefresh(Boolean(cred.isNeedRefresh) && !CREDENTIALS_CONTEXT.getIsTokenStartRefresh()).then(
|
|
757
812
|
async () => CREDENTIALS_CONTEXT.processCredentials(await CREDENTIALS_CONTEXT.getCredentials())
|
|
758
813
|
) : cred;
|
|
759
814
|
}
|
|
@@ -771,52 +826,57 @@ async function getInstanceOfFetchSystem(isGetBody) {
|
|
|
771
826
|
}
|
|
772
827
|
return (CREDENTIALS_CONTEXT?.isUseRefreshTokensPropcessing ? CREDENTIALS_CONTEXT.waitRefresh() : Promise.resolve()).then(
|
|
773
828
|
async () => new AbortableFetch_default2({
|
|
774
|
-
|
|
829
|
+
// ? Метод по умолчанию
|
|
775
830
|
method: "GET",
|
|
776
|
-
|
|
831
|
+
// ? Заголовки по умолчанию
|
|
777
832
|
headers: {
|
|
778
833
|
...headersToAbortableFetchInstance,
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
834
|
+
// ? (*) Тут обрабатываются кейсы
|
|
835
|
+
// ? - когда нет this.credentialsProcessing
|
|
836
|
+
// ? (мы НЕ хотим добавлять токены в принципе, не зашли в верхнюю if-ку)
|
|
837
|
+
// ? - когда есть this.credentialsProcessing, но нет credentials.token (не авторизованы)
|
|
838
|
+
// ? (зашли в верхнюю if-ку, попробовали получить/обновить креды)
|
|
784
839
|
...credentials.token ? CREDENTIALS_CONTEXT?.getHeadersForAuthorize?.(credentials.token) || {} : {}
|
|
785
840
|
},
|
|
786
841
|
queryParameters: await API_CONTEXT.processQueryParams(queryParamsToAbortableFetchInstance),
|
|
787
|
-
|
|
842
|
+
// ? Опции по умолчанию
|
|
788
843
|
options: {
|
|
789
844
|
mode: "cors",
|
|
790
845
|
redirect: "follow",
|
|
791
846
|
...optionsToAbortableFetchInstance
|
|
792
847
|
},
|
|
793
|
-
|
|
848
|
+
// ? Каждый запрос (каждый запрос мультизапроса), сделаный методом request этого экземпляра выполнит этот колбек
|
|
794
849
|
everyPromiseCallback: async function everyPromiseCallback(response) {
|
|
795
850
|
const ABORTABLE_FETCH_INSTANCE = this;
|
|
796
851
|
if (!response.status) {
|
|
797
|
-
const
|
|
798
|
-
const
|
|
852
|
+
const reqInput = ABORTABLE_FETCH_INSTANCE.requestInput;
|
|
853
|
+
const responseRequest = getIsOnlyAnObject(response.request) ? response.request : {};
|
|
854
|
+
const request = Array.isArray(reqInput) ? reqInput.find((item) => getIsOnlyAnObject(item) && item.path === responseRequest.path) : void 0;
|
|
855
|
+
const mesageOptions = getIsOnlyAnObject(request) && getIsOnlyAnObject(request.mesageOptions) ? request.mesageOptions : void 0;
|
|
856
|
+
const isUseErrorToast = mesageOptions?.isUseErrorToast;
|
|
799
857
|
if (isUseErrorToast) {
|
|
800
|
-
API_CONTEXT.sendMessage?.(API_CONTEXT.NO_INET,
|
|
858
|
+
API_CONTEXT.sendMessage?.(API_CONTEXT.NO_INET, mesageOptions, response);
|
|
801
859
|
}
|
|
802
860
|
}
|
|
803
|
-
return API_CONTEXT.REJECT_CODES.includes(response.status) || CREDENTIALS_CONTEXT?.isUseRefreshTokensPropcessing && CREDENTIALS_CONTEXT?.CODES_USING_THE_REFRESH_ATTEMPT?.includes
|
|
861
|
+
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));
|
|
804
862
|
},
|
|
805
|
-
|
|
806
|
-
|
|
863
|
+
// ? Если хоть один запрос из пачки будет зареджекчен, зареджектится вся пачка.
|
|
864
|
+
// ? В этом случае будет выполнен этот колбэк
|
|
807
865
|
catchCallback: async function catchCallback(res) {
|
|
808
866
|
const ABORTABLE_FETCH_INSTANCE = this;
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
867
|
+
if (!CREDENTIALS_CONTEXT) return Promise.reject(res);
|
|
868
|
+
const code = Number(res instanceof Error ? res.message.split(":")[1] : "");
|
|
869
|
+
if (CREDENTIALS_CONTEXT.CODES_USING_THE_REFRESH_ATTEMPT?.includes(code)) {
|
|
870
|
+
const isDoRefresh = !CREDENTIALS_CONTEXT.getIsTokenStartRefresh();
|
|
871
|
+
return CREDENTIALS_CONTEXT.waitRefresh(isDoRefresh).then(async () => {
|
|
872
|
+
const newCredentials = await CREDENTIALS_CONTEXT.processCredentials({
|
|
873
|
+
...await CREDENTIALS_CONTEXT.getCredentials(true),
|
|
815
874
|
isCatchCallbackProcess: isDoRefresh
|
|
816
875
|
});
|
|
876
|
+
const currentHeaders = ABORTABLE_FETCH_INSTANCE.getHeaders();
|
|
817
877
|
ABORTABLE_FETCH_INSTANCE.setHeaders({
|
|
818
|
-
...
|
|
819
|
-
...newCredentials
|
|
878
|
+
...getIsOnlyAnObject(currentHeaders) ? currentHeaders : {},
|
|
879
|
+
...newCredentials.token ? { Authorization: `Bearer ${newCredentials.token}` } : {}
|
|
820
880
|
});
|
|
821
881
|
if (newCredentials.token) return ABORTABLE_FETCH_INSTANCE.repeatRequest();
|
|
822
882
|
return Promise.reject(res);
|
|
@@ -828,13 +888,23 @@ async function getInstanceOfFetchSystem(isGetBody) {
|
|
|
828
888
|
);
|
|
829
889
|
}
|
|
830
890
|
|
|
831
|
-
// src/Classes/RESTAPI/partials/Utils.
|
|
891
|
+
// src/Classes/RESTAPI/partials/Utils.ts
|
|
832
892
|
var Utils = class {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
893
|
+
// ! Могут содержаться НЕасинхронные методы!
|
|
894
|
+
/**
|
|
895
|
+
* Нормализатор сложных query-параметров.
|
|
896
|
+
*
|
|
897
|
+
* Например: `&key1=&&&===&&&key2====&&&&&&&&key3=...`. Для корректной работы на вход нужно подавать
|
|
898
|
+
* НЕ кодированные значения. По умолчанию выходные значения query-параметров НЕ кодируются.
|
|
899
|
+
*
|
|
900
|
+
* @param queryParams - query в виде строки, массива или объекта.
|
|
901
|
+
* @param settings - формат вывода (`array` | `string` | `object`) и флаг кодирования.
|
|
902
|
+
* @returns Нормализованные query-параметры в выбранном формате.
|
|
903
|
+
*/
|
|
904
|
+
// ? Ф-я normalizeQueryParams является нормализатором сложных квери
|
|
905
|
+
// ? Например: &key1=&&&===&&&key2====&&&&&&&&key3=....
|
|
906
|
+
// ? Для корректной работы на вход нужно подавать НЕ кодированные значения
|
|
907
|
+
// ? По умолчанию выходные значения квери-параметров НЕ кодируются
|
|
838
908
|
normalizeQueryParams(queryParams, settings) {
|
|
839
909
|
if (settings && !getIsOnlyAnObject(settings)) {
|
|
840
910
|
throw new Error("Bad settings [class Utils, normalizeQueryParams]");
|
|
@@ -853,9 +923,13 @@ var Utils = class {
|
|
|
853
923
|
if (index === -1) return [item];
|
|
854
924
|
return [item.slice(0, index), item.slice(index + 1)];
|
|
855
925
|
}).filter(([key]) => Boolean(key)).map(([key, value]) => prepareParam(key, value));
|
|
856
|
-
} else if (getIsOnlyAnObject(input))
|
|
857
|
-
|
|
858
|
-
else
|
|
926
|
+
} else if (getIsOnlyAnObject(input)) {
|
|
927
|
+
return Object.keys(input).map((key) => prepareParam(key, input[key]));
|
|
928
|
+
} else if (typeof input === "string") {
|
|
929
|
+
return (input[0] === "?" ? input.slice(1) : input).split("&");
|
|
930
|
+
} else {
|
|
931
|
+
return [];
|
|
932
|
+
}
|
|
859
933
|
};
|
|
860
934
|
const { isEncode = false, outputAs = "array" } = settings || {};
|
|
861
935
|
const initialStructure = getInitialArr(queryParams);
|
|
@@ -872,7 +946,9 @@ var Utils = class {
|
|
|
872
946
|
if (index !== -1 && index !== 0) {
|
|
873
947
|
const key = str.slice(0, index);
|
|
874
948
|
acc.result.push(`${key}=${encodeURIComponent(str.slice(index + 1))}`);
|
|
875
|
-
} else
|
|
949
|
+
} else {
|
|
950
|
+
acc.toJoin = str;
|
|
951
|
+
}
|
|
876
952
|
if (idx === initialStructure.length - 1 && typeof acc.toJoin === "string") processToJoin(acc.toJoin);
|
|
877
953
|
return acc;
|
|
878
954
|
},
|
|
@@ -880,7 +956,7 @@ var Utils = class {
|
|
|
880
956
|
).result;
|
|
881
957
|
const outputStructure = normalizedStructure.map((item) => {
|
|
882
958
|
const [key, value] = item.split("=");
|
|
883
|
-
return [key, !isEncode ? decodeURIComponent(value) : value];
|
|
959
|
+
return [key, !isEncode ? decodeURIComponent(value ?? "") : value ?? ""];
|
|
884
960
|
});
|
|
885
961
|
switch (outputAs) {
|
|
886
962
|
case "string":
|
|
@@ -894,16 +970,25 @@ var Utils = class {
|
|
|
894
970
|
};
|
|
895
971
|
var Utils_default = Utils;
|
|
896
972
|
|
|
897
|
-
// src/Classes/RESTAPI/partials/ApiUtils.
|
|
973
|
+
// src/Classes/RESTAPI/partials/ApiUtils.ts
|
|
898
974
|
var ApiUtils = class extends Utils_default {
|
|
975
|
+
/** Корневой путь API (раскладывается в ApiBase из constants.API_PATH). */
|
|
976
|
+
API_PATH;
|
|
899
977
|
constructor(settings) {
|
|
900
978
|
super();
|
|
901
979
|
const { utils } = settings || {};
|
|
902
980
|
if (getIsOnlyAnObject(utils)) addCustomMethods.call(this, utils);
|
|
903
981
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
982
|
+
/**
|
|
983
|
+
* Разбирает единый объект параметров запроса на части в зависимости от варианта использования.
|
|
984
|
+
*
|
|
985
|
+
* @param apiParams - объединённые параметры запроса.
|
|
986
|
+
* @param variant - `'doRequestMapping'` для мультизапроса либо `undefined` для одиночного.
|
|
987
|
+
* @returns Для `doRequestMapping` — объект параметров; иначе кортеж `[параметры, настройки]`.
|
|
988
|
+
*/
|
|
989
|
+
// ? Планируется, что метод будет использоваться неизменно, однако технически его можно перегрузить на экземпляре
|
|
990
|
+
// ? Метод не планировался как асинхронный,
|
|
991
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
907
992
|
async splitProperties(apiParams, variant) {
|
|
908
993
|
const {
|
|
909
994
|
isResponseAsObject,
|
|
@@ -962,79 +1047,224 @@ var ApiUtils = class extends Utils_default {
|
|
|
962
1047
|
];
|
|
963
1048
|
}
|
|
964
1049
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1050
|
+
/**
|
|
1051
|
+
* Обработчик пропы `api` из объекта описания запроса — возвращает корневой путь API.
|
|
1052
|
+
*
|
|
1053
|
+
* @returns Корневой путь (по умолчанию — API_PATH).
|
|
1054
|
+
*/
|
|
1055
|
+
// ! Обработчик пропы api из объекта описания запроса
|
|
1056
|
+
// ? Планируется, что метод будет перегружаться на экземпляре,
|
|
1057
|
+
// ? т.к. на разных проектах могут быть разные интерпретации пропы api
|
|
1058
|
+
// ? Метод не планировался как асинхронный,
|
|
1059
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
970
1060
|
async getRootPath() {
|
|
971
1061
|
return this.API_PATH;
|
|
972
1062
|
}
|
|
973
|
-
|
|
974
|
-
|
|
1063
|
+
/**
|
|
1064
|
+
* Извлекает тело ответа в нужном виде (json/blob/text/arrayBuffer/formData) либо по content-type.
|
|
1065
|
+
*
|
|
1066
|
+
* @param response - объект Response (иначе значение возвращается как есть).
|
|
1067
|
+
* @param getBodyAs - желаемый способ извлечения тела.
|
|
1068
|
+
* @returns Промис с телом ответа (или исходным значением / null при ошибке).
|
|
1069
|
+
*/
|
|
1070
|
+
// ? Планируется, что метод будет использоваться неизменно, однако технически его можно перегрузить на экземпляре
|
|
1071
|
+
// ? Метод планировался как асинхронный
|
|
975
1072
|
async getResponseBody(response, getBodyAs) {
|
|
976
1073
|
if (!(response instanceof Response)) return response;
|
|
977
1074
|
const contentType = response.headers.get("content-type");
|
|
978
1075
|
if (!contentType) return "";
|
|
979
|
-
const
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1076
|
+
const bodyReaders = {
|
|
1077
|
+
json: (r) => r.json(),
|
|
1078
|
+
blob: (r) => r.blob(),
|
|
1079
|
+
text: (r) => r.text(),
|
|
1080
|
+
arrayBuffer: (r) => r.arrayBuffer(),
|
|
1081
|
+
formData: (r) => r.formData()
|
|
1082
|
+
};
|
|
1083
|
+
const isBodyKey = (key) => key in bodyReaders;
|
|
1084
|
+
const reader = typeof getBodyAs === "string" && isBodyKey(getBodyAs) ? bodyReaders[getBodyAs] : contentType.includes("text/csv") ? bodyReaders.blob : contentType.includes("json") ? bodyReaders.json : bodyReaders.text;
|
|
988
1085
|
try {
|
|
989
|
-
return await
|
|
1086
|
+
return await reader(response);
|
|
990
1087
|
} catch {
|
|
991
1088
|
console.log("Failed to extract the body");
|
|
992
1089
|
return null;
|
|
993
1090
|
}
|
|
994
1091
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1092
|
+
/**
|
|
1093
|
+
* Формирует структуру ошибки из тела ответа (точка расширения под формат бэкенда).
|
|
1094
|
+
*
|
|
1095
|
+
* @param res - уже извлечённое тело ответа.
|
|
1096
|
+
* @returns Структура сообщения об ошибке.
|
|
1097
|
+
*/
|
|
1098
|
+
// ! Обработчик структуры для ошибки (не рендер месседжа, а имеено формирование ошибки),
|
|
1099
|
+
// ? Планируется, что метод будет перегружаться на экземпляре,
|
|
1100
|
+
// ? т.к. на разных проектах могут быть разные структуры тела ответа для ошибки
|
|
1101
|
+
// ? Метод не планировался как асинхронный,
|
|
1102
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
1103
|
+
// ? res - уже тело ответа
|
|
1001
1104
|
async getErrorMessage(res) {
|
|
1002
1105
|
return res;
|
|
1003
1106
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1107
|
+
/**
|
|
1108
|
+
* Проверяет код ответа и (если задан sendMessage) информирует пользователя об успехе/ошибке.
|
|
1109
|
+
*
|
|
1110
|
+
* @param res - объект Response (или совместимый с полем `ok`).
|
|
1111
|
+
* @param settings - сообщения и настройки тостов для данного запроса.
|
|
1112
|
+
* @returns Исходный `res` (метод не меняет ответ, только сигналит сообщением).
|
|
1113
|
+
*/
|
|
1114
|
+
// ? Планируется, что метод будет использоваться неизменно, однако технически его можно перегрузить на экземпляре
|
|
1115
|
+
// ? Метод планировался как асинхронный
|
|
1006
1116
|
async checkResponseCode(res, settings) {
|
|
1007
|
-
|
|
1117
|
+
const send = this.sendMessage;
|
|
1118
|
+
if (typeof send !== "function") return res;
|
|
1008
1119
|
const { successMess, errorMess } = settings || {};
|
|
1009
|
-
const
|
|
1120
|
+
const isOk = getIsOnlyAnObject(res) ? Boolean(res.ok) : false;
|
|
1121
|
+
const message = isOk ? successMess || this.DEFAULT_SUCCESS_MESSAGE : errorMess || await this.getErrorMessage(await this.getResponseBody(await getResponseClone(res)));
|
|
1010
1122
|
try {
|
|
1011
|
-
|
|
1012
|
-
} catch
|
|
1123
|
+
send(message, settings, await getResponseClone(res));
|
|
1124
|
+
} catch {
|
|
1013
1125
|
}
|
|
1014
1126
|
return res;
|
|
1015
1127
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1128
|
+
/**
|
|
1129
|
+
* Структуры, которые будут использоваться для КАЖДОГО запроса, сделанного экземпляром RESTAPI.
|
|
1130
|
+
*
|
|
1131
|
+
* @returns Объект `{ headers, queryParameters, options }` (по умолчанию пустой).
|
|
1132
|
+
*/
|
|
1133
|
+
// ? Суть метода:
|
|
1134
|
+
// ? передать из вне структуры, которые будут использоваться для КАЖДОГО запроса сделанного экземпляром RESTAPI
|
|
1135
|
+
// ! Данные затрут прочие настройки КРОМЕ данных по логике авторизации
|
|
1136
|
+
// ? Планируется, что метод будет перегружаться на экземпляре
|
|
1137
|
+
// ? Метод не планировался как асинхронный,
|
|
1138
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
1022
1139
|
async addAsCommon() {
|
|
1023
1140
|
return {};
|
|
1024
1141
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1142
|
+
/**
|
|
1143
|
+
* Общий обработчик query-параметров (точка расширения, напр. кодирование/приведение к массиву).
|
|
1144
|
+
*
|
|
1145
|
+
* @param queryParams - входные query-параметры.
|
|
1146
|
+
* @returns Обработанные query-параметры (по умолчанию — без изменений).
|
|
1147
|
+
*/
|
|
1148
|
+
// ! Обработчик квери-параметров для общего процессинга,
|
|
1149
|
+
// ! Например для кодирования decodeURIComponent или/и приведения в формат массива
|
|
1150
|
+
// ? Планируется, что метод будет перегружаться на экземпляре,
|
|
1151
|
+
// ? т.к. на разных проектах могут быть разные договоренности по форматам
|
|
1152
|
+
// ? Метод не планировался как асинхронный,
|
|
1153
|
+
// ? однако ввиду того что он может быть перегружен на экземпляре асинхронность предусматривается
|
|
1031
1154
|
async processQueryParams(queryParams) {
|
|
1032
1155
|
return queryParams;
|
|
1033
1156
|
}
|
|
1034
1157
|
};
|
|
1035
1158
|
var ApiUtils_default = ApiUtils;
|
|
1036
1159
|
|
|
1037
|
-
// src/Classes/RESTAPI/partials/
|
|
1160
|
+
// src/Classes/RESTAPI/partials/sse.ts
|
|
1161
|
+
function parseSSEEvent(block) {
|
|
1162
|
+
if (typeof block !== "string") return null;
|
|
1163
|
+
const event = { event: "message", data: "", id: void 0, retry: void 0 };
|
|
1164
|
+
const dataLines = [];
|
|
1165
|
+
let hasField = false;
|
|
1166
|
+
block.split("\n").forEach((line) => {
|
|
1167
|
+
if (line === "" || line[0] === ":") return;
|
|
1168
|
+
const colonIdx = line.indexOf(":");
|
|
1169
|
+
const field = colonIdx === -1 ? line : line.slice(0, colonIdx);
|
|
1170
|
+
let value = colonIdx === -1 ? "" : line.slice(colonIdx + 1);
|
|
1171
|
+
if (value[0] === " ") value = value.slice(1);
|
|
1172
|
+
switch (field) {
|
|
1173
|
+
case "event":
|
|
1174
|
+
event.event = value;
|
|
1175
|
+
hasField = true;
|
|
1176
|
+
break;
|
|
1177
|
+
case "data":
|
|
1178
|
+
dataLines.push(value);
|
|
1179
|
+
hasField = true;
|
|
1180
|
+
break;
|
|
1181
|
+
case "id":
|
|
1182
|
+
event.id = value;
|
|
1183
|
+
hasField = true;
|
|
1184
|
+
break;
|
|
1185
|
+
case "retry":
|
|
1186
|
+
if (/^\d+$/.test(value)) {
|
|
1187
|
+
event.retry = Number(value);
|
|
1188
|
+
hasField = true;
|
|
1189
|
+
}
|
|
1190
|
+
break;
|
|
1191
|
+
default:
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
if (!hasField) return null;
|
|
1196
|
+
event.data = dataLines.join("\n");
|
|
1197
|
+
return event;
|
|
1198
|
+
}
|
|
1199
|
+
function safeCall(fn, ...args) {
|
|
1200
|
+
if (typeof fn !== "function") return;
|
|
1201
|
+
try {
|
|
1202
|
+
fn(...args);
|
|
1203
|
+
} catch {
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
async function readSSE(response, { onEvent, onChunk, handlers, parseJson } = {}) {
|
|
1207
|
+
const events = [];
|
|
1208
|
+
const stream = response.body;
|
|
1209
|
+
if (!stream) return events;
|
|
1210
|
+
const reader = stream.getReader();
|
|
1211
|
+
const decoder = new TextDecoder("utf-8");
|
|
1212
|
+
let buffer = "";
|
|
1213
|
+
let pendingCR = "";
|
|
1214
|
+
const normalize = (chunk) => chunk.replace(/\r\n|\r/g, "\n");
|
|
1215
|
+
const flush = (rawBlock) => {
|
|
1216
|
+
const event = parseSSEEvent(rawBlock);
|
|
1217
|
+
if (!event) return;
|
|
1218
|
+
if (parseJson && typeof event.data === "string" && event.data !== "") {
|
|
1219
|
+
try {
|
|
1220
|
+
event.data = JSON.parse(event.data);
|
|
1221
|
+
} catch {
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
events.push(event);
|
|
1225
|
+
safeCall(onEvent, event);
|
|
1226
|
+
safeCall(onChunk, event.data, event);
|
|
1227
|
+
if (handlers) safeCall(handlers[event.event], event.data, event);
|
|
1228
|
+
};
|
|
1229
|
+
try {
|
|
1230
|
+
while (true) {
|
|
1231
|
+
const { done, value } = await reader.read();
|
|
1232
|
+
if (done) break;
|
|
1233
|
+
let chunk = pendingCR + decoder.decode(value, { stream: true });
|
|
1234
|
+
pendingCR = "";
|
|
1235
|
+
if (chunk.endsWith("\r")) {
|
|
1236
|
+
pendingCR = "\r";
|
|
1237
|
+
chunk = chunk.slice(0, -1);
|
|
1238
|
+
}
|
|
1239
|
+
buffer += normalize(chunk);
|
|
1240
|
+
let sepIdx;
|
|
1241
|
+
while ((sepIdx = buffer.indexOf("\n\n")) !== -1) {
|
|
1242
|
+
const rawBlock = buffer.slice(0, sepIdx);
|
|
1243
|
+
buffer = buffer.slice(sepIdx + 2);
|
|
1244
|
+
flush(rawBlock);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
buffer += normalize(pendingCR + decoder.decode());
|
|
1248
|
+
buffer = buffer.replace(/\n+$/g, "");
|
|
1249
|
+
if (buffer !== "") flush(buffer);
|
|
1250
|
+
} catch (error) {
|
|
1251
|
+
const name = error && typeof error === "object" && "name" in error ? error.name : void 0;
|
|
1252
|
+
if (name !== "AbortError") throw error;
|
|
1253
|
+
} finally {
|
|
1254
|
+
try {
|
|
1255
|
+
reader.releaseLock?.();
|
|
1256
|
+
} catch {
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
return events;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// src/Classes/RESTAPI/partials/ApiRequestCreators.ts
|
|
1263
|
+
function isStreamResponse(value) {
|
|
1264
|
+
if (!getIsOnlyAnObject(value) || !value.ok) return false;
|
|
1265
|
+
const body = value.body;
|
|
1266
|
+
return typeof body === "object" && body !== null && "getReader" in body && typeof body.getReader === "function";
|
|
1267
|
+
}
|
|
1038
1268
|
var PREFIX_OF_CLASS_UTILS = "createRequest_";
|
|
1039
1269
|
var ApiRequestCreators = class extends ApiUtils_default {
|
|
1040
1270
|
constructor(settings) {
|
|
@@ -1042,8 +1272,14 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1042
1272
|
const { requestsCreators } = settings || {};
|
|
1043
1273
|
if (getIsOnlyAnObject(requestsCreators)) addCustomMethods.call(this, requestsCreators, PREFIX_OF_CLASS_UTILS);
|
|
1044
1274
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1275
|
+
/**
|
|
1276
|
+
* Крейтер типа `toJson`: пользовательский callback получит тело ответа (Response.json()).
|
|
1277
|
+
*
|
|
1278
|
+
* @param props - объект описания запроса.
|
|
1279
|
+
* @param variant - вариант обработки splitProperties.
|
|
1280
|
+
*/
|
|
1281
|
+
// ? При типе toJson пользовательский callback на вход получит тело ответа реализованное методом Response.json()
|
|
1282
|
+
// ? независимо от насторойки isGetBody
|
|
1047
1283
|
async createRequest_toJson(props, variant) {
|
|
1048
1284
|
const safelyProps = omitKeys(props, ["getBodyAs"]);
|
|
1049
1285
|
return this.splitProperties(
|
|
@@ -1052,15 +1288,21 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1052
1288
|
isGetBody: false,
|
|
1053
1289
|
callback: async (res) => {
|
|
1054
1290
|
const output = await this.getResponseBody(res, "json");
|
|
1055
|
-
return await (
|
|
1291
|
+
return await (props.callback?.(output) ?? output);
|
|
1056
1292
|
}
|
|
1057
1293
|
},
|
|
1058
1294
|
variant
|
|
1059
1295
|
);
|
|
1060
1296
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1297
|
+
/**
|
|
1298
|
+
* Крейтер типа `toJsonAdvanced`: callback получит структуру `{ response, result }`.
|
|
1299
|
+
*
|
|
1300
|
+
* @param props - объект описания запроса.
|
|
1301
|
+
* @param variant - вариант обработки splitProperties.
|
|
1302
|
+
*/
|
|
1303
|
+
// ? При типе toJsonAdvanced пользовательский callback на вход получит структуру { response, result },
|
|
1304
|
+
// ? где response - объект Response, result - тело ответа реализованное методом Response.json()
|
|
1305
|
+
// ? независимо от насторойки isGetBody
|
|
1064
1306
|
async createRequest_toJsonAdvanced(props, variant) {
|
|
1065
1307
|
const safelyProps = omitKeys(props, ["getBodyAs"]);
|
|
1066
1308
|
return this.splitProperties(
|
|
@@ -1072,14 +1314,20 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1072
1314
|
response: res,
|
|
1073
1315
|
result: await this.getResponseBody(await getResponseClone(res), "json")
|
|
1074
1316
|
};
|
|
1075
|
-
return await (
|
|
1317
|
+
return await (props.callback?.(output) ?? output);
|
|
1076
1318
|
}
|
|
1077
1319
|
},
|
|
1078
1320
|
variant
|
|
1079
1321
|
);
|
|
1080
1322
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1323
|
+
/**
|
|
1324
|
+
* Крейтер типа `blob`: callback получит тело ответа (Response.blob()).
|
|
1325
|
+
*
|
|
1326
|
+
* @param props - объект описания запроса.
|
|
1327
|
+
* @param variant - вариант обработки splitProperties.
|
|
1328
|
+
*/
|
|
1329
|
+
// ? При типе blob пользовательский callback на вход получит тело ответа реализованное методом Response.blob(),
|
|
1330
|
+
// ? независимо от насторойки isGetBody
|
|
1083
1331
|
async createRequest_blob(props, variant) {
|
|
1084
1332
|
const safelyProps = omitKeys(props, ["getBodyAs"]);
|
|
1085
1333
|
return this.splitProperties(
|
|
@@ -1088,14 +1336,67 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1088
1336
|
isGetBody: false,
|
|
1089
1337
|
callback: async (res) => {
|
|
1090
1338
|
const output = await this.getResponseBody(await getResponseClone(res), "blob");
|
|
1091
|
-
return await (
|
|
1339
|
+
return await (props.callback?.(output) ?? output);
|
|
1092
1340
|
}
|
|
1093
1341
|
},
|
|
1094
1342
|
variant
|
|
1095
1343
|
);
|
|
1096
1344
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1345
|
+
/**
|
|
1346
|
+
* Крейтер типа `sse`: обрабатывает ответ как поток Server-Sent Events (text/event-stream).
|
|
1347
|
+
*
|
|
1348
|
+
* Дополнительные пропы объекта описания запроса: `onEvent`, `onChunk`, `handlers`, `parseJson`.
|
|
1349
|
+
* По умолчанию добавляется заголовок `Accept: text/event-stream`. Метод doRequest резолвится
|
|
1350
|
+
* массивом всех событий ПОСЛЕ закрытия потока; отмена — методом `.abort()` возвращённого промиса.
|
|
1351
|
+
*
|
|
1352
|
+
* @param props - объект описания запроса (плюс onEvent/onChunk/handlers/parseJson).
|
|
1353
|
+
* @param variant - вариант обработки splitProperties.
|
|
1354
|
+
*/
|
|
1355
|
+
// ? При типе sse запрос обрабатывается как поток Server-Sent Events (text/event-stream).
|
|
1356
|
+
// ? Дополнительные пропы объекта описания запроса:
|
|
1357
|
+
// ? - onEvent(event) — вызывается на каждое распарсенное событие { event, data, id, retry };
|
|
1358
|
+
// ? - onChunk(data, event) — вызывается на полезную нагрузку (поле data) каждого события;
|
|
1359
|
+
// ? - handlers — карта { имяСобытия: cb } для типизированной обработки по полю event
|
|
1360
|
+
// ? (например { delta, status, done }); cb получает (data, event);
|
|
1361
|
+
// ? - parseJson — если true, поле data каждого события прогоняется через JSON.parse.
|
|
1362
|
+
// ? По умолчанию добавляется заголовок Accept: text/event-stream (его можно переопределить через headers).
|
|
1363
|
+
// ? Пользовательский callback (если передан) на вход получит итоговый массив всех событий.
|
|
1364
|
+
// ? Метод doRequest резолвится массивом всех событий ПОСЛЕ закрытия потока;
|
|
1365
|
+
// ? отмена потока выполняется методом .abort() возвращённого промиса (через встроенный AbortController).
|
|
1366
|
+
async createRequest_sse(props, variant) {
|
|
1367
|
+
const safelyProps = omitKeys(props, ["getBodyAs", "onChunk", "onEvent", "handlers", "parseJson"]);
|
|
1368
|
+
const { onChunk, onEvent, handlers, parseJson } = props;
|
|
1369
|
+
const sseOptions = {
|
|
1370
|
+
onChunk: typeof onChunk === "function" ? (data, event) => onChunk(data, event) : void 0,
|
|
1371
|
+
onEvent: typeof onEvent === "function" ? (event) => onEvent(event) : void 0,
|
|
1372
|
+
parseJson: Boolean(parseJson),
|
|
1373
|
+
handlers: getIsOnlyAnObject(handlers) ? Object.keys(handlers).reduce((acc, key) => {
|
|
1374
|
+
const fn = handlers[key];
|
|
1375
|
+
acc[key] = typeof fn === "function" ? (data, event) => fn(data, event) : void 0;
|
|
1376
|
+
return acc;
|
|
1377
|
+
}, {}) : void 0
|
|
1378
|
+
};
|
|
1379
|
+
return this.splitProperties(
|
|
1380
|
+
{
|
|
1381
|
+
...safelyProps,
|
|
1382
|
+
headers: { Accept: "text/event-stream", ...getIsOnlyAnObject(safelyProps.headers) ? safelyProps.headers : {} },
|
|
1383
|
+
isGetBody: false,
|
|
1384
|
+
callback: async (res) => {
|
|
1385
|
+
const output = isStreamResponse(res) ? await readSSE(res, sseOptions) : res;
|
|
1386
|
+
return await (props.callback?.(output) ?? output);
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
variant
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Крейтер типа `testBadResponse`: callback получит синтетический Response со статусом 401.
|
|
1394
|
+
*
|
|
1395
|
+
* @param props - объект описания запроса.
|
|
1396
|
+
* @param variant - вариант обработки splitProperties.
|
|
1397
|
+
*/
|
|
1398
|
+
// ? При типе testBadResponse пользовательский callback на вход получит объект Response в 401-м статусе
|
|
1399
|
+
// ? независимо независимо вообще ни от чего
|
|
1099
1400
|
async createRequest_testBadResponse(props, variant) {
|
|
1100
1401
|
return this.splitProperties(
|
|
1101
1402
|
{
|
|
@@ -1115,17 +1416,33 @@ var ApiRequestCreators = class extends ApiUtils_default {
|
|
|
1115
1416
|
variant
|
|
1116
1417
|
);
|
|
1117
1418
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1419
|
+
/**
|
|
1420
|
+
* Крейтер по умолчанию: callback получит объект Response (или тело ответа при isGetBody: 'first').
|
|
1421
|
+
*
|
|
1422
|
+
* @param props - объект описания запроса.
|
|
1423
|
+
* @param variant - вариант обработки splitProperties.
|
|
1424
|
+
*/
|
|
1425
|
+
// ? По умолчанию пользовательский callback на вход получит
|
|
1426
|
+
// ? - либо объект Response
|
|
1427
|
+
// ? - либо тело ответа (в случае isGetBody: 'first') полученное методом getResponseBody (смотри класс ApiUtils)
|
|
1121
1428
|
async createRequest_default(props, variant) {
|
|
1122
1429
|
return this.splitProperties(props, variant);
|
|
1123
1430
|
}
|
|
1124
1431
|
};
|
|
1125
1432
|
var ApiRequestCreators_default = ApiRequestCreators;
|
|
1126
1433
|
|
|
1127
|
-
// src/Classes/RESTAPI/partials/ApiBase.
|
|
1434
|
+
// src/Classes/RESTAPI/partials/ApiBase.ts
|
|
1128
1435
|
var ApiBase = class extends ApiRequestCreators_default {
|
|
1436
|
+
/** Текст ошибки невалидных данных запроса. */
|
|
1437
|
+
BAD_REQUEST_DATA_TEXT;
|
|
1438
|
+
/** Текст сообщения об успехе по умолчанию. */
|
|
1439
|
+
DEFAULT_SUCCESS_MESSAGE;
|
|
1440
|
+
/** Текст сообщения об ошибке по умолчанию. */
|
|
1441
|
+
DEFAULT_ERROR_MESSAGE;
|
|
1442
|
+
/** Текст сообщения об отсутствии сети. */
|
|
1443
|
+
NO_INET;
|
|
1444
|
+
/** Коды ответа, по которым запрос считается отклонённым. */
|
|
1445
|
+
REJECT_CODES;
|
|
1129
1446
|
constructor(settings) {
|
|
1130
1447
|
super(settings);
|
|
1131
1448
|
const {
|
|
@@ -1154,49 +1471,76 @@ var ApiBase = class extends ApiRequestCreators_default {
|
|
|
1154
1471
|
};
|
|
1155
1472
|
var ApiBase_default = ApiBase;
|
|
1156
1473
|
|
|
1157
|
-
// src/Classes/RESTAPI/partials/CredentialsProcessing.
|
|
1474
|
+
// src/Classes/RESTAPI/partials/CredentialsProcessing.ts
|
|
1158
1475
|
function decodeJWT(token) {
|
|
1159
1476
|
try {
|
|
1160
|
-
const payload = token.split(".")[1];
|
|
1161
|
-
|
|
1162
|
-
|
|
1477
|
+
const payload = token.split(".")[1] ?? "";
|
|
1478
|
+
const decoded = JSON.parse(atob(payload));
|
|
1479
|
+
return getIsOnlyAnObject(decoded) ? decoded : null;
|
|
1480
|
+
} catch {
|
|
1163
1481
|
return null;
|
|
1164
1482
|
}
|
|
1165
1483
|
}
|
|
1166
1484
|
var CredentialsProcessing = class {
|
|
1485
|
+
/** Включён ли флоу рефреша токенов. */
|
|
1486
|
+
isUseRefreshTokensPropcessing = false;
|
|
1487
|
+
/** Учётные данные по умолчанию (пустые). */
|
|
1488
|
+
DEFAULT_CREDENTIALS = {};
|
|
1489
|
+
/** Внешний метод получения учётных данных. */
|
|
1490
|
+
getCredentialsByOuter;
|
|
1491
|
+
/** Внешний метод формирования заголовков авторизации по токену. */
|
|
1492
|
+
getHeadersForAuthorize;
|
|
1493
|
+
/** Необязательный преобразователь учётных данных после getCredentials. */
|
|
1494
|
+
importCredentials;
|
|
1495
|
+
/** Необязательный метод сохранения учётных данных (обязателен для флоу рефреша). */
|
|
1496
|
+
saveCredentials;
|
|
1497
|
+
/** Внешний метод рефреша учётных данных. */
|
|
1498
|
+
refreshCredentialsByOuter;
|
|
1499
|
+
/** Полный путь до эндпоинта рефреша токена. */
|
|
1500
|
+
REFRESH_TOKEN_PATH;
|
|
1501
|
+
/** Коды ответа, по которым триггерится попытка рефреша. */
|
|
1502
|
+
CODES_USING_THE_REFRESH_ATTEMPT;
|
|
1503
|
+
/** Ключ флага «рефреш начат» в localStorage. */
|
|
1504
|
+
REFRESH_TOKEN_FLAG = "refreshTokenFlag";
|
|
1505
|
+
/** Интервал опроса флага обновления токена, мс. */
|
|
1506
|
+
INTERVAL_FOR_CHECKING_TOKEN_UPDATE = 50;
|
|
1507
|
+
/** Колбэк, вызываемый после неудачного рефреша. */
|
|
1508
|
+
callbackAfterRejectRefresh;
|
|
1509
|
+
/** Доступ к верхнему контексту RESTAPI (навешивается из конструктора RESTAPI). */
|
|
1510
|
+
getRESTAPIContext;
|
|
1167
1511
|
constructor(settings) {
|
|
1168
1512
|
const { credentialsProcessing } = settings;
|
|
1169
1513
|
const {
|
|
1170
|
-
|
|
1171
|
-
|
|
1514
|
+
// ? Для корректной работы установки токенов в запросы от API
|
|
1515
|
+
// ? нужно передавать методы getCredentials и getHeadersForAuthorize
|
|
1172
1516
|
getCredentials,
|
|
1173
1517
|
getHeadersForAuthorize,
|
|
1174
|
-
|
|
1175
|
-
|
|
1518
|
+
// ? На вход получит токен, должна вернуть объект для коструктора Headers
|
|
1519
|
+
// ? Так же опционально можно передавать
|
|
1176
1520
|
importCredentials,
|
|
1177
|
-
|
|
1521
|
+
// ? если он передается, то он будет применяться к выводу от вызова getCredentials
|
|
1178
1522
|
saveCredentials,
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1523
|
+
// ? можно будет найти в объекте credentialsProcessing, чтобы использовать кастомными методами
|
|
1524
|
+
// ! Либо вызов getCredentials, либо цепочка вызовов importCredentials(getCredentials())
|
|
1525
|
+
// ! должна возвращать требуемую классом структуру
|
|
1526
|
+
// ! Класс требует структуры
|
|
1527
|
+
// ! - { token }, если флоу рефреш токена НЕ используется
|
|
1528
|
+
// ! - { token, refreshToken, expires }, если используется флоу рефреш токена
|
|
1185
1529
|
// *********
|
|
1186
|
-
|
|
1530
|
+
// ? Подключает флоу рефреша токенов
|
|
1187
1531
|
isUseRefreshTokensPropcessing = false,
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1532
|
+
// ! Для корректной работы флоу рефреша токенов передача метода saveCredentials становится ОБЯЗАТЕЛЬНОЙ
|
|
1533
|
+
// ? Так же для корректной работы флоу рефреша токенов нужно
|
|
1534
|
+
// ? - либо
|
|
1191
1535
|
refreshCredentials,
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1536
|
+
// ! метод должен возвращать такую же структуру как и метод getCredentials,
|
|
1537
|
+
// ? на вход получит текущие креды, к выходу будет применен importCredentials, если этот метод передавался
|
|
1538
|
+
// ? - либо
|
|
1195
1539
|
REFRESH_TOKEN_PATH,
|
|
1196
|
-
|
|
1540
|
+
// ! REFRESH_TOKEN_PATH передается ПОЛНОСТЬЮ (глобальная адресация)!
|
|
1197
1541
|
CODES_USING_THE_REFRESH_ATTEMPT,
|
|
1198
|
-
|
|
1199
|
-
|
|
1542
|
+
// ? указывает по каким кодам ответа триггериться рефреш, массив чисел
|
|
1543
|
+
// ? Опционально
|
|
1200
1544
|
REFRESH_TOKEN_FLAG = "refreshTokenFlag",
|
|
1201
1545
|
INTERVAL_FOR_CHECKING_TOKEN_UPDATE = 50,
|
|
1202
1546
|
// ms
|
|
@@ -1204,40 +1548,44 @@ var CredentialsProcessing = class {
|
|
|
1204
1548
|
} = credentialsProcessing || {};
|
|
1205
1549
|
if (typeof getCredentials !== "function") throw new Error("No getCredentials method [CredentialsProcessing]");
|
|
1206
1550
|
if (typeof getHeadersForAuthorize !== "function") {
|
|
1207
|
-
throw new
|
|
1551
|
+
throw new TypeError("No getHeadersForAuthorize method [CredentialsProcessing]");
|
|
1208
1552
|
}
|
|
1209
1553
|
if (importCredentials && typeof importCredentials !== "function") {
|
|
1210
1554
|
throw new Error("Bad importCredentials method [CredentialsProcessing]");
|
|
1211
1555
|
}
|
|
1212
|
-
this.isUseRefreshTokensPropcessing = isUseRefreshTokensPropcessing;
|
|
1556
|
+
this.isUseRefreshTokensPropcessing = Boolean(isUseRefreshTokensPropcessing);
|
|
1213
1557
|
this.DEFAULT_CREDENTIALS = {};
|
|
1214
|
-
this.getCredentialsByOuter = getCredentials;
|
|
1215
|
-
this.getHeadersForAuthorize =
|
|
1216
|
-
|
|
1558
|
+
this.getCredentialsByOuter = () => getCredentials();
|
|
1559
|
+
this.getHeadersForAuthorize = (token) => {
|
|
1560
|
+
const result = getHeadersForAuthorize(token);
|
|
1561
|
+
return getIsOnlyAnObject(result) ? result : {};
|
|
1562
|
+
};
|
|
1563
|
+
if (typeof importCredentials === "function") this.importCredentials = (cred) => importCredentials(cred);
|
|
1217
1564
|
if (saveCredentials || isUseRefreshTokensPropcessing) {
|
|
1218
1565
|
if (typeof saveCredentials !== "function") throw new Error("No saveCredentials method [CredentialsProcessing]");
|
|
1219
|
-
else this.saveCredentials = saveCredentials;
|
|
1566
|
+
else this.saveCredentials = (cred) => saveCredentials(cred);
|
|
1220
1567
|
}
|
|
1221
1568
|
if (isUseRefreshTokensPropcessing) {
|
|
1222
|
-
if (typeof refreshCredentials === "function")
|
|
1223
|
-
|
|
1569
|
+
if (typeof refreshCredentials === "function") {
|
|
1570
|
+
this.refreshCredentialsByOuter = (cred) => refreshCredentials(cred);
|
|
1571
|
+
} else {
|
|
1224
1572
|
if (typeof this.refreshCredentialsByOuter === "function" && typeof REFRESH_TOKEN_PATH !== "string") {
|
|
1225
|
-
throw new
|
|
1573
|
+
throw new TypeError("No REFRESH_TOKEN_PATH [CredentialsProcessing]");
|
|
1226
1574
|
}
|
|
1227
|
-
this.REFRESH_TOKEN_PATH = REFRESH_TOKEN_PATH;
|
|
1575
|
+
this.REFRESH_TOKEN_PATH = typeof REFRESH_TOKEN_PATH === "string" ? REFRESH_TOKEN_PATH : void 0;
|
|
1228
1576
|
}
|
|
1229
1577
|
if (!Array.isArray(CODES_USING_THE_REFRESH_ATTEMPT)) {
|
|
1230
|
-
throw new
|
|
1578
|
+
throw new TypeError("No CODES_USING_THE_REFRESH_ATTEMPT [CredentialsProcessing]");
|
|
1231
1579
|
}
|
|
1232
1580
|
if (!CODES_USING_THE_REFRESH_ATTEMPT.every((i) => typeof i === "number")) {
|
|
1233
1581
|
throw new Error("Invalid format of CODES_USING_THE_REFRESH_ATTEMPT elements [CredentialsProcessing]");
|
|
1234
1582
|
}
|
|
1235
1583
|
if (typeof REFRESH_TOKEN_FLAG !== "string") throw new Error("Bad REFRESH_TOKEN_FLAG [CredentialsProcessing]");
|
|
1236
1584
|
if (typeof INTERVAL_FOR_CHECKING_TOKEN_UPDATE !== "number") {
|
|
1237
|
-
throw new
|
|
1585
|
+
throw new TypeError("Bad INTERVAL_FOR_CHECKING_TOKEN_UPDATE [CredentialsProcessing]");
|
|
1238
1586
|
}
|
|
1239
1587
|
if (typeof INTERVAL_FOR_CHECKING_TOKEN_UPDATE !== "number") {
|
|
1240
|
-
throw new
|
|
1588
|
+
throw new TypeError("Bad INTERVAL_FOR_CHECKING_TOKEN_UPDATE [CredentialsProcessing]");
|
|
1241
1589
|
}
|
|
1242
1590
|
if (callbackAfterRejectRefresh && typeof callbackAfterRejectRefresh !== "function") {
|
|
1243
1591
|
throw new Error("Bad INTERVAL_FOR_CHECKING_TOKEN_UPDATE [CredentialsProcessing]");
|
|
@@ -1245,23 +1593,33 @@ var CredentialsProcessing = class {
|
|
|
1245
1593
|
this.CODES_USING_THE_REFRESH_ATTEMPT = CODES_USING_THE_REFRESH_ATTEMPT;
|
|
1246
1594
|
this.REFRESH_TOKEN_FLAG = REFRESH_TOKEN_FLAG;
|
|
1247
1595
|
this.INTERVAL_FOR_CHECKING_TOKEN_UPDATE = INTERVAL_FOR_CHECKING_TOKEN_UPDATE;
|
|
1248
|
-
if (callbackAfterRejectRefresh) this.callbackAfterRejectRefresh = callbackAfterRejectRefresh;
|
|
1596
|
+
if (typeof callbackAfterRejectRefresh === "function") this.callbackAfterRejectRefresh = () => callbackAfterRejectRefresh();
|
|
1249
1597
|
}
|
|
1250
1598
|
}
|
|
1599
|
+
/** Возвращает значение флага «рефреш начат» из localStorage. */
|
|
1251
1600
|
getIsTokenStartRefresh() {
|
|
1252
1601
|
return localStorage.getItem(this.REFRESH_TOKEN_FLAG);
|
|
1253
1602
|
}
|
|
1603
|
+
/** Выставляет флаг «рефреш начат» в localStorage. */
|
|
1254
1604
|
setIsTokenStartRefresh() {
|
|
1255
|
-
localStorage.setItem(this.REFRESH_TOKEN_FLAG, true);
|
|
1605
|
+
localStorage.setItem(this.REFRESH_TOKEN_FLAG, String(true));
|
|
1256
1606
|
}
|
|
1607
|
+
/** Снимает флаг «рефреш начат» из localStorage. */
|
|
1257
1608
|
removeIsTokenStartRefresh() {
|
|
1258
1609
|
localStorage.removeItem(this.REFRESH_TOKEN_FLAG);
|
|
1259
1610
|
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Возвращает текущие учётные данные (с учётом importCredentials и проверки истечения JWT).
|
|
1613
|
+
*
|
|
1614
|
+
* @param isCatchCallbackProcess - флаг процесса обработки ошибки (отключает проверку истечения).
|
|
1615
|
+
* @param callback - необязательный колбэк, получающий итоговые учётные данные.
|
|
1616
|
+
* @returns Промис с учётными данными.
|
|
1617
|
+
*/
|
|
1260
1618
|
async getCredentials(isCatchCallbackProcess, callback) {
|
|
1261
1619
|
let credentials = await this.getCredentialsByOuter();
|
|
1262
1620
|
if (typeof this.importCredentials === "function") credentials = await this.importCredentials(credentials);
|
|
1263
|
-
|
|
1264
|
-
const token =
|
|
1621
|
+
const credObj = getIsOnlyAnObject(credentials) ? credentials : {};
|
|
1622
|
+
const token = credObj.token || null;
|
|
1265
1623
|
if (token && !isCatchCallbackProcess) {
|
|
1266
1624
|
let decoded;
|
|
1267
1625
|
try {
|
|
@@ -1270,11 +1628,18 @@ var CredentialsProcessing = class {
|
|
|
1270
1628
|
decoded = null;
|
|
1271
1629
|
}
|
|
1272
1630
|
const currentTime = Date.now() / 1e3;
|
|
1273
|
-
if (decoded !== null && Number(decoded.exp) < currentTime)
|
|
1631
|
+
if (decoded !== null && Number(decoded.exp) < currentTime) credObj.isNeedRefresh = true;
|
|
1274
1632
|
}
|
|
1275
|
-
if (callback) await callback({ ...
|
|
1276
|
-
return { ...
|
|
1277
|
-
}
|
|
1633
|
+
if (callback) await callback({ ...credObj, isCatchCallbackProcess });
|
|
1634
|
+
return { ...credObj, isCatchCallbackProcess };
|
|
1635
|
+
}
|
|
1636
|
+
/**
|
|
1637
|
+
* Выполняет рефреш учётных данных (внешним методом либо дефолтным OAuth-флоу).
|
|
1638
|
+
*
|
|
1639
|
+
* @param currentCredentials - текущие учётные данные.
|
|
1640
|
+
* @param callback - необязательный колбэк сохранения новых учётных данных.
|
|
1641
|
+
* @returns Промис с новыми учётными данными.
|
|
1642
|
+
*/
|
|
1278
1643
|
async refreshCredentials(currentCredentials, callback) {
|
|
1279
1644
|
const CONTEXT = this;
|
|
1280
1645
|
async function finalize(cred) {
|
|
@@ -1287,11 +1652,10 @@ var CredentialsProcessing = class {
|
|
|
1287
1652
|
if (!currentCredentials?.token || !currentCredentials?.refreshToken) return finalize(CONTEXT.DEFAULT_CREDENTIALS);
|
|
1288
1653
|
async function refreshCredentialsByDefault() {
|
|
1289
1654
|
const { token, refreshToken } = currentCredentials;
|
|
1290
|
-
const headers = new Headers();
|
|
1291
|
-
headers.append(...Object.entries(CONTEXT.getHeadersForAuthorize(token)));
|
|
1655
|
+
const headers = new Headers(Object.entries(CONTEXT.getHeadersForAuthorize(token || "")).map(([key, value]) => [key, `${value}`]));
|
|
1292
1656
|
const body = new FormData();
|
|
1293
1657
|
body.append("grant_type", "refresh_token");
|
|
1294
|
-
body.append("refresh_token", refreshToken);
|
|
1658
|
+
body.append("refresh_token", refreshToken || "");
|
|
1295
1659
|
body.append("client_id", "oauth");
|
|
1296
1660
|
body.append("client_secret", "secret");
|
|
1297
1661
|
body.append("access_type", "offline");
|
|
@@ -1304,8 +1668,14 @@ var CredentialsProcessing = class {
|
|
|
1304
1668
|
});
|
|
1305
1669
|
}
|
|
1306
1670
|
const newCredentials = typeof CONTEXT.refreshCredentialsByOuter === "function" ? await CONTEXT.refreshCredentialsByOuter(currentCredentials) : await refreshCredentialsByDefault();
|
|
1307
|
-
return finalize(newCredentials);
|
|
1308
|
-
}
|
|
1671
|
+
return finalize(getIsOnlyAnObject(newCredentials) ? newCredentials : CONTEXT.DEFAULT_CREDENTIALS);
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Ожидает завершения рефреша токена (или запускает его флаг при необходимости).
|
|
1675
|
+
*
|
|
1676
|
+
* @param isNeedRefresh - выставить ли флаг «рефреш начат» при отсутствии активного рефреша.
|
|
1677
|
+
* @returns Промис, который резолвится по завершении ожидания.
|
|
1678
|
+
*/
|
|
1309
1679
|
async waitRefresh(isNeedRefresh) {
|
|
1310
1680
|
return new Promise((resolve) => {
|
|
1311
1681
|
if (!this.getIsTokenStartRefresh()) {
|
|
@@ -1321,10 +1691,16 @@ var CredentialsProcessing = class {
|
|
|
1321
1691
|
}
|
|
1322
1692
|
});
|
|
1323
1693
|
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Обрабатывает учётные данные: при необходимости рефрешит токен и возвращает актуальные данные.
|
|
1696
|
+
*
|
|
1697
|
+
* @param cred - текущие учётные данные.
|
|
1698
|
+
* @returns Промис с актуальными учётными данными (с флагом isRefreshFailed при неудаче).
|
|
1699
|
+
*/
|
|
1324
1700
|
async processCredentials(cred) {
|
|
1325
1701
|
if (!cred.isNeedRefresh && !cred.isCatchCallbackProcess) return cred;
|
|
1326
1702
|
const CONTEXT = this;
|
|
1327
|
-
return CONTEXT.refreshCredentials(cred, (response) => CONTEXT.saveCredentials(response)).then(() => {
|
|
1703
|
+
return CONTEXT.refreshCredentials(cred, (response) => CONTEXT.saveCredentials?.(response)).then(() => {
|
|
1328
1704
|
return new Promise((resolve) => {
|
|
1329
1705
|
setTimeout(async () => {
|
|
1330
1706
|
const newCredentials = await CONTEXT.getCredentials();
|
|
@@ -1342,11 +1718,15 @@ var CredentialsProcessing = class {
|
|
|
1342
1718
|
};
|
|
1343
1719
|
var CredentialsProcessing_default = CredentialsProcessing;
|
|
1344
1720
|
|
|
1345
|
-
// src/Classes/RESTAPI/index.
|
|
1721
|
+
// src/Classes/RESTAPI/index.ts
|
|
1346
1722
|
function returnTheContext() {
|
|
1347
1723
|
return this;
|
|
1348
1724
|
}
|
|
1349
1725
|
var RESTAPI = class extends ApiBase_default {
|
|
1726
|
+
/** Функция показа сообщений пользователю (или null, если информирование отключено). */
|
|
1727
|
+
sendMessage = null;
|
|
1728
|
+
/** Обработчик учётных данных (создаётся при наличии настройки credentialsProcessing). */
|
|
1729
|
+
credentialsProcessing;
|
|
1350
1730
|
constructor(settings) {
|
|
1351
1731
|
super(settings);
|
|
1352
1732
|
const { sendMessage, credentialsProcessing } = settings || {};
|
|
@@ -1356,7 +1736,14 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1356
1736
|
this.credentialsProcessing.getRESTAPIContext = returnTheContext.bind(this);
|
|
1357
1737
|
}
|
|
1358
1738
|
}
|
|
1359
|
-
|
|
1739
|
+
/**
|
|
1740
|
+
* Основной (базовый) метод API: выполняет мультизапрос (или одиночный запрос).
|
|
1741
|
+
*
|
|
1742
|
+
* @param inputRequests - путь, объект описания запроса или их массив.
|
|
1743
|
+
* @param settings - общие настройки запроса (формат ответа, тосты, сообщения и т.п.).
|
|
1744
|
+
* @returns Промис с результатом (форма зависит от isResponseAsObject).
|
|
1745
|
+
*/
|
|
1746
|
+
// ! Основной (базовый) метод API, мультизапросы
|
|
1360
1747
|
async doRequest(inputRequests, settings) {
|
|
1361
1748
|
if (typeof inputRequests !== "string" && typeof inputRequests !== "object") {
|
|
1362
1749
|
return Promise.reject(new Error(this.BAD_REQUEST_DATA_TEXT));
|
|
@@ -1380,24 +1767,29 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1380
1767
|
throw new Error("It is impossible to make a request!");
|
|
1381
1768
|
}
|
|
1382
1769
|
instance.setIsResponseAsObject(isResponseAsObject ?? true);
|
|
1383
|
-
if (callback) instance.setCallback(callback);
|
|
1770
|
+
if (typeof callback === "function") instance.setCallback(callback);
|
|
1384
1771
|
function getRequests() {
|
|
1385
1772
|
let output;
|
|
1386
1773
|
if (typeof inputRequests === "string") output = [{ path: inputRequests }];
|
|
1387
1774
|
else output = Array.isArray(inputRequests) ? inputRequests : [inputRequests];
|
|
1388
1775
|
function getCallback(item, mesageOptions) {
|
|
1389
|
-
const
|
|
1776
|
+
const getBodyAs = typeof item.getBodyAs === "string" ? item.getBodyAs : void 0;
|
|
1390
1777
|
const finalIsGetBody = typeof item.isGetBody === "boolean" || typeof item.isGetBody === "string" ? item.isGetBody : isGetBody;
|
|
1391
1778
|
const finalIsGetBodyFirst = finalIsGetBody === "first";
|
|
1392
|
-
const checkResponseCallback = finalIsGetBodyFirst ? async (res,
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1779
|
+
const checkResponseCallback = finalIsGetBodyFirst ? async (res, options) => API_CONTEXT.getResponseBody(await API_CONTEXT.checkResponseCode(res, options), getBodyAs) : async (res, options) => API_CONTEXT.checkResponseCode(res, options);
|
|
1780
|
+
const itemCallback = item.callback;
|
|
1781
|
+
const callbackFn = typeof itemCallback === "function" ? async (res) => itemCallback(await checkResponseCallback(res, mesageOptions)) : async (res) => checkResponseCallback(res, mesageOptions);
|
|
1782
|
+
return finalIsGetBody && !finalIsGetBodyFirst ? async (res) => API_CONTEXT.getResponseBody(await callbackFn(res), getBodyAs) : callbackFn;
|
|
1395
1783
|
}
|
|
1396
1784
|
async function getRequestItem(item, idx) {
|
|
1397
|
-
const
|
|
1785
|
+
const itemObj = getIsOnlyAnObject(item) ? item : { path: item };
|
|
1786
|
+
const { type, ...partialRestFirst } = itemObj;
|
|
1398
1787
|
const itemAfterRequestCreating = await (async () => {
|
|
1399
|
-
const key = `createRequest_${type
|
|
1400
|
-
|
|
1788
|
+
const key = `createRequest_${typeof type === "string" ? type : "default"}`;
|
|
1789
|
+
const creator = key in API_CONTEXT ? API_CONTEXT[key] : void 0;
|
|
1790
|
+
const result = typeof creator === "function" ? creator.call(API_CONTEXT, partialRestFirst, "doRequestMapping") : API_CONTEXT.createRequest_default(partialRestFirst, "doRequestMapping");
|
|
1791
|
+
const awaited = await result;
|
|
1792
|
+
return getIsOnlyAnObject(awaited) ? awaited : {};
|
|
1401
1793
|
})();
|
|
1402
1794
|
const { fullPath, api, path, query, queryParameters, ...partialRestSecond } = itemAfterRequestCreating;
|
|
1403
1795
|
const {
|
|
@@ -1413,23 +1805,25 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1413
1805
|
isNoToast,
|
|
1414
1806
|
...rest
|
|
1415
1807
|
} = partialRestSecond;
|
|
1808
|
+
const successMessagesArr = Array.isArray(successMessages) ? successMessages : void 0;
|
|
1809
|
+
const errorMessagesArr = Array.isArray(errorMessages) ? errorMessages : void 0;
|
|
1416
1810
|
const useSuccessMessageFlag = Boolean(
|
|
1417
|
-
successMess || commonSuccessMessage ||
|
|
1811
|
+
successMess || commonSuccessMessage || successMessagesArr?.[idx] || CSMfromSettings || isToastResult || isToastFromSettings
|
|
1418
1812
|
);
|
|
1419
1813
|
const isUseSuccessToast = useSuccessMessageFlag && !isNoToast && !isNoToastFromSettings && !isNoToastSuccess && !isNTSFromSettings;
|
|
1420
1814
|
const isUseErrorToast = !isNoToast && !isNoToastFromSettings && !isNoToastError && !isNTEFromSettings;
|
|
1421
1815
|
const mesageOptions = {
|
|
1422
|
-
successMess: successMess || commonSuccessMessage ||
|
|
1816
|
+
successMess: successMess || commonSuccessMessage || successMessagesArr?.[idx] || CSMfromSettings,
|
|
1423
1817
|
successMessageType: successMessageType || SMTfromSettings,
|
|
1424
|
-
errorMess: errorMess || commonErrorMessage ||
|
|
1818
|
+
errorMess: errorMess || commonErrorMessage || errorMessagesArr?.[idx] || CEMfromSettings,
|
|
1425
1819
|
isUseSuccessToast,
|
|
1426
1820
|
isUseErrorToast,
|
|
1427
1821
|
toastOptions: toastOptions || TOFomSettings
|
|
1428
1822
|
};
|
|
1429
1823
|
return {
|
|
1430
1824
|
...rest,
|
|
1431
|
-
path: `${fullPath || await API_CONTEXT.getRootPath(
|
|
1432
|
-
|
|
1825
|
+
path: `${fullPath || await API_CONTEXT.getRootPath() + (typeof path === "string" ? path : "")}`,
|
|
1826
|
+
// ? Запускаем самовызывающуюся асинхронную ф-ю, ждем резолва промиса от нее
|
|
1433
1827
|
queryParameters: await (async () => {
|
|
1434
1828
|
const queryParams = query || queryParameters || "";
|
|
1435
1829
|
const preparedQueryParams = await API_CONTEXT.processQueryParams(queryParams);
|
|
@@ -1439,28 +1833,26 @@ var RESTAPI = class extends ApiBase_default {
|
|
|
1439
1833
|
callback: getCallback(itemAfterRequestCreating, mesageOptions)
|
|
1440
1834
|
};
|
|
1441
1835
|
}
|
|
1442
|
-
return output
|
|
1836
|
+
return output.map((item, idx) => getRequestItem(item, idx));
|
|
1443
1837
|
}
|
|
1444
1838
|
return instance.request(await Promise.all(getRequests()));
|
|
1445
1839
|
}
|
|
1446
|
-
|
|
1840
|
+
/**
|
|
1841
|
+
* Метод API для одиночных запросов: применяет крейтер по `type` и делегирует в {@link RESTAPI.doRequest}.
|
|
1842
|
+
*
|
|
1843
|
+
* @param requestSettings - объект описания одиночного запроса (с необязательным `type`).
|
|
1844
|
+
* @returns Промис с результатом запроса.
|
|
1845
|
+
*/
|
|
1846
|
+
// ! Метод API для одиночных запросов
|
|
1447
1847
|
async doMonoRequest(requestSettings) {
|
|
1448
1848
|
if (!getIsOnlyAnObject(requestSettings)) throw new Error(`${this.BAD_REQUEST_DATA_TEXT} [RESTAPI.doMonoRequest]`);
|
|
1449
1849
|
const { type, ...requestSettingsRest } = requestSettings;
|
|
1450
|
-
const
|
|
1451
|
-
|
|
1850
|
+
const key = `createRequest_${typeof type === "string" ? type : ""}`;
|
|
1851
|
+
const creator = type && key in this ? this[key] : void 0;
|
|
1852
|
+
const created = typeof creator === "function" ? await creator.call(this, requestSettingsRest) : await this.createRequest_default(requestSettingsRest);
|
|
1853
|
+
const doRequestArgs = Array.isArray(created) ? created : [created];
|
|
1854
|
+
return this.doRequest(doRequestArgs[0], doRequestArgs[1]);
|
|
1452
1855
|
}
|
|
1453
1856
|
};
|
|
1454
1857
|
var RESTAPI_default = RESTAPI;
|
|
1455
|
-
//! При получении экземпляра, если sendMessage не является ф-ей,
|
|
1456
|
-
//! то это воспринимается как отключение шага информирования об ошибке запроса как такового
|
|
1457
|
-
//! Планируемая структура { headers, queryParameters, options }, где
|
|
1458
|
-
//! - headers и options - объекты,
|
|
1459
|
-
//! - queryParameters - строка, массив или объект
|
|
1460
|
-
//! ВНИМАНИЕ! Данный механизм рефреша принят на проекте finturfreactfrontend (админка)
|
|
1461
|
-
//! На кабинете он ТОЧНО НЕ ТАКОЙ
|
|
1462
|
-
//! currentCredentials передаются в формате класса! ({ token, refreshToken, expires })
|
|
1463
|
-
//! Наличие credentialsProcessing подключает ДОБАВЛЕНИЕ ТОКЕНОВ В ЗАПРОСЫ,
|
|
1464
|
-
//! НО по умолчанию НЕ добавляет флоу рефреша токенов
|
|
1465
|
-
//! (флоу рефреша подключается пропой isUseRefreshTokensPropcessing из credentialsProcessing)
|
|
1466
1858
|
//# sourceMappingURL=classes.cjs.map
|