bx-rest 1.5.1 → 1.6.0
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/CHANGELOG.md +94 -0
- package/README.en.md +113 -2
- package/README.md +114 -2
- package/esm2022/functions/errors.mjs +17 -5
- package/esm2022/functions/uniqueElementCode.mjs +24 -0
- package/esm2022/public-api.mjs +2 -2
- package/esm2022/request-navvy/bizproc.mjs +18 -9
- package/esm2022/request-navvy/calendar/event.mjs +1 -9
- package/esm2022/request-navvy/disk/operation.mjs +3 -10
- package/esm2022/request-navvy/socialnetwork/api/livefeed.mjs +1 -5
- package/esm2022/request-navvy/task/operation/elapseditem.mjs +8 -8
- package/esm2022/request-navvy/tasks/task.mjs +1 -119
- package/esm2022/rest/navvy.mjs +66 -64
- package/esm2022/services/base.mjs +1 -4
- package/esm2022/services/context.mjs +59 -0
- package/esm2022/services/http/HttpBX.mjs +49 -19
- package/esm2022/services/http/authRefresh.mjs +25 -23
- package/esm2022/services/http/http.mjs +14 -69
- package/esm2022/services/http/middleware.mjs +149 -0
- package/esm2022/services/http/sessionKey.mjs +16 -5
- package/esm2022/services/http/transport.mjs +5 -0
- package/esm2022/services/navvy/navvy-support.mjs +2 -15
- package/esm2022/services/navvy.mjs +18 -31
- package/esm2022/typification/rest/calendar/event/get.mjs +1 -1
- package/esm2022/typification/rest/tasks/task/get.mjs +1 -1
- package/esm2022/typification/settings.mjs +1 -1
- package/fesm2022/bx-rest.mjs +450 -463
- package/fesm2022/bx-rest.mjs.map +1 -1
- package/functions/errors.d.ts +9 -0
- package/functions/uniqueElementCode.d.ts +12 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -1
- package/rest/navvy.d.ts +9 -0
- package/services/context.d.ts +43 -0
- package/services/http/HttpBX.d.ts +10 -0
- package/services/http/authRefresh.d.ts +5 -1
- package/services/http/http.d.ts +12 -9
- package/services/http/middleware.d.ts +31 -0
- package/services/http/sessionKey.d.ts +10 -0
- package/services/http/transport.d.ts +28 -0
- package/services/navvy/navvy-support.d.ts +0 -10
- package/services/navvy.d.ts +1 -0
- package/typification/rest/calendar/event/get.d.ts +1 -1
- package/typification/settings.d.ts +34 -0
- package/esm2022/functions/errorHandler.mjs +0 -34
- package/esm2022/request/app.mjs +0 -13
- package/esm2022/request/bizproc/activity.mjs +0 -3
- package/esm2022/request/bizproc/event.mjs +0 -3
- package/esm2022/request/bizproc/robot.mjs +0 -3
- package/esm2022/request/bizproc/task.mjs +0 -3
- package/esm2022/request/bizproc/workflow/instance.mjs +0 -3
- package/esm2022/request/bizproc/workflow/template.mjs +0 -3
- package/esm2022/request/bizproc/workflow.mjs +0 -18
- package/esm2022/request/bizproc.mjs +0 -15
- package/esm2022/request/department.mjs +0 -26
- package/esm2022/request/disk/attachedObject.mjs +0 -14
- package/esm2022/request/disk/file.mjs +0 -18
- package/esm2022/request/disk/folder.mjs +0 -117
- package/esm2022/request/disk.mjs +0 -11
- package/esm2022/request/lists/element.mjs +0 -18
- package/esm2022/request/lists/field.mjs +0 -35
- package/esm2022/request/lists.mjs +0 -86
- package/esm2022/request/log/blogcomment.mjs +0 -3
- package/esm2022/request/log/blogpost.mjs +0 -18
- package/esm2022/request/log.mjs +0 -9
- package/esm2022/request/pull/application/config.mjs +0 -11
- package/esm2022/request/pull/channel/public.mjs +0 -18
- package/esm2022/request/pull/config.mjs +0 -13
- package/esm2022/request/pull.mjs +0 -11
- package/esm2022/request/server.mjs +0 -14
- package/esm2022/request/socialnetwork/api/contentview.mjs +0 -14
- package/esm2022/request/socialnetwork/api/livefeed/blogpost/important.mjs +0 -14
- package/esm2022/request/socialnetwork/api/livefeed/blogpost.mjs +0 -7
- package/esm2022/request/socialnetwork/api/livefeed.mjs +0 -7
- package/esm2022/request/socialnetwork/api.mjs +0 -9
- package/esm2022/request/socialnetwork.mjs +0 -8
- package/esm2022/request/sonet_group.mjs +0 -24
- package/esm2022/request/task/commentitem.mjs +0 -32
- package/esm2022/request/task/elapseditem.mjs +0 -40
- package/esm2022/request/task/item/userfield.mjs +0 -14
- package/esm2022/request/task/item.mjs +0 -7
- package/esm2022/request/task/planner.mjs +0 -11
- package/esm2022/request/task.mjs +0 -13
- package/esm2022/request/tasks/task/result.mjs +0 -22
- package/esm2022/request/tasks/task.mjs +0 -110
- package/esm2022/request/tasks.mjs +0 -7
- package/esm2022/request/user/userfield.mjs +0 -14
- package/esm2022/request/user.mjs +0 -40
- package/esm2022/rest/base.mjs +0 -39
- package/esm2022/services/http/HttpData.mjs +0 -77
- package/esm2022/services/http/base/base.mjs +0 -4
- package/esm2022/services/http/httpNavvy.mjs +0 -14
- package/esm2022/typification/base/answers.mjs +0 -438
- package/esm2022/typification/base/params.mjs +0 -525
- package/esm2022/typification/base/workpiece/methods-list.mjs +0 -2
- package/esm2022/typification/base/workpiece/methods.mjs +0 -2
- package/functions/errorHandler.d.ts +0 -10
- package/request/app.d.ts +0 -8
- package/request/bizproc/activity.d.ts +0 -2
- package/request/bizproc/event.d.ts +0 -2
- package/request/bizproc/robot.d.ts +0 -2
- package/request/bizproc/task.d.ts +0 -2
- package/request/bizproc/workflow/instance.d.ts +0 -2
- package/request/bizproc/workflow/template.d.ts +0 -2
- package/request/bizproc/workflow.d.ts +0 -13
- package/request/bizproc.d.ts +0 -12
- package/request/department.d.ts +0 -18
- package/request/disk/attachedObject.d.ts +0 -8
- package/request/disk/file.d.ts +0 -10
- package/request/disk/folder.d.ts +0 -96
- package/request/disk.d.ts +0 -8
- package/request/lists/element.d.ts +0 -11
- package/request/lists/field.d.ts +0 -11
- package/request/lists.d.ts +0 -31
- package/request/log/blogcomment.d.ts +0 -2
- package/request/log/blogpost.d.ts +0 -11
- package/request/log.d.ts +0 -6
- package/request/pull/application/config.d.ts +0 -5
- package/request/pull/channel/public.d.ts +0 -5
- package/request/pull/config.d.ts +0 -7
- package/request/pull.d.ts +0 -8
- package/request/server.d.ts +0 -7
- package/request/socialnetwork/api/contentview.d.ts +0 -6
- package/request/socialnetwork/api/livefeed/blogpost/important.d.ts +0 -6
- package/request/socialnetwork/api/livefeed/blogpost.d.ts +0 -4
- package/request/socialnetwork/api/livefeed.d.ts +0 -4
- package/request/socialnetwork/api.d.ts +0 -6
- package/request/socialnetwork.d.ts +0 -4
- package/request/sonet_group.d.ts +0 -8
- package/request/task/commentitem.d.ts +0 -23
- package/request/task/elapseditem.d.ts +0 -26
- package/request/task/item/userfield.d.ts +0 -6
- package/request/task/item.d.ts +0 -4
- package/request/task/planner.d.ts +0 -4
- package/request/task.d.ts +0 -10
- package/request/tasks/task/result.d.ts +0 -13
- package/request/tasks/task.d.ts +0 -37
- package/request/tasks.d.ts +0 -4
- package/request/user/userfield.d.ts +0 -8
- package/request/user.d.ts +0 -24
- package/rest/base.d.ts +0 -33
- package/services/http/HttpData.d.ts +0 -7
- package/services/http/base/base.d.ts +0 -7
- package/services/http/httpNavvy.d.ts +0 -10
- package/typification/base/answers.d.ts +0 -12
- package/typification/base/params.d.ts +0 -16
- package/typification/base/workpiece/methods-list.d.ts +0 -247
- package/typification/base/workpiece/methods.d.ts +0 -20
package/fesm2022/bx-rest.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Subscription, of, throwError, from,
|
|
2
|
-
import {
|
|
1
|
+
import { Subscription, of, defer, throwError, from, forkJoin, Observable, concatMap, toArray, mergeMap, shareReplay, tap, catchError as catchError$1 } from 'rxjs';
|
|
2
|
+
import { catchError, switchMap, map, take, mergeMap as mergeMap$1 } from 'rxjs/operators';
|
|
3
3
|
import clone from 'just-clone';
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
import flatten from 'just-flatten-it';
|
|
@@ -414,9 +414,6 @@ async function getBase64FileLikeStr(file) {
|
|
|
414
414
|
return undefined;
|
|
415
415
|
}
|
|
416
416
|
function prepareBaseAddress(url, add = '') {
|
|
417
|
-
// if (url.search('https://') !== 0 && url.search('http://')) {
|
|
418
|
-
// url = 'https://' + url
|
|
419
|
-
// }
|
|
420
417
|
if (add && add.length > 0) {
|
|
421
418
|
if (url.lastIndexOf('/') !== (url.length - 1)) {
|
|
422
419
|
url = url + '/';
|
|
@@ -523,6 +520,64 @@ class SessionStorage {
|
|
|
523
520
|
}
|
|
524
521
|
}
|
|
525
522
|
|
|
523
|
+
/**
|
|
524
|
+
* Контекст клиента: его настройки, экземпляр axios и общее состояние
|
|
525
|
+
* продления авторизации и очереди `throttle`.
|
|
526
|
+
*
|
|
527
|
+
* Объекты библиотеки запоминают контекст в момент создания
|
|
528
|
+
* (`currentContext()`), поэтому все запросы клиента `new BXRestNavvy(settings)`
|
|
529
|
+
* идут с его настройками, а не с глобальными. Внутренняя деталь библиотеки.
|
|
530
|
+
*/
|
|
531
|
+
class BXRestContext {
|
|
532
|
+
constructor(own) {
|
|
533
|
+
this.own = own;
|
|
534
|
+
/** Сколько продлений уже завершилось успешно. */
|
|
535
|
+
this.refreshCount = 0;
|
|
536
|
+
/** Очередь `throttle`: когда можно отправить следующий запрос клиента (мс, Date.now()). */
|
|
537
|
+
this.throttleNextSlot = 0;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Свои настройки клиента, а без них — глобальные `BXRestSettings.value`,
|
|
541
|
+
* прочитанные в момент обращения: `BXRestSettings.update()` заменяет объект.
|
|
542
|
+
*/
|
|
543
|
+
get settings() {
|
|
544
|
+
return this.own ?? BXRestSettings.value;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Контекст глобальных настроек. С ним работают `new BXRestNavvy()` без
|
|
549
|
+
* аргумента и объекты, созданные приложением напрямую (`new Navvy()`,
|
|
550
|
+
* `new BXRestRequest()`).
|
|
551
|
+
*/
|
|
552
|
+
const globalContext = /* @__PURE__ */ new BXRestContext();
|
|
553
|
+
let current = globalContext;
|
|
554
|
+
function currentContext() {
|
|
555
|
+
return current;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Делает `ctx` текущим и возвращает прежний контекст. Вызывающий обязан
|
|
559
|
+
* вернуть его через `restoreContext()` в `finally`: иначе после исключения
|
|
560
|
+
* чужие настройки достанутся объектам, созданным позже.
|
|
561
|
+
*/
|
|
562
|
+
function enterContext(ctx) {
|
|
563
|
+
const previous = current;
|
|
564
|
+
current = ctx;
|
|
565
|
+
return previous;
|
|
566
|
+
}
|
|
567
|
+
function restoreContext(previous) {
|
|
568
|
+
current = previous;
|
|
569
|
+
}
|
|
570
|
+
/** Создаёт объекты в контексте `ctx` и возвращает прежний контекст, даже при исключении. */
|
|
571
|
+
function runInContext(ctx, build) {
|
|
572
|
+
const previous = enterContext(ctx);
|
|
573
|
+
try {
|
|
574
|
+
return build();
|
|
575
|
+
}
|
|
576
|
+
finally {
|
|
577
|
+
restoreContext(previous);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
526
581
|
class SessionKeyError extends Error {
|
|
527
582
|
constructor(message) {
|
|
528
583
|
super(message);
|
|
@@ -534,12 +589,18 @@ class SessionKeyServices {
|
|
|
534
589
|
// НОВЫЙ объект (this.value = {...this.value, ...}), а не мутирует старый —
|
|
535
590
|
// поэтому `= BXRestSettings.value` в виде обычного поля навсегда
|
|
536
591
|
// "заморозил" бы то, что было на момент создания SessionKeyServices.
|
|
537
|
-
// Геттер вместо этого читает
|
|
538
|
-
//
|
|
592
|
+
// Геттер вместо этого читает актуальные настройки при каждом обращении:
|
|
593
|
+
// свои настройки клиента или глобальные BXRestSettings.value.
|
|
539
594
|
get BX_REST_SETTINGS() {
|
|
540
|
-
return
|
|
595
|
+
return this.ctx.settings;
|
|
541
596
|
}
|
|
542
597
|
constructor() {
|
|
598
|
+
/**
|
|
599
|
+
* Контекст клиента, в котором создан объект: внутри `new BXRestNavvy(settings)`
|
|
600
|
+
* — контекст этого клиента, в остальных случаях — глобальные настройки.
|
|
601
|
+
* Объявлен первым: конструктор ниже уже читает настройки.
|
|
602
|
+
*/
|
|
603
|
+
this.ctx = currentContext();
|
|
543
604
|
this.authHave = false;
|
|
544
605
|
this.subscribe = {
|
|
545
606
|
authData: new Subscription()
|
|
@@ -598,6 +659,10 @@ class SessionKeyServices {
|
|
|
598
659
|
getHeaders() {
|
|
599
660
|
return { ...this.BX_REST_SETTINGS.headers };
|
|
600
661
|
}
|
|
662
|
+
/** Свои middleware из настроек (`middleware`), читаются при каждом запросе — как и остальные настройки. */
|
|
663
|
+
getMiddleware() {
|
|
664
|
+
return this.BX_REST_SETTINGS.middleware ?? [];
|
|
665
|
+
}
|
|
601
666
|
getSessid() {
|
|
602
667
|
const check = this.getSearchParam('sessid');
|
|
603
668
|
if (check) {
|
|
@@ -763,151 +828,21 @@ class SessionKeyServices {
|
|
|
763
828
|
}
|
|
764
829
|
}
|
|
765
830
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
levelOut: false
|
|
772
|
-
}
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
getHttpParamsPost(obj, sendHttpParams = new FormData(), nesting = [], settings = this.defSettings) {
|
|
776
|
-
if (obj instanceof Blob) {
|
|
777
|
-
let first = nesting[0];
|
|
778
|
-
let setKey = (nesting.length > 1)
|
|
779
|
-
? first + '[' + nesting.slice(1).join('][') + ']'
|
|
780
|
-
: first;
|
|
781
|
-
sendHttpParams.set(setKey, obj);
|
|
782
|
-
return sendHttpParams;
|
|
783
|
-
}
|
|
784
|
-
else if (obj instanceof Date) {
|
|
785
|
-
let first = nesting[0];
|
|
786
|
-
let tzoffset = (settings.timeZone.calc) ? obj.getTimezoneOffset() * 60000 : 0; // вычисляем влияние часового пояса
|
|
787
|
-
let levelOut = (settings.timeZone.levelOut) ? obj.getTimezoneOffset() * 60000 : 0; // вычисляем влияние часового пояса
|
|
788
|
-
let setKey = (nesting.length > 1)
|
|
789
|
-
? first + '[' + nesting.slice(1).join('][') + ']'
|
|
790
|
-
: first;
|
|
791
|
-
sendHttpParams.set(setKey, (new Date(obj.valueOf() + tzoffset - levelOut)).toISOString());
|
|
792
|
-
return sendHttpParams;
|
|
793
|
-
}
|
|
794
|
-
else {
|
|
795
|
-
for (const key in obj) {
|
|
796
|
-
let setKey = '';
|
|
797
|
-
if (nesting.length) {
|
|
798
|
-
let first = nesting[0];
|
|
799
|
-
setKey = (nesting.length > 1)
|
|
800
|
-
? first + '[' + nesting.slice(1).join('][') + '][' + key + ']'
|
|
801
|
-
: first + '[' + key + ']';
|
|
802
|
-
}
|
|
803
|
-
else {
|
|
804
|
-
setKey = key;
|
|
805
|
-
}
|
|
806
|
-
switch (typeof obj[key]) {
|
|
807
|
-
case 'string':
|
|
808
|
-
sendHttpParams.set(setKey, obj[key]);
|
|
809
|
-
break;
|
|
810
|
-
case 'symbol':
|
|
811
|
-
case 'number':
|
|
812
|
-
case 'bigint':
|
|
813
|
-
case 'boolean':
|
|
814
|
-
sendHttpParams.set(setKey, String(obj[key]));
|
|
815
|
-
break;
|
|
816
|
-
case 'object':
|
|
817
|
-
nesting.push(key);
|
|
818
|
-
sendHttpParams = this.getHttpParamsPost(obj[key], sendHttpParams, nesting, settings);
|
|
819
|
-
nesting.pop();
|
|
820
|
-
break;
|
|
821
|
-
case 'function':
|
|
822
|
-
case 'undefined':
|
|
823
|
-
default:
|
|
824
|
-
console.error('You sent something wrong', obj[key], typeof obj[key], typeof obj);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
return sendHttpParams;
|
|
829
|
-
}
|
|
830
|
-
sliceArrayIntoChunks(arr, chunkSize) {
|
|
831
|
-
const res = [];
|
|
832
|
-
for (let i = 0; i < arr.length; i += chunkSize) {
|
|
833
|
-
const chunk = arr.slice(i, i + chunkSize);
|
|
834
|
-
res.push(chunk);
|
|
835
|
-
}
|
|
836
|
-
return res;
|
|
837
|
-
}
|
|
838
|
-
removingMultipleSlashes(str) {
|
|
839
|
-
return str.replace(/\/{2,}/g, '/');
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
class BaseHttp extends HttpData {
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
class HttpServices extends BaseHttp {
|
|
831
|
+
/**
|
|
832
|
+
* Общая часть HTTP-клиента: экземпляр axios и источник токена и адреса.
|
|
833
|
+
* Сами запросы отправляет `HttpBXServices` (`BXRestRequest`).
|
|
834
|
+
*/
|
|
835
|
+
class HttpServices {
|
|
847
836
|
constructor() {
|
|
848
|
-
super();
|
|
849
837
|
this.session = new SessionKeyServices();
|
|
850
|
-
this.axiosInstance = axios.create();
|
|
851
|
-
}
|
|
852
|
-
httpPost(url, params = {}, settings = this.defSettings) {
|
|
853
|
-
const auth = this.session.getAuthParams();
|
|
854
|
-
const checkIsOn = this.session.getCheckAuthParamsIsOn();
|
|
855
|
-
const paramsClone = clone(params);
|
|
856
|
-
if (checkIsOn) {
|
|
857
|
-
if (!auth) {
|
|
858
|
-
return throwError(() => this.session.getAuthError('post'));
|
|
859
|
-
}
|
|
860
|
-
paramsClone[this.session.getKeyAuth()] = auth;
|
|
861
|
-
}
|
|
862
|
-
return this.session.getBaseUrl().pipe(switchMap((baseUrl) => {
|
|
863
|
-
if (!baseUrl) {
|
|
864
|
-
return throwError(() => this.session.getBaseUrlError('post'));
|
|
865
|
-
}
|
|
866
|
-
const fullUrl = prepareBaseAddress(baseUrl) + url;
|
|
867
|
-
if (this.session.getKeyAuth() === 'sessid') {
|
|
868
|
-
const urlEncodedBody = new URLSearchParams();
|
|
869
|
-
Object.keys(paramsClone).forEach((key) => {
|
|
870
|
-
const value = paramsClone[key];
|
|
871
|
-
if (typeof value === 'object' && value !== null) {
|
|
872
|
-
for (const subKey in value) {
|
|
873
|
-
if (Object.prototype.hasOwnProperty.call(value, subKey)) {
|
|
874
|
-
urlEncodedBody.append(`${key}[${subKey}]`, value[subKey]);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
else {
|
|
879
|
-
urlEncodedBody.append(key, value);
|
|
880
|
-
}
|
|
881
|
-
});
|
|
882
|
-
return from(this.axiosInstance.post(fullUrl, urlEncodedBody.toString(), {
|
|
883
|
-
headers: {
|
|
884
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
885
|
-
},
|
|
886
|
-
}).then((response) => response.data));
|
|
887
|
-
}
|
|
888
|
-
const body = this.getHttpParamsPost(paramsClone, new FormData(), [], settings);
|
|
889
|
-
return from(this.axiosInstance.post(fullUrl, body).then((response) => response.data));
|
|
890
|
-
}));
|
|
891
838
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
}
|
|
900
|
-
paramsClone[this.session.getKeyAuth()] = auth;
|
|
901
|
-
}
|
|
902
|
-
return this.session.getBaseUrl().pipe(switchMap((baseUrl) => {
|
|
903
|
-
if (!baseUrl) {
|
|
904
|
-
return throwError(() => this.session.getBaseUrlError('get'));
|
|
905
|
-
}
|
|
906
|
-
const fullUrl = prepareBaseAddress(baseUrl) + url;
|
|
907
|
-
const queryString = new URLSearchParams(paramsClone).toString();
|
|
908
|
-
const finalUrl = `${fullUrl}?${queryString}`;
|
|
909
|
-
return from(this.axiosInstance.get(finalUrl).then((response) => response.data));
|
|
910
|
-
}));
|
|
839
|
+
/**
|
|
840
|
+
* Экземпляр axios клиента. Один на контекст (клиента со своими настройками
|
|
841
|
+
* или глобальные настройки) и создаётся при первом запросе — раньше каждый
|
|
842
|
+
* объект запроса создавал свой.
|
|
843
|
+
*/
|
|
844
|
+
get axiosInstance() {
|
|
845
|
+
return this.session.ctx.axios ??= axios.create();
|
|
911
846
|
}
|
|
912
847
|
}
|
|
913
848
|
|
|
@@ -1008,20 +943,33 @@ function parseBXRestErrorBody(body) {
|
|
|
1008
943
|
* Bitrix error body, so the caller can keep its own handling for them.
|
|
1009
944
|
*/
|
|
1010
945
|
function bxRestApiErrorFromHttp(err, method) {
|
|
1011
|
-
|
|
946
|
+
const response = httpErrorResponse(err);
|
|
947
|
+
if (!response) {
|
|
1012
948
|
return undefined;
|
|
1013
949
|
}
|
|
1014
|
-
const parsed = parseBXRestErrorBody(
|
|
950
|
+
const parsed = parseBXRestErrorBody(response.data);
|
|
1015
951
|
if (!parsed) {
|
|
1016
952
|
return undefined;
|
|
1017
953
|
}
|
|
1018
954
|
return new BXRestApiError(parsed.error, parsed.error_description, {
|
|
1019
|
-
status:
|
|
955
|
+
status: response.status,
|
|
1020
956
|
method,
|
|
1021
957
|
cause: err,
|
|
1022
958
|
authRefreshError: getAuthRefreshError(err)
|
|
1023
959
|
});
|
|
1024
960
|
}
|
|
961
|
+
/**
|
|
962
|
+
* HTTP-ответ из ошибки транспорта: `response: { status, data }`. Так устроен
|
|
963
|
+
* `AxiosError`, и так же должны отклоняться свои транспорты (middleware).
|
|
964
|
+
* Для сетевых ошибок, отмены и прочих ошибок — `undefined`.
|
|
965
|
+
*/
|
|
966
|
+
function httpErrorResponse(error) {
|
|
967
|
+
const response = (error && typeof error === 'object') ? error.response : undefined;
|
|
968
|
+
if (!response || typeof response !== 'object' || typeof response.status !== 'number') {
|
|
969
|
+
return undefined;
|
|
970
|
+
}
|
|
971
|
+
return response;
|
|
972
|
+
}
|
|
1025
973
|
|
|
1026
974
|
/**
|
|
1027
975
|
* Коды ошибок Bitrix, которые лечатся продлением токена. `expired_token` —
|
|
@@ -1044,34 +992,34 @@ const AUTH_ERROR_CODES = ['expired_token', 'invalid_token'];
|
|
|
1044
992
|
* Ответ 401 с другим кодом Bitrix ошибкой авторизации не считается.
|
|
1045
993
|
*/
|
|
1046
994
|
function isBXRestAuthError(error) {
|
|
1047
|
-
|
|
995
|
+
const response = httpErrorResponse(error);
|
|
996
|
+
if (!response) {
|
|
1048
997
|
return false;
|
|
1049
998
|
}
|
|
1050
|
-
const parsed = parseBXRestErrorBody(
|
|
999
|
+
const parsed = parseBXRestErrorBody(response.data);
|
|
1051
1000
|
if (parsed) {
|
|
1052
1001
|
return AUTH_ERROR_CODES.includes(parsed.error);
|
|
1053
1002
|
}
|
|
1054
|
-
return
|
|
1003
|
+
return response.status === 401;
|
|
1055
1004
|
}
|
|
1056
|
-
//
|
|
1057
|
-
//
|
|
1058
|
-
//
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
pendingRefresh = Promise.resolve()
|
|
1005
|
+
// Состояние продления живёт в контексте клиента (BXRestContext): у глобальных
|
|
1006
|
+
// настроек оно одно на всю библиотеку, у каждого new BXRestNavvy(settings) —
|
|
1007
|
+
// своё. pendingRefresh — идущее сейчас продление, его ждут все упавшие
|
|
1008
|
+
// запросы клиента; refreshCount — сколько продлений уже завершилось успешно.
|
|
1009
|
+
function sharedRefresh(refresh, ctx) {
|
|
1010
|
+
if (!ctx.pendingRefresh) {
|
|
1011
|
+
ctx.pendingRefresh = Promise.resolve()
|
|
1064
1012
|
// Через then, чтобы синхронное исключение в refresh() тоже стало
|
|
1065
1013
|
// отклонённым промисом, а не вылетело из catchError
|
|
1066
1014
|
.then(() => refresh())
|
|
1067
1015
|
.then(() => {
|
|
1068
|
-
refreshCount++;
|
|
1016
|
+
ctx.refreshCount++;
|
|
1069
1017
|
})
|
|
1070
1018
|
.finally(() => {
|
|
1071
|
-
pendingRefresh = undefined;
|
|
1019
|
+
ctx.pendingRefresh = undefined;
|
|
1072
1020
|
});
|
|
1073
1021
|
}
|
|
1074
|
-
return pendingRefresh;
|
|
1022
|
+
return ctx.pendingRefresh;
|
|
1075
1023
|
}
|
|
1076
1024
|
/**
|
|
1077
1025
|
* Повтор запроса после продления авторизации (`BXRestSettings.auth.refresh`).
|
|
@@ -1080,23 +1028,26 @@ function sharedRefresh(refresh) {
|
|
|
1080
1028
|
* `defer()` в HttpBXServices): повтор — это повторная подписка, поэтому
|
|
1081
1029
|
* токен, адрес и заголовки берутся уже новые. На второй попытке ошибка не
|
|
1082
1030
|
* перехватывается — запрос повторяется не больше одного раза.
|
|
1031
|
+
*
|
|
1032
|
+
* `ctx` — контекст клиента, из которого берутся `refresh`, `isAuthError` и
|
|
1033
|
+
* общее состояние продления.
|
|
1083
1034
|
*/
|
|
1084
|
-
function withAuthRefresh(request
|
|
1035
|
+
function withAuthRefresh(request$, ctx = globalContext) {
|
|
1085
1036
|
return defer(() => {
|
|
1086
|
-
const { refresh, isAuthError = isBXRestAuthError } =
|
|
1037
|
+
const { refresh, isAuthError = isBXRestAuthError } = ctx.settings.auth;
|
|
1087
1038
|
if (!refresh) {
|
|
1088
1039
|
return request$;
|
|
1089
1040
|
}
|
|
1090
|
-
const refreshCountAtStart = refreshCount;
|
|
1041
|
+
const refreshCountAtStart = ctx.refreshCount;
|
|
1091
1042
|
return request$.pipe(catchError((error) => {
|
|
1092
1043
|
if (!isAuthError(error)) {
|
|
1093
1044
|
return throwError(() => error);
|
|
1094
1045
|
}
|
|
1095
1046
|
// Пока этот запрос был в пути, токен уже продлили по ошибке другого
|
|
1096
1047
|
// запроса — повторяем без нового продления
|
|
1097
|
-
const refreshed = (refreshCount !== refreshCountAtStart)
|
|
1048
|
+
const refreshed = (ctx.refreshCount !== refreshCountAtStart)
|
|
1098
1049
|
? Promise.resolve()
|
|
1099
|
-
: sharedRefresh(refresh);
|
|
1050
|
+
: sharedRefresh(refresh, ctx);
|
|
1100
1051
|
return from(refreshed).pipe(catchError((refreshError) => {
|
|
1101
1052
|
if (error && typeof error === 'object') {
|
|
1102
1053
|
error.authRefreshError = refreshError;
|
|
@@ -1107,6 +1058,159 @@ function withAuthRefresh(request$) {
|
|
|
1107
1058
|
});
|
|
1108
1059
|
}
|
|
1109
1060
|
|
|
1061
|
+
/** Первый middleware в списке — внешний: он первым видит запрос и последним — ответ. */
|
|
1062
|
+
function composeMiddleware(middleware, terminal) {
|
|
1063
|
+
return middleware.reduceRight((next, step) => config => step(config, next), terminal);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/** `retryOnQueryLimit: true`: всего 3 попытки, пауза перед второй — 1000 мс, дальше вдвое больше. */
|
|
1067
|
+
const DEFAULT_RETRY_ON_QUERY_LIMIT = { attempts: 3, delay: 1000 };
|
|
1068
|
+
/** `timeout: true`: 60 000 мс на один HTTP-запрос. */
|
|
1069
|
+
const DEFAULT_TIMEOUT$1 = 60_000;
|
|
1070
|
+
/** `throttle: true`: 2 запроса в секунду — лимит Bitrix24 на обычных тарифах. */
|
|
1071
|
+
const DEFAULT_THROTTLE = { perSecond: 2 };
|
|
1072
|
+
/**
|
|
1073
|
+
* Запрос не завершился за время из `timeout` в настройках. В `.resVanilla()`
|
|
1074
|
+
* приходит сама эта ошибка, в `.res()` — в `cause`.
|
|
1075
|
+
*/
|
|
1076
|
+
class BXRestTimeoutError extends Error {
|
|
1077
|
+
constructor(timeout) {
|
|
1078
|
+
super(`The request did not finish in ${timeout} ms`);
|
|
1079
|
+
this.timeout = timeout;
|
|
1080
|
+
this.name = 'BXRestTimeoutError';
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Встроенные шаги из настроек, в этом порядке: повтор, очередь, таймаут.
|
|
1085
|
+
* Повтор — снаружи: каждая попытка заново встаёт в очередь и получает свой
|
|
1086
|
+
* таймаут. Таймаут — внутри очереди: ожидание своей очереди его не тратит.
|
|
1087
|
+
*/
|
|
1088
|
+
function builtInMiddleware(settings, state) {
|
|
1089
|
+
const steps = [];
|
|
1090
|
+
if (settings.retryOnQueryLimit) {
|
|
1091
|
+
const own = (settings.retryOnQueryLimit === true) ? {} : settings.retryOnQueryLimit;
|
|
1092
|
+
const attempts = own.attempts ?? DEFAULT_RETRY_ON_QUERY_LIMIT.attempts;
|
|
1093
|
+
const delay = own.delay ?? DEFAULT_RETRY_ON_QUERY_LIMIT.delay;
|
|
1094
|
+
if (!Number.isInteger(attempts) || attempts < 1) {
|
|
1095
|
+
throw invalid('retryOnQueryLimit.attempts', attempts, 'a whole number from 1');
|
|
1096
|
+
}
|
|
1097
|
+
if (!Number.isFinite(delay) || delay < 0) {
|
|
1098
|
+
throw invalid('retryOnQueryLimit.delay', delay, 'a number of milliseconds from 0');
|
|
1099
|
+
}
|
|
1100
|
+
steps.push(retryOnQueryLimit(attempts, delay));
|
|
1101
|
+
}
|
|
1102
|
+
if (settings.throttle) {
|
|
1103
|
+
const own = (settings.throttle === true) ? {} : settings.throttle;
|
|
1104
|
+
const perSecond = own.perSecond ?? DEFAULT_THROTTLE.perSecond;
|
|
1105
|
+
if (!Number.isFinite(perSecond) || perSecond <= 0) {
|
|
1106
|
+
throw invalid('throttle.perSecond', perSecond, 'a number above 0');
|
|
1107
|
+
}
|
|
1108
|
+
steps.push(throttle(perSecond, state));
|
|
1109
|
+
}
|
|
1110
|
+
if (settings.timeout) {
|
|
1111
|
+
const ms = (settings.timeout === true) ? DEFAULT_TIMEOUT$1 : settings.timeout;
|
|
1112
|
+
// setTimeout считает больше 2^31 − 1 мс за 0 и сработал бы сразу
|
|
1113
|
+
if (!Number.isFinite(ms) || ms <= 0 || ms > 2_147_483_647) {
|
|
1114
|
+
throw invalid('timeout', ms, 'a number of milliseconds from 1 to 2147483647');
|
|
1115
|
+
}
|
|
1116
|
+
steps.push(timeout(ms));
|
|
1117
|
+
}
|
|
1118
|
+
return steps;
|
|
1119
|
+
}
|
|
1120
|
+
function invalid(name, value, expected) {
|
|
1121
|
+
return new TypeError(`bx-rest settings: ${name} must be ${expected}, got ${String(value)}`);
|
|
1122
|
+
}
|
|
1123
|
+
function abortReason(signal) {
|
|
1124
|
+
return signal.reason ?? new Error('The request was aborted');
|
|
1125
|
+
}
|
|
1126
|
+
/** Пауза, которую прерывает отмена запроса. */
|
|
1127
|
+
function wait(ms, signal) {
|
|
1128
|
+
return new Promise((resolve, reject) => {
|
|
1129
|
+
if (signal?.aborted) {
|
|
1130
|
+
reject(abortReason(signal));
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
const onAbort = () => {
|
|
1134
|
+
clearTimeout(timer);
|
|
1135
|
+
reject(abortReason(signal));
|
|
1136
|
+
};
|
|
1137
|
+
const timer = setTimeout(() => {
|
|
1138
|
+
signal?.removeEventListener('abort', onAbort);
|
|
1139
|
+
resolve();
|
|
1140
|
+
}, ms);
|
|
1141
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Повтор при `QUERY_LIMIT_EXCEEDED`: портал отвечает так (HTTP 503), когда
|
|
1146
|
+
* превышен лимит частоты запросов. Пауза растёт вдвое: `delay`, `2 × delay`, ...
|
|
1147
|
+
* `attempts` — сколько всего попыток, вместе с первой.
|
|
1148
|
+
*/
|
|
1149
|
+
function retryOnQueryLimit(attempts, delay) {
|
|
1150
|
+
return async (config, next) => {
|
|
1151
|
+
for (let attempt = 1;; attempt++) {
|
|
1152
|
+
try {
|
|
1153
|
+
return await next(config);
|
|
1154
|
+
}
|
|
1155
|
+
catch (error) {
|
|
1156
|
+
const code = parseBXRestErrorBody(httpErrorResponse(error)?.data)?.error;
|
|
1157
|
+
if (attempt >= attempts || code !== 'QUERY_LIMIT_EXCEEDED') {
|
|
1158
|
+
throw error;
|
|
1159
|
+
}
|
|
1160
|
+
await wait(delay * 2 ** (attempt - 1), config.signal);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Не больше `perSecond` запросов в секунду: лишние ждут своей очереди.
|
|
1167
|
+
* Очередь общая для всех запросов клиента (`state` — его контекст).
|
|
1168
|
+
*/
|
|
1169
|
+
function throttle(perSecond, state) {
|
|
1170
|
+
const interval = 1000 / perSecond;
|
|
1171
|
+
return (config, next) => {
|
|
1172
|
+
const now = Date.now();
|
|
1173
|
+
const start = Math.max(now, state.throttleNextSlot);
|
|
1174
|
+
const reserved = start + interval;
|
|
1175
|
+
state.throttleNextSlot = reserved;
|
|
1176
|
+
if (start <= now) {
|
|
1177
|
+
return next(config);
|
|
1178
|
+
}
|
|
1179
|
+
return wait(start - now, config.signal).then(() => next(config), (error) => {
|
|
1180
|
+
// Отменённый запрос освобождает своё место, если за ним никто не встал
|
|
1181
|
+
if (state.throttleNextSlot === reserved) {
|
|
1182
|
+
state.throttleNextSlot = start;
|
|
1183
|
+
}
|
|
1184
|
+
throw error;
|
|
1185
|
+
});
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
/** Отменяет запрос, если он не завершился за `ms` миллисекунд. */
|
|
1189
|
+
function timeout(ms) {
|
|
1190
|
+
return (config, next) => {
|
|
1191
|
+
const controller = new AbortController();
|
|
1192
|
+
const onAbort = () => controller.abort(abortReason(config.signal));
|
|
1193
|
+
if (config.signal?.aborted) {
|
|
1194
|
+
onAbort();
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
config.signal?.addEventListener('abort', onAbort, { once: true });
|
|
1198
|
+
}
|
|
1199
|
+
let timer;
|
|
1200
|
+
const timedOut = new Promise((_, reject) => {
|
|
1201
|
+
timer = setTimeout(() => {
|
|
1202
|
+
const error = new BXRestTimeoutError(ms);
|
|
1203
|
+
controller.abort(error);
|
|
1204
|
+
reject(error);
|
|
1205
|
+
}, ms);
|
|
1206
|
+
});
|
|
1207
|
+
return Promise.race([next({ ...config, signal: controller.signal }), timedOut]).finally(() => {
|
|
1208
|
+
clearTimeout(timer);
|
|
1209
|
+
config.signal?.removeEventListener('abort', onAbort);
|
|
1210
|
+
});
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1110
1214
|
class HttpBXServices extends HttpServices {
|
|
1111
1215
|
/**
|
|
1112
1216
|
* Не считайте этот метод образцом/финальным API.
|
|
@@ -1171,8 +1275,8 @@ class HttpBXServices extends HttpServices {
|
|
|
1171
1275
|
get(name, params = {}, headers) {
|
|
1172
1276
|
return this.httpGet(this.getNameMethod(name), params, undefined, headers);
|
|
1173
1277
|
}
|
|
1174
|
-
// settings
|
|
1175
|
-
//
|
|
1278
|
+
// settings не используется и оставлен ради прежней сигнатуры: headers
|
|
1279
|
+
// остаётся четвёртым параметром у httpPost и httpGet.
|
|
1176
1280
|
httpPost(url, params = {}, settings, headers) {
|
|
1177
1281
|
// defer() откладывает всё содержимое (в том числе чтение BXRestSettings
|
|
1178
1282
|
// через this.session.*) до реальной подписки — иначе даже с "живым"
|
|
@@ -1203,20 +1307,19 @@ class HttpBXServices extends HttpServices {
|
|
|
1203
1307
|
return throwError(() => this.session.getBaseUrlError('post'));
|
|
1204
1308
|
}
|
|
1205
1309
|
const fullUrl = prepareBaseAddress(baseUrl) + url;
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
}).then((response) => response.data));
|
|
1213
|
-
}
|
|
1214
|
-
return from(this.axiosInstance.post(fullUrl, paramsClone, {
|
|
1310
|
+
// sessid — тело x-www-form-urlencoded, остальные ключи — JSON
|
|
1311
|
+
const urlencoded = key === 'sessid';
|
|
1312
|
+
return this.send({
|
|
1313
|
+
method: 'POST',
|
|
1314
|
+
url: fullUrl,
|
|
1315
|
+
data: urlencoded ? this.serializeBitrixParams(paramsClone) : paramsClone,
|
|
1215
1316
|
withCredentials: this.session.getWithCredentials(),
|
|
1216
|
-
headers: this.buildHeaders(headers, {
|
|
1217
|
-
|
|
1317
|
+
headers: this.buildHeaders(headers, {
|
|
1318
|
+
'Content-Type': urlencoded ? 'application/x-www-form-urlencoded' : 'application/json'
|
|
1319
|
+
}),
|
|
1320
|
+
});
|
|
1218
1321
|
}));
|
|
1219
|
-
}));
|
|
1322
|
+
}), this.session.ctx);
|
|
1220
1323
|
}
|
|
1221
1324
|
httpGet(url, params = {}, settings, headers) {
|
|
1222
1325
|
// Та же причина, что и у httpPost выше: откладываем чтение BXRestSettings
|
|
@@ -1244,12 +1347,41 @@ class HttpBXServices extends HttpServices {
|
|
|
1244
1347
|
const fullUrl = prepareBaseAddress(baseUrl) + url;
|
|
1245
1348
|
const queryString = this.serializeBitrixParams(paramsClone);
|
|
1246
1349
|
const finalUrl = `${fullUrl}?${queryString}`;
|
|
1247
|
-
return
|
|
1350
|
+
return this.send({
|
|
1351
|
+
method: 'GET',
|
|
1352
|
+
url: finalUrl,
|
|
1248
1353
|
withCredentials: this.session.getWithCredentials(),
|
|
1249
1354
|
headers: this.buildHeaders(headers),
|
|
1250
|
-
})
|
|
1355
|
+
});
|
|
1251
1356
|
}));
|
|
1252
|
-
}));
|
|
1357
|
+
}), this.session.ctx);
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Отправка через шаги из настроек: `retryOnQueryLimit`, `throttle`,
|
|
1361
|
+
* `timeout`, затем `middleware`; последним идёт axios клиента. Настройки
|
|
1362
|
+
* читаются при подписке. Отписка отменяет HTTP-запрос (AbortSignal).
|
|
1363
|
+
* Ошибка транспорта уходит дальше как есть: у axios в ней весь запрос,
|
|
1364
|
+
* вместе с токеном и секретом вебхука (см. README, «Обработка ошибок»).
|
|
1365
|
+
*/
|
|
1366
|
+
send(config) {
|
|
1367
|
+
return new Observable(subscriber => {
|
|
1368
|
+
const controller = new AbortController();
|
|
1369
|
+
const ctx = this.session.ctx;
|
|
1370
|
+
const send = composeMiddleware([...builtInMiddleware(ctx.settings, ctx), ...this.session.getMiddleware()], request => this.axiosSend(request));
|
|
1371
|
+
send({ ...config, signal: controller.signal }).then(data => {
|
|
1372
|
+
subscriber.next(data);
|
|
1373
|
+
subscriber.complete();
|
|
1374
|
+
}, (error) => subscriber.error(error));
|
|
1375
|
+
return () => controller.abort();
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
/** Транспорт по умолчанию: axios клиента, как и раньше через post()/get(). */
|
|
1379
|
+
axiosSend(config) {
|
|
1380
|
+
const options = { headers: config.headers, withCredentials: config.withCredentials, signal: config.signal };
|
|
1381
|
+
const request = (config.method === 'GET')
|
|
1382
|
+
? this.axiosInstance.get(config.url, options)
|
|
1383
|
+
: this.axiosInstance.post(config.url, config.data, options);
|
|
1384
|
+
return request.then(response => response.data);
|
|
1253
1385
|
}
|
|
1254
1386
|
/**
|
|
1255
1387
|
* Заголовки запроса: `BXRestSettings.headers`, поверх них — заголовки
|
|
@@ -1503,25 +1635,17 @@ class NavvyPagNavResultKeyObject extends NavvyPagBase {
|
|
|
1503
1635
|
}
|
|
1504
1636
|
}
|
|
1505
1637
|
|
|
1506
|
-
class NavvySupport {
|
|
1507
|
-
constructor(requestClass) {
|
|
1508
|
-
this.requestClass = requestClass;
|
|
1509
|
-
this.pageSize = 50; // стандартный размер страницы
|
|
1510
|
-
}
|
|
1511
|
-
mapAndError(request) {
|
|
1512
|
-
return request.pipe(map(v => BXRestMapResult(v)), catchError((err) => {
|
|
1513
|
-
console.error(err);
|
|
1514
|
-
throw new Error((err.error) ? err.error : err);
|
|
1515
|
-
}));
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
1638
|
class Navvy {
|
|
1639
|
+
constructor() {
|
|
1640
|
+
// Контекст, в котором создан Navvy. Запросы создаются позже, при вызове
|
|
1641
|
+
// метода, поэтому их HTTP-объекты получают этот контекст явно, а не текущий.
|
|
1642
|
+
this.ctx = currentContext();
|
|
1643
|
+
}
|
|
1520
1644
|
simple(url, arg, map) {
|
|
1521
|
-
return new NavvySimple(url, arg !== undefined ? arg : undefined, map);
|
|
1645
|
+
return runInContext(this.ctx, () => new NavvySimple(url, arg !== undefined ? arg : undefined, map));
|
|
1522
1646
|
}
|
|
1523
1647
|
simpleV3(url, arg, map) {
|
|
1524
|
-
return new NavvySimple(url, arg !== undefined ? arg : undefined, map, true);
|
|
1648
|
+
return runInContext(this.ctx, () => new NavvySimple(url, arg !== undefined ? arg : undefined, map, true));
|
|
1525
1649
|
}
|
|
1526
1650
|
/**
|
|
1527
1651
|
* Новый, пока тестируемый метод для api методов с пагинацией
|
|
@@ -1532,41 +1656,22 @@ class Navvy {
|
|
|
1532
1656
|
* @constructor
|
|
1533
1657
|
*/
|
|
1534
1658
|
pagNav(url, arg, map) {
|
|
1535
|
-
return new NavvyPag(url, arg, map);
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
// func: (param: A) => Observable<iBXRestAnswer<T[]> | undefined>,
|
|
1540
|
-
// arg: A,
|
|
1541
|
-
// map: ((param: T[] | undefined) => R[] | undefined) | undefined) {
|
|
1542
|
-
// return new NavvyPagNav(this.requestClass, this.mapClass, func, arg, map)
|
|
1543
|
-
// }
|
|
1544
|
-
// Batch<T, R, A extends iBXRestPagination>(
|
|
1545
|
-
// func: (param: A) => Observable<iBXRestAnswer<T[]> | undefined>,
|
|
1546
|
-
// arg: A,
|
|
1547
|
-
// map: ((param: T[] | undefined) => R[] | undefined) | undefined) {
|
|
1548
|
-
// return new NavvyBatch(this.requestClass, this.mapClass, func, arg, map)
|
|
1549
|
-
// }
|
|
1550
|
-
pagNavTasks(url,
|
|
1551
|
-
// func: (param: A) => Observable<iBXRestAnswer<{tasks: T[] | undefined}> | undefined>,
|
|
1552
|
-
arg, map) {
|
|
1553
|
-
return new NavvyPagNavTasks(url, arg, map);
|
|
1659
|
+
return runInContext(this.ctx, () => new NavvyPag(url, arg, map));
|
|
1660
|
+
}
|
|
1661
|
+
pagNavTasks(url, arg, map) {
|
|
1662
|
+
return runInContext(this.ctx, () => new NavvyPagNavTasks(url, arg, map));
|
|
1554
1663
|
}
|
|
1555
1664
|
pagNavResultKey(url, arg, key, map) {
|
|
1556
|
-
return new NavvyPagNavResultKey(url, arg, key, map);
|
|
1665
|
+
return runInContext(this.ctx, () => new NavvyPagNavResultKey(url, arg, key, map));
|
|
1557
1666
|
}
|
|
1558
1667
|
pagNavResultKeyObject(url, arg, key, map) {
|
|
1559
|
-
return new NavvyPagNavResultKeyObject(url, arg, key, map);
|
|
1668
|
+
return runInContext(this.ctx, () => new NavvyPagNavResultKeyObject(url, arg, key, map));
|
|
1560
1669
|
}
|
|
1561
|
-
pagNavWithUselessKey(url,
|
|
1562
|
-
|
|
1563
|
-
arg, map) {
|
|
1564
|
-
return new NavvyPagNavWithUselessKey(url, arg, map);
|
|
1670
|
+
pagNavWithUselessKey(url, arg, map) {
|
|
1671
|
+
return runInContext(this.ctx, () => new NavvyPagNavWithUselessKey(url, arg, map));
|
|
1565
1672
|
}
|
|
1566
|
-
alterPagNav(url,
|
|
1567
|
-
|
|
1568
|
-
arg, map) {
|
|
1569
|
-
return new NavvyAlterPagNav(url, arg, map);
|
|
1673
|
+
alterPagNav(url, arg, map) {
|
|
1674
|
+
return runInContext(this.ctx, () => new NavvyAlterPagNav(url, arg, map));
|
|
1570
1675
|
}
|
|
1571
1676
|
}
|
|
1572
1677
|
|
|
@@ -3600,12 +3705,6 @@ class BXRestNavvyTasksTask {
|
|
|
3600
3705
|
* Переводит задачу в статус «завершена»
|
|
3601
3706
|
*/
|
|
3602
3707
|
complete: [$tasks, $task, $complete],
|
|
3603
|
-
// counters: {
|
|
3604
|
-
// /**
|
|
3605
|
-
// * Получает счетчики пользователя
|
|
3606
|
-
// */
|
|
3607
|
-
// get: [$tasks, $task, $counters, $get],
|
|
3608
|
-
// },
|
|
3609
3708
|
/**
|
|
3610
3709
|
* Переводит задачу в статус «отложена»
|
|
3611
3710
|
*/
|
|
@@ -3618,30 +3717,6 @@ class BXRestNavvyTasksTask {
|
|
|
3618
3717
|
* Возвращает информацию о конкретной задаче
|
|
3619
3718
|
*/
|
|
3620
3719
|
get: [$tasks, $task, $get],
|
|
3621
|
-
// /**
|
|
3622
|
-
// * Удаляет задачу
|
|
3623
|
-
// */
|
|
3624
|
-
// delete: [$tasks, $task, $delete],
|
|
3625
|
-
// /**
|
|
3626
|
-
// * Позволяет отклонить задачу
|
|
3627
|
-
// */
|
|
3628
|
-
// disapprove: [$tasks, $task, $disapprove],
|
|
3629
|
-
// favorite: {
|
|
3630
|
-
// /**
|
|
3631
|
-
// * Добавляет задачи в "Избранное"
|
|
3632
|
-
// */
|
|
3633
|
-
// add: [$tasks, $task, $favorite, $add],
|
|
3634
|
-
// /**
|
|
3635
|
-
// * Удаляет задачи из "Избранного"
|
|
3636
|
-
// */
|
|
3637
|
-
// delete: [$tasks, $task, $favorite, $delete],
|
|
3638
|
-
// },
|
|
3639
|
-
// files: {
|
|
3640
|
-
// /**
|
|
3641
|
-
// * Прикрепляет загруженный на диск файл к задаче
|
|
3642
|
-
// */
|
|
3643
|
-
// attach: [$tasks, $task, $files, $attach],
|
|
3644
|
-
// },
|
|
3645
3720
|
/**
|
|
3646
3721
|
* Возвращает все доступные поля
|
|
3647
3722
|
*/
|
|
@@ -3650,36 +3725,10 @@ class BXRestNavvyTasksTask {
|
|
|
3650
3725
|
* Метод для проверки доступа к задаче
|
|
3651
3726
|
*/
|
|
3652
3727
|
getAccess: [$tasks, $task, $getaccess],
|
|
3653
|
-
// history: {
|
|
3654
|
-
// /**
|
|
3655
|
-
// * Получает историю задачи
|
|
3656
|
-
// */
|
|
3657
|
-
// list: [$tasks, $task, $history, $list],
|
|
3658
|
-
// },
|
|
3659
3728
|
/**
|
|
3660
3729
|
* Возвращает массив задач, каждая из которых содержит массив полей
|
|
3661
3730
|
*/
|
|
3662
3731
|
list: [$tasks, $task, $list],
|
|
3663
|
-
// /**
|
|
3664
|
-
// * Останавливает выполнение задачи, переводя ее в статус "ждет выполнения"
|
|
3665
|
-
// */
|
|
3666
|
-
// pause: [$tasks, $task, $pause],
|
|
3667
|
-
// /**
|
|
3668
|
-
// * Возобновляет задачу после ее завершения
|
|
3669
|
-
// */
|
|
3670
|
-
// renew: [$tasks, $task, $renew],
|
|
3671
|
-
// /**
|
|
3672
|
-
// * Переводит задачу в статус «выполняется»
|
|
3673
|
-
// */
|
|
3674
|
-
// start: [$tasks, $task, $start],
|
|
3675
|
-
// /**
|
|
3676
|
-
// * Позволяет наблюдать за задачей
|
|
3677
|
-
// */
|
|
3678
|
-
// startWatch: [$tasks, $task, 'startwatch'],
|
|
3679
|
-
// /**
|
|
3680
|
-
// * Останавливает наблюдение за задачей
|
|
3681
|
-
// */
|
|
3682
|
-
// stopwatch: [$tasks, $task, 'stopwatch'],
|
|
3683
3732
|
/**
|
|
3684
3733
|
* Обновляет задачу
|
|
3685
3734
|
*/
|
|
@@ -3784,68 +3833,6 @@ class BXRestNavvyTasksTask {
|
|
|
3784
3833
|
list(param = {}) {
|
|
3785
3834
|
return this.Navvy.pagNavTasks(this.url.list, param, (BXRestMapTasksTask.list));
|
|
3786
3835
|
}
|
|
3787
|
-
/*
|
|
3788
|
-
listArray(requestArray: RequestApiTaskListBX = {}) {
|
|
3789
|
-
return this.list(requestArray).pipe(
|
|
3790
|
-
map(v => this.http.mapResult(v)),
|
|
3791
|
-
map(v => (v && v.tasks) ? v.tasks : [])
|
|
3792
|
-
)
|
|
3793
|
-
}
|
|
3794
|
-
|
|
3795
|
-
listAll(requestArray: RequestApiTaskListBX = {}, cache = false): Observable<TaskBX[]> {
|
|
3796
|
-
if (!requestArray.select) {
|
|
3797
|
-
requestArray.select = this.def.select
|
|
3798
|
-
if (cache) {
|
|
3799
|
-
return this.storeTask$.pipe(
|
|
3800
|
-
take(1),
|
|
3801
|
-
mergeMap(tasks => {
|
|
3802
|
-
if (tasks && tasks.data.http.list && requestArray.filter && requestArray.filter.ID) {
|
|
3803
|
-
const ids = (typeof requestArray.filter.ID === 'number') ? [requestArray.filter.ID] : requestArray.filter.ID
|
|
3804
|
-
let filter = tasks.data.http.list.filter(i => (i.id) ? ids.includes(i.id) : false)
|
|
3805
|
-
if (filter.length === ids.length) {
|
|
3806
|
-
return of(filter)
|
|
3807
|
-
}
|
|
3808
|
-
}
|
|
3809
|
-
return this.getEndListArray(requestArray)
|
|
3810
|
-
})
|
|
3811
|
-
)
|
|
3812
|
-
}
|
|
3813
|
-
return this.getEndListArray(requestArray)
|
|
3814
|
-
}
|
|
3815
|
-
return this.getEndListArray(requestArray)
|
|
3816
|
-
}
|
|
3817
|
-
|
|
3818
|
-
getEndListArray(requestArray: RequestApiTaskListBX): Observable<TaskBX[]> {
|
|
3819
|
-
return this.list(requestArray).pipe(
|
|
3820
|
-
mergeMap((items: AnswerApiTaskBX | undefined): ObservableInput<any> | Observable<AnswerApiTaskBX[]> => {
|
|
3821
|
-
if (items && items.result && typeof items.result.tasks === 'object') {
|
|
3822
|
-
const items$ = of(items.result.tasks)
|
|
3823
|
-
if (items.next) {
|
|
3824
|
-
this.nowLoad$.next({
|
|
3825
|
-
total: (items.total) ? items.total : 0,
|
|
3826
|
-
next: items.next
|
|
3827
|
-
})
|
|
3828
|
-
requestArray.start = items.next
|
|
3829
|
-
return this.getEndListArray(requestArray).pipe(
|
|
3830
|
-
map(vEnd => {
|
|
3831
|
-
if (vEnd && items.result.tasks) {
|
|
3832
|
-
return [...items.result.tasks, ...vEnd]
|
|
3833
|
-
}
|
|
3834
|
-
return (items.result.tasks) ? items.result.tasks : []
|
|
3835
|
-
}))
|
|
3836
|
-
}
|
|
3837
|
-
this.nowLoad$.next({
|
|
3838
|
-
total: 0,
|
|
3839
|
-
next: 0
|
|
3840
|
-
})
|
|
3841
|
-
return items$
|
|
3842
|
-
} else {
|
|
3843
|
-
return of([])
|
|
3844
|
-
}
|
|
3845
|
-
})
|
|
3846
|
-
)
|
|
3847
|
-
}
|
|
3848
|
-
*/
|
|
3849
3836
|
/**
|
|
3850
3837
|
* Возвращает список полей задачи.
|
|
3851
3838
|
*/
|
|
@@ -4327,12 +4314,12 @@ class BXRestNavvyOperationElapsedItem {
|
|
|
4327
4314
|
return this.BXRestNavvyElapsedItem.add(param).res();
|
|
4328
4315
|
}
|
|
4329
4316
|
else {
|
|
4330
|
-
return throwError(() => new Error('
|
|
4317
|
+
return throwError(() => new Error('No permission to add an elapsed time record to the task'));
|
|
4331
4318
|
}
|
|
4332
4319
|
}));
|
|
4333
4320
|
}
|
|
4334
4321
|
else {
|
|
4335
|
-
return throwError(() => new Error('
|
|
4322
|
+
return throwError(() => new Error('No permission to read the task'));
|
|
4336
4323
|
}
|
|
4337
4324
|
}));
|
|
4338
4325
|
}
|
|
@@ -4349,10 +4336,10 @@ class BXRestNavvyOperationElapsedItem {
|
|
|
4349
4336
|
if (allowed) {
|
|
4350
4337
|
return this.BXRestNavvyElapsedItem.update(param).res();
|
|
4351
4338
|
}
|
|
4352
|
-
return throwError(() => new Error('
|
|
4339
|
+
return throwError(() => new Error('No permission to update the elapsed time record'));
|
|
4353
4340
|
}));
|
|
4354
4341
|
}
|
|
4355
|
-
return throwError(() => new Error('
|
|
4342
|
+
return throwError(() => new Error('No permission to read the task'));
|
|
4356
4343
|
}));
|
|
4357
4344
|
}
|
|
4358
4345
|
/**
|
|
@@ -4380,7 +4367,7 @@ class BXRestNavvyOperationElapsedItem {
|
|
|
4380
4367
|
if (canRead) {
|
|
4381
4368
|
return this.BXRestNavvyElapsedItem.isActionAllowed(param).res();
|
|
4382
4369
|
}
|
|
4383
|
-
return throwError(() => new Error('
|
|
4370
|
+
return throwError(() => new Error('No permission to read the task'));
|
|
4384
4371
|
}));
|
|
4385
4372
|
}
|
|
4386
4373
|
/**
|
|
@@ -4396,12 +4383,12 @@ class BXRestNavvyOperationElapsedItem {
|
|
|
4396
4383
|
return this.BXRestNavvyElapsedItem.delete(param).res();
|
|
4397
4384
|
}
|
|
4398
4385
|
else {
|
|
4399
|
-
return throwError(() => new Error('
|
|
4386
|
+
return throwError(() => new Error('No permission to delete the elapsed time record'));
|
|
4400
4387
|
}
|
|
4401
4388
|
}));
|
|
4402
4389
|
}
|
|
4403
4390
|
else {
|
|
4404
|
-
return throwError(() => new Error('
|
|
4391
|
+
return throwError(() => new Error('No permission to read the task'));
|
|
4405
4392
|
}
|
|
4406
4393
|
}));
|
|
4407
4394
|
}
|
|
@@ -5414,7 +5401,7 @@ class BXRestNavvyDiskOperation {
|
|
|
5414
5401
|
generateUniqueName: true
|
|
5415
5402
|
}).res();
|
|
5416
5403
|
}
|
|
5417
|
-
return throwError(() => new Error('
|
|
5404
|
+
return throwError(() => new Error('Could not get the app storage'));
|
|
5418
5405
|
}));
|
|
5419
5406
|
}
|
|
5420
5407
|
/**
|
|
@@ -5432,13 +5419,6 @@ class BXRestNavvyDiskOperation {
|
|
|
5432
5419
|
* Возвращает список папок и файлов в общем хранилище приложения.
|
|
5433
5420
|
*/
|
|
5434
5421
|
getRootFoldersApp() {
|
|
5435
|
-
// return this.BXDiskFolder$.pipe(
|
|
5436
|
-
// take(1),
|
|
5437
|
-
// mergeMap(
|
|
5438
|
-
// saveData => {
|
|
5439
|
-
// if (saveData.content.root.app) {
|
|
5440
|
-
// return of(saveData.content.root.app)
|
|
5441
|
-
// }
|
|
5442
5422
|
return this.storage.getForApp().res().pipe(mergeMap$1(v => {
|
|
5443
5423
|
if (v && v.ID) {
|
|
5444
5424
|
return this.storage.getChildren({ id: v.ID }).res();
|
|
@@ -5464,7 +5444,7 @@ class BXRestNavvyDiskOperation {
|
|
|
5464
5444
|
if (v && v.ID) {
|
|
5465
5445
|
return this.storage.addFolder({ id: v.ID, data: { NAME: folderName } }).res();
|
|
5466
5446
|
}
|
|
5467
|
-
return throwError(() => new Error('
|
|
5447
|
+
return throwError(() => new Error('Could not get the app storage'));
|
|
5468
5448
|
}));
|
|
5469
5449
|
}));
|
|
5470
5450
|
}
|
|
@@ -5835,6 +5815,32 @@ class BXRestNavvyBizProcRobot {
|
|
|
5835
5815
|
}
|
|
5836
5816
|
}
|
|
5837
5817
|
|
|
5818
|
+
/**
|
|
5819
|
+
* Символьный код нового элемента списка: `bx_rest_` и 128 случайных бит в hex.
|
|
5820
|
+
* Только латиница, цифры и `_`: допустимые символы документация Bitrix24 не
|
|
5821
|
+
* описывает.
|
|
5822
|
+
*
|
|
5823
|
+
* Случайные байты дают `crypto.getRandomValues` (в отличие от
|
|
5824
|
+
* `crypto.randomUUID`, он есть и на страницах по http). Глобального `crypto`
|
|
5825
|
+
* нет только в Node 18: там байты берутся из `Math.random`. Это не
|
|
5826
|
+
* криптостойко, но код нужен лишь уникальный, а совпадение с уже занятым кодом
|
|
5827
|
+
* ловит повтор в вызывающем методе.
|
|
5828
|
+
*/
|
|
5829
|
+
function uniqueElementCode() {
|
|
5830
|
+
const bytes = new Uint8Array(16);
|
|
5831
|
+
if (typeof globalThis.crypto?.getRandomValues === 'function') {
|
|
5832
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
5833
|
+
}
|
|
5834
|
+
else {
|
|
5835
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
5836
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5839
|
+
return 'bx_rest_' + Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
|
|
5840
|
+
}
|
|
5841
|
+
|
|
5842
|
+
/** Сколько раз пробуем новый `ELEMENT_CODE`, если такой код в списке уже занят. */
|
|
5843
|
+
const ELEMENT_CODE_ATTEMPTS = 3;
|
|
5838
5844
|
/** Бизнес-процессы, задания, действия и роботы (`bizproc.*`). */
|
|
5839
5845
|
class BXRestNavvyBizProc {
|
|
5840
5846
|
constructor() {
|
|
@@ -5867,18 +5873,23 @@ class BXRestNavvyBizProc {
|
|
|
5867
5873
|
if (value === null || value === undefined || (typeof value === 'string' && value.trim() === '')) {
|
|
5868
5874
|
parametersElement['DATE_CREATE'] = new Date();
|
|
5869
5875
|
}
|
|
5870
|
-
|
|
5876
|
+
// ELEMENT_CODE обязателен и должен быть уникальным в списке. Занятые коды
|
|
5877
|
+
// знает только портал, поэтому на совпадение создаём новый код и повторяем.
|
|
5878
|
+
// throwOnApiError: иначе ошибка в ответе 2xx пришла бы как undefined.
|
|
5879
|
+
const addElement = (attempt) => this.BXRestNavvyLists.element.add({
|
|
5871
5880
|
IBLOCK_TYPE_ID: 'bitrix_processes',
|
|
5872
5881
|
IBLOCK_ID: id,
|
|
5873
|
-
ELEMENT_CODE:
|
|
5874
|
-
// тут должно быть уникально значение (генерация уникальных значений на фронте лол),
|
|
5875
|
-
// как ещё уникальнее сделать я просто не знаю
|
|
5876
|
-
// это поле обязательно без него не работает
|
|
5882
|
+
ELEMENT_CODE: uniqueElementCode(),
|
|
5877
5883
|
FIELDS: {
|
|
5878
5884
|
NAME: String(parametersElement['NAME']),
|
|
5879
5885
|
...parametersElement
|
|
5880
5886
|
}
|
|
5881
|
-
}).res().pipe(
|
|
5887
|
+
}).res({ throwOnApiError: true }).pipe(catchError$1((error) => (attempt < ELEMENT_CODE_ATTEMPTS
|
|
5888
|
+
&& error instanceof BXRestApiError
|
|
5889
|
+
&& error.error === 'ERROR_ELEMENT_ALREADY_EXISTS')
|
|
5890
|
+
? addElement(attempt + 1)
|
|
5891
|
+
: throwError(() => error)));
|
|
5892
|
+
return addElement(1).pipe(mergeMap(v => {
|
|
5882
5893
|
if (v) {
|
|
5883
5894
|
if (Object.keys(parametersBizProc).length && templateIDs.length) {
|
|
5884
5895
|
let request = [];
|
|
@@ -5895,7 +5906,7 @@ class BXRestNavvyBizProc {
|
|
|
5895
5906
|
return of(true);
|
|
5896
5907
|
}
|
|
5897
5908
|
}
|
|
5898
|
-
return throwError(() => new Error('
|
|
5909
|
+
return throwError(() => new Error('Could not start the business process: the list element was not created'));
|
|
5899
5910
|
}));
|
|
5900
5911
|
}
|
|
5901
5912
|
}
|
|
@@ -6165,14 +6176,6 @@ class BXRestNavvyRestCalendarEvent {
|
|
|
6165
6176
|
update: [$calendar, $event, $update],
|
|
6166
6177
|
};
|
|
6167
6178
|
this.Navvy = new Navvy();
|
|
6168
|
-
// /** Возвращает список событий календаря, всегда весь список, паганации в методе нет да и не нужна */
|
|
6169
|
-
// get(param: iBXRestCalendarEventGetParam) {
|
|
6170
|
-
// return this.Navvy.simple(
|
|
6171
|
-
// this.url.get,
|
|
6172
|
-
// param,
|
|
6173
|
-
// BXRestMapCalendarEvent.get
|
|
6174
|
-
// )
|
|
6175
|
-
// }
|
|
6176
6179
|
this.get = Object.assign(
|
|
6177
6180
|
/**
|
|
6178
6181
|
* Возвращает список событий календаря, всегда весь список, паганации в методе нет да и не нужна.
|
|
@@ -8070,12 +8073,8 @@ class BXRestNavvySocialNetWorkApiLiveFeedBlogPost {
|
|
|
8070
8073
|
}
|
|
8071
8074
|
}
|
|
8072
8075
|
|
|
8073
|
-
// import { Navvy } from '../../../services/navvy'
|
|
8074
|
-
// import { BXRestSocialNetWorkApiLiveFeed } from '../../../request/socialnetwork/api/livefeed'
|
|
8075
8076
|
class BXRestNavvySocialNetWorkApiLiveFeed {
|
|
8076
8077
|
constructor() {
|
|
8077
|
-
// private readonly contentView = new BXRestSocialNetWorkApiLiveFeed)
|
|
8078
|
-
// private readonly Navvy = new Navvy(this.contentView, null)
|
|
8079
8078
|
/**
|
|
8080
8079
|
* Сообщения Ленты новостей в социальной сети (`socialnetwork.api.liveFeed.blogPost.*`).
|
|
8081
8080
|
*/
|
|
@@ -19009,69 +19008,70 @@ class BXRestNavvyUserFieldType {
|
|
|
19009
19008
|
}
|
|
19010
19009
|
|
|
19011
19010
|
class BXRestNavvy {
|
|
19012
|
-
|
|
19013
|
-
|
|
19014
|
-
|
|
19015
|
-
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
|
|
19019
|
-
|
|
19020
|
-
|
|
19021
|
-
|
|
19022
|
-
|
|
19023
|
-
|
|
19024
|
-
|
|
19025
|
-
|
|
19026
|
-
|
|
19027
|
-
|
|
19028
|
-
|
|
19029
|
-
|
|
19030
|
-
|
|
19031
|
-
|
|
19032
|
-
|
|
19033
|
-
|
|
19034
|
-
|
|
19035
|
-
|
|
19036
|
-
|
|
19037
|
-
|
|
19038
|
-
|
|
19039
|
-
|
|
19040
|
-
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
19060
|
-
|
|
19061
|
-
|
|
19062
|
-
|
|
19063
|
-
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
19069
|
-
|
|
19070
|
-
|
|
19071
|
-
|
|
19072
|
-
|
|
19073
|
-
|
|
19074
|
-
|
|
19011
|
+
/**
|
|
19012
|
+
* @param settings Свои настройки клиента: адрес портала, способ авторизации,
|
|
19013
|
+
* заголовки. Все запросы этого клиента идут с ними, даже если глобальные
|
|
19014
|
+
* `BXRestSettings` позже изменятся. Так в одном процессе можно работать
|
|
19015
|
+
* с несколькими порталами. Без аргумента клиент работает с глобальными
|
|
19016
|
+
* `BXRestSettings`, как раньше.
|
|
19017
|
+
*/
|
|
19018
|
+
constructor(settings) {
|
|
19019
|
+
// Каждый HTTP-объект запоминает контекст в момент создания, поэтому все
|
|
19020
|
+
// разделы создаются, пока включён контекст клиента. Создание идёт в теле
|
|
19021
|
+
// конструктора, а не в инициализаторах полей: только так finally вернёт
|
|
19022
|
+
// прежний контекст, даже если какой-то раздел бросит исключение. Иначе
|
|
19023
|
+
// объекты, созданные приложением позже, ушли бы на портал этого клиента.
|
|
19024
|
+
const previous = enterContext(settings ? new BXRestContext(settings) : globalContext);
|
|
19025
|
+
try {
|
|
19026
|
+
this.ai = new BXRestNavvyAi();
|
|
19027
|
+
this.mailService = new BXRestNavvyMailService();
|
|
19028
|
+
this.messageService = new BXRestNavvyMessageService();
|
|
19029
|
+
this.userConsent = new BXRestNavvyUserConsent();
|
|
19030
|
+
this.telephony = new BXRestNavvyTelephony();
|
|
19031
|
+
this.vote = new BXRestNavvyVote();
|
|
19032
|
+
this.imConnector = new BXRestNavvyImConnector();
|
|
19033
|
+
this.entity = new BXRestNavvyEntity();
|
|
19034
|
+
this.biConnector = new BXRestNavvyBiConnector();
|
|
19035
|
+
this.voxImplant = new BXRestNavvyVoxImplant();
|
|
19036
|
+
this.mail = new BXRestNavvyMail();
|
|
19037
|
+
this.note = new BXRestNavvyNote();
|
|
19038
|
+
this.documentGenerator = new BXRestNavvyDocumentGenerator();
|
|
19039
|
+
this.imBot = new BXRestNavvyImBot();
|
|
19040
|
+
this.booking = new BXRestNavvyBooking();
|
|
19041
|
+
this.imOpenLines = new BXRestNavvyImOpenLines();
|
|
19042
|
+
this.landing = new BXRestNavvyLanding();
|
|
19043
|
+
this.catalog = new BXRestNavvyCatalog();
|
|
19044
|
+
this.sale = new BXRestNavvySale();
|
|
19045
|
+
this.sign = new BXRestNavvySign();
|
|
19046
|
+
this.eventLog = new BXRestNavvyEventLog();
|
|
19047
|
+
this.placement = new BXRestNavvyPlacement();
|
|
19048
|
+
this.userFieldType = new BXRestNavvyUserFieldType();
|
|
19049
|
+
this.user = new BXRestNavvyUser();
|
|
19050
|
+
this.lists = new BXRestNavvyLists();
|
|
19051
|
+
this.task = new BXRestNavvyTask();
|
|
19052
|
+
this.tasks = new BXRestNavvyTasks();
|
|
19053
|
+
this.disk = new BXRestNavvyDisk();
|
|
19054
|
+
this.bizProc = new BXRestNavvyBizProc();
|
|
19055
|
+
this.log = new BXRestNavvyLog();
|
|
19056
|
+
this.calendar = new BXRestNavvyCalendar();
|
|
19057
|
+
this.sonet_group = new BXRestNavvySonetGroup();
|
|
19058
|
+
this.server = new BXRestNavvyServer();
|
|
19059
|
+
this.department = new BXRestNavvyDepartment();
|
|
19060
|
+
this.im = new BXRestNavvyIm();
|
|
19061
|
+
this.app = new BXRestNavvyApp();
|
|
19062
|
+
this.timeMan = new BXRestNavvyTimeMan();
|
|
19063
|
+
this.socialNetWork = new BXRestNavvySocialNetWork();
|
|
19064
|
+
this.pull = new BXRestNavvyPull();
|
|
19065
|
+
this.crm = new BXRestNavvyCrm();
|
|
19066
|
+
this.event = new BXRestNavvyEvent();
|
|
19067
|
+
this.method = new BXRestNavvyMethod();
|
|
19068
|
+
this.access = new BXRestNavvyAccess();
|
|
19069
|
+
this.feature = new BXRestNavvyFeature();
|
|
19070
|
+
this.Navvy = new Navvy();
|
|
19071
|
+
}
|
|
19072
|
+
finally {
|
|
19073
|
+
restoreContext(previous);
|
|
19074
|
+
}
|
|
19075
19075
|
}
|
|
19076
19076
|
/**
|
|
19077
19077
|
* Возвращает базовую информацию о текущем пользователе без scope `user`.
|
|
@@ -19757,19 +19757,6 @@ function toRecord(value) {
|
|
|
19757
19757
|
: {};
|
|
19758
19758
|
}
|
|
19759
19759
|
|
|
19760
|
-
class HttpNavvyServices {
|
|
19761
|
-
constructor() {
|
|
19762
|
-
this.httpServices = new HttpBXServices();
|
|
19763
|
-
}
|
|
19764
|
-
// Реализация метода
|
|
19765
|
-
post(url, params) {
|
|
19766
|
-
if (params === undefined) {
|
|
19767
|
-
params = {};
|
|
19768
|
-
}
|
|
19769
|
-
return this.httpServices.post(url, params);
|
|
19770
|
-
}
|
|
19771
|
-
}
|
|
19772
|
-
|
|
19773
19760
|
/**
|
|
19774
19761
|
* Public API Surface of bx-rest
|
|
19775
19762
|
*/
|
|
@@ -19778,5 +19765,5 @@ class HttpNavvyServices {
|
|
|
19778
19765
|
* Generated bundle index. Do not edit.
|
|
19779
19766
|
*/
|
|
19780
19767
|
|
|
19781
|
-
export { base as BXBaseServices, BXRestApiError, BXRestFrame, BXRestFrameError, BXRestMap, BXRestMapResult, BXRestNavvy, HttpBXServices as BXRestRequest, BXRestSettings,
|
|
19768
|
+
export { base as BXBaseServices, BXRestApiError, BXRestFrame, BXRestFrameError, BXRestMap, BXRestMapResult, BXRestNavvy, HttpBXServices as BXRestRequest, BXRestSettings, BXRestTimeoutError, Navvy, SessionKeyError, SessionKeyServices, getAuthRefreshError, instanceOfiBXRestAnswerSuccess as isBXRestAnswerSuccess, isBXRestAuthError, partNameMethods$1 as partNameMethods };
|
|
19782
19769
|
//# sourceMappingURL=bx-rest.mjs.map
|